From 060a2c52fa1d6eb750964aa4bc75680d03911b26 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Thu, 14 Nov 2019 17:17:43 -0800 Subject: [PATCH] iris: Maintain CPU-side SURFACE_STATE copies for views and surfaces. When replacing the backing storage for texture buffers, image buffers, and so on, we may need to update the "Surface Base Address" field in any corresponding SURFACE_STATE. This is easier to accomplish if we have a copy on the CPU - we can just compare the current field, update it, and re-upload. This patch adds a CPU-side copy to the new iris_surface_state wrapper struct, and reworks allocation and upload to fill things out on the CPU copy first, then upload that to the GPU when finished. This will be necessary to fix iris_invalidate_resource bugs shortly. Technically, we never replace the backing storage for pipe_surfaces (render targets), so we don't need to make this change there. However, it's nice to have surfaces, sampler views, and image views handled similarly. Plus, if we ever wanted to swap out backing storage for busy textures, we'd need this infrastructure. v2: Properly free memory (caught by Andrii Simiklit) --- src/gallium/drivers/iris/iris_resource.h | 19 +++ src/gallium/drivers/iris/iris_state.c | 172 +++++++++++++++-------- 2 files changed, 136 insertions(+), 55 deletions(-) diff --git a/src/gallium/drivers/iris/iris_resource.h b/src/gallium/drivers/iris/iris_resource.h index 4eac653bd3a..f477daa946f 100644 --- a/src/gallium/drivers/iris/iris_resource.h +++ b/src/gallium/drivers/iris/iris_resource.h @@ -183,6 +183,25 @@ struct iris_state_ref { * The SURFACE_STATE descriptors for a resource. */ struct iris_surface_state { + /** + * CPU-side copy of the packed SURFACE_STATE structures, already + * aligned so they can be uploaded as a contiguous pile of bytes. + * + * This can be updated and re-uploaded if (e.g.) addresses need to change. + */ + uint32_t *cpu; + + /** + * How many states are there? (Each aux mode has its own state.) + */ + unsigned num_states; + + /** + * Address of the resource (res->bo->gtt_offset). Note that "Surface + * Base Address" may be offset from this value. + */ + uint64_t bo_address; + /** A reference to the GPU buffer holding our uploaded SURFACE_STATE */ struct iris_state_ref ref; }; diff --git a/src/gallium/drivers/iris/iris_state.c b/src/gallium/drivers/iris/iris_state.c index 8336e33e744..2a1e53d9643 100644 --- a/src/gallium/drivers/iris/iris_state.c +++ b/src/gallium/drivers/iris/iris_state.c @@ -2105,11 +2105,11 @@ fill_buffer_surface_state(struct isl_device *isl_dev, /** * Allocate several contiguous SURFACE_STATE structures, one for each - * supported auxiliary surface mode. + * supported auxiliary surface mode. This only allocates the CPU-side + * copy, they will need to be uploaded later after they're filled in. */ -static void * -alloc_surface_states(struct u_upload_mgr *mgr, - struct iris_state_ref *ref, +static void +alloc_surface_states(struct iris_surface_state *surf_state, unsigned aux_usages) { const unsigned surf_size = 4 * GENX(RENDER_SURFACE_STATE_length); @@ -2119,13 +2119,68 @@ alloc_surface_states(struct u_upload_mgr *mgr, assert(aux_usages != 0); + /* In case we're re-allocating them... */ + free(surf_state->cpu); + + surf_state->num_states = util_bitcount(aux_usages); + surf_state->cpu = calloc(surf_state->num_states, surf_size); + surf_state->ref.offset = 0; + pipe_resource_reference(&surf_state->ref.res, NULL); + + assert(surf_state->cpu); +} + +/** + * Upload the CPU side SURFACE_STATEs into a GPU buffer. + */ +static void +upload_surface_states(struct u_upload_mgr *mgr, + struct iris_surface_state *surf_state) +{ + const unsigned surf_size = 4 * GENX(RENDER_SURFACE_STATE_length); + const unsigned bytes = surf_state->num_states * surf_size; + void *map = - upload_state(mgr, ref, util_bitcount(aux_usages) * surf_size, - SURFACE_STATE_ALIGNMENT); + upload_state(mgr, &surf_state->ref, bytes, SURFACE_STATE_ALIGNMENT); - ref->offset += iris_bo_offset_from_base_address(iris_resource_bo(ref->res)); + surf_state->ref.offset += + iris_bo_offset_from_base_address(iris_resource_bo(surf_state->ref.res)); - return map; + if (map) + memcpy(map, surf_state->cpu, bytes); +} + +/** + * Update resource addresses in a set of SURFACE_STATE descriptors, + * and re-upload them if necessary. + */ +static bool +update_surface_state_addrs(struct u_upload_mgr *mgr, + struct iris_surface_state *surf_state, + struct iris_bo *bo) +{ + if (surf_state->bo_address == bo->gtt_offset) + return false; + + STATIC_ASSERT(GENX(RENDER_SURFACE_STATE_SurfaceBaseAddress_start) % 64 == 0); + STATIC_ASSERT(GENX(RENDER_SURFACE_STATE_SurfaceBaseAddress_bits) == 64); + + uint64_t *ss_addr = (uint64_t *) &surf_state->cpu[GENX(RENDER_SURFACE_STATE_SurfaceBaseAddress_start) / 32]; + + /* First, update the CPU copies. We assume no other fields exist in + * the QWord containing Surface Base Address. + */ + for (unsigned i = 0; i < surf_state->num_states; i++) { + *ss_addr = *ss_addr - surf_state->bo_address + bo->gtt_offset; + ss_addr = ((void *) ss_addr) + SURFACE_STATE_ALIGNMENT; + } + + /* Next, upload the updated copies to a GPU buffer. */ + upload_surface_states(mgr, surf_state); + + surf_state->bo_address = bo->gtt_offset; + + return true; } #if GEN_GEN == 8 @@ -2263,11 +2318,9 @@ iris_create_sampler_view(struct pipe_context *ctx, isv->res = (struct iris_resource *) tex; - void *map = alloc_surface_states(ice->state.surface_uploader, - &isv->surface_state.ref, - isv->res->aux.sampler_usages); - if (!unlikely(map)) - return NULL; + alloc_surface_states(&isv->surface_state, isv->res->aux.sampler_usages); + + isv->surface_state.bo_address = isv->res->bo->gtt_offset; isl_surf_usage_flags_t usage = ISL_SURF_USAGE_TEXTURE_BIT; @@ -2291,6 +2344,8 @@ iris_create_sampler_view(struct pipe_context *ctx, .usage = usage, }; + void *map = isv->surface_state.cpu; + /* Fill out SURFACE_STATE for this view. */ if (tmpl->target != PIPE_BUFFER) { isv->view.base_level = tmpl->u.tex.first_level; @@ -2321,6 +2376,8 @@ iris_create_sampler_view(struct pipe_context *ctx, tmpl->u.buf.offset, tmpl->u.buf.size); } + upload_surface_states(ice->state.surface_uploader, &isv->surface_state); + return &isv->base; } @@ -2331,6 +2388,7 @@ iris_sampler_view_destroy(struct pipe_context *ctx, struct iris_sampler_view *isv = (void *) state; pipe_resource_reference(&state->texture, NULL); pipe_resource_reference(&isv->surface_state.ref.res, NULL); + free(isv->surface_state.cpu); free(isv); } @@ -2426,28 +2484,21 @@ iris_create_surface(struct pipe_context *ctx, return psurf; - void *map = alloc_surface_states(ice->state.surface_uploader, - &surf->surface_state.ref, - res->aux.possible_usages); - if (!unlikely(map)) { - pipe_resource_reference(&surf->surface_state.ref.res, NULL); - return NULL; - } + alloc_surface_states(&surf->surface_state, res->aux.possible_usages); + surf->surface_state.bo_address = res->bo->gtt_offset; #if GEN_GEN == 8 - void *map_read = alloc_surface_states(ice->state.surface_uploader, - &surf->surface_state_read.ref, - res->aux.possible_usages); - if (!unlikely(map_read)) { - pipe_resource_reference(&surf->surface_state_read.ref.res, NULL); - return NULL; - } + alloc_surface_states(&surf->surface_state_read, res->aux.possible_usages); + surf->surface_state_read.bo_address = res->bo->gtt_offset; #endif if (!isl_format_is_compressed(res->surf.format)) { if (iris_resource_unfinished_aux_import(res)) iris_resource_finish_aux_import(&screen->base, res); + void *map = surf->surface_state.cpu; + UNUSED void *map_read = surf->surface_state_read.cpu; + /* This is a normal surface. Fill out a SURFACE_STATE for each possible * auxiliary surface mode and return the pipe_surface. */ @@ -2469,6 +2520,13 @@ iris_create_surface(struct pipe_context *ctx, #endif } + upload_surface_states(ice->state.surface_uploader, &surf->surface_state); + +#if GEN_GEN == 8 + upload_surface_states(ice->state.surface_uploader, + &surf->surface_state_read); +#endif + return psurf; } @@ -2547,7 +2605,10 @@ iris_create_surface(struct pipe_context *ctx, .y_offset_sa = tile_y_sa, }; - isl_surf_fill_state_s(&screen->isl_dev, map, &f); + isl_surf_fill_state_s(&screen->isl_dev, surf->surface_state.cpu, &f); + + upload_surface_states(ice->state.surface_uploader, &surf->surface_state); + return psurf; } @@ -2609,12 +2670,6 @@ iris_set_shader_images(struct pipe_context *ctx, const struct pipe_image_view *img = &p_images[i]; struct iris_resource *res = (void *) img->resource; - void *map = - alloc_surface_states(ice->state.surface_uploader, - &iv->surface_state.ref, 1 << ISL_AUX_USAGE_NONE); - if (!unlikely(map)) - return; - util_copy_image_view(&iv->base, img); shs->bound_image_views |= 1 << (start_slot + i); @@ -2642,6 +2697,11 @@ iris_set_shader_images(struct pipe_context *ctx, isl_fmt = isl_lower_storage_image_format(devinfo, isl_fmt); } + alloc_surface_states(&iv->surface_state, 1 << ISL_AUX_USAGE_NONE); + iv->surface_state.bo_address = res->bo->gtt_offset; + + void *map = iv->surface_state.cpu; + if (res->base.target != PIPE_BUFFER) { struct isl_view view = { .format = isl_fmt, @@ -2683,6 +2743,8 @@ iris_set_shader_images(struct pipe_context *ctx, fill_buffer_image_param(&image_params[start_slot + i], img->format, img->u.buf.size); } + + upload_surface_states(ice->state.surface_uploader, &iv->surface_state); } else { pipe_resource_reference(&iv->base.resource, NULL); pipe_resource_reference(&iv->surface_state.ref.res, NULL); @@ -2762,6 +2824,7 @@ iris_surface_destroy(struct pipe_context *ctx, struct pipe_surface *p_surf) pipe_resource_reference(&p_surf->texture, NULL); pipe_resource_reference(&surf->surface_state.ref.res, NULL); pipe_resource_reference(&surf->surface_state_read.ref.res, NULL); + free(surf->surface_state.cpu); free(surf); } @@ -4437,7 +4500,7 @@ static void update_clear_value(struct iris_context *ice, struct iris_batch *batch, struct iris_resource *res, - struct iris_state_ref *state, + struct iris_surface_state *surf_state, unsigned all_aux_modes, struct isl_view *view) { @@ -4454,20 +4517,23 @@ update_clear_value(struct iris_context *ice, while (aux_modes) { enum isl_aux_usage aux_usage = u_bit_scan(&aux_modes); - surf_state_update_clear_value(batch, res, state, all_aux_modes, - aux_usage); + surf_state_update_clear_value(batch, res, &surf_state->ref, + all_aux_modes, aux_usage); } #elif GEN_GEN == 8 - pipe_resource_reference(&state->res, NULL); + /* TODO: Could update rather than re-filling */ + alloc_surface_states(surf_state, all_aux_modes); + + void *map = surf_state->cpu; - void *map = alloc_surface_states(ice->state.surface_uploader, - state, all_aux_modes); while (aux_modes) { enum isl_aux_usage aux_usage = u_bit_scan(&aux_modes); fill_surface_state(isl_dev, map, res, &res->surf, view, aux_usage, 0, 0, 0); map += SURFACE_STATE_ALIGNMENT; } + + upload_surface_states(ice->state.surface_uploader, surf_state); #endif } @@ -4503,10 +4569,10 @@ use_surface(struct iris_context *ice, if (memcmp(&res->aux.clear_color, &surf->clear_color, sizeof(surf->clear_color)) != 0) { - update_clear_value(ice, batch, res, &surf->surface_state.ref, + update_clear_value(ice, batch, res, &surf->surface_state, res->aux.possible_usages, &surf->view); if (GEN_GEN == 8) { - update_clear_value(ice, batch, res, &surf->surface_state_read.ref, + update_clear_value(ice, batch, res, &surf->surface_state_read, res->aux.possible_usages, &surf->read_view); } surf->clear_color = res->aux.clear_color; @@ -4539,7 +4605,7 @@ use_sampler_view(struct iris_context *ice, iris_use_pinned_bo(batch, isv->res->aux.clear_color_bo, false); if (memcmp(&isv->res->aux.clear_color, &isv->clear_color, sizeof(isv->clear_color)) != 0) { - update_clear_value(ice, batch, isv->res, &isv->surface_state.ref, + update_clear_value(ice, batch, isv->res, &isv->surface_state, isv->res->aux.sampler_usages, &isv->view); isv->clear_color = isv->res->aux.clear_color; } @@ -6338,6 +6404,7 @@ iris_destroy_state(struct iris_context *ice) for (int i = 0; i < PIPE_MAX_SHADER_IMAGES; i++) { pipe_resource_reference(&shs->image[i].base.resource, NULL); pipe_resource_reference(&shs->image[i].surface_state.ref.res, NULL); + free(shs->image[i].surface_state.cpu); } for (int i = 0; i < PIPE_MAX_SHADER_BUFFERS; i++) { pipe_resource_reference(&shs->ssbo[i].buffer, NULL); @@ -6372,7 +6439,6 @@ iris_rebind_buffer(struct iris_context *ice, struct iris_resource *res) { struct pipe_context *ctx = &ice->ctx; - struct iris_screen *screen = (void *) ctx->screen; struct iris_genx_state *genx = ice->state.genx; assert(res->base.target == PIPE_BUFFER); @@ -6465,16 +6531,10 @@ iris_rebind_buffer(struct iris_context *ice, while (bound_sampler_views) { const int i = u_bit_scan(&bound_sampler_views); struct iris_sampler_view *isv = shs->textures[i]; + struct iris_bo *bo = isv->res->bo; - if (res->bo == iris_resource_bo(isv->base.texture)) { - void *map = alloc_surface_states(ice->state.surface_uploader, - &isv->surface_state.ref, - isv->res->aux.sampler_usages); - assert(map); - fill_buffer_surface_state(&screen->isl_dev, isv->res, map, - isv->view.format, isv->view.swizzle, - isv->base.u.buf.offset, - isv->base.u.buf.size); + if (update_surface_state_addrs(ice->state.surface_uploader, + &isv->surface_state, bo)) { ice->state.dirty |= IRIS_DIRTY_BINDINGS_VS << s; } } @@ -6485,9 +6545,11 @@ iris_rebind_buffer(struct iris_context *ice, while (bound_image_views) { const int i = u_bit_scan(&bound_image_views); struct iris_image_view *iv = &shs->image[i]; + struct iris_bo *bo = iris_resource_bo(iv->base.resource); - if (res->bo == iris_resource_bo(iv->base.resource)) { - iris_set_shader_images(ctx, p_stage, i, 1, &iv->base); + if (update_surface_state_addrs(ice->state.surface_uploader, + &iv->surface_state, bo)) { + ice->state.dirty |= IRIS_DIRTY_BINDINGS_VS << s; } } } -- 2.30.2