From ccec5bab5b6cb1b6c71d10527f4e75429d225d31 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Thu, 28 Jun 2018 02:25:25 -0700 Subject: [PATCH] iris: implement border color, fix other sampler nonsense --- src/gallium/drivers/iris/iris_border_color.c | 121 +++++++++++++++++++ src/gallium/drivers/iris/iris_bufmgr.h | 8 +- src/gallium/drivers/iris/iris_context.c | 1 + src/gallium/drivers/iris/iris_context.h | 19 +++ src/gallium/drivers/iris/iris_state.c | 46 +++++-- src/gallium/drivers/iris/meson.build | 1 + 6 files changed, 182 insertions(+), 14 deletions(-) create mode 100644 src/gallium/drivers/iris/iris_border_color.c diff --git a/src/gallium/drivers/iris/iris_border_color.c b/src/gallium/drivers/iris/iris_border_color.c new file mode 100644 index 00000000000..03a698a9c6e --- /dev/null +++ b/src/gallium/drivers/iris/iris_border_color.c @@ -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 +#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; +} + diff --git a/src/gallium/drivers/iris/iris_bufmgr.h b/src/gallium/drivers/iris/iris_bufmgr.h index ffde3673731..b64dbee96b2 100644 --- a/src/gallium/drivers/iris/iris_bufmgr.h +++ b/src/gallium/drivers/iris/iris_bufmgr.h @@ -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 { /** diff --git a/src/gallium/drivers/iris/iris_context.c b/src/gallium/drivers/iris/iris_context.c index 4812d7c3af8..155d3932cb6 100644 --- a/src/gallium/drivers/iris/iris_context.c +++ b/src/gallium/drivers/iris/iris_context.c @@ -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, diff --git a/src/gallium/drivers/iris/iris_context.h b/src/gallium/drivers/iris/iris_context.h index 597dfc28065..aa7449c0aba 100644 --- a/src/gallium/drivers/iris/iris_context.h +++ b/src/gallium/drivers/iris/iris_context.h @@ -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); diff --git a/src/gallium/drivers/iris/iris_state.c b/src/gallium/drivers/iris/iris_state.c index 5bfab87a0ce..95116900bb6 100644 --- a/src/gallium/drivers/iris/iris_state.c +++ b/src/gallium/drivers/iris/iris_state.c @@ -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 = <> + /* .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]) diff --git a/src/gallium/drivers/iris/meson.build b/src/gallium/drivers/iris/meson.build index d09e2d546f5..18a45f418f0 100644 --- a/src/gallium/drivers/iris/meson.build +++ b/src/gallium/drivers/iris/meson.build @@ -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', -- 2.30.2