diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 09c678c5094..45d97877676 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -1106,6 +1106,38 @@ viewtype_is_cube(const VkImageViewCreateInfo *ivci) ivci->viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; } +static struct pipe_resource * +rebind_buffer_as_image(struct pipe_context *pctx, struct pipe_resource *pres, enum pipe_format pformat, const struct pipe_tex2d_from_buf *tex2d, bool storage) +{ + struct winsys_handle whandle = {.type = WINSYS_HANDLE_TYPE_FD,}; + unsigned bind = storage ? PIPE_BIND_SHADER_IMAGE : PIPE_BIND_SAMPLER_VIEW; + if (zink_resource_usage_is_unflushed(zink_resource(pres))) + pctx->flush(pctx, NULL, 0); + if (!pctx->screen->resource_get_handle(pctx->screen, pctx, pres, &whandle, 0)) + abort(); + struct pipe_resource tmpl = { + .format = pformat, + .target = PIPE_TEXTURE_2D, + .bind = PIPE_BIND_LINEAR | bind, + .width0 = tex2d->width, + .height0 = tex2d->height, + .depth0 = 1, + .array_size = 1, + }; + whandle.offset = tex2d->offset; + whandle.stride = util_format_get_stride(pformat, tex2d->row_stride); + whandle.modifier = 0; + + struct pipe_resource *import = pctx->screen->resource_from_handle(pctx->screen, &tmpl, &whandle, 0); + if (import) + /* this isn't actually used cross-process, so don't emit extra sync */ + zink_resource(import)->obj->exportable = false; +#if !defined(_WIN32) + close(whandle.handle); +#endif + return import; +} + static struct pipe_sampler_view * zink_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *pres, const struct pipe_sampler_view *state) @@ -1114,6 +1146,7 @@ zink_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *pres, struct zink_resource *res = zink_resource(pres); struct zink_context *ctx = zink_context(pctx); struct zink_sampler_view *sampler_view = CALLOC_STRUCT_CL(zink_sampler_view); + enum pipe_texture_target target = state->is_tex2d_from_buf ? PIPE_TEXTURE_2D : state->target; bool err; if (!sampler_view) { @@ -1127,16 +1160,24 @@ zink_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *pres, sampler_view->base.reference.count = 1; sampler_view->base.context = pctx; - if (state->target != PIPE_BUFFER) { + if (target != PIPE_BUFFER) { VkImageViewCreateInfo ivci; + if (state->is_tex2d_from_buf) { + struct pipe_resource *import = rebind_buffer_as_image(pctx, pres, state->format, &state->u.tex2d_from_buf, false); + assert(import); + sampler_view->import2d = zink_resource(import); + res = sampler_view->import2d; + pres = import; + } struct pipe_surface templ = {0}; - templ.u.tex.level = state->u.tex.first_level; + if (!state->is_tex2d_from_buf) + templ.u.tex.level = state->u.tex.first_level; templ.format = state->format; /* avoid needing mutable for depth/stencil sampling */ if (util_format_is_depth_and_stencil(pres->format)) templ.format = pres->format; - if (state->target != PIPE_TEXTURE_3D) { + if (target != PIPE_TEXTURE_3D && !state->is_tex2d_from_buf) { templ.u.tex.first_layer = state->u.tex.first_layer; templ.u.tex.last_layer = state->u.tex.last_layer; } @@ -1148,8 +1189,8 @@ zink_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *pres, } } - ivci = create_ivci(screen, res, &templ, state->target); - ivci.subresourceRange.levelCount = state->u.tex.last_level - state->u.tex.first_level + 1; + ivci = create_ivci(screen, res, &templ, target); + ivci.subresourceRange.levelCount = state->is_tex2d_from_buf ? 1 : (state->u.tex.last_level - state->u.tex.first_level + 1); ivci.subresourceRange.aspectMask = util_format_is_depth_or_stencil(state->format) ? sampler_aspect_from_format(state->format) : res->aspect; bool red_depth_sampler_view = false; /* samplers for stencil aspects of packed formats need to always use stencil swizzle */ @@ -1294,7 +1335,7 @@ zink_sampler_view_destroy(struct pipe_context *pctx, struct pipe_sampler_view *pview) { struct zink_sampler_view *view = zink_sampler_view(pview); - if (pview->texture->target == PIPE_BUFFER) { + if (pview->texture->target == PIPE_BUFFER && !view->import2d) { if (zink_descriptor_mode != ZINK_DESCRIPTOR_MODE_DB) zink_buffer_view_reference(zink_screen(pctx->screen), &view->buffer_view, NULL); } else { @@ -1302,6 +1343,7 @@ zink_sampler_view_destroy(struct pipe_context *pctx, zink_surface_reference(zink_screen(pctx->screen), &view->cube_array, NULL); zink_surface_reference(zink_screen(pctx->screen), &view->zs_view, NULL); } + zink_resource_reference(&view->import2d, NULL); pipe_resource_reference(&pview->texture, NULL); FREE_CL(view); } @@ -1834,7 +1876,12 @@ unbind_shader_image(struct zink_context *ctx, gl_shader_stage stage, unsigned sl if (!res->write_bind_count[is_compute]) res->barrier_access[stage == MESA_SHADER_COMPUTE] &= ~VK_ACCESS_SHADER_WRITE_BIT; - if (image_view->base.resource->target == PIPE_BUFFER) { + if (image_view->import2d) { + unbind_buffer_descriptor_stage(res, stage); + unbind_buffer_descriptor_reads(res, stage == MESA_SHADER_COMPUTE); + _mesa_set_remove_key(ctx->need_barriers[is_compute], image_view->import2d); + zink_surface_reference(zink_screen(ctx->base.screen), &image_view->surface, NULL); + } else if (image_view->base.resource->target == PIPE_BUFFER) { unbind_buffer_descriptor_stage(res, stage); unbind_buffer_descriptor_reads(res, stage == MESA_SHADER_COMPUTE); zink_buffer_view_reference(zink_screen(ctx->base.screen), &image_view->buffer_view, NULL); @@ -1849,6 +1896,7 @@ unbind_shader_image(struct zink_context *ctx, gl_shader_stage stage, unsigned sl } image_view->base.resource = NULL; image_view->surface = NULL; + image_view->import2d = NULL; } static struct zink_buffer_view * @@ -1886,15 +1934,25 @@ static struct zink_surface * create_image_surface(struct zink_context *ctx, const struct pipe_image_view *view, bool is_compute) { struct zink_screen *screen = zink_screen(ctx->base.screen); - struct zink_resource *res = zink_resource(view->resource); + struct pipe_resource *pres = view->resource; + struct zink_resource *res = zink_resource(pres); struct pipe_surface tmpl = {0}; - enum pipe_texture_target target = res->base.b.target; + bool tex2d_from_buf = view->access & PIPE_IMAGE_ACCESS_TEX2D_FROM_BUFFER; + enum pipe_texture_target target = tex2d_from_buf ? PIPE_TEXTURE_2D : res->base.b.target; + unsigned depth = 1, z = 0; tmpl.format = view->format; - tmpl.u.tex.level = view->u.tex.level; - tmpl.u.tex.first_layer = view->u.tex.first_layer; - tmpl.u.tex.last_layer = view->u.tex.last_layer; - unsigned depth = 1 + tmpl.u.tex.last_layer - tmpl.u.tex.first_layer; - unsigned z = tmpl.u.tex.first_layer; + if (tex2d_from_buf) { + struct pipe_resource *import = rebind_buffer_as_image(&ctx->base, pres, view->format, &view->u.tex2d_from_buf, true); + assert(import); + res = zink_resource(import); + pres = import; + } else { + tmpl.u.tex.level = view->u.tex.level; + tmpl.u.tex.first_layer = view->u.tex.first_layer; + tmpl.u.tex.last_layer = view->u.tex.last_layer; + depth += tmpl.u.tex.last_layer - tmpl.u.tex.first_layer; + z = tmpl.u.tex.first_layer; + } switch (target) { case PIPE_TEXTURE_3D: if (depth < u_minify(res->base.b.depth0, view->u.tex.level)) { @@ -1917,15 +1975,17 @@ create_image_surface(struct zink_context *ctx, const struct pipe_image_view *vie break; default: break; } - if (zink_format_needs_mutable(view->resource->format, view->format)) + if (zink_format_needs_mutable(pres->format, view->format)) /* mutable not set by default */ zink_resource_object_init_mutable(ctx, res); VkImageViewCreateInfo ivci = create_ivci(screen, res, &tmpl, target); - struct zink_surface *surface = zink_get_surface(ctx, view->resource, &tmpl, &ivci); + struct zink_surface *surface = zink_get_surface(ctx, pres, &tmpl, &ivci); if (!surface) return NULL; if (is_compute) flush_pending_clears(ctx, res, z, depth); + if (tex2d_from_buf) + pipe_resource_reference(&pres, NULL); return surface; } @@ -1955,6 +2015,7 @@ zink_set_shader_images(struct pipe_context *pctx, struct zink_image_view *a = &ctx->image_views[shader_type][start_slot + i]; const struct pipe_image_view *b = images ? &images[i] : NULL; struct zink_resource *res = b ? zink_resource(b->resource) : NULL; + bool tex2d_from_buf = b && b->access & PIPE_IMAGE_ACCESS_TEX2D_FROM_BUFFER; if (b && b->resource) { if (!zink_resource_object_init_storage(ctx, res)) { debug_printf("couldn't create storage image!"); @@ -1975,8 +2036,11 @@ zink_set_shader_images(struct pipe_context *pctx, changed = true; unbind_shader_image(ctx, shader_type, start_slot + i); bind_shaderimage_resource_stage(ctx, b, res, is_compute); - /* db mode refcounts these */ - if (zink_descriptor_mode == ZINK_DESCRIPTOR_MODE_DB && b->resource->target == PIPE_BUFFER) + if (b->resource->target == PIPE_BUFFER && + /* db mode refcounts these */ + (zink_descriptor_mode == ZINK_DESCRIPTOR_MODE_DB || + /* this path refcounts the import2d resource but not the base */ + tex2d_from_buf)) pipe_resource_reference(&a->base.resource, b->resource); } else { /* resource matches: check for write flag change and partial rebind */ @@ -1994,7 +2058,9 @@ zink_set_shader_images(struct pipe_context *pctx, /* this may need a partial rebind */ changed = a->base.format != b->format || zink_resource(a->base.resource)->obj != res->obj; if (!changed) { - if (b->resource->target == PIPE_BUFFER) { + if (tex2d_from_buf) { + changed = !!memcmp(&a->base.u.tex2d_from_buf, &b->u.tex2d_from_buf, sizeof(b->u.tex2d_from_buf)); + } else if (b->resource->target == PIPE_BUFFER) { /* db mode has no partial rebind */ if (zink_descriptor_mode != ZINK_DESCRIPTOR_MODE_DB) changed = !!memcmp(&a->base.u.buf, &b->u.buf, sizeof(b->u.buf)); @@ -2009,7 +2075,7 @@ zink_set_shader_images(struct pipe_context *pctx, if (changed) { /* this is a partial rebind */ - if (b->resource->target == PIPE_BUFFER) { + if (b->resource->target == PIPE_BUFFER && !tex2d_from_buf) { /* db has no partial rebind */ if (zink_descriptor_mode != ZINK_DESCRIPTOR_MODE_DB) { /* bufferview rebind: get updated bufferview and unref old one */ @@ -2026,6 +2092,10 @@ zink_set_shader_images(struct pipe_context *pctx, /* identical rebind was already checked above */ assert(surface && surface != a->surface); zink_surface_reference(screen, &a->surface, NULL); + if (tex2d_from_buf) { + a->import2d = zink_resource(surface->base.texture); + bind_shaderimage_resource_stage(ctx, b, a->import2d, is_compute); + } /* ref already added by create */ a->surface = surface; } @@ -2034,7 +2104,20 @@ zink_set_shader_images(struct pipe_context *pctx, /* these operations occur regardless of binding/rebinding */ res->gfx_barrier |= zink_pipeline_flags_from_pipe_stage(shader_type); res->barrier_access[is_compute] |= access; - if (b->resource->target == PIPE_BUFFER) { + if (tex2d_from_buf) { + a->import2d->gfx_barrier |= zink_pipeline_flags_from_pipe_stage(shader_type); + a->import2d->barrier_access[is_compute] |= access; + screen->buffer_barrier(ctx, res, access, + res->gfx_barrier); + zink_batch_resource_usage_set(ctx->bs, res, + zink_resource_access_is_write(access), true); + finalize_image_bind(ctx, a->import2d, is_compute); + zink_batch_resource_usage_set(ctx->bs, a->import2d, + zink_resource_access_is_write(access), false); + if (zink_resource_access_is_write(access)) + res->obj->unordered_write = false; + res->obj->unordered_read = false; + } else if (b->resource->target == PIPE_BUFFER) { screen->buffer_barrier(ctx, res, access, res->gfx_barrier); zink_batch_resource_usage_set(ctx->bs, res, @@ -2048,18 +2131,20 @@ zink_set_shader_images(struct pipe_context *pctx, zink_resource_access_is_write(access), false); } memcpy(&a->base, images + i, sizeof(struct pipe_image_view)); - if (b->resource->target == PIPE_BUFFER) { + if (b->resource->target == PIPE_BUFFER && !tex2d_from_buf) { /* always enforce limit clamping */ unsigned blocksize = util_format_get_blocksize(a->base.format); a->base.u.buf.size = MIN2(a->base.u.buf.size / blocksize, screen->info.props.limits.maxTexelBufferElements) * blocksize; } update = true; res->image_binds[shader_type] |= BITFIELD_BIT(start_slot + i); + if (tex2d_from_buf) + a->import2d->image_binds[shader_type] |= BITFIELD_BIT(start_slot + i); } else if (a->base.resource) { update = true; unbind_shader_image(ctx, shader_type, start_slot + i); } - update_descriptor_state_image(ctx, shader_type, start_slot + i, res); + update_descriptor_state_image(ctx, shader_type, start_slot + i, tex2d_from_buf ? a->import2d : res); } for (unsigned i = 0; i < unbind_num_trailing_slots; i++) { update |= !!ctx->image_views[shader_type][start_slot + count + i].base.resource; @@ -2138,6 +2223,8 @@ unbind_samplerview(struct zink_context *ctx, gl_shader_stage stage, unsigned slo return; struct zink_resource *res = zink_resource(sv->base.texture); unbind_samplerview_res(ctx, stage, slot, res); + if (sv->import2d) + unbind_samplerview_res(ctx, stage, slot, sv->import2d); assert(slot < 32); ctx->di.zs_swizzle[stage].mask &= ~BITFIELD_BIT(slot); } @@ -2188,8 +2275,15 @@ zink_set_sampler_views(struct pipe_context *pctx, if (a) unbind_samplerview(ctx, shader_type, start_slot + i); bind_samplerview_resource_stage(ctx, res, shader_type); + if (b->import2d) { + bind_samplerview_resource_stage(ctx, b->import2d, shader_type); + zink_batch_resource_usage_set(ctx->bs, res, false, true); + } } - if (res->base.b.target == PIPE_BUFFER) { + /* switch to possible tex2d_from_buf resource: none of this buffer stuff matters */ + if (b->import2d) + res = b->import2d; + if (res->base.b.target == PIPE_BUFFER && !b->import2d) { if (zink_descriptor_mode == ZINK_DESCRIPTOR_MODE_DB) { if (!a || a->base.texture != b->base.texture || zink_resource(a->base.texture)->obj != res->obj || memcmp(&a->base.u.buf, &b->base.u.buf, sizeof(b->base.u.buf))) diff --git a/src/gallium/drivers/zink/zink_screen.c b/src/gallium/drivers/zink/zink_screen.c index 6248c27ddd3..4756e3ad4e9 100644 --- a/src/gallium/drivers/zink/zink_screen.c +++ b/src/gallium/drivers/zink/zink_screen.c @@ -1114,6 +1114,18 @@ zink_init_screen_caps(struct zink_screen *screen) caps->post_depth_coverage = screen->info.have_EXT_post_depth_coverage; caps->cl_gl_sharing = caps->dmabuf && screen->info.have_KHR_external_semaphore_fd; + switch (zink_driverid(screen)) { + case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA: + caps->linear_image_pitch_alignment = 1; + break; + /* AMD requires 256 */ + case VK_DRIVER_ID_AMD_PROPRIETARY: + case VK_DRIVER_ID_MESA_RADV: + default: + caps->linear_image_pitch_alignment = 256; + break; + } + caps->linear_image_base_address_alignment = 1; caps->string_marker = screen->instance_info->have_EXT_debug_utils; diff --git a/src/gallium/drivers/zink/zink_types.h b/src/gallium/drivers/zink/zink_types.h index 5b1e5f31fca..a226bcaab87 100644 --- a/src/gallium/drivers/zink/zink_types.h +++ b/src/gallium/drivers/zink/zink_types.h @@ -1691,6 +1691,7 @@ struct zink_sampler_view { /* Optional sampler view returning red (depth) in all channels, for shader rewrites. */ struct zink_surface *zs_view; struct zink_zs_swizzle swizzle; + struct zink_resource *import2d; }; struct zink_image_view { @@ -1699,6 +1700,7 @@ struct zink_image_view { struct zink_surface *surface; struct zink_buffer_view *buffer_view; }; + struct zink_resource *import2d; }; static inline struct zink_sampler_view *