--- /dev/null
+/*
+ * 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;
+}
+
*
* 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
#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 {
/**
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,
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;
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];
// "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
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);
};
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);
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);
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;
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],
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;
}
}
}
+ 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])
'iris_binder.c',
'iris_binder.h',
'iris_blit.c',
+ 'iris_border_color.c',
'iris_bufmgr.c',
'iris_bufmgr.h',
'iris_clear.c',