iris: implement border color, fix other sampler nonsense
authorKenneth Graunke <kenneth@whitecape.org>
Thu, 28 Jun 2018 09:25:25 +0000 (02:25 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 21 Feb 2019 18:26:07 +0000 (10:26 -0800)
src/gallium/drivers/iris/iris_border_color.c [new file with mode: 0644]
src/gallium/drivers/iris/iris_bufmgr.h
src/gallium/drivers/iris/iris_context.c
src/gallium/drivers/iris/iris_context.h
src/gallium/drivers/iris/iris_state.c
src/gallium/drivers/iris/meson.build

diff --git a/src/gallium/drivers/iris/iris_border_color.c b/src/gallium/drivers/iris/iris_border_color.c
new file mode 100644 (file)
index 0000000..03a698a
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright © 2018 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include "util/u_math.h"
+#include "iris_binder.h"
+#include "iris_bufmgr.h"
+#include "iris_context.h"
+
+#define BC_ALIGNMENT 64
+
+static bool
+color_equals(const void *a, const void *b)
+{
+   return memcmp(a, b, sizeof(union pipe_color_union)) == 0;
+}
+
+static uint32_t
+color_hash(const void *key)
+{
+   return _mesa_hash_data(key, sizeof(union pipe_color_union));
+}
+
+static void
+iris_reset_border_color_pool(struct iris_border_color_pool *pool,
+                             struct iris_bufmgr *bufmgr)
+{
+   _mesa_hash_table_clear(pool->ht, NULL);
+
+   iris_bo_unreference(pool->bo);
+
+   pool->bo = iris_bo_alloc(bufmgr, "border colors",
+                            IRIS_BORDER_COLOR_POOL_SIZE,
+                            IRIS_MEMZONE_BORDER_COLOR_POOL);
+   pool->map = iris_bo_map(NULL, pool->bo, MAP_WRITE);
+
+   /* Don't make 0 a valid offset - tools treat that as a NULL pointer. */
+   pool->insert_point = BC_ALIGNMENT;
+}
+
+void
+iris_init_border_color_pool(struct iris_context *ice)
+{
+   struct iris_screen *screen = (void *) ice->ctx.screen;
+   struct iris_bufmgr *bufmgr = screen->bufmgr;
+
+   struct iris_border_color_pool *pool = &ice->state.border_color_pool;
+
+   pool->bo = NULL;
+   pool->ht = _mesa_hash_table_create(ice, color_hash, color_equals);
+
+   iris_reset_border_color_pool(pool, bufmgr);
+}
+
+/**
+ * Reserve space for a number of border colors.  If no space, flushes any
+ * batches that are referring to the old BO and makes a new one.
+ */
+void
+iris_border_color_pool_reserve(struct iris_context *ice, unsigned count)
+{
+   struct iris_border_color_pool *pool = &ice->state.border_color_pool;
+   const unsigned remaining_entries =
+      (IRIS_BORDER_COLOR_POOL_SIZE - pool->insert_point) / BC_ALIGNMENT;
+
+   if (remaining_entries < count) {
+      if (iris_batch_references(&ice->render_batch, pool->bo))
+         iris_batch_flush(&ice->render_batch);
+
+      iris_reset_border_color_pool(pool, pool->bo->bufmgr);
+   }
+}
+
+/**
+ * Upload a border color (or use a cached version).
+ *
+ * Returns the offset into the border color pool BO.
+ */
+uint32_t
+iris_upload_border_color(struct iris_context *ice,
+                         union pipe_color_union *color)
+{
+   struct iris_border_color_pool *pool = &ice->state.border_color_pool;
+
+   uint32_t hash = color_hash(color);
+   struct hash_entry *entry =
+      _mesa_hash_table_search_pre_hashed(pool->ht, hash, color);
+   if (entry)
+      return (uintptr_t) entry->data;
+
+   assert(pool->insert_point + BC_ALIGNMENT < IRIS_BORDER_COLOR_POOL_SIZE);
+
+   uint32_t offset = pool->insert_point;
+   memcpy(pool->map + offset, color, sizeof(*color));
+   pool->insert_point += BC_ALIGNMENT;
+
+   _mesa_hash_table_insert_pre_hashed(pool->ht, hash, color,
+                                      (void *) (uintptr_t) offset);
+   return offset;
+}
+
index ffde367373181aa9fe35e4b6770254b13f5ec24e..b64dbee96b2f69134eea1cf9375f5c5ca56f002b 100644 (file)
@@ -59,7 +59,7 @@ struct pipe_debug_callback;
  *
  * A special buffer for border color lives at the start of the dynamic state
  * memory zone.  This unfortunately has to be handled specially because the
- * hardware designers only gave us 24-bit pointers.
+ * SAMPLER_STATE "Indirect State Pointer" field is only a 24-bit pointer.
  *
  * Each GL context uses a separate GEM context, which technically gives them
  * each a separate VMA.  However, we assign address globally, so buffers will
@@ -88,15 +88,11 @@ enum iris_memory_zone {
 #define IRIS_MEMZONE_DYNAMIC_START    (2ull * (1ull << 32))
 #define IRIS_MEMZONE_OTHER_START      (3ull * (1ull << 32))
 
-#define IRIS_BINDER_SIZE (64 * 1024)
 #define IRIS_BINDER_ADDRESS IRIS_MEMZONE_SURFACE_START
 #define IRIS_BINDER_SIZE (64 * 1024)
 
-/* This is large enough for every surface in the binder to have a border
- * color, which although unlikely, guarantees we'll never overflow.
- */
-#define IRIS_BORDER_COLOR_POOL_SIZE ((IRIS_BINDER_SIZE / 4) * 64)
 #define IRIS_BORDER_COLOR_POOL_ADDRESS IRIS_MEMZONE_DYNAMIC_START
+#define IRIS_BORDER_COLOR_POOL_SIZE (64 * 1024)
 
 struct iris_bo {
    /**
index 4812d7c3af8b6c26a756e6f2af6a91f24f22dbc9..155d3932cb68e21f805f15aa1a1e703cb22ab2ab 100644 (file)
@@ -136,6 +136,7 @@ iris_create_context(struct pipe_screen *pscreen, void *priv, unsigned flags)
    iris_init_query_functions(ctx);
 
    iris_init_program_cache(ice);
+   iris_init_border_color_pool(ice);
 
    ice->state.surface_uploader =
       u_upload_create(&ice->ctx, 16384, PIPE_BIND_CUSTOM, PIPE_USAGE_IMMUTABLE,
index 597dfc2806592ee7141275d6c3a383873a8d00c8..aa7449c0abad8dab6899860bfe5a7ad00accf525 100644 (file)
@@ -215,6 +215,15 @@ struct iris_vtable {
                            struct brw_wm_prog_key *key);
 };
 
+struct iris_border_color_pool {
+   struct iris_bo *bo;
+   void *map;
+   unsigned insert_point;
+
+   /** Map from border colors to offsets in the buffer. */
+   struct hash_table *ht;
+};
+
 struct iris_context {
    struct pipe_context ctx;
 
@@ -259,6 +268,7 @@ struct iris_context {
       struct iris_depth_buffer_state *cso_depthbuffer;
 
       struct iris_state_ref sampler_table[MESA_SHADER_STAGES];
+      bool need_border_colors;
       struct iris_sampler_state *samplers[MESA_SHADER_STAGES][IRIS_MAX_TEXTURE_SAMPLERS];
       struct iris_sampler_view *textures[MESA_SHADER_STAGES][IRIS_MAX_TEXTURE_SAMPLERS];
       unsigned num_samplers[MESA_SHADER_STAGES];
@@ -271,6 +281,8 @@ struct iris_context {
       // "I'm streaming this out at draw time and never want it again!"
       struct u_upload_mgr *dynamic_uploader;
 
+      struct iris_border_color_pool border_color_pool;
+
       /**
        * Resources containing streamed state which our render context
        * currently points to.  Used to re-add these to the validation
@@ -343,6 +355,13 @@ void iris_depth_cache_add_bo(struct iris_batch *batch, struct iris_bo *bo);
 void gen9_init_blorp(struct iris_context *ice);
 void gen10_init_blorp(struct iris_context *ice);
 
+/* iris_border_color.c */
+
+void iris_init_border_color_pool(struct iris_context *ice);
+void iris_border_color_pool_reserve(struct iris_context *ice, unsigned count);
+uint32_t iris_upload_border_color(struct iris_context *ice,
+                                  union pipe_color_union *color);
+
 /* iris_state.c */
 
 void gen9_init_state(struct iris_context *ice);
index 5bfab87a0ce5b3a6c024554fd99b558b0c0663a7..95116900bb688900d4480ca486ff30cb18c071e6 100644 (file)
@@ -786,7 +786,7 @@ struct iris_sampler_state {
 };
 
 static void *
-iris_create_sampler_state(struct pipe_context *pctx,
+iris_create_sampler_state(struct pipe_context *ctx,
                           const struct pipe_sampler_state *state)
 {
    struct iris_sampler_state *cso = CALLOC_STRUCT(iris_sampler_state);
@@ -794,6 +794,8 @@ iris_create_sampler_state(struct pipe_context *pctx,
    if (!cso)
       return NULL;
 
+   memcpy(&cso->base, state, sizeof(*state));
+
    STATIC_ASSERT(PIPE_TEX_FILTER_NEAREST == MAPFILTER_NEAREST);
    STATIC_ASSERT(PIPE_TEX_FILTER_LINEAR == MAPFILTER_LINEAR);
 
@@ -852,7 +854,7 @@ iris_create_sampler_state(struct pipe_context *pctx,
       samp.MaxLOD = CLAMP(state->max_lod, 0, hw_max_lod);
       samp.TextureLODBias = CLAMP(state->lod_bias, -16, 15);
 
-      //samp.BorderColorPointer = <<comes from elsewhere>>
+      /* .BorderColorPointer is filled in by iris_bind_sampler_states. */
    }
 
    return cso;
@@ -868,9 +870,16 @@ iris_bind_sampler_states(struct pipe_context *ctx,
    gl_shader_stage stage = stage_from_pipe(p_stage);
 
    assert(start + count <= IRIS_MAX_TEXTURE_SAMPLERS);
+   ice->state.num_samplers[stage] =
+      MAX2(ice->state.num_samplers[stage], start + count);
+
+   for (int i = 0; i < count; i++) {
+      ice->state.samplers[stage][start + i] = states[i];
+   }
 
-   /* Assemble the SAMPLER_STATEs into a contiguous chunk of memory
-    * relative to Dynamic State Base Address.
+   /* Assemble the SAMPLER_STATEs into a contiguous table that lives
+    * in the dynamic state memory zone, so we can point to it via the
+    * 3DSTATE_SAMPLER_STATE_POINTERS_* commands.
     */
    void *map = upload_state(ice->state.dynamic_uploader,
                             &ice->state.sampler_table[stage],
@@ -882,22 +891,40 @@ iris_bind_sampler_states(struct pipe_context *ctx,
    ice->state.sampler_table[stage].offset +=
       iris_bo_offset_from_base_address(iris_resource_bo(res));
 
+   /* Make sure all land in the same BO */
+   iris_border_color_pool_reserve(ice, IRIS_MAX_TEXTURE_SAMPLERS);
+
    for (int i = 0; i < count; i++) {
-      struct iris_sampler_state *state = states[i];
+      struct iris_sampler_state *state = ice->state.samplers[stage][i];
 
       /* Save a pointer to the iris_sampler_state, a few fields need
        * to inform draw-time decisions.
        */
       ice->state.samplers[stage][start + i] = state;
 
-      if (state)
+      if (!state) {
+         memset(map, 0, 4 * GENX(SAMPLER_STATE_length));
+      } else if (!state->needs_border_color) {
          memcpy(map, state->sampler_state, 4 * GENX(SAMPLER_STATE_length));
+      } else {
+         ice->state.need_border_colors = true;
+
+         /* Stream out the border color and merge the pointer. */
+         uint32_t offset =
+            iris_upload_border_color(ice, &state->base.border_color);
+
+         uint32_t dynamic[GENX(SAMPLER_STATE_length)];
+         iris_pack_state(GENX(SAMPLER_STATE), dynamic, dyns) {
+            dyns.BorderColorPointer = offset;
+         }
+
+         for (uint32_t j = 0; j < GENX(SAMPLER_STATE_length); j++)
+            ((uint32_t *) map)[j] = state->sampler_state[j] | dynamic[j];
+      }
 
       map += GENX(SAMPLER_STATE_length);
    }
 
-   ice->state.num_samplers[stage] = count;
-
    ice->state.dirty |= IRIS_DIRTY_SAMPLER_STATES_VS << stage;
 }
 
@@ -2602,6 +2629,9 @@ iris_upload_render_state(struct iris_context *ice,
       }
    }
 
+   if (ice->state.need_border_colors)
+      iris_use_pinned_bo(batch, ice->state.border_color_pool.bo, false);
+
    for (int stage = 0; stage <= MESA_SHADER_FRAGMENT; stage++) {
       if (!(dirty & (IRIS_DIRTY_SAMPLER_STATES_VS << stage)) ||
           !ice->shaders.prog[stage])
index d09e2d546f56acc637de9e92d3bc6bf3d06f1d9e..18a45f418f0fbdf04e54945c96d93f9ab1114798 100644 (file)
@@ -24,6 +24,7 @@ files_libiris = files(
   'iris_binder.c',
   'iris_binder.h',
   'iris_blit.c',
+  'iris_border_color.c',
   'iris_bufmgr.c',
   'iris_bufmgr.h',
   'iris_clear.c',