if (images && images[i].resource) {
util_dynarray_init(&image_view->desc_set_refs.refs, NULL);
struct zink_resource *res = zink_resource(images[i].resource);
+ if (!zink_resource_object_init_storage(ctx, res)) {
+ debug_printf("couldn't create storage image!");
+ continue;
+ }
res->bind_history |= BITFIELD_BIT(ZINK_DESCRIPTOR_TYPE_IMAGE);
res->bind_stages |= 1 << p_stage;
util_copy_image_view(&image_view->base, images + i);
sampler_view_buffer_clear(ctx, b);
b->buffer_view = buffer_view;
}
+ } else if (!res->obj->is_buffer) {
+ if (res->obj != b->image_view->obj) {
+ struct pipe_surface *psurf = &b->image_view->base;
+ zink_rebind_surface(ctx, &psurf);
+ b->image_view = zink_surface(psurf);
+ }
}
res->bind_history |= BITFIELD_BIT(ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW);
res->bind_stages |= 1 << shader_type;
flush_batch(ctx);
}
+static bool
+rebind_fb_surface(struct zink_context *ctx, struct pipe_surface **surf, struct zink_resource *match_res)
+{
+ if (!*surf)
+ return false;
+ struct zink_resource *surf_res = zink_resource((*surf)->texture);
+ if ((match_res == surf_res) || surf_res->obj != zink_surface(*surf)->obj)
+ return zink_rebind_surface(ctx, surf);
+ return false;
+}
+
+static bool
+rebind_fb_state(struct zink_context *ctx, struct zink_resource *match_res)
+{
+ bool rebind = false;
+ for (int i = 0; i < ctx->fb_state.nr_cbufs; i++)
+ rebind |= rebind_fb_surface(ctx, &ctx->fb_state.cbufs[i], match_res);
+ rebind |= rebind_fb_surface(ctx, &ctx->fb_state.zsbuf, match_res);
+ return rebind;
+}
+
static void
zink_set_framebuffer_state(struct pipe_context *pctx,
const struct pipe_framebuffer_state *state)
}
util_copy_framebuffer_state(&ctx->fb_state, state);
+ rebind_fb_state(ctx, NULL);
/* get_framebuffer adds a ref if the fb is reused or created;
* always do get_framebuffer first to avoid deleting the same fb
* we're about to use
/* only barrier if we're changing layout or doing something besides read -> read */
batch = zink_batch_no_rp(ctx);
assert(!batch->in_rp);
+ assert(new_layout);
vkCmdPipelineBarrier(
batch->state->cmdbuf,
res->access_stage ? res->access_stage : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
}
void
+zink_rebind_framebuffer(struct zink_context *ctx, struct zink_resource *res)
+{
+ if (!ctx->framebuffer)
+ return;
+ for (unsigned i = 0; i < ctx->framebuffer->state.num_attachments; i++) {
+ if (!ctx->framebuffer->surfaces[i] ||
+ zink_resource(ctx->framebuffer->surfaces[i]->texture) != res)
+ continue;
+ zink_rebind_surface(ctx, &ctx->framebuffer->surfaces[i]);
+ zink_batch_no_rp(ctx);
+ }
+ if (rebind_fb_state(ctx, res))
+ zink_batch_no_rp(ctx);
+}
+
+void
zink_resource_rebind(struct zink_context *ctx, struct zink_resource *res)
{
assert(res->base.target == PIPE_BUFFER);
struct zink_image_view *image_view = &ctx->image_views[shader][i];
zink_descriptor_set_refs_clear(&image_view->desc_set_refs, image_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;
+ }
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);
zink_resource_rebind(struct zink_context *ctx, struct zink_resource *res);
void
+zink_rebind_framebuffer(struct zink_context *ctx, struct zink_resource *res);
+
+void
zink_draw_vbo(struct pipe_context *pctx,
const struct pipe_draw_info *dinfo,
const struct pipe_draw_indirect_info *indirect,
zink_destroy_resource_object(struct zink_screen *screen, struct zink_resource_object *obj)
{
assert(!obj->map_count);
- if (obj->is_buffer)
+ if (obj->is_buffer) {
+ if (obj->sbuffer)
+ vkDestroyBuffer(screen->dev, obj->sbuffer, NULL);
vkDestroyBuffer(screen->dev, obj->buffer, NULL);
- else
+ } else {
vkDestroyImage(screen->dev, obj->image, NULL);
+ }
zink_descriptor_set_refs_clear(&obj->desc_set_refs, obj);
cache_or_free_mem(screen, obj);
VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
- VkFormatProperties props = screen->format_props[templ->format];
- if (props.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)
- bci.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
}
if (bind & PIPE_BIND_VERTEX_BUFFER)
if (bind & PIPE_BIND_SHADER_BUFFER)
bci.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ if (bind & PIPE_BIND_SHADER_IMAGE)
+ bci.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
+
if (bind & PIPE_BIND_COMMAND_ARGS_BUFFER)
bci.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
VK_IMAGE_USAGE_SAMPLED_BIT;
if ((templ->nr_samples <= 1 || screen->info.feats.features.shaderStorageImageMultisample) &&
- (bind & PIPE_BIND_SHADER_IMAGE ||
- (bind & PIPE_BIND_SAMPLER_VIEW && templ->flags & PIPE_RESOURCE_FLAG_TEXTURING_MORE_LIKELY))) {
+ (bind & PIPE_BIND_SHADER_IMAGE)) {
VkFormatProperties props = screen->format_props[templ->format];
- /* gallium doesn't provide any way to actually know whether this will be used as a shader image,
- * so we have to just assume and set the bit if it's available
- */
if ((ici.tiling == VK_IMAGE_TILING_LINEAR && props.linearTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) ||
(ici.tiling == VK_IMAGE_TILING_OPTIMAL && props.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT))
ici.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
}
+bool
+zink_resource_object_init_storage(struct zink_context *ctx, struct zink_resource *res)
+{
+ struct zink_screen *screen = zink_screen(ctx->base.screen);
+ /* base resource already has the cap */
+ if (res->base.bind & PIPE_BIND_SHADER_IMAGE)
+ return true;
+ if (res->obj->is_buffer) {
+ if (res->obj->sbuffer)
+ return true;
+ VkBufferCreateInfo bci = create_bci(screen, &res->base, res->base.bind | PIPE_BIND_SHADER_IMAGE);
+ VkBuffer buffer;
+ if (vkCreateBuffer(screen->dev, &bci, NULL, &buffer) != VK_SUCCESS)
+ return false;
+ vkBindBufferMemory(screen->dev, buffer, res->obj->mem, res->obj->offset);
+ res->obj->sbuffer = res->obj->buffer;
+ res->obj->buffer = buffer;
+ } else {
+ zink_fb_clears_apply_region(ctx, &res->base, (struct u_rect){0, res->base.width0, 0, res->base.height0});
+ zink_resource_image_barrier(ctx, NULL, res, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 0);
+ res->base.bind |= PIPE_BIND_SHADER_IMAGE;
+ struct zink_resource_object *old_obj = res->obj;
+ struct zink_resource_object *new_obj = resource_object_create(screen, &res->base, NULL, &res->optimal_tiling);
+ if (!new_obj) {
+ debug_printf("new backing resource alloc failed!");
+ res->base.bind &= ~PIPE_BIND_SHADER_IMAGE;
+ return false;
+ }
+ struct zink_resource staging = *res;
+ staging.obj = old_obj;
+ res->obj = new_obj;
+ zink_descriptor_set_refs_clear(&old_obj->desc_set_refs, old_obj);
+ for (unsigned i = 0; i <= res->base.last_level; i++) {
+ struct pipe_box box = {0, 0, 0,
+ u_minify(res->base.width0, i),
+ u_minify(res->base.height0, i), res->base.array_size};
+ box.depth = util_num_layers(&res->base, i);
+ ctx->base.resource_copy_region(&ctx->base, &res->base, i, 0, 0, 0, &staging.base, i, &box);
+ }
+ zink_resource_object_reference(screen, &old_obj, NULL);
+ }
+
+ if (res->bind_history & BITFIELD64_BIT(ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW)) {
+ for (unsigned shader = 0; shader < PIPE_SHADER_TYPES; shader++) {
+ if (res->bind_stages & (1 << shader)) {
+ for (unsigned i = 0; i < ZINK_DESCRIPTOR_TYPE_IMAGE; i++) {
+ if (res->bind_history & BITFIELD64_BIT(i))
+ zink_context_invalidate_descriptor_state(ctx, shader, i);
+ }
+ }
+ }
+ }
+ if (res->obj->is_buffer)
+ zink_resource_rebind(ctx, res);
+ else {
+ zink_rebind_framebuffer(ctx, res);
+ /* this will be cleaned up in future commits */
+ if (res->bind_history & BITFIELD_BIT(ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW)) {
+ for (unsigned i = 0; i < PIPE_SHADER_TYPES; i++) {
+ for (unsigned j = 0; j < ctx->num_sampler_views[i]; j++) {
+ struct zink_sampler_view *sv = zink_sampler_view(ctx->sampler_views[i][j]);
+ if (sv && sv->base.texture == &res->base) {
+ struct pipe_surface *psurf = &sv->image_view->base;
+ zink_rebind_surface(ctx, &psurf);
+ sv->image_view = zink_surface(psurf);
+ zink_context_invalidate_descriptor_state(ctx, i, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW);
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
void
zink_resource_setup_transfer_layouts(struct zink_context *ctx, struct zink_resource *src, struct zink_resource *dst)
{
VkBuffer buffer;
VkImage image;
};
+
+ VkBuffer sbuffer;
+ bool storage_init; //layout was set for image
+
VkDeviceMemory mem;
uint32_t mem_hash;
struct mem_key mkey;
if (dst) *dst = src;
}
+bool
+zink_resource_object_init_storage(struct zink_context *ctx, struct zink_resource *res);
#endif
surface->base.u.tex.level = level;
surface->base.u.tex.first_layer = templ->u.tex.first_layer;
surface->base.u.tex.last_layer = templ->u.tex.last_layer;
+ surface->obj = zink_resource(pres)->obj;
util_dynarray_init(&surface->framebuffer_refs, NULL);
if (vkCreateImageView(screen->dev, ivci, NULL,
simple_mtx_lock(&screen->surface_mtx);
struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci);
assert(he);
+ assert(he->data == surface);
_mesa_hash_table_remove(&screen->surface_cache, he);
simple_mtx_unlock(&screen->surface_mtx);
surface_clear_fb_refs(screen, psurface);
util_dynarray_fini(&surface->framebuffer_refs);
pipe_resource_reference(&psurface->texture, NULL);
+ if (surface->simage_view)
+ vkDestroyImageView(screen->dev, surface->simage_view, NULL);
vkDestroyImageView(screen->dev, surface->image_view, NULL);
FREE(surface);
}
zink_destroy_surface(zink_screen(pctx->screen), psurface);
}
+bool
+zink_rebind_surface(struct zink_context *ctx, struct pipe_surface **psurface)
+{
+ struct zink_surface *surface = zink_surface(*psurface);
+ struct zink_screen *screen = zink_screen(ctx->base.screen);
+ if (surface->simage_view)
+ return false;
+ VkImageViewCreateInfo ivci = create_ivci(screen,
+ zink_resource((*psurface)->texture), (*psurface));
+ uint32_t hash = hash_ivci(&ivci);
+
+ simple_mtx_lock(&screen->surface_mtx);
+ struct hash_entry *new_entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, hash, &ivci);
+ surface_clear_fb_refs(screen, *psurface);
+ if (new_entry) {
+ /* reuse existing surface; old one will be cleaned up naturally */
+ struct zink_surface *new_surface = new_entry->data;
+ simple_mtx_unlock(&screen->surface_mtx);
+ zink_surface_reference(screen, (struct zink_surface**)psurface, new_surface);
+ return true;
+ }
+ struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci);
+ assert(entry);
+ _mesa_hash_table_remove(&screen->surface_cache, entry);
+ VkImageView image_view;
+ if (vkCreateImageView(screen->dev, &ivci, NULL, &image_view) != VK_SUCCESS) {
+ debug_printf("zink: failed to create new imageview");
+ simple_mtx_unlock(&screen->surface_mtx);
+ return false;
+ }
+ surface->hash = hash;
+ surface->ivci = ivci;
+ entry = _mesa_hash_table_insert_pre_hashed(&screen->surface_cache, surface->hash, &surface->ivci, surface);
+ assert(entry);
+ surface->simage_view = surface->image_view;
+ surface->image_view = image_view;
+ surface->obj = zink_resource(surface->base.texture)->obj;
+ simple_mtx_unlock(&screen->surface_mtx);
+ return true;
+}
+
void
zink_context_surface_init(struct pipe_context *context)
{
struct pipe_surface base;
VkImageViewCreateInfo ivci;
VkImageView image_view;
+ VkImageView simage_view;//old iview after storage replacement/rebind
+ void *obj; //backing resource object
uint32_t hash;
struct zink_batch_usage batch_uses;
struct util_dynarray framebuffer_refs;
}
return viewType;
}
+
+bool
+zink_rebind_surface(struct zink_context *ctx, struct pipe_surface **psurface);
#endif