1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2018 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
12bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
21bf215546Sopenharmony_ci */
22bf215546Sopenharmony_ci
23bf215546Sopenharmony_ci/**
24bf215546Sopenharmony_ci * @file iris_binder.c
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci * Shader programs refer to most resources via integer handles.  These are
27bf215546Sopenharmony_ci * indexes (BTIs) into a "Binding Table", which is simply a list of pointers
28bf215546Sopenharmony_ci * to SURFACE_STATE entries.  Each shader stage has its own binding table,
29bf215546Sopenharmony_ci * set by the 3DSTATE_BINDING_TABLE_POINTERS_* commands.  We stream out
30bf215546Sopenharmony_ci * binding tables dynamically, storing them in special BOs we call "binders."
31bf215546Sopenharmony_ci *
32bf215546Sopenharmony_ci * Unfortunately, the hardware designers made 3DSTATE_BINDING_TABLE_POINTERS
33bf215546Sopenharmony_ci * only accept a 16-bit pointer.  This means that all binding tables have to
34bf215546Sopenharmony_ci * live within the 64kB range starting at Surface State Base Address.  (The
35bf215546Sopenharmony_ci * actual SURFACE_STATE entries can live anywhere in the 4GB zone, as the
36bf215546Sopenharmony_ci * binding table entries are full 32-bit pointers.)
37bf215546Sopenharmony_ci *
38bf215546Sopenharmony_ci * To handle this, we split a 4GB region of VMA into two memory zones.
39bf215546Sopenharmony_ci * IRIS_MEMZONE_BINDER is a 1GB region at the bottom able to hold a few
40bf215546Sopenharmony_ci * binder BOs.  IRIS_MEMZONE_SURFACE contains the rest of the 4GB, and is
41bf215546Sopenharmony_ci * always at a higher address than the binders.  This allows us to program
42bf215546Sopenharmony_ci * Surface State Base Address to the binder BO's address, and offset the
43bf215546Sopenharmony_ci * values in the binding table to account for the base not starting at the
44bf215546Sopenharmony_ci * beginning of the 4GB region.
45bf215546Sopenharmony_ci *
46bf215546Sopenharmony_ci * This does mean that we have to emit STATE_BASE_ADDRESS and stall when
47bf215546Sopenharmony_ci * we run out of space in the binder, which hopefully won't happen too often.
48bf215546Sopenharmony_ci */
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci#include <stdlib.h>
51bf215546Sopenharmony_ci#include "util/u_math.h"
52bf215546Sopenharmony_ci#include "iris_binder.h"
53bf215546Sopenharmony_ci#include "iris_bufmgr.h"
54bf215546Sopenharmony_ci#include "iris_context.h"
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_cistatic bool
57bf215546Sopenharmony_cibinder_has_space(struct iris_binder *binder, unsigned size)
58bf215546Sopenharmony_ci{
59bf215546Sopenharmony_ci   return binder->insert_point + size <= binder->size;
60bf215546Sopenharmony_ci}
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_cistatic void
63bf215546Sopenharmony_cibinder_realloc(struct iris_context *ice)
64bf215546Sopenharmony_ci{
65bf215546Sopenharmony_ci   struct iris_screen *screen = (void *) ice->ctx.screen;
66bf215546Sopenharmony_ci   struct iris_bufmgr *bufmgr = screen->bufmgr;
67bf215546Sopenharmony_ci   struct iris_binder *binder = &ice->state.binder;
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci   if (binder->bo)
70bf215546Sopenharmony_ci      iris_bo_unreference(binder->bo);
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci   binder->bo = iris_bo_alloc(bufmgr, "binder", binder->size, binder->alignment,
73bf215546Sopenharmony_ci                              IRIS_MEMZONE_BINDER, 4096);
74bf215546Sopenharmony_ci   binder->map = iris_bo_map(NULL, binder->bo, MAP_WRITE);
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   /* Avoid using offset 0 - tools consider it NULL. */
77bf215546Sopenharmony_ci   binder->insert_point = binder->alignment;
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci   /* Allocating a new binder requires changing Surface State Base Address,
80bf215546Sopenharmony_ci    * which also invalidates all our previous binding tables - each entry
81bf215546Sopenharmony_ci    * in those tables is an offset from the old base.
82bf215546Sopenharmony_ci    *
83bf215546Sopenharmony_ci    * We do this here so that iris_binder_reserve_3d correctly gets a new
84bf215546Sopenharmony_ci    * larger total_size when making the updated reservation.
85bf215546Sopenharmony_ci    *
86bf215546Sopenharmony_ci    * Gfx11+ simply updates the binding table pool address instead, which
87bf215546Sopenharmony_ci    * means the old binding table's contents are still valid.  Nevertheless,
88bf215546Sopenharmony_ci    * it still lives in the old BO, so we'd at least need to copy it to the
89bf215546Sopenharmony_ci    * new one.  Instead, we just flag it dirty and re-emit it anyway.
90bf215546Sopenharmony_ci    */
91bf215546Sopenharmony_ci   ice->state.dirty |= IRIS_DIRTY_RENDER_BUFFER;
92bf215546Sopenharmony_ci   ice->state.stage_dirty |= IRIS_ALL_STAGE_DIRTY_BINDINGS;
93bf215546Sopenharmony_ci}
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_cistatic uint32_t
96bf215546Sopenharmony_cibinder_insert(struct iris_binder *binder, unsigned size)
97bf215546Sopenharmony_ci{
98bf215546Sopenharmony_ci   uint32_t offset = binder->insert_point;
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci   binder->insert_point =
101bf215546Sopenharmony_ci      align(binder->insert_point + size, binder->alignment);
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci   return offset;
104bf215546Sopenharmony_ci}
105bf215546Sopenharmony_ci
106bf215546Sopenharmony_ci/**
107bf215546Sopenharmony_ci * Reserve a block of space in the binder, given the raw size in bytes.
108bf215546Sopenharmony_ci */
109bf215546Sopenharmony_ciuint32_t
110bf215546Sopenharmony_ciiris_binder_reserve(struct iris_context *ice,
111bf215546Sopenharmony_ci                    unsigned size)
112bf215546Sopenharmony_ci{
113bf215546Sopenharmony_ci   struct iris_binder *binder = &ice->state.binder;
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci   if (!binder_has_space(binder, size))
116bf215546Sopenharmony_ci      binder_realloc(ice);
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   assert(size > 0);
119bf215546Sopenharmony_ci   return binder_insert(binder, size);
120bf215546Sopenharmony_ci}
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci/**
123bf215546Sopenharmony_ci * Reserve and record binder space for 3D pipeline shader stages.
124bf215546Sopenharmony_ci *
125bf215546Sopenharmony_ci * Note that you must actually populate the new binding tables after
126bf215546Sopenharmony_ci * calling this command - the new area is uninitialized.
127bf215546Sopenharmony_ci */
128bf215546Sopenharmony_civoid
129bf215546Sopenharmony_ciiris_binder_reserve_3d(struct iris_context *ice)
130bf215546Sopenharmony_ci{
131bf215546Sopenharmony_ci   struct iris_compiled_shader **shaders = ice->shaders.prog;
132bf215546Sopenharmony_ci   struct iris_binder *binder = &ice->state.binder;
133bf215546Sopenharmony_ci   unsigned sizes[MESA_SHADER_STAGES] = {};
134bf215546Sopenharmony_ci   unsigned total_size;
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   /* If nothing is dirty, skip all this. */
137bf215546Sopenharmony_ci   if (!(ice->state.dirty & IRIS_DIRTY_RENDER_BUFFER) &&
138bf215546Sopenharmony_ci       !(ice->state.stage_dirty & IRIS_ALL_STAGE_DIRTY_BINDINGS_FOR_RENDER))
139bf215546Sopenharmony_ci      return;
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   /* Get the binding table sizes for each stage */
142bf215546Sopenharmony_ci   for (int stage = 0; stage <= MESA_SHADER_FRAGMENT; stage++) {
143bf215546Sopenharmony_ci      if (!shaders[stage])
144bf215546Sopenharmony_ci         continue;
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci      /* Round up the size so our next table has an aligned starting offset */
147bf215546Sopenharmony_ci      sizes[stage] = align(shaders[stage]->bt.size_bytes, binder->alignment);
148bf215546Sopenharmony_ci   }
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci   /* Make space for the new binding tables...this may take two tries. */
151bf215546Sopenharmony_ci   while (true) {
152bf215546Sopenharmony_ci      total_size = 0;
153bf215546Sopenharmony_ci      for (int stage = 0; stage <= MESA_SHADER_FRAGMENT; stage++) {
154bf215546Sopenharmony_ci         if (ice->state.stage_dirty & (IRIS_STAGE_DIRTY_BINDINGS_VS << stage))
155bf215546Sopenharmony_ci            total_size += sizes[stage];
156bf215546Sopenharmony_ci      }
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci      assert(total_size < binder->size);
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci      if (total_size == 0)
161bf215546Sopenharmony_ci         return;
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci      if (binder_has_space(binder, total_size))
164bf215546Sopenharmony_ci         break;
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci      /* It didn't fit.  Allocate a new buffer and try again.  Note that
167bf215546Sopenharmony_ci       * this will flag all bindings dirty, which may increase total_size
168bf215546Sopenharmony_ci       * on the next iteration.
169bf215546Sopenharmony_ci       */
170bf215546Sopenharmony_ci      binder_realloc(ice);
171bf215546Sopenharmony_ci   }
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   /* Assign space and record the new binding table offsets. */
174bf215546Sopenharmony_ci   uint32_t offset = binder_insert(binder, total_size);
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_ci   for (int stage = 0; stage <= MESA_SHADER_FRAGMENT; stage++) {
177bf215546Sopenharmony_ci      if (ice->state.stage_dirty & (IRIS_STAGE_DIRTY_BINDINGS_VS << stage)) {
178bf215546Sopenharmony_ci         binder->bt_offset[stage] = sizes[stage] > 0 ? offset : 0;
179bf215546Sopenharmony_ci         iris_record_state_size(ice->state.sizes,
180bf215546Sopenharmony_ci                                binder->bo->address + offset, sizes[stage]);
181bf215546Sopenharmony_ci         offset += sizes[stage];
182bf215546Sopenharmony_ci      }
183bf215546Sopenharmony_ci   }
184bf215546Sopenharmony_ci}
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_civoid
187bf215546Sopenharmony_ciiris_binder_reserve_compute(struct iris_context *ice)
188bf215546Sopenharmony_ci{
189bf215546Sopenharmony_ci   if (!(ice->state.stage_dirty & IRIS_STAGE_DIRTY_BINDINGS_CS))
190bf215546Sopenharmony_ci      return;
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_ci   struct iris_binder *binder = &ice->state.binder;
193bf215546Sopenharmony_ci   struct iris_compiled_shader *shader =
194bf215546Sopenharmony_ci      ice->shaders.prog[MESA_SHADER_COMPUTE];
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci   unsigned size = shader->bt.size_bytes;
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci   if (size == 0)
199bf215546Sopenharmony_ci      return;
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   binder->bt_offset[MESA_SHADER_COMPUTE] = iris_binder_reserve(ice, size);
202bf215546Sopenharmony_ci}
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_civoid
205bf215546Sopenharmony_ciiris_init_binder(struct iris_context *ice)
206bf215546Sopenharmony_ci{
207bf215546Sopenharmony_ci   struct iris_screen *screen = (void *) ice->ctx.screen;
208bf215546Sopenharmony_ci   const struct intel_device_info *devinfo = &screen->devinfo;
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci   memset(&ice->state.binder, 0, sizeof(struct iris_binder));
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci   /* We use different binding table pointer formats on various generations.
213bf215546Sopenharmony_ci    *
214bf215546Sopenharmony_ci    * - The 20:5 format gives us an alignment of 32B and max size of 1024kB.
215bf215546Sopenharmony_ci    * - The 18:8 format gives us an alignment of 256B and max size of 512kB.
216bf215546Sopenharmony_ci    * - The 15:5 format gives us an alignment of 32B and max size of 64kB.
217bf215546Sopenharmony_ci    *
218bf215546Sopenharmony_ci    * XeHP and later use the 20:5 format.  Icelake and Tigerlake use 18:8
219bf215546Sopenharmony_ci    * in iris, but can use 15:5 if desired,  Older platforms require 15:5.
220bf215546Sopenharmony_ci    */
221bf215546Sopenharmony_ci   if (devinfo->verx10 >= 125) {
222bf215546Sopenharmony_ci      ice->state.binder.alignment = 32;
223bf215546Sopenharmony_ci      ice->state.binder.size = 1024 * 1024;
224bf215546Sopenharmony_ci   } else if (devinfo->ver >= 11) {
225bf215546Sopenharmony_ci      ice->state.binder.alignment = 256;
226bf215546Sopenharmony_ci      ice->state.binder.size = 512 * 1024;
227bf215546Sopenharmony_ci   } else {
228bf215546Sopenharmony_ci      ice->state.binder.alignment = 32;
229bf215546Sopenharmony_ci      ice->state.binder.size = 64 * 1024;
230bf215546Sopenharmony_ci   }
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   binder_realloc(ice);
233bf215546Sopenharmony_ci}
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_civoid
236bf215546Sopenharmony_ciiris_destroy_binder(struct iris_binder *binder)
237bf215546Sopenharmony_ci{
238bf215546Sopenharmony_ci   iris_bo_unreference(binder->bo);
239bf215546Sopenharmony_ci}
240