zink: optimize buffer rebinds

this leverages all the slot masks to more optimally run through all
the rebinds, also enabling some code consolidation

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11747>
This commit is contained in:
Mike Blumenkrantz 2021-05-11 11:08:03 -04:00
parent f6e058ea4a
commit 59cc9c8df1

View file

@ -3127,127 +3127,81 @@ zink_rebind_framebuffer(struct zink_context *ctx, struct zink_resource *res)
zink_batch_no_rp(ctx);
}
static bool
check_and_rebind_buffer(struct zink_context *ctx, struct zink_resource *res, unsigned shader, enum zink_descriptor_type type, unsigned i)
{
bool is_write = false;
bool is_read = true;
struct zink_resource *cres = zink_get_resource_for_descriptor(ctx, type, shader, i);
if (res != cres)
return false;
switch (type) {
case ZINK_DESCRIPTOR_TYPE_UBO:
update_descriptor_state_ubo(ctx, shader, i);
break;
case ZINK_DESCRIPTOR_TYPE_SSBO: {
struct pipe_shader_buffer *ssbo = &ctx->ssbos[shader][i];
is_write = ctx->writable_ssbos[shader] & BITFIELD64_BIT(i);
util_range_add(&res->base.b, &res->valid_buffer_range, ssbo->buffer_offset,
ssbo->buffer_offset + ssbo->buffer_size);
update_descriptor_state_ssbo(ctx, shader, i);
break;
}
case ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW: {
struct zink_sampler_view *sampler_view = zink_sampler_view(ctx->sampler_views[shader][i]);
if (zink_batch_usage_exists(sampler_view->buffer_view->batch_uses))
zink_batch_reference_bufferview(&ctx->batch, sampler_view->buffer_view);
zink_buffer_view_reference(zink_screen(ctx->base.screen), &sampler_view->buffer_view, NULL);
sampler_view->buffer_view = get_buffer_view(ctx, res, sampler_view->base.format,
sampler_view->base.u.buf.offset, sampler_view->base.u.buf.size);
update_descriptor_state_sampler(ctx, shader, i);
break;
}
case ZINK_DESCRIPTOR_TYPE_IMAGE: {
struct zink_image_view *image_view = &ctx->image_views[shader][i];
zink_descriptor_set_refs_clear(&image_view->buffer_view->desc_set_refs, image_view->buffer_view);
if (zink_batch_usage_exists(image_view->buffer_view->batch_uses))
zink_batch_reference_bufferview(&ctx->batch, image_view->buffer_view);
zink_buffer_view_reference(zink_screen(ctx->base.screen), &image_view->buffer_view, NULL);
if (!zink_resource_object_init_storage(ctx, res)) {
debug_printf("couldn't create storage image!");
return false;
}
is_write = image_view->base.access & PIPE_IMAGE_ACCESS_WRITE;
is_read = image_view->base.access & PIPE_IMAGE_ACCESS_READ;
image_view->buffer_view = get_buffer_view(ctx, res, image_view->base.format,
image_view->base.u.buf.offset, image_view->base.u.buf.size);
assert(image_view->buffer_view);
util_range_add(&res->base.b, &res->valid_buffer_range, image_view->base.u.buf.offset,
image_view->base.u.buf.offset + image_view->base.u.buf.size);
update_descriptor_state_image(ctx, shader, i);
break;
}
default:
break;
}
zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, shader, type, i, 1);
zink_batch_resource_usage_set(&ctx->batch, res, is_write);
return true;
}
static void
rebind_buffer(struct zink_context *ctx, struct zink_resource *res)
{
unsigned num_rebinds = 0;
const unsigned total_rebinds = res->bind_count[0] + res->bind_count[1];
unsigned num_rebinds = 0, num_image_rebinds_remaining[2] = {res->image_bind_count[0], res->image_bind_count[1]};
bool has_write = false;
for (unsigned shader = 0; shader < PIPE_SHADER_TYPES; shader++) {
if (!(res->bind_stages & (1 << shader)))
continue;
for (enum zink_descriptor_type type = 0; type < ZINK_DESCRIPTOR_TYPES; type++) {
if (!(res->bind_history & BITFIELD64_BIT(type)))
continue;
uint32_t usage = zink_program_get_descriptor_usage(ctx, shader, type);
u_foreach_bit(i, usage) {
if (check_and_rebind_buffer(ctx, res, shader, type, i))
num_rebinds++;
}
}
if (res->vbo_bind_count) {
ctx->vertex_buffers_dirty = true;
num_rebinds += res->vbo_bind_count;
}
unsigned total_binds = res->bind_count[0] + res->bind_count[1] - res->vbo_bind_count;
/* we've missed some rebinds, so we have to go back for them */
if (total_binds != num_rebinds) {
for (unsigned shader = 0; shader < PIPE_SHADER_TYPES; shader++) {
if (!(res->bind_stages & (1 << shader)))
continue;
for (enum zink_descriptor_type type = 0; type < ZINK_DESCRIPTOR_TYPES; type++) {
if (!(res->bind_history & BITFIELD64_BIT(type)))
for (unsigned shader = 0; num_rebinds < total_rebinds && shader < PIPE_SHADER_TYPES; shader++) {
u_foreach_bit(slot, res->ubo_bind_mask[shader]) {
if (&res->base.b != ctx->ubos[shader][slot].buffer) //wrong context
return;
update_descriptor_state_ubo(ctx, shader, slot);
zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, shader, ZINK_DESCRIPTOR_TYPE_UBO, slot, 1);
num_rebinds++;
}
u_foreach_bit(slot, res->ssbo_bind_mask[shader]) {
struct pipe_shader_buffer *ssbo = &ctx->ssbos[shader][slot];
if (&res->base.b != ssbo->buffer) //wrong context
return;
has_write |= ctx->writable_ssbos[shader] & BITFIELD64_BIT(slot);
util_range_add(&res->base.b, &res->valid_buffer_range, ssbo->buffer_offset,
ssbo->buffer_offset + ssbo->buffer_size);
update_descriptor_state_ssbo(ctx, shader, slot);
zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, shader, ZINK_DESCRIPTOR_TYPE_SSBO, slot, 1);
num_rebinds++;
}
u_foreach_bit(slot, res->sampler_binds[shader]) {
struct zink_sampler_view *sampler_view = zink_sampler_view(ctx->sampler_views[shader][slot]);
if (&res->base.b != sampler_view->base.texture) //wrong context
return;
if (zink_batch_usage_exists(sampler_view->buffer_view->batch_uses))
zink_batch_reference_bufferview(&ctx->batch, sampler_view->buffer_view);
zink_buffer_view_reference(zink_screen(ctx->base.screen), &sampler_view->buffer_view, NULL);
sampler_view->buffer_view = get_buffer_view(ctx, res, sampler_view->base.format,
sampler_view->base.u.buf.offset, sampler_view->base.u.buf.size);
update_descriptor_state_sampler(ctx, shader, slot);
zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, shader, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW, slot, 1);
num_rebinds++;
}
if (unlikely(num_image_rebinds_remaining[shader == PIPE_SHADER_COMPUTE])) {
for (unsigned slot = 0; num_image_rebinds_remaining[shader == PIPE_SHADER_COMPUTE] &&
slot < ctx->di.num_images[shader]; slot++) {
struct zink_resource *cres = zink_get_resource_for_descriptor(ctx, ZINK_DESCRIPTOR_TYPE_IMAGE, shader, slot);
if (res != cres)
continue;
unsigned num_descriptors = 0;
switch (type) {
case ZINK_DESCRIPTOR_TYPE_UBO:
num_descriptors = ctx->di.num_ubos[shader];
break;
case ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW:
num_descriptors = ctx->di.num_sampler_views[shader];
break;
case ZINK_DESCRIPTOR_TYPE_SSBO:
num_descriptors = ctx->di.num_ssbos[shader];
break;
case ZINK_DESCRIPTOR_TYPE_IMAGE:
num_descriptors = ctx->di.num_images[shader];
break;
default:
unreachable("ack");
}
for (unsigned i = 0; i < num_descriptors; i++) {
if (check_and_rebind_buffer(ctx, res, shader, type, i))
num_rebinds++;
if (total_binds == num_rebinds)
goto out;
struct zink_image_view *image_view = &ctx->image_views[shader][slot];
zink_descriptor_set_refs_clear(&image_view->buffer_view->desc_set_refs, image_view->buffer_view);
if (zink_batch_usage_exists(image_view->buffer_view->batch_uses))
zink_batch_reference_bufferview(&ctx->batch, image_view->buffer_view);
zink_buffer_view_reference(zink_screen(ctx->base.screen), &image_view->buffer_view, NULL);
if (!zink_resource_object_init_storage(ctx, res)) {
debug_printf("couldn't create storage image!");
continue;
}
has_write |= image_view->base.access & PIPE_IMAGE_ACCESS_WRITE;
image_view->buffer_view = get_buffer_view(ctx, res, image_view->base.format,
image_view->base.u.buf.offset, image_view->base.u.buf.size);
assert(image_view->buffer_view);
util_range_add(&res->base.b, &res->valid_buffer_range, image_view->base.u.buf.offset,
image_view->base.u.buf.offset + image_view->base.u.buf.size);
update_descriptor_state_image(ctx, shader, slot);
zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, shader, ZINK_DESCRIPTOR_TYPE_IMAGE, slot, 1);
num_image_rebinds_remaining[shader == PIPE_SHADER_COMPUTE]--;
}
}
}
out:
assert(total_binds == num_rebinds);
if (!res->vbo_bind_count)
return;
zink_batch_resource_usage_set(&ctx->batch, res, false);
ctx->vertex_buffers_dirty = true;
zink_batch_resource_usage_set(&ctx->batch, res, has_write);
}
static inline struct zink_screen **