Path: blob/21.2-virgl/src/gallium/drivers/zink/zink_context.c
4570 views
/*1* Copyright 2018 Collabora Ltd.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* on the rights to use, copy, modify, merge, publish, distribute, sub7* license, and/or sell copies of the Software, and to permit persons to whom8* the Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL17* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,18* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR19* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE20* USE OR OTHER DEALINGS IN THE SOFTWARE.21*/2223#include "zink_context.h"2425#include "zink_batch.h"26#include "zink_compiler.h"27#include "zink_fence.h"28#include "zink_framebuffer.h"29#include "zink_helpers.h"30#include "zink_program.h"31#include "zink_pipeline.h"32#include "zink_query.h"33#include "zink_render_pass.h"34#include "zink_resource.h"35#include "zink_screen.h"36#include "zink_state.h"37#include "zink_surface.h"3839#include "util/u_blitter.h"40#include "util/u_debug.h"41#include "util/format_srgb.h"42#include "util/format/u_format.h"43#include "util/u_framebuffer.h"44#include "util/u_helpers.h"45#include "util/u_inlines.h"46#include "util/u_thread.h"47#include "util/u_cpu_detect.h"48#include "util/strndup.h"49#include "nir.h"5051#include "util/u_memory.h"52#include "util/u_upload_mgr.h"5354#define XXH_INLINE_ALL55#include "util/xxhash.h"5657static void58calc_descriptor_hash_sampler_state(struct zink_sampler_state *sampler_state)59{60void *hash_data = &sampler_state->sampler;61size_t data_size = sizeof(VkSampler);62sampler_state->hash = XXH32(hash_data, data_size, 0);63}6465void66debug_describe_zink_buffer_view(char *buf, const struct zink_buffer_view *ptr)67{68sprintf(buf, "zink_buffer_view");69}7071ALWAYS_INLINE static void72check_resource_for_batch_ref(struct zink_context *ctx, struct zink_resource *res)73{74if (!res->bind_count[0] && !res->bind_count[1])75zink_batch_reference_resource(&ctx->batch, res);76}7778static void79zink_context_destroy(struct pipe_context *pctx)80{81struct zink_context *ctx = zink_context(pctx);82struct zink_screen *screen = zink_screen(pctx->screen);8384if (screen->queue && !screen->device_lost && vkQueueWaitIdle(screen->queue) != VK_SUCCESS)85debug_printf("vkQueueWaitIdle failed\n");8687util_blitter_destroy(ctx->blitter);88for (unsigned i = 0; i < ctx->fb_state.nr_cbufs; i++)89zink_surface_reference(screen, (struct zink_surface**)&ctx->fb_state.cbufs[i], NULL);90zink_surface_reference(screen, (struct zink_surface**)&ctx->fb_state.zsbuf, NULL);9192pipe_resource_reference(&ctx->dummy_vertex_buffer, NULL);93pipe_resource_reference(&ctx->dummy_xfb_buffer, NULL);9495zink_surface_reference(screen, (struct zink_surface**)&ctx->dummy_surface, NULL);96zink_buffer_view_reference(screen, &ctx->dummy_bufferview, NULL);9798simple_mtx_destroy(&ctx->batch_mtx);99zink_clear_batch_state(ctx, ctx->batch.state);100zink_batch_state_reference(screen, &ctx->batch.state, NULL);101hash_table_foreach(&ctx->batch_states, entry) {102struct zink_batch_state *bs = entry->data;103zink_clear_batch_state(ctx, bs);104zink_batch_state_reference(screen, &bs, NULL);105}106util_dynarray_foreach(&ctx->free_batch_states, struct zink_batch_state*, bs) {107zink_clear_batch_state(ctx, *bs);108zink_batch_state_reference(screen, bs, NULL);109}110111if (ctx->framebuffer) {112simple_mtx_lock(&screen->framebuffer_mtx);113struct hash_entry *entry = _mesa_hash_table_search(&screen->framebuffer_cache, &ctx->framebuffer->state);114if (zink_framebuffer_reference(screen, &ctx->framebuffer, NULL))115_mesa_hash_table_remove(&screen->framebuffer_cache, entry);116simple_mtx_unlock(&screen->framebuffer_mtx);117}118119hash_table_foreach(ctx->render_pass_cache, he)120zink_destroy_render_pass(screen, he->data);121122u_upload_destroy(pctx->stream_uploader);123u_upload_destroy(pctx->const_uploader);124slab_destroy_child(&ctx->transfer_pool);125_mesa_hash_table_destroy(ctx->program_cache, NULL);126_mesa_hash_table_destroy(ctx->compute_program_cache, NULL);127_mesa_hash_table_destroy(ctx->render_pass_cache, NULL);128slab_destroy_child(&ctx->transfer_pool_unsync);129130screen->descriptors_deinit(ctx);131132zink_descriptor_layouts_deinit(ctx);133134p_atomic_dec(&screen->base.num_contexts);135136ralloc_free(ctx);137}138139static void140check_device_lost(struct zink_context *ctx)141{142if (!zink_screen(ctx->base.screen)->device_lost || ctx->is_device_lost)143return;144debug_printf("ZINK: device lost detected!\n");145if (ctx->reset.reset)146ctx->reset.reset(ctx->reset.data, PIPE_GUILTY_CONTEXT_RESET);147ctx->is_device_lost = true;148}149150static enum pipe_reset_status151zink_get_device_reset_status(struct pipe_context *pctx)152{153struct zink_context *ctx = zink_context(pctx);154155enum pipe_reset_status status = PIPE_NO_RESET;156157if (ctx->is_device_lost) {158// Since we don't know what really happened to the hardware, just159// assume that we are in the wrong160status = PIPE_GUILTY_CONTEXT_RESET;161162debug_printf("ZINK: device lost detected!\n");163164if (ctx->reset.reset)165ctx->reset.reset(ctx->reset.data, status);166}167168return status;169}170171static void172zink_set_device_reset_callback(struct pipe_context *pctx,173const struct pipe_device_reset_callback *cb)174{175struct zink_context *ctx = zink_context(pctx);176177if (cb)178ctx->reset = *cb;179else180memset(&ctx->reset, 0, sizeof(ctx->reset));181}182183static void184zink_set_context_param(struct pipe_context *pctx, enum pipe_context_param param,185unsigned value)186{187struct zink_context *ctx = zink_context(pctx);188189switch (param) {190case PIPE_CONTEXT_PARAM_PIN_THREADS_TO_L3_CACHE:191util_set_thread_affinity(zink_screen(ctx->base.screen)->flush_queue.threads[0],192util_get_cpu_caps()->L3_affinity_mask[value],193NULL, util_get_cpu_caps()->num_cpu_mask_bits);194break;195default:196break;197}198}199200static VkSamplerMipmapMode201sampler_mipmap_mode(enum pipe_tex_mipfilter filter)202{203switch (filter) {204case PIPE_TEX_MIPFILTER_NEAREST: return VK_SAMPLER_MIPMAP_MODE_NEAREST;205case PIPE_TEX_MIPFILTER_LINEAR: return VK_SAMPLER_MIPMAP_MODE_LINEAR;206case PIPE_TEX_MIPFILTER_NONE:207unreachable("PIPE_TEX_MIPFILTER_NONE should be dealt with earlier");208}209unreachable("unexpected filter");210}211212static VkSamplerAddressMode213sampler_address_mode(enum pipe_tex_wrap filter)214{215switch (filter) {216case PIPE_TEX_WRAP_REPEAT: return VK_SAMPLER_ADDRESS_MODE_REPEAT;217case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;218case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;219case PIPE_TEX_WRAP_MIRROR_REPEAT: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;220case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;221case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; /* not technically correct, but kinda works */222default: break;223}224unreachable("unexpected wrap");225}226227static VkCompareOp228compare_op(enum pipe_compare_func op)229{230switch (op) {231case PIPE_FUNC_NEVER: return VK_COMPARE_OP_NEVER;232case PIPE_FUNC_LESS: return VK_COMPARE_OP_LESS;233case PIPE_FUNC_EQUAL: return VK_COMPARE_OP_EQUAL;234case PIPE_FUNC_LEQUAL: return VK_COMPARE_OP_LESS_OR_EQUAL;235case PIPE_FUNC_GREATER: return VK_COMPARE_OP_GREATER;236case PIPE_FUNC_NOTEQUAL: return VK_COMPARE_OP_NOT_EQUAL;237case PIPE_FUNC_GEQUAL: return VK_COMPARE_OP_GREATER_OR_EQUAL;238case PIPE_FUNC_ALWAYS: return VK_COMPARE_OP_ALWAYS;239}240unreachable("unexpected compare");241}242243static inline bool244wrap_needs_border_color(unsigned wrap)245{246return wrap == PIPE_TEX_WRAP_CLAMP || wrap == PIPE_TEX_WRAP_CLAMP_TO_BORDER ||247wrap == PIPE_TEX_WRAP_MIRROR_CLAMP || wrap == PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER;248}249250static VkBorderColor251get_border_color(const union pipe_color_union *color, bool is_integer, bool need_custom)252{253if (is_integer) {254if (color->ui[0] == 0 && color->ui[1] == 0 && color->ui[2] == 0 && color->ui[3] == 0)255return VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;256if (color->ui[0] == 0 && color->ui[1] == 0 && color->ui[2] == 0 && color->ui[3] == 1)257return VK_BORDER_COLOR_INT_OPAQUE_BLACK;258if (color->ui[0] == 1 && color->ui[1] == 1 && color->ui[2] == 1 && color->ui[3] == 1)259return VK_BORDER_COLOR_INT_OPAQUE_WHITE;260return need_custom ? VK_BORDER_COLOR_INT_CUSTOM_EXT : VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;261}262263if (color->f[0] == 0 && color->f[1] == 0 && color->f[2] == 0 && color->f[3] == 0)264return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;265if (color->f[0] == 0 && color->f[1] == 0 && color->f[2] == 0 && color->f[3] == 1)266return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;267if (color->f[0] == 1 && color->f[1] == 1 && color->f[2] == 1 && color->f[3] == 1)268return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;269return need_custom ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT : VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;270}271272static void *273zink_create_sampler_state(struct pipe_context *pctx,274const struct pipe_sampler_state *state)275{276struct zink_screen *screen = zink_screen(pctx->screen);277bool need_custom = false;278279VkSamplerCreateInfo sci = {0};280VkSamplerCustomBorderColorCreateInfoEXT cbci = {0};281sci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;282sci.magFilter = zink_filter(state->mag_img_filter);283sci.minFilter = zink_filter(state->min_img_filter);284285VkSamplerReductionModeCreateInfo rci;286rci.sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO;287rci.pNext = NULL;288switch (state->reduction_mode) {289case PIPE_TEX_REDUCTION_MIN:290rci.reductionMode = VK_SAMPLER_REDUCTION_MODE_MIN;291break;292case PIPE_TEX_REDUCTION_MAX:293rci.reductionMode = VK_SAMPLER_REDUCTION_MODE_MAX;294break;295default:296rci.reductionMode = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;297break;298}299if (state->reduction_mode)300sci.pNext = &rci;301302if (state->min_mip_filter != PIPE_TEX_MIPFILTER_NONE) {303sci.mipmapMode = sampler_mipmap_mode(state->min_mip_filter);304sci.minLod = state->min_lod;305sci.maxLod = state->max_lod;306} else {307sci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;308sci.minLod = 0;309sci.maxLod = 0.25f;310}311312sci.addressModeU = sampler_address_mode(state->wrap_s);313sci.addressModeV = sampler_address_mode(state->wrap_t);314sci.addressModeW = sampler_address_mode(state->wrap_r);315sci.mipLodBias = state->lod_bias;316317need_custom |= wrap_needs_border_color(state->wrap_s);318need_custom |= wrap_needs_border_color(state->wrap_t);319need_custom |= wrap_needs_border_color(state->wrap_r);320321if (state->compare_mode == PIPE_TEX_COMPARE_NONE)322sci.compareOp = VK_COMPARE_OP_NEVER;323else {324sci.compareOp = compare_op(state->compare_func);325sci.compareEnable = VK_TRUE;326}327328bool is_integer = state->border_color_is_integer;329330sci.borderColor = get_border_color(&state->border_color, is_integer, need_custom);331if (sci.borderColor > VK_BORDER_COLOR_INT_OPAQUE_WHITE && need_custom) {332if (screen->info.have_EXT_custom_border_color &&333screen->info.border_color_feats.customBorderColorWithoutFormat) {334cbci.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT;335cbci.format = VK_FORMAT_UNDEFINED;336/* these are identical unions */337memcpy(&cbci.customBorderColor, &state->border_color, sizeof(union pipe_color_union));338cbci.pNext = sci.pNext;339sci.pNext = &cbci;340UNUSED uint32_t check = p_atomic_inc_return(&screen->cur_custom_border_color_samplers);341assert(check <= screen->info.border_color_props.maxCustomBorderColorSamplers);342} else343sci.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; // TODO with custom shader if we're super interested?344}345346sci.unnormalizedCoordinates = !state->normalized_coords;347348if (state->max_anisotropy > 1) {349sci.maxAnisotropy = state->max_anisotropy;350sci.anisotropyEnable = VK_TRUE;351}352353struct zink_sampler_state *sampler = CALLOC_STRUCT(zink_sampler_state);354if (!sampler)355return NULL;356357if (vkCreateSampler(screen->dev, &sci, NULL, &sampler->sampler) != VK_SUCCESS) {358FREE(sampler);359return NULL;360}361util_dynarray_init(&sampler->desc_set_refs.refs, NULL);362calc_descriptor_hash_sampler_state(sampler);363sampler->custom_border_color = need_custom;364365return sampler;366}367368ALWAYS_INLINE static VkImageLayout369get_layout_for_binding(struct zink_resource *res, enum zink_descriptor_type type, bool is_compute)370{371if (res->obj->is_buffer)372return 0;373switch (type) {374case ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW:375return res->image_bind_count[is_compute] ?376VK_IMAGE_LAYOUT_GENERAL :377res->aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) ?378//Vulkan-Docs#1490379//(res->aspect == VK_IMAGE_ASPECT_DEPTH_BIT ? VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL :380//res->aspect == VK_IMAGE_ASPECT_STENCIL_BIT ? VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL :381(res->aspect == VK_IMAGE_ASPECT_DEPTH_BIT ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL :382res->aspect == VK_IMAGE_ASPECT_STENCIL_BIT ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL :383VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) :384VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;385case ZINK_DESCRIPTOR_TYPE_IMAGE:386return VK_IMAGE_LAYOUT_GENERAL;387default:388break;389}390return 0;391}392393ALWAYS_INLINE static struct zink_surface *394get_imageview_for_binding(struct zink_context *ctx, enum pipe_shader_type stage, enum zink_descriptor_type type, unsigned idx)395{396switch (type) {397case ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW: {398struct zink_sampler_view *sampler_view = zink_sampler_view(ctx->sampler_views[stage][idx]);399return sampler_view->base.texture ? sampler_view->image_view : NULL;400}401case ZINK_DESCRIPTOR_TYPE_IMAGE: {402struct zink_image_view *image_view = &ctx->image_views[stage][idx];403return image_view->base.resource ? image_view->surface : NULL;404}405default:406break;407}408unreachable("ACK");409return VK_NULL_HANDLE;410}411412ALWAYS_INLINE static struct zink_buffer_view *413get_bufferview_for_binding(struct zink_context *ctx, enum pipe_shader_type stage, enum zink_descriptor_type type, unsigned idx)414{415switch (type) {416case ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW: {417struct zink_sampler_view *sampler_view = zink_sampler_view(ctx->sampler_views[stage][idx]);418return sampler_view->base.texture ? sampler_view->buffer_view : NULL;419}420case ZINK_DESCRIPTOR_TYPE_IMAGE: {421struct zink_image_view *image_view = &ctx->image_views[stage][idx];422return image_view->base.resource ? image_view->buffer_view : NULL;423}424default:425break;426}427unreachable("ACK");428return VK_NULL_HANDLE;429}430431ALWAYS_INLINE static void432update_descriptor_state_ubo(struct zink_context *ctx, enum pipe_shader_type shader, unsigned slot)433{434struct zink_screen *screen = zink_screen(ctx->base.screen);435bool have_null_descriptors = screen->info.rb2_feats.nullDescriptor;436const enum zink_descriptor_type type = ZINK_DESCRIPTOR_TYPE_UBO;437struct zink_resource *res = zink_get_resource_for_descriptor(ctx, type, shader, slot);438ctx->di.descriptor_res[type][shader][slot] = res;439ctx->di.ubos[shader][slot].offset = ctx->ubos[shader][slot].buffer_offset;440if (res) {441ctx->di.ubos[shader][slot].buffer = res->obj->buffer;442ctx->di.ubos[shader][slot].range = ctx->ubos[shader][slot].buffer_size;443assert(ctx->di.ubos[shader][slot].range <= screen->info.props.limits.maxUniformBufferRange);444} else {445VkBuffer null_buffer = zink_resource(ctx->dummy_vertex_buffer)->obj->buffer;446ctx->di.ubos[shader][slot].buffer = have_null_descriptors ? VK_NULL_HANDLE : null_buffer;447ctx->di.ubos[shader][slot].range = VK_WHOLE_SIZE;448}449if (!slot) {450if (res)451ctx->di.push_valid |= BITFIELD64_BIT(shader);452else453ctx->di.push_valid &= ~BITFIELD64_BIT(shader);454}455}456457ALWAYS_INLINE static void458update_descriptor_state_ssbo(struct zink_context *ctx, enum pipe_shader_type shader, unsigned slot)459{460struct zink_screen *screen = zink_screen(ctx->base.screen);461bool have_null_descriptors = screen->info.rb2_feats.nullDescriptor;462const enum zink_descriptor_type type = ZINK_DESCRIPTOR_TYPE_SSBO;463struct zink_resource *res = zink_get_resource_for_descriptor(ctx, type, shader, slot);464ctx->di.descriptor_res[type][shader][slot] = res;465ctx->di.ssbos[shader][slot].offset = ctx->ssbos[shader][slot].buffer_offset;466if (res) {467ctx->di.ssbos[shader][slot].buffer = res->obj->buffer;468ctx->di.ssbos[shader][slot].range = ctx->ssbos[shader][slot].buffer_size;469} else {470VkBuffer null_buffer = zink_resource(ctx->dummy_vertex_buffer)->obj->buffer;471ctx->di.ssbos[shader][slot].buffer = have_null_descriptors ? VK_NULL_HANDLE : null_buffer;472ctx->di.ssbos[shader][slot].range = VK_WHOLE_SIZE;473}474}475476ALWAYS_INLINE static void477update_descriptor_state_sampler(struct zink_context *ctx, enum pipe_shader_type shader, unsigned slot)478{479struct zink_screen *screen = zink_screen(ctx->base.screen);480bool have_null_descriptors = screen->info.rb2_feats.nullDescriptor;481const enum zink_descriptor_type type = ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW;482struct zink_resource *res = zink_get_resource_for_descriptor(ctx, type, shader, slot);483ctx->di.descriptor_res[type][shader][slot] = res;484if (res) {485if (res->obj->is_buffer) {486struct zink_buffer_view *bv = get_bufferview_for_binding(ctx, shader, type, slot);487ctx->di.tbos[shader][slot] = bv->buffer_view;488ctx->di.sampler_surfaces[shader][slot].bufferview = bv;489ctx->di.sampler_surfaces[shader][slot].is_buffer = true;490} else {491struct zink_surface *surface = get_imageview_for_binding(ctx, shader, type, slot);492ctx->di.textures[shader][slot].imageLayout = get_layout_for_binding(res, type, shader == PIPE_SHADER_COMPUTE);493ctx->di.textures[shader][slot].imageView = surface->image_view;494ctx->di.sampler_surfaces[shader][slot].surface = surface;495ctx->di.sampler_surfaces[shader][slot].is_buffer = false;496}497} else {498if (likely(have_null_descriptors)) {499ctx->di.textures[shader][slot].imageView = VK_NULL_HANDLE;500ctx->di.textures[shader][slot].imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;501ctx->di.tbos[shader][slot] = VK_NULL_HANDLE;502} else {503struct zink_surface *null_surface = zink_surface(ctx->dummy_surface);504struct zink_buffer_view *null_bufferview = ctx->dummy_bufferview;505ctx->di.textures[shader][slot].imageView = null_surface->image_view;506ctx->di.textures[shader][slot].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;507ctx->di.tbos[shader][slot] = null_bufferview->buffer_view;508}509memset(&ctx->di.sampler_surfaces[shader][slot], 0, sizeof(ctx->di.sampler_surfaces[shader][slot]));510}511}512513ALWAYS_INLINE static void514update_descriptor_state_image(struct zink_context *ctx, enum pipe_shader_type shader, unsigned slot)515{516struct zink_screen *screen = zink_screen(ctx->base.screen);517bool have_null_descriptors = screen->info.rb2_feats.nullDescriptor;518const enum zink_descriptor_type type = ZINK_DESCRIPTOR_TYPE_IMAGE;519struct zink_resource *res = zink_get_resource_for_descriptor(ctx, type, shader, slot);520ctx->di.descriptor_res[type][shader][slot] = res;521if (res) {522if (res->obj->is_buffer) {523struct zink_buffer_view *bv = get_bufferview_for_binding(ctx, shader, type, slot);524ctx->di.texel_images[shader][slot] = bv->buffer_view;525ctx->di.image_surfaces[shader][slot].bufferview = bv;526ctx->di.image_surfaces[shader][slot].is_buffer = true;527} else {528struct zink_surface *surface = get_imageview_for_binding(ctx, shader, type, slot);529ctx->di.images[shader][slot].imageLayout = VK_IMAGE_LAYOUT_GENERAL;530ctx->di.images[shader][slot].imageView = surface->image_view;531ctx->di.image_surfaces[shader][slot].surface = surface;532ctx->di.image_surfaces[shader][slot].is_buffer = false;533}534} else {535if (likely(have_null_descriptors)) {536memset(&ctx->di.images[shader][slot], 0, sizeof(ctx->di.images[shader][slot]));537ctx->di.texel_images[shader][slot] = VK_NULL_HANDLE;538} else {539struct zink_surface *null_surface = zink_surface(ctx->dummy_surface);540struct zink_buffer_view *null_bufferview = ctx->dummy_bufferview;541ctx->di.images[shader][slot].imageView = null_surface->image_view;542ctx->di.images[shader][slot].imageLayout = VK_IMAGE_LAYOUT_GENERAL;543ctx->di.texel_images[shader][slot] = null_bufferview->buffer_view;544}545memset(&ctx->di.image_surfaces[shader][slot], 0, sizeof(ctx->di.image_surfaces[shader][slot]));546}547}548549static void550zink_bind_sampler_states(struct pipe_context *pctx,551enum pipe_shader_type shader,552unsigned start_slot,553unsigned num_samplers,554void **samplers)555{556struct zink_context *ctx = zink_context(pctx);557for (unsigned i = 0; i < num_samplers; ++i) {558struct zink_sampler_state *state = samplers[i];559if (ctx->sampler_states[shader][start_slot + i] != state)560zink_screen(pctx->screen)->context_invalidate_descriptor_state(ctx, shader, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW, start_slot, 1);561ctx->sampler_states[shader][start_slot + i] = state;562ctx->di.textures[shader][start_slot + i].sampler = state ? state->sampler : VK_NULL_HANDLE;563if (state)564zink_batch_usage_set(&state->batch_uses, ctx->batch.state);565}566ctx->di.num_samplers[shader] = start_slot + num_samplers;567}568569static void570zink_delete_sampler_state(struct pipe_context *pctx,571void *sampler_state)572{573struct zink_sampler_state *sampler = sampler_state;574struct zink_batch *batch = &zink_context(pctx)->batch;575zink_descriptor_set_refs_clear(&sampler->desc_set_refs, sampler_state);576util_dynarray_append(&batch->state->zombie_samplers, VkSampler,577sampler->sampler);578if (sampler->custom_border_color)579p_atomic_dec(&zink_screen(pctx->screen)->cur_custom_border_color_samplers);580FREE(sampler);581}582583static VkComponentSwizzle584component_mapping(enum pipe_swizzle swizzle)585{586switch (swizzle) {587case PIPE_SWIZZLE_X: return VK_COMPONENT_SWIZZLE_R;588case PIPE_SWIZZLE_Y: return VK_COMPONENT_SWIZZLE_G;589case PIPE_SWIZZLE_Z: return VK_COMPONENT_SWIZZLE_B;590case PIPE_SWIZZLE_W: return VK_COMPONENT_SWIZZLE_A;591case PIPE_SWIZZLE_0: return VK_COMPONENT_SWIZZLE_ZERO;592case PIPE_SWIZZLE_1: return VK_COMPONENT_SWIZZLE_ONE;593case PIPE_SWIZZLE_NONE: return VK_COMPONENT_SWIZZLE_IDENTITY; // ???594default:595unreachable("unexpected swizzle");596}597}598599static VkImageAspectFlags600sampler_aspect_from_format(enum pipe_format fmt)601{602if (util_format_is_depth_or_stencil(fmt)) {603const struct util_format_description *desc = util_format_description(fmt);604if (util_format_has_depth(desc))605return VK_IMAGE_ASPECT_DEPTH_BIT;606assert(util_format_has_stencil(desc));607return VK_IMAGE_ASPECT_STENCIL_BIT;608} else609return VK_IMAGE_ASPECT_COLOR_BIT;610}611612static uint32_t613hash_bufferview(void *bvci)614{615size_t offset = offsetof(VkBufferViewCreateInfo, flags);616return _mesa_hash_data((char*)bvci + offset, sizeof(VkBufferViewCreateInfo) - offset);617}618619static struct zink_buffer_view *620get_buffer_view(struct zink_context *ctx, struct zink_resource *res, enum pipe_format format, uint32_t offset, uint32_t range)621{622struct zink_screen *screen = zink_screen(ctx->base.screen);623struct zink_buffer_view *buffer_view = NULL;624VkBufferViewCreateInfo bvci = {0};625bvci.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;626bvci.buffer = res->obj->buffer;627bvci.format = zink_get_format(screen, format);628assert(bvci.format);629bvci.offset = offset;630bvci.range = range;631632uint32_t hash = hash_bufferview(&bvci);633simple_mtx_lock(&screen->bufferview_mtx);634struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&screen->bufferview_cache, hash, &bvci);635if (he) {636buffer_view = he->data;637p_atomic_inc(&buffer_view->reference.count);638} else {639VkBufferView view;640if (vkCreateBufferView(screen->dev, &bvci, NULL, &view) != VK_SUCCESS)641goto out;642buffer_view = CALLOC_STRUCT(zink_buffer_view);643if (!buffer_view) {644vkDestroyBufferView(screen->dev, view, NULL);645goto out;646}647pipe_reference_init(&buffer_view->reference, 1);648util_dynarray_init(&buffer_view->desc_set_refs.refs, NULL);649buffer_view->bvci = bvci;650buffer_view->buffer_view = view;651buffer_view->hash = hash;652_mesa_hash_table_insert_pre_hashed(&screen->bufferview_cache, hash, &buffer_view->bvci, buffer_view);653}654out:655simple_mtx_unlock(&screen->bufferview_mtx);656return buffer_view;657}658659static inline enum pipe_swizzle660clamp_void_swizzle(const struct util_format_description *desc, enum pipe_swizzle swizzle)661{662switch (swizzle) {663case PIPE_SWIZZLE_X:664case PIPE_SWIZZLE_Y:665case PIPE_SWIZZLE_Z:666case PIPE_SWIZZLE_W:667return desc->channel[swizzle].type == UTIL_FORMAT_TYPE_VOID ? PIPE_SWIZZLE_1 : swizzle;668default:669break;670}671return swizzle;672}673674ALWAYS_INLINE static enum pipe_swizzle675clamp_zs_swizzle(enum pipe_swizzle swizzle)676{677switch (swizzle) {678case PIPE_SWIZZLE_X:679case PIPE_SWIZZLE_Y:680case PIPE_SWIZZLE_Z:681case PIPE_SWIZZLE_W:682return PIPE_SWIZZLE_X;683default:684break;685}686return swizzle;687}688689static inline bool690format_is_usable_rgba_variant(const struct util_format_description *desc)691{692unsigned chan;693694if(desc->block.width != 1 ||695desc->block.height != 1 ||696(desc->block.bits != 32 && desc->block.bits != 64))697return false;698699if (desc->nr_channels != 4)700return false;701702unsigned size = desc->channel[0].size;703for(chan = 0; chan < 4; ++chan) {704if(desc->channel[chan].size != size)705return false;706}707708return true;709}710711static struct pipe_sampler_view *712zink_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *pres,713const struct pipe_sampler_view *state)714{715struct zink_screen *screen = zink_screen(pctx->screen);716struct zink_resource *res = zink_resource(pres);717struct zink_sampler_view *sampler_view = CALLOC_STRUCT(zink_sampler_view);718bool err;719720sampler_view->base = *state;721sampler_view->base.texture = NULL;722pipe_resource_reference(&sampler_view->base.texture, pres);723sampler_view->base.reference.count = 1;724sampler_view->base.context = pctx;725726if (state->target != PIPE_BUFFER) {727VkImageViewCreateInfo ivci;728729struct pipe_surface templ = {0};730templ.u.tex.level = state->u.tex.first_level;731templ.format = state->format;732if (state->target != PIPE_TEXTURE_3D) {733templ.u.tex.first_layer = state->u.tex.first_layer;734templ.u.tex.last_layer = state->u.tex.last_layer;735}736737ivci = create_ivci(screen, res, &templ, state->target);738ivci.subresourceRange.levelCount = state->u.tex.last_level - state->u.tex.first_level + 1;739ivci.subresourceRange.aspectMask = sampler_aspect_from_format(state->format);740/* samplers for stencil aspects of packed formats need to always use stencil swizzle */741if (ivci.subresourceRange.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {742ivci.components.r = component_mapping(clamp_zs_swizzle(sampler_view->base.swizzle_r));743ivci.components.g = component_mapping(clamp_zs_swizzle(sampler_view->base.swizzle_g));744ivci.components.b = component_mapping(clamp_zs_swizzle(sampler_view->base.swizzle_b));745ivci.components.a = component_mapping(clamp_zs_swizzle(sampler_view->base.swizzle_a));746} else {747/* if we have e.g., R8G8B8X8, then we have to ignore alpha since we're just emulating748* these formats749*/750const struct util_format_description *desc = util_format_description(state->format);751if (format_is_usable_rgba_variant(desc)) {752sampler_view->base.swizzle_r = clamp_void_swizzle(desc, sampler_view->base.swizzle_r);753sampler_view->base.swizzle_g = clamp_void_swizzle(desc, sampler_view->base.swizzle_g);754sampler_view->base.swizzle_b = clamp_void_swizzle(desc, sampler_view->base.swizzle_b);755sampler_view->base.swizzle_a = clamp_void_swizzle(desc, sampler_view->base.swizzle_a);756}757ivci.components.r = component_mapping(sampler_view->base.swizzle_r);758ivci.components.g = component_mapping(sampler_view->base.swizzle_g);759ivci.components.b = component_mapping(sampler_view->base.swizzle_b);760ivci.components.a = component_mapping(sampler_view->base.swizzle_a);761}762assert(ivci.format);763764sampler_view->image_view = (struct zink_surface*)zink_get_surface(zink_context(pctx), pres, &templ, &ivci);765err = !sampler_view->image_view;766} else {767sampler_view->buffer_view = get_buffer_view(zink_context(pctx), res, state->format, state->u.buf.offset, state->u.buf.size);768err = !sampler_view->buffer_view;769}770if (err) {771FREE(sampler_view);772return NULL;773}774return &sampler_view->base;775}776777void778zink_destroy_buffer_view(struct zink_screen *screen, struct zink_buffer_view *buffer_view)779{780simple_mtx_lock(&screen->bufferview_mtx);781struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&screen->bufferview_cache, buffer_view->hash, &buffer_view->bvci);782assert(he);783_mesa_hash_table_remove(&screen->bufferview_cache, he);784simple_mtx_unlock(&screen->bufferview_mtx);785vkDestroyBufferView(screen->dev, buffer_view->buffer_view, NULL);786zink_descriptor_set_refs_clear(&buffer_view->desc_set_refs, buffer_view);787FREE(buffer_view);788}789790static void791zink_sampler_view_destroy(struct pipe_context *pctx,792struct pipe_sampler_view *pview)793{794struct zink_sampler_view *view = zink_sampler_view(pview);795if (pview->texture->target == PIPE_BUFFER)796zink_buffer_view_reference(zink_screen(pctx->screen), &view->buffer_view, NULL);797else {798zink_surface_reference(zink_screen(pctx->screen), &view->image_view, NULL);799}800pipe_resource_reference(&pview->texture, NULL);801FREE(view);802}803804static void805zink_get_sample_position(struct pipe_context *ctx,806unsigned sample_count,807unsigned sample_index,808float *out_value)809{810/* TODO: handle this I guess */811assert(zink_screen(ctx->screen)->info.props.limits.standardSampleLocations);812/* from 26.4. Multisampling */813switch (sample_count) {814case 0:815case 1: {816float pos[][2] = { {0.5,0.5}, };817out_value[0] = pos[sample_index][0];818out_value[1] = pos[sample_index][1];819break;820}821case 2: {822float pos[][2] = { {0.75,0.75},823{0.25,0.25}, };824out_value[0] = pos[sample_index][0];825out_value[1] = pos[sample_index][1];826break;827}828case 4: {829float pos[][2] = { {0.375, 0.125},830{0.875, 0.375},831{0.125, 0.625},832{0.625, 0.875}, };833out_value[0] = pos[sample_index][0];834out_value[1] = pos[sample_index][1];835break;836}837case 8: {838float pos[][2] = { {0.5625, 0.3125},839{0.4375, 0.6875},840{0.8125, 0.5625},841{0.3125, 0.1875},842{0.1875, 0.8125},843{0.0625, 0.4375},844{0.6875, 0.9375},845{0.9375, 0.0625}, };846out_value[0] = pos[sample_index][0];847out_value[1] = pos[sample_index][1];848break;849}850case 16: {851float pos[][2] = { {0.5625, 0.5625},852{0.4375, 0.3125},853{0.3125, 0.625},854{0.75, 0.4375},855{0.1875, 0.375},856{0.625, 0.8125},857{0.8125, 0.6875},858{0.6875, 0.1875},859{0.375, 0.875},860{0.5, 0.0625},861{0.25, 0.125},862{0.125, 0.75},863{0.0, 0.5},864{0.9375, 0.25},865{0.875, 0.9375},866{0.0625, 0.0}, };867out_value[0] = pos[sample_index][0];868out_value[1] = pos[sample_index][1];869break;870}871default:872unreachable("unhandled sample count!");873}874}875876static void877zink_set_polygon_stipple(struct pipe_context *pctx,878const struct pipe_poly_stipple *ps)879{880}881882ALWAYS_INLINE static void883update_res_bind_count(struct zink_context *ctx, struct zink_resource *res, bool is_compute, bool decrement)884{885if (decrement) {886assert(res->bind_count[is_compute]);887if (!--res->bind_count[is_compute])888_mesa_set_remove_key(ctx->need_barriers[is_compute], res);889check_resource_for_batch_ref(ctx, res);890} else891res->bind_count[is_compute]++;892}893894ALWAYS_INLINE static void895update_existing_vbo(struct zink_context *ctx, unsigned slot)896{897if (!ctx->vertex_buffers[slot].buffer.resource)898return;899struct zink_resource *res = zink_resource(ctx->vertex_buffers[slot].buffer.resource);900res->vbo_bind_count--;901update_res_bind_count(ctx, res, false, true);902}903904static void905zink_set_vertex_buffers(struct pipe_context *pctx,906unsigned start_slot,907unsigned num_buffers,908unsigned unbind_num_trailing_slots,909bool take_ownership,910const struct pipe_vertex_buffer *buffers)911{912struct zink_context *ctx = zink_context(pctx);913914uint32_t enabled_buffers = ctx->gfx_pipeline_state.vertex_buffers_enabled_mask;915enabled_buffers |= u_bit_consecutive(start_slot, num_buffers);916enabled_buffers &= ~u_bit_consecutive(start_slot + num_buffers, unbind_num_trailing_slots);917918if (buffers) {919if (!zink_screen(pctx->screen)->info.have_EXT_extended_dynamic_state)920ctx->gfx_pipeline_state.vertex_state_dirty = true;921for (unsigned i = 0; i < num_buffers; ++i) {922const struct pipe_vertex_buffer *vb = buffers + i;923struct pipe_vertex_buffer *ctx_vb = &ctx->vertex_buffers[start_slot + i];924update_existing_vbo(ctx, start_slot + i);925if (!take_ownership)926pipe_resource_reference(&ctx_vb->buffer.resource, vb->buffer.resource);927else {928pipe_resource_reference(&ctx_vb->buffer.resource, NULL);929ctx_vb->buffer.resource = vb->buffer.resource;930}931if (vb->buffer.resource) {932struct zink_resource *res = zink_resource(vb->buffer.resource);933res->vbo_bind_count++;934update_res_bind_count(ctx, res, false, false);935ctx_vb->stride = vb->stride;936ctx_vb->buffer_offset = vb->buffer_offset;937zink_batch_resource_usage_set(&ctx->batch, res, false);938zink_resource_buffer_barrier(ctx, NULL, res, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,939VK_PIPELINE_STAGE_VERTEX_INPUT_BIT);940}941}942} else {943if (!zink_screen(pctx->screen)->info.have_EXT_extended_dynamic_state)944ctx->gfx_pipeline_state.vertex_state_dirty = true;945for (unsigned i = 0; i < num_buffers; ++i) {946update_existing_vbo(ctx, start_slot + i);947pipe_resource_reference(&ctx->vertex_buffers[start_slot + i].buffer.resource, NULL);948}949}950for (unsigned i = 0; i < unbind_num_trailing_slots; i++) {951update_existing_vbo(ctx, start_slot + i);952pipe_resource_reference(&ctx->vertex_buffers[start_slot + i].buffer.resource, NULL);953}954ctx->gfx_pipeline_state.vertex_buffers_enabled_mask = enabled_buffers;955ctx->vertex_buffers_dirty = num_buffers > 0;956}957958static void959zink_set_viewport_states(struct pipe_context *pctx,960unsigned start_slot,961unsigned num_viewports,962const struct pipe_viewport_state *state)963{964struct zink_context *ctx = zink_context(pctx);965966for (unsigned i = 0; i < num_viewports; ++i)967ctx->vp_state.viewport_states[start_slot + i] = state[i];968ctx->vp_state.num_viewports = start_slot + num_viewports;969970if (!zink_screen(pctx->screen)->info.have_EXT_extended_dynamic_state) {971if (ctx->gfx_pipeline_state.num_viewports != ctx->vp_state.num_viewports)972ctx->gfx_pipeline_state.dirty = true;973ctx->gfx_pipeline_state.num_viewports = ctx->vp_state.num_viewports;974}975ctx->vp_state_changed = true;976}977978static void979zink_set_scissor_states(struct pipe_context *pctx,980unsigned start_slot, unsigned num_scissors,981const struct pipe_scissor_state *states)982{983struct zink_context *ctx = zink_context(pctx);984985for (unsigned i = 0; i < num_scissors; i++)986ctx->vp_state.scissor_states[start_slot + i] = states[i];987ctx->scissor_changed = true;988}989990static void991zink_set_inlinable_constants(struct pipe_context *pctx,992enum pipe_shader_type shader,993uint num_values, uint32_t *values)994{995struct zink_context *ctx = (struct zink_context *)pctx;996997memcpy(ctx->inlinable_uniforms[shader], values, num_values * 4);998ctx->dirty_shader_stages |= 1 << shader;999ctx->inlinable_uniforms_valid_mask |= 1 << shader;1000}10011002ALWAYS_INLINE static void1003unbind_ubo(struct zink_context *ctx, struct zink_resource *res, enum pipe_shader_type pstage, unsigned slot)1004{1005if (!res)1006return;1007res->ubo_bind_mask[pstage] &= ~BITFIELD_BIT(slot);1008res->ubo_bind_count[pstage == PIPE_SHADER_COMPUTE]--;1009update_res_bind_count(ctx, res, pstage == PIPE_SHADER_COMPUTE, true);1010}10111012static void1013zink_set_constant_buffer(struct pipe_context *pctx,1014enum pipe_shader_type shader, uint index,1015bool take_ownership,1016const struct pipe_constant_buffer *cb)1017{1018struct zink_context *ctx = zink_context(pctx);1019bool update = false;10201021struct zink_resource *res = zink_resource(ctx->ubos[shader][index].buffer);1022if (cb) {1023struct pipe_resource *buffer = cb->buffer;1024unsigned offset = cb->buffer_offset;1025struct zink_screen *screen = zink_screen(pctx->screen);1026if (cb->user_buffer) {1027u_upload_data(ctx->base.const_uploader, 0, cb->buffer_size,1028screen->info.props.limits.minUniformBufferOffsetAlignment,1029cb->user_buffer, &offset, &buffer);1030}1031struct zink_resource *new_res = zink_resource(buffer);1032if (new_res) {1033if (new_res != res) {1034unbind_ubo(ctx, res, shader, index);1035new_res->bind_history |= BITFIELD_BIT(ZINK_DESCRIPTOR_TYPE_UBO);1036new_res->bind_stages |= 1 << shader;1037new_res->ubo_bind_count[shader == PIPE_SHADER_COMPUTE]++;1038new_res->ubo_bind_mask[shader] |= BITFIELD_BIT(index);1039update_res_bind_count(ctx, new_res, shader == PIPE_SHADER_COMPUTE, false);1040}1041zink_batch_resource_usage_set(&ctx->batch, new_res, false);1042zink_fake_buffer_barrier(new_res, VK_ACCESS_UNIFORM_READ_BIT,1043zink_pipeline_flags_from_pipe_stage(shader));1044}1045update |= ((index || screen->descriptor_mode == ZINK_DESCRIPTOR_MODE_LAZY) && ctx->ubos[shader][index].buffer_offset != offset) ||1046!!res != !!buffer || (res && res->obj->buffer != new_res->obj->buffer) ||1047ctx->ubos[shader][index].buffer_size != cb->buffer_size;10481049if (take_ownership) {1050pipe_resource_reference(&ctx->ubos[shader][index].buffer, NULL);1051ctx->ubos[shader][index].buffer = buffer;1052} else {1053pipe_resource_reference(&ctx->ubos[shader][index].buffer, buffer);1054}1055ctx->ubos[shader][index].buffer_offset = offset;1056ctx->ubos[shader][index].buffer_size = cb->buffer_size;1057ctx->ubos[shader][index].user_buffer = NULL;10581059if (cb->user_buffer)1060pipe_resource_reference(&buffer, NULL);10611062if (index + 1 >= ctx->di.num_ubos[shader])1063ctx->di.num_ubos[shader] = index + 1;1064} else {1065if (res)1066unbind_ubo(ctx, res, shader, index);1067update = !!ctx->ubos[shader][index].buffer;10681069pipe_resource_reference(&ctx->ubos[shader][index].buffer, NULL);1070ctx->ubos[shader][index].buffer_offset = 0;1071ctx->ubos[shader][index].buffer_size = 0;1072ctx->ubos[shader][index].user_buffer = NULL;1073if (ctx->di.num_ubos[shader] == index + 1)1074ctx->di.num_ubos[shader]--;1075}1076if (index == 0) {1077/* Invalidate current inlinable uniforms. */1078ctx->inlinable_uniforms_valid_mask &= ~(1 << shader);1079}1080update_descriptor_state_ubo(ctx, shader, index);10811082if (update)1083zink_screen(pctx->screen)->context_invalidate_descriptor_state(ctx, shader, ZINK_DESCRIPTOR_TYPE_UBO, index, 1);1084}10851086ALWAYS_INLINE static void1087unbind_ssbo(struct zink_context *ctx, struct zink_resource *res, enum pipe_shader_type pstage, unsigned slot, bool writable)1088{1089if (!res)1090return;1091res->ssbo_bind_mask[pstage] &= ~BITFIELD_BIT(slot);1092update_res_bind_count(ctx, res, pstage == PIPE_SHADER_COMPUTE, true);1093if (writable)1094res->write_bind_count[pstage == PIPE_SHADER_COMPUTE]--;1095}10961097static void1098zink_set_shader_buffers(struct pipe_context *pctx,1099enum pipe_shader_type p_stage,1100unsigned start_slot, unsigned count,1101const struct pipe_shader_buffer *buffers,1102unsigned writable_bitmask)1103{1104struct zink_context *ctx = zink_context(pctx);1105bool update = false;1106unsigned max_slot = 0;11071108unsigned modified_bits = u_bit_consecutive(start_slot, count);1109unsigned old_writable_mask = ctx->writable_ssbos[p_stage];1110ctx->writable_ssbos[p_stage] &= ~modified_bits;1111ctx->writable_ssbos[p_stage] |= writable_bitmask << start_slot;11121113for (unsigned i = 0; i < count; i++) {1114struct pipe_shader_buffer *ssbo = &ctx->ssbos[p_stage][start_slot + i];1115struct zink_resource *res = ssbo->buffer ? zink_resource(ssbo->buffer) : NULL;1116bool was_writable = old_writable_mask & BITFIELD64_BIT(start_slot + i);1117if (buffers && buffers[i].buffer) {1118struct zink_resource *new_res = zink_resource(buffers[i].buffer);1119if (new_res != res) {1120unbind_ssbo(ctx, res, p_stage, i, was_writable);1121new_res->bind_history |= BITFIELD_BIT(ZINK_DESCRIPTOR_TYPE_SSBO);1122new_res->bind_stages |= 1 << p_stage;1123new_res->ssbo_bind_mask[p_stage] |= BITFIELD_BIT(i);1124update_res_bind_count(ctx, new_res, p_stage == PIPE_SHADER_COMPUTE, false);1125}1126VkAccessFlags access = VK_ACCESS_SHADER_READ_BIT;1127if (ctx->writable_ssbos[p_stage] & BITFIELD64_BIT(start_slot + i)) {1128new_res->write_bind_count[p_stage == PIPE_SHADER_COMPUTE]++;1129access |= VK_ACCESS_SHADER_WRITE_BIT;1130}1131pipe_resource_reference(&ssbo->buffer, &new_res->base.b);1132zink_batch_resource_usage_set(&ctx->batch, new_res, access & VK_ACCESS_SHADER_WRITE_BIT);1133ssbo->buffer_offset = buffers[i].buffer_offset;1134ssbo->buffer_size = MIN2(buffers[i].buffer_size, new_res->base.b.width0 - ssbo->buffer_offset);1135util_range_add(&new_res->base.b, &new_res->valid_buffer_range, ssbo->buffer_offset,1136ssbo->buffer_offset + ssbo->buffer_size);1137zink_fake_buffer_barrier(new_res, access,1138zink_pipeline_flags_from_pipe_stage(p_stage));1139update = true;1140max_slot = MAX2(max_slot, start_slot + i);1141} else {1142update = !!res;1143if (res)1144unbind_ssbo(ctx, res, p_stage, i, was_writable);1145pipe_resource_reference(&ssbo->buffer, NULL);1146ssbo->buffer_offset = 0;1147ssbo->buffer_size = 0;1148}1149update_descriptor_state_ssbo(ctx, p_stage, start_slot + i);1150}1151if (start_slot + count >= ctx->di.num_ssbos[p_stage])1152ctx->di.num_ssbos[p_stage] = max_slot + 1;1153if (update)1154zink_screen(pctx->screen)->context_invalidate_descriptor_state(ctx, p_stage, ZINK_DESCRIPTOR_TYPE_SSBO, start_slot, count);1155}11561157static void1158update_binds_for_samplerviews(struct zink_context *ctx, struct zink_resource *res, bool is_compute)1159{1160VkImageLayout layout = get_layout_for_binding(res, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW, is_compute);1161if (is_compute) {1162u_foreach_bit(slot, res->sampler_binds[PIPE_SHADER_COMPUTE]) {1163if (ctx->di.textures[PIPE_SHADER_COMPUTE][slot].imageLayout != layout) {1164update_descriptor_state_sampler(ctx, PIPE_SHADER_COMPUTE, slot);1165zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, PIPE_SHADER_COMPUTE, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW, slot, 1);1166}1167}1168} else {1169for (unsigned i = 0; i < ZINK_SHADER_COUNT; i++) {1170u_foreach_bit(slot, res->sampler_binds[i]) {1171if (ctx->di.textures[i][slot].imageLayout != layout) {1172update_descriptor_state_sampler(ctx, i, slot);1173zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, i, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW, slot, 1);1174}1175}1176}1177}1178}11791180static void1181flush_pending_clears(struct zink_context *ctx, struct zink_resource *res)1182{1183if (res->fb_binds && ctx->clears_enabled)1184zink_fb_clears_apply(ctx, &res->base.b);1185}11861187static inline void1188unbind_shader_image_counts(struct zink_context *ctx, struct zink_resource *res, bool is_compute, bool writable)1189{1190update_res_bind_count(ctx, res, is_compute, true);1191if (writable)1192res->write_bind_count[is_compute]--;1193res->image_bind_count[is_compute]--;1194/* if this was the last image bind, the sampler bind layouts must be updated */1195if (!res->obj->is_buffer && !res->image_bind_count[is_compute] && res->bind_count[is_compute])1196update_binds_for_samplerviews(ctx, res, is_compute);1197}11981199ALWAYS_INLINE static void1200check_for_layout_update(struct zink_context *ctx, struct zink_resource *res, bool is_compute)1201{1202VkImageLayout layout = res->bind_count[is_compute] ? zink_descriptor_util_image_layout_eval(res, is_compute) : VK_IMAGE_LAYOUT_UNDEFINED;1203VkImageLayout other_layout = res->bind_count[!is_compute] ? zink_descriptor_util_image_layout_eval(res, !is_compute) : VK_IMAGE_LAYOUT_UNDEFINED;1204if (res->bind_count[is_compute] && res->layout != layout)1205_mesa_set_add(ctx->need_barriers[is_compute], res);1206if (res->bind_count[!is_compute] && (layout != other_layout || res->layout != other_layout))1207_mesa_set_add(ctx->need_barriers[!is_compute], res);1208}12091210static void1211unbind_shader_image(struct zink_context *ctx, enum pipe_shader_type stage, unsigned slot)1212{1213struct zink_image_view *image_view = &ctx->image_views[stage][slot];1214bool is_compute = stage == PIPE_SHADER_COMPUTE;1215if (!image_view->base.resource)1216return;12171218struct zink_resource *res = zink_resource(image_view->base.resource);1219unbind_shader_image_counts(ctx, res, is_compute, image_view->base.access & PIPE_IMAGE_ACCESS_WRITE);12201221if (image_view->base.resource->target == PIPE_BUFFER) {1222if (zink_batch_usage_exists(image_view->buffer_view->batch_uses))1223zink_batch_reference_bufferview(&ctx->batch, image_view->buffer_view);1224zink_buffer_view_reference(zink_screen(ctx->base.screen), &image_view->buffer_view, NULL);1225} else {1226if (!res->image_bind_count[is_compute])1227check_for_layout_update(ctx, res, is_compute);1228if (zink_batch_usage_exists(image_view->surface->batch_uses))1229zink_batch_reference_surface(&ctx->batch, image_view->surface);1230zink_surface_reference(zink_screen(ctx->base.screen), &image_view->surface, NULL);1231}1232pipe_resource_reference(&image_view->base.resource, NULL);1233image_view->base.resource = NULL;1234image_view->surface = NULL;1235}12361237static void1238zink_set_shader_images(struct pipe_context *pctx,1239enum pipe_shader_type p_stage,1240unsigned start_slot, unsigned count,1241unsigned unbind_num_trailing_slots,1242const struct pipe_image_view *images)1243{1244struct zink_context *ctx = zink_context(pctx);1245bool update = false;1246for (unsigned i = 0; i < count; i++) {1247struct zink_image_view *image_view = &ctx->image_views[p_stage][start_slot + i];1248if (images && images[i].resource) {1249struct zink_resource *res = zink_resource(images[i].resource);1250struct zink_resource *old_res = zink_resource(image_view->base.resource);1251if (!zink_resource_object_init_storage(ctx, res)) {1252debug_printf("couldn't create storage image!");1253continue;1254}1255if (res != old_res) {1256if (old_res) {1257unbind_shader_image_counts(ctx, old_res, p_stage == PIPE_SHADER_COMPUTE, image_view->base.access & PIPE_IMAGE_ACCESS_WRITE);1258if (!old_res->obj->is_buffer && !old_res->image_bind_count[p_stage == PIPE_SHADER_COMPUTE])1259check_for_layout_update(ctx, old_res, p_stage == PIPE_SHADER_COMPUTE);1260}1261res->bind_history |= BITFIELD_BIT(ZINK_DESCRIPTOR_TYPE_IMAGE);1262res->bind_stages |= 1 << p_stage;1263update_res_bind_count(ctx, res, p_stage == PIPE_SHADER_COMPUTE, false);1264}1265util_copy_image_view(&image_view->base, images + i);1266VkAccessFlags access = 0;1267if (image_view->base.access & PIPE_IMAGE_ACCESS_WRITE) {1268zink_resource(image_view->base.resource)->write_bind_count[p_stage == PIPE_SHADER_COMPUTE]++;1269access |= VK_ACCESS_SHADER_WRITE_BIT;1270}1271if (image_view->base.access & PIPE_IMAGE_ACCESS_READ) {1272access |= VK_ACCESS_SHADER_READ_BIT;1273}1274res->image_bind_count[p_stage == PIPE_SHADER_COMPUTE]++;1275if (images[i].resource->target == PIPE_BUFFER) {1276image_view->buffer_view = get_buffer_view(ctx, res, images[i].format, images[i].u.buf.offset, images[i].u.buf.size);1277assert(image_view->buffer_view);1278util_range_add(&res->base.b, &res->valid_buffer_range, images[i].u.buf.offset,1279images[i].u.buf.offset + images[i].u.buf.size);1280zink_batch_usage_set(&image_view->buffer_view->batch_uses, ctx->batch.state);1281zink_fake_buffer_barrier(res, access,1282zink_pipeline_flags_from_pipe_stage(p_stage));1283} else {1284struct pipe_surface tmpl = {0};1285tmpl.format = images[i].format;1286tmpl.nr_samples = 1;1287tmpl.u.tex.level = images[i].u.tex.level;1288tmpl.u.tex.first_layer = images[i].u.tex.first_layer;1289tmpl.u.tex.last_layer = images[i].u.tex.last_layer;1290image_view->surface = zink_surface(pctx->create_surface(pctx, &res->base.b, &tmpl));1291assert(image_view->surface);1292/* if this is the first image bind and there are sampler binds, the image's sampler layout1293* must be updated to GENERAL1294*/1295if (res->image_bind_count[p_stage == PIPE_SHADER_COMPUTE] == 1 &&1296res->bind_count[p_stage == PIPE_SHADER_COMPUTE] > 1)1297update_binds_for_samplerviews(ctx, res, p_stage == PIPE_SHADER_COMPUTE);1298check_for_layout_update(ctx, res, p_stage == PIPE_SHADER_COMPUTE);1299zink_batch_usage_set(&image_view->surface->batch_uses, ctx->batch.state);1300flush_pending_clears(ctx, res);1301}1302zink_batch_resource_usage_set(&ctx->batch, zink_resource(image_view->base.resource),1303zink_resource_access_is_write(access));1304update = true;1305} else if (image_view->base.resource) {1306update |= !!image_view->base.resource;13071308unbind_shader_image(ctx, p_stage, start_slot + i);1309}1310update_descriptor_state_image(ctx, p_stage, start_slot + i);1311}1312for (unsigned i = 0; i < unbind_num_trailing_slots; i++) {1313update |= !!ctx->image_views[p_stage][start_slot + count + i].base.resource;1314unbind_shader_image(ctx, p_stage, start_slot + count + i);1315update_descriptor_state_image(ctx, p_stage, start_slot + count + i);1316}1317ctx->di.num_images[p_stage] = start_slot + count;1318if (update)1319zink_screen(pctx->screen)->context_invalidate_descriptor_state(ctx, p_stage, ZINK_DESCRIPTOR_TYPE_IMAGE, start_slot, count);1320}13211322ALWAYS_INLINE static void1323check_samplerview_for_batch_ref(struct zink_context *ctx, struct zink_sampler_view *sv)1324{1325const struct zink_resource *res = zink_resource(sv->base.texture);1326if ((res->obj->is_buffer && zink_batch_usage_exists(sv->buffer_view->batch_uses)) ||1327(!res->obj->is_buffer && zink_batch_usage_exists(sv->image_view->batch_uses)))1328zink_batch_reference_sampler_view(&ctx->batch, sv);1329}13301331ALWAYS_INLINE static void1332unbind_samplerview(struct zink_context *ctx, enum pipe_shader_type stage, unsigned slot)1333{1334struct zink_sampler_view *sv = zink_sampler_view(ctx->sampler_views[stage][slot]);1335if (!sv || !sv->base.texture)1336return;1337struct zink_resource *res = zink_resource(sv->base.texture);1338check_samplerview_for_batch_ref(ctx, sv);1339update_res_bind_count(ctx, res, stage == PIPE_SHADER_COMPUTE, true);1340res->sampler_binds[stage] &= ~BITFIELD_BIT(slot);1341}13421343static void1344zink_set_sampler_views(struct pipe_context *pctx,1345enum pipe_shader_type shader_type,1346unsigned start_slot,1347unsigned num_views,1348unsigned unbind_num_trailing_slots,1349struct pipe_sampler_view **views)1350{1351struct zink_context *ctx = zink_context(pctx);1352unsigned i;13531354bool update = false;1355for (i = 0; i < num_views; ++i) {1356struct pipe_sampler_view *pview = views ? views[i] : NULL;1357struct zink_sampler_view *a = zink_sampler_view(ctx->sampler_views[shader_type][start_slot + i]);1358struct zink_sampler_view *b = zink_sampler_view(pview);1359if (b && b->base.texture) {1360struct zink_resource *res = zink_resource(b->base.texture);1361if (!a || zink_resource(a->base.texture) != res) {1362if (a)1363unbind_samplerview(ctx, shader_type, start_slot + i);1364update_res_bind_count(ctx, res, shader_type == PIPE_SHADER_COMPUTE, false);1365res->bind_history |= BITFIELD64_BIT(ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW);1366res->bind_stages |= 1 << shader_type;1367} else if (a != b) {1368check_samplerview_for_batch_ref(ctx, a);1369}1370if (res->base.b.target == PIPE_BUFFER) {1371if (res->bind_history & BITFIELD64_BIT(ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW)) {1372/* if this resource has been rebound while it wasn't set here,1373* its backing resource will have changed and thus we need to update1374* the bufferview1375*/1376struct zink_buffer_view *buffer_view = get_buffer_view(ctx, res, b->base.format, b->base.u.buf.offset, b->base.u.buf.size);1377if (buffer_view == b->buffer_view)1378p_atomic_dec(&buffer_view->reference.count);1379else {1380if (zink_batch_usage_exists(b->buffer_view->batch_uses))1381zink_batch_reference_bufferview(&ctx->batch, b->buffer_view);1382zink_buffer_view_reference(zink_screen(ctx->base.screen), &b->buffer_view, NULL);1383b->buffer_view = buffer_view;1384update = true;1385}1386}1387zink_batch_usage_set(&b->buffer_view->batch_uses, ctx->batch.state);1388zink_fake_buffer_barrier(res, VK_ACCESS_SHADER_READ_BIT,1389zink_pipeline_flags_from_pipe_stage(shader_type));1390if (!a || a->buffer_view->buffer_view != b->buffer_view->buffer_view)1391update = true;1392} else if (!res->obj->is_buffer) {1393if (res->obj != b->image_view->obj) {1394struct pipe_surface *psurf = &b->image_view->base;1395VkImageView iv = b->image_view->image_view;1396zink_rebind_surface(ctx, &psurf);1397b->image_view = zink_surface(psurf);1398update |= iv != b->image_view->image_view;1399} else if (a != b)1400update = true;1401flush_pending_clears(ctx, res);1402check_for_layout_update(ctx, res, shader_type == PIPE_SHADER_COMPUTE);1403zink_batch_usage_set(&b->image_view->batch_uses, ctx->batch.state);1404if (!a)1405update = true;1406}1407res->sampler_binds[shader_type] |= BITFIELD_BIT(start_slot + i);1408zink_batch_resource_usage_set(&ctx->batch, res, false);1409} else if (a) {1410unbind_samplerview(ctx, shader_type, start_slot + i);1411update = true;1412}1413pipe_sampler_view_reference(&ctx->sampler_views[shader_type][start_slot + i], pview);1414update_descriptor_state_sampler(ctx, shader_type, start_slot + i);1415}1416for (; i < num_views + unbind_num_trailing_slots; ++i) {1417update |= !!ctx->sampler_views[shader_type][start_slot + i];1418unbind_samplerview(ctx, shader_type, start_slot + i);1419pipe_sampler_view_reference(1420&ctx->sampler_views[shader_type][start_slot + i],1421NULL);1422update_descriptor_state_sampler(ctx, shader_type, start_slot + i);1423}1424ctx->di.num_sampler_views[shader_type] = start_slot + num_views;1425if (update)1426zink_screen(pctx->screen)->context_invalidate_descriptor_state(ctx, shader_type, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW, start_slot, num_views);1427}14281429static void1430zink_set_stencil_ref(struct pipe_context *pctx,1431const struct pipe_stencil_ref ref)1432{1433struct zink_context *ctx = zink_context(pctx);1434ctx->stencil_ref = ref;1435ctx->stencil_ref_changed = true;1436}14371438static void1439zink_set_clip_state(struct pipe_context *pctx,1440const struct pipe_clip_state *pcs)1441{1442}14431444static void1445zink_set_tess_state(struct pipe_context *pctx,1446const float default_outer_level[4],1447const float default_inner_level[2])1448{1449struct zink_context *ctx = zink_context(pctx);1450memcpy(&ctx->default_inner_level, default_inner_level, sizeof(ctx->default_inner_level));1451memcpy(&ctx->default_outer_level, default_outer_level, sizeof(ctx->default_outer_level));1452}14531454static uint32_t1455hash_render_pass_state(const void *key)1456{1457struct zink_render_pass_state* s = (struct zink_render_pass_state*)key;1458return _mesa_hash_data(key, offsetof(struct zink_render_pass_state, rts) + sizeof(s->rts[0]) * s->num_rts);1459}14601461static bool1462equals_render_pass_state(const void *a, const void *b)1463{1464const struct zink_render_pass_state *s_a = a, *s_b = b;1465if (s_a->num_rts != s_b->num_rts)1466return false;1467return memcmp(a, b, offsetof(struct zink_render_pass_state, rts) + sizeof(s_a->rts[0]) * s_a->num_rts) == 0;1468}14691470static struct zink_render_pass *1471get_render_pass(struct zink_context *ctx)1472{1473struct zink_screen *screen = zink_screen(ctx->base.screen);1474const struct pipe_framebuffer_state *fb = &ctx->fb_state;1475struct zink_render_pass_state state = {0};1476uint32_t clears = 0;1477state.swapchain_init = ctx->new_swapchain;14781479for (int i = 0; i < fb->nr_cbufs; i++) {1480struct pipe_surface *surf = fb->cbufs[i];1481if (surf) {1482state.rts[i].format = zink_get_format(screen, surf->format);1483state.rts[i].samples = surf->texture->nr_samples > 0 ? surf->texture->nr_samples :1484VK_SAMPLE_COUNT_1_BIT;1485state.rts[i].clear_color = zink_fb_clear_enabled(ctx, i) && !zink_fb_clear_first_needs_explicit(&ctx->fb_clears[i]);1486clears |= !!state.rts[i].clear_color ? PIPE_CLEAR_COLOR0 << i : 0;1487state.rts[i].swapchain = surf->texture->bind & PIPE_BIND_SCANOUT;1488} else {1489state.rts[i].format = VK_FORMAT_R8_UINT;1490state.rts[i].samples = MAX2(fb->samples, 1);1491}1492state.num_rts++;1493}1494state.num_cbufs = fb->nr_cbufs;14951496if (fb->zsbuf) {1497struct zink_resource *zsbuf = zink_resource(fb->zsbuf->texture);1498struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS];1499state.rts[fb->nr_cbufs].format = zsbuf->format;1500state.rts[fb->nr_cbufs].samples = zsbuf->base.b.nr_samples > 0 ? zsbuf->base.b.nr_samples : VK_SAMPLE_COUNT_1_BIT;1501state.rts[fb->nr_cbufs].clear_color = zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS) &&1502!zink_fb_clear_first_needs_explicit(fb_clear) &&1503(zink_fb_clear_element(fb_clear, 0)->zs.bits & PIPE_CLEAR_DEPTH);1504state.rts[fb->nr_cbufs].clear_stencil = zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS) &&1505!zink_fb_clear_first_needs_explicit(fb_clear) &&1506(zink_fb_clear_element(fb_clear, 0)->zs.bits & PIPE_CLEAR_STENCIL);1507if (state.rts[fb->nr_cbufs].clear_color)1508clears |= PIPE_CLEAR_DEPTH;1509if (state.rts[fb->nr_cbufs].clear_stencil)1510clears |= PIPE_CLEAR_STENCIL;1511const uint64_t outputs_written = ctx->gfx_stages[PIPE_SHADER_FRAGMENT] ?1512ctx->gfx_stages[PIPE_SHADER_FRAGMENT]->nir->info.outputs_written : 0;1513bool needs_write = (ctx->dsa_state && ctx->dsa_state->hw_state.depth_write) ||1514outputs_written & (BITFIELD64_BIT(FRAG_RESULT_DEPTH) | BITFIELD64_BIT(FRAG_RESULT_STENCIL));1515state.rts[fb->nr_cbufs].needs_write = needs_write || state.rts[fb->nr_cbufs].clear_color || state.rts[fb->nr_cbufs].clear_stencil;1516state.num_rts++;1517}1518state.have_zsbuf = fb->zsbuf != NULL;1519assert(clears == ctx->rp_clears_enabled);1520state.clears = clears;1521uint32_t hash = hash_render_pass_state(&state);1522struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ctx->render_pass_cache, hash,1523&state);1524struct zink_render_pass *rp;1525if (entry) {1526rp = entry->data;1527assert(rp->state.clears == clears);1528} else {1529rp = zink_create_render_pass(screen, &state);1530if (!_mesa_hash_table_insert_pre_hashed(ctx->render_pass_cache, hash, &rp->state, rp))1531return NULL;1532}1533return rp;1534}15351536static struct zink_framebuffer *1537get_framebuffer(struct zink_context *ctx)1538{1539struct zink_screen *screen = zink_screen(ctx->base.screen);1540struct pipe_surface *attachments[PIPE_MAX_COLOR_BUFS + 1] = {0};15411542struct zink_framebuffer_state state = {0};1543for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {1544struct pipe_surface *psurf = ctx->fb_state.cbufs[i];1545state.attachments[i] = psurf ? zink_surface(psurf)->image_view : VK_NULL_HANDLE;1546attachments[i] = psurf;1547}15481549state.num_attachments = ctx->fb_state.nr_cbufs;1550if (ctx->fb_state.zsbuf) {1551struct pipe_surface *psurf = ctx->fb_state.zsbuf;1552state.attachments[state.num_attachments] = psurf ? zink_surface(psurf)->image_view : VK_NULL_HANDLE;1553attachments[state.num_attachments++] = psurf;1554}15551556state.width = MAX2(ctx->fb_state.width, 1);1557state.height = MAX2(ctx->fb_state.height, 1);1558state.layers = MAX2(util_framebuffer_get_num_layers(&ctx->fb_state), 1);1559state.samples = ctx->fb_state.samples;15601561struct zink_framebuffer *fb;1562simple_mtx_lock(&screen->framebuffer_mtx);1563struct hash_entry *entry = _mesa_hash_table_search(&screen->framebuffer_cache, &state);1564if (entry) {1565fb = (void*)entry->data;1566struct zink_framebuffer *fb_ref = NULL;1567/* this gains 1 ref every time we reuse it */1568zink_framebuffer_reference(screen, &fb_ref, fb);1569} else {1570/* this adds 1 extra ref on creation because all newly-created framebuffers are1571* going to be bound; necessary to handle framebuffers which have no "real" attachments1572* and are only using null surfaces since the only ref they get is the extra one here1573*/1574fb = zink_create_framebuffer(ctx, &state, attachments);1575_mesa_hash_table_insert(&screen->framebuffer_cache, &fb->state, fb);1576}1577simple_mtx_unlock(&screen->framebuffer_mtx);15781579return fb;1580}15811582static void1583setup_framebuffer(struct zink_context *ctx)1584{1585struct zink_screen *screen = zink_screen(ctx->base.screen);1586struct zink_render_pass *rp = ctx->gfx_pipeline_state.render_pass;15871588if (ctx->gfx_pipeline_state.sample_locations_enabled && ctx->sample_locations_changed) {1589unsigned samples = ctx->gfx_pipeline_state.rast_samples;1590unsigned idx = util_logbase2_ceil(MAX2(samples, 1));1591VkExtent2D grid_size = screen->maxSampleLocationGridSize[idx];15921593for (unsigned pixel = 0; pixel < grid_size.width * grid_size.height; pixel++) {1594for (unsigned sample = 0; sample < samples; sample++) {1595unsigned pixel_x = pixel % grid_size.width;1596unsigned pixel_y = pixel / grid_size.width;1597unsigned wi = pixel * samples + sample;1598unsigned ri = (pixel_y * grid_size.width + pixel_x % grid_size.width);1599ri = ri * samples + sample;1600ctx->vk_sample_locations[wi].x = (ctx->sample_locations[ri] & 0xf) / 16.0f;1601ctx->vk_sample_locations[wi].y = (16 - (ctx->sample_locations[ri] >> 4)) / 16.0f;1602}1603}1604}16051606if (rp)1607ctx->rp_changed |= ctx->rp_clears_enabled != rp->state.clears;1608if (ctx->rp_changed)1609rp = get_render_pass(ctx);16101611if (rp != ctx->gfx_pipeline_state.render_pass)1612ctx->gfx_pipeline_state.dirty =1613ctx->fb_changed = true;16141615ctx->rp_changed = false;16161617if (!ctx->fb_changed)1618return;16191620zink_init_framebuffer(screen, ctx->framebuffer, rp);1621ctx->fb_changed = false;1622ctx->gfx_pipeline_state.render_pass = rp;1623}16241625static unsigned1626begin_render_pass(struct zink_context *ctx)1627{1628struct zink_batch *batch = &ctx->batch;1629struct pipe_framebuffer_state *fb_state = &ctx->fb_state;16301631VkRenderPassBeginInfo rpbi = {0};1632rpbi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;1633rpbi.renderPass = ctx->gfx_pipeline_state.render_pass->render_pass;1634rpbi.renderArea.offset.x = 0;1635rpbi.renderArea.offset.y = 0;1636rpbi.renderArea.extent.width = fb_state->width;1637rpbi.renderArea.extent.height = fb_state->height;16381639VkClearValue clears[PIPE_MAX_COLOR_BUFS + 1] = {0};1640unsigned clear_buffers = 0;1641uint32_t clear_validate = 0;1642for (int i = 0; i < fb_state->nr_cbufs; i++) {1643/* these are no-ops */1644if (!fb_state->cbufs[i] || !zink_fb_clear_enabled(ctx, i))1645continue;1646/* these need actual clear calls inside the rp */1647struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(&ctx->fb_clears[i], 0);1648if (zink_fb_clear_needs_explicit(&ctx->fb_clears[i])) {1649clear_buffers |= (PIPE_CLEAR_COLOR0 << i);1650if (zink_fb_clear_count(&ctx->fb_clears[i]) < 2 ||1651zink_fb_clear_element_needs_explicit(clear))1652continue;1653}1654/* we now know there's one clear that can be done here */1655zink_fb_clear_util_unpack_clear_color(clear, fb_state->cbufs[i]->format, (void*)&clears[i].color);1656rpbi.clearValueCount = i + 1;1657clear_validate |= PIPE_CLEAR_COLOR0 << i;1658assert(ctx->framebuffer->rp->state.clears);1659}1660if (fb_state->zsbuf && zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS)) {1661struct zink_framebuffer_clear *fb_clear = &ctx->fb_clears[PIPE_MAX_COLOR_BUFS];1662struct zink_framebuffer_clear_data *clear = zink_fb_clear_element(fb_clear, 0);1663if (!zink_fb_clear_element_needs_explicit(clear)) {1664clears[fb_state->nr_cbufs].depthStencil.depth = clear->zs.depth;1665clears[fb_state->nr_cbufs].depthStencil.stencil = clear->zs.stencil;1666rpbi.clearValueCount = fb_state->nr_cbufs + 1;1667clear_validate |= clear->zs.bits;1668assert(ctx->framebuffer->rp->state.clears);1669}1670if (zink_fb_clear_needs_explicit(fb_clear)) {1671for (int j = !zink_fb_clear_element_needs_explicit(clear);1672(clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL && j < zink_fb_clear_count(fb_clear);1673j++)1674clear_buffers |= zink_fb_clear_element(fb_clear, j)->zs.bits;1675}1676}1677assert(clear_validate == ctx->framebuffer->rp->state.clears);1678rpbi.pClearValues = &clears[0];1679rpbi.framebuffer = ctx->framebuffer->fb;16801681assert(ctx->gfx_pipeline_state.render_pass && ctx->framebuffer);16821683zink_batch_reference_framebuffer(batch, ctx->framebuffer);1684for (int i = 0; i < ctx->framebuffer->state.num_attachments; i++) {1685if (ctx->framebuffer->surfaces[i]) {1686struct zink_surface *surf = zink_surface(ctx->framebuffer->surfaces[i]);1687zink_batch_resource_usage_set(batch, zink_resource(surf->base.texture), true);1688zink_batch_usage_set(&surf->batch_uses, batch->state);16891690struct zink_resource *res = zink_resource(surf->base.texture);1691VkAccessFlags access;1692VkPipelineStageFlags pipeline;1693VkImageLayout layout = zink_render_pass_attachment_get_barrier_info(ctx->gfx_pipeline_state.render_pass,1694i, &pipeline, &access);1695zink_resource_image_barrier(ctx, NULL, res, layout, access, pipeline);1696}1697}16981699vkCmdBeginRenderPass(batch->state->cmdbuf, &rpbi, VK_SUBPASS_CONTENTS_INLINE);1700batch->in_rp = true;1701ctx->new_swapchain = false;1702return clear_buffers;1703}17041705void1706zink_init_vk_sample_locations(struct zink_context *ctx, VkSampleLocationsInfoEXT *loc)1707{1708struct zink_screen *screen = zink_screen(ctx->base.screen);1709unsigned idx = util_logbase2_ceil(MAX2(ctx->gfx_pipeline_state.rast_samples, 1));1710loc->sType = VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT;1711loc->pNext = NULL;1712loc->sampleLocationsPerPixel = 1 << idx;1713loc->sampleLocationsCount = ctx->gfx_pipeline_state.rast_samples;1714loc->sampleLocationGridSize = screen->maxSampleLocationGridSize[idx];1715loc->pSampleLocations = ctx->vk_sample_locations;1716}17171718static void1719zink_evaluate_depth_buffer(struct pipe_context *pctx)1720{1721struct zink_context *ctx = zink_context(pctx);17221723if (!ctx->fb_state.zsbuf)1724return;17251726struct zink_resource *res = zink_resource(ctx->fb_state.zsbuf->texture);1727res->obj->needs_zs_evaluate = true;1728zink_init_vk_sample_locations(ctx, &res->obj->zs_evaluate);1729zink_batch_no_rp(ctx);1730}17311732void1733zink_begin_render_pass(struct zink_context *ctx, struct zink_batch *batch)1734{1735setup_framebuffer(ctx);1736assert(ctx->gfx_pipeline_state.render_pass);1737unsigned clear_buffers = begin_render_pass(ctx);17381739if (ctx->render_condition.query)1740zink_start_conditional_render(ctx);1741zink_clear_framebuffer(ctx, clear_buffers);1742}17431744static void1745zink_end_render_pass(struct zink_context *ctx, struct zink_batch *batch)1746{1747if (batch->in_rp) {1748if (ctx->render_condition.query)1749zink_stop_conditional_render(ctx);1750vkCmdEndRenderPass(batch->state->cmdbuf);1751}1752batch->in_rp = false;1753}17541755static void1756sync_flush(struct zink_context *ctx, struct zink_batch_state *bs)1757{1758if (zink_screen(ctx->base.screen)->threaded)1759util_queue_fence_wait(&bs->flush_completed);1760}17611762static inline VkAccessFlags1763get_access_flags_for_binding(struct zink_context *ctx, enum zink_descriptor_type type, enum pipe_shader_type stage, unsigned idx)1764{1765VkAccessFlags flags = 0;1766switch (type) {1767case ZINK_DESCRIPTOR_TYPE_UBO:1768return VK_ACCESS_UNIFORM_READ_BIT;1769case ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW:1770return VK_ACCESS_SHADER_READ_BIT;1771case ZINK_DESCRIPTOR_TYPE_SSBO: {1772flags = VK_ACCESS_SHADER_READ_BIT;1773if (ctx->writable_ssbos[stage] & (1 << idx))1774flags |= VK_ACCESS_SHADER_WRITE_BIT;1775return flags;1776}1777case ZINK_DESCRIPTOR_TYPE_IMAGE: {1778struct zink_image_view *image_view = &ctx->image_views[stage][idx];1779if (image_view->base.access & PIPE_IMAGE_ACCESS_READ)1780flags |= VK_ACCESS_SHADER_READ_BIT;1781if (image_view->base.access & PIPE_IMAGE_ACCESS_WRITE)1782flags |= VK_ACCESS_SHADER_WRITE_BIT;1783return flags;1784}1785default:1786break;1787}1788unreachable("ACK");1789return 0;1790}17911792static void1793update_resource_refs_for_stage(struct zink_context *ctx, enum pipe_shader_type stage)1794{1795struct zink_batch *batch = &ctx->batch;1796unsigned max_slot[] = {1797[ZINK_DESCRIPTOR_TYPE_UBO] = ctx->di.num_ubos[stage],1798[ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW] = ctx->di.num_samplers[stage],1799[ZINK_DESCRIPTOR_TYPE_SSBO] = ctx->di.num_ssbos[stage],1800[ZINK_DESCRIPTOR_TYPE_IMAGE] = ctx->di.num_images[stage]1801};1802for (unsigned i = 0; i < ZINK_DESCRIPTOR_TYPES; i++) {1803for (unsigned j = 0; j < max_slot[i]; j++) {1804if (ctx->di.descriptor_res[i][stage][j]) {1805struct zink_resource *res = ctx->di.descriptor_res[i][stage][j];1806if (!res)1807continue;1808bool is_write = zink_resource_access_is_write(get_access_flags_for_binding(ctx, i, stage, j));1809zink_batch_resource_usage_set(batch, res, is_write);18101811struct zink_sampler_view *sv = zink_sampler_view(ctx->sampler_views[stage][j]);1812struct zink_sampler_state *sampler_state = ctx->sampler_states[stage][j];1813struct zink_image_view *iv = &ctx->image_views[stage][j];1814if (sampler_state && i == ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW && j <= ctx->di.num_samplers[stage])1815zink_batch_usage_set(&sampler_state->batch_uses, ctx->batch.state);1816if (sv && i == ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW && j <= ctx->di.num_sampler_views[stage]) {1817if (res->obj->is_buffer)1818zink_batch_usage_set(&sv->buffer_view->batch_uses, ctx->batch.state);1819else1820zink_batch_usage_set(&sv->image_view->batch_uses, ctx->batch.state);1821zink_batch_reference_sampler_view(batch, sv);1822} else if (i == ZINK_DESCRIPTOR_TYPE_IMAGE && j <= ctx->di.num_images[stage]) {1823if (res->obj->is_buffer)1824zink_batch_usage_set(&iv->buffer_view->batch_uses, ctx->batch.state);1825else1826zink_batch_usage_set(&iv->surface->batch_uses, ctx->batch.state);1827zink_batch_reference_image_view(batch, iv);1828}1829}1830}1831}1832}18331834void1835zink_update_descriptor_refs(struct zink_context *ctx, bool compute)1836{1837struct zink_batch *batch = &ctx->batch;1838if (compute) {1839update_resource_refs_for_stage(ctx, PIPE_SHADER_COMPUTE);1840if (ctx->curr_compute)1841zink_batch_reference_program(batch, &ctx->curr_compute->base);1842} else {1843for (unsigned i = 0; i < ZINK_SHADER_COUNT; i++)1844update_resource_refs_for_stage(ctx, i);1845unsigned vertex_buffers_enabled_mask = ctx->gfx_pipeline_state.vertex_buffers_enabled_mask;1846unsigned last_vbo = util_last_bit(vertex_buffers_enabled_mask);1847for (unsigned i = 0; i < last_vbo + 1; i++) {1848if (ctx->vertex_buffers[i].buffer.resource)1849zink_batch_resource_usage_set(batch, zink_resource(ctx->vertex_buffers[i].buffer.resource), false);1850}1851if (ctx->curr_program)1852zink_batch_reference_program(batch, &ctx->curr_program->base);1853}1854ctx->descriptor_refs_dirty[compute] = false;1855}18561857static void1858flush_batch(struct zink_context *ctx, bool sync)1859{1860struct zink_batch *batch = &ctx->batch;1861if (ctx->clears_enabled)1862/* start rp to do all the clears */1863zink_begin_render_pass(ctx, batch);1864zink_end_render_pass(ctx, batch);1865zink_end_batch(ctx, batch);1866ctx->deferred_fence = NULL;18671868if (sync)1869sync_flush(ctx, ctx->batch.state);18701871if (ctx->batch.state->is_device_lost) {1872check_device_lost(ctx);1873} else {1874zink_start_batch(ctx, batch);1875if (zink_screen(ctx->base.screen)->info.have_EXT_transform_feedback && ctx->num_so_targets)1876ctx->dirty_so_targets = true;1877ctx->descriptor_refs_dirty[0] = ctx->descriptor_refs_dirty[1] = true;1878ctx->pipeline_changed[0] = ctx->pipeline_changed[1] = true;1879ctx->sample_locations_changed |= ctx->gfx_pipeline_state.sample_locations_enabled;1880ctx->vertex_buffers_dirty = true;1881ctx->vp_state_changed = true;1882ctx->scissor_changed = true;1883ctx->rast_state_changed = true;1884ctx->stencil_ref_changed = true;1885ctx->dsa_state_changed = true;1886}1887}18881889struct zink_batch *1890zink_batch_rp(struct zink_context *ctx)1891{1892struct zink_batch *batch = &ctx->batch;1893if (!batch->in_rp) {1894zink_begin_render_pass(ctx, batch);1895assert(ctx->framebuffer && ctx->framebuffer->rp);1896}1897return batch;1898}18991900struct zink_batch *1901zink_batch_no_rp(struct zink_context *ctx)1902{1903struct zink_batch *batch = &ctx->batch;1904zink_end_render_pass(ctx, batch);1905assert(!batch->in_rp);1906return batch;1907}19081909void1910zink_flush_queue(struct zink_context *ctx)1911{1912flush_batch(ctx, true);1913}19141915static bool1916rebind_fb_surface(struct zink_context *ctx, struct pipe_surface **surf, struct zink_resource *match_res)1917{1918if (!*surf)1919return false;1920struct zink_resource *surf_res = zink_resource((*surf)->texture);1921if ((match_res == surf_res) || surf_res->obj != zink_surface(*surf)->obj)1922return zink_rebind_surface(ctx, surf);1923return false;1924}19251926static bool1927rebind_fb_state(struct zink_context *ctx, struct zink_resource *match_res, bool from_set_fb)1928{1929bool rebind = false;1930for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {1931rebind |= rebind_fb_surface(ctx, &ctx->fb_state.cbufs[i], match_res);1932if (from_set_fb && ctx->fb_state.cbufs[i] && ctx->fb_state.cbufs[i]->texture->bind & PIPE_BIND_SCANOUT)1933ctx->new_swapchain = true;1934}1935rebind |= rebind_fb_surface(ctx, &ctx->fb_state.zsbuf, match_res);1936return rebind;1937}19381939static void1940unbind_fb_surface(struct zink_context *ctx, struct pipe_surface *surf, bool changed)1941{1942if (!surf)1943return;1944if (changed) {1945zink_fb_clears_apply(ctx, surf->texture);1946if (zink_batch_usage_exists(zink_surface(surf)->batch_uses))1947zink_batch_reference_surface(&ctx->batch, zink_surface(surf));1948ctx->rp_changed = true;1949}1950struct zink_resource *res = zink_resource(surf->texture);1951res->fb_binds--;1952if (!res->fb_binds)1953check_resource_for_batch_ref(ctx, res);1954}19551956static void1957zink_set_framebuffer_state(struct pipe_context *pctx,1958const struct pipe_framebuffer_state *state)1959{1960struct zink_context *ctx = zink_context(pctx);19611962for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {1963struct pipe_surface *surf = ctx->fb_state.cbufs[i];1964unbind_fb_surface(ctx, surf, i >= state->nr_cbufs || surf != state->cbufs[i]);1965}1966if (ctx->fb_state.zsbuf) {1967struct pipe_surface *surf = ctx->fb_state.zsbuf;1968struct zink_resource *res = zink_resource(surf->texture);1969bool changed = surf != state->zsbuf;1970unbind_fb_surface(ctx, surf, changed);1971if (changed && unlikely(res->obj->needs_zs_evaluate))1972/* have to flush zs eval while the sample location data still exists,1973* so just throw some random barrier */1974zink_resource_image_barrier(ctx, NULL, res, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,1975VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);1976}1977/* renderpass changes if the number or types of attachments change */1978ctx->rp_changed |= ctx->fb_state.nr_cbufs != state->nr_cbufs;1979ctx->rp_changed |= !!ctx->fb_state.zsbuf != !!state->zsbuf;19801981unsigned w = ctx->fb_state.width;1982unsigned h = ctx->fb_state.height;19831984util_copy_framebuffer_state(&ctx->fb_state, state);1985unsigned prev_void_alpha_attachments = ctx->gfx_pipeline_state.void_alpha_attachments;1986ctx->gfx_pipeline_state.void_alpha_attachments = 0;1987for (int i = 0; i < ctx->fb_state.nr_cbufs; i++) {1988struct pipe_surface *surf = ctx->fb_state.cbufs[i];1989if (surf) {1990zink_resource(surf->texture)->fb_binds++;1991ctx->gfx_pipeline_state.void_alpha_attachments |= util_format_has_alpha1(surf->format) ? BITFIELD_BIT(i) : 0;1992}1993}1994if (ctx->gfx_pipeline_state.void_alpha_attachments != prev_void_alpha_attachments)1995ctx->gfx_pipeline_state.dirty = true;1996if (ctx->fb_state.zsbuf) {1997struct pipe_surface *surf = ctx->fb_state.zsbuf;1998zink_resource(surf->texture)->fb_binds++;1999}2000if (ctx->fb_state.width != w || ctx->fb_state.height != h)2001ctx->scissor_changed = true;2002rebind_fb_state(ctx, NULL, true);2003/* get_framebuffer adds a ref if the fb is reused or created;2004* always do get_framebuffer first to avoid deleting the same fb2005* we're about to use2006*/2007struct zink_framebuffer *fb = get_framebuffer(ctx);2008if (ctx->framebuffer) {2009struct zink_screen *screen = zink_screen(pctx->screen);2010simple_mtx_lock(&screen->framebuffer_mtx);2011struct hash_entry *he = _mesa_hash_table_search(&screen->framebuffer_cache, &ctx->framebuffer->state);2012if (ctx->framebuffer && !ctx->framebuffer->state.num_attachments) {2013/* if this has no attachments then its lifetime has ended */2014_mesa_hash_table_remove(&screen->framebuffer_cache, he);2015he = NULL;2016}2017/* a framebuffer loses 1 ref every time we unset it;2018* we do NOT add refs here, as the ref has already been added in2019* get_framebuffer()2020*/2021if (zink_framebuffer_reference(screen, &ctx->framebuffer, NULL) && he)2022_mesa_hash_table_remove(&screen->framebuffer_cache, he);2023simple_mtx_unlock(&screen->framebuffer_mtx);2024}2025ctx->fb_changed |= ctx->framebuffer != fb;2026ctx->framebuffer = fb;20272028uint8_t rast_samples = util_framebuffer_get_num_samples(state);2029/* in vulkan, gl_SampleMask needs to be explicitly ignored for sampleCount == 1 */2030if ((ctx->gfx_pipeline_state.rast_samples > 1) != (rast_samples > 1))2031ctx->dirty_shader_stages |= 1 << PIPE_SHADER_FRAGMENT;2032if (ctx->gfx_pipeline_state.rast_samples != rast_samples) {2033ctx->sample_locations_changed |= ctx->gfx_pipeline_state.sample_locations_enabled;2034ctx->gfx_pipeline_state.dirty = true;2035}2036ctx->gfx_pipeline_state.rast_samples = rast_samples;2037if (ctx->gfx_pipeline_state.num_attachments != state->nr_cbufs)2038ctx->gfx_pipeline_state.dirty = true;2039ctx->gfx_pipeline_state.num_attachments = state->nr_cbufs;20402041/* need to ensure we start a new rp on next draw */2042zink_batch_no_rp(ctx);2043}20442045static void2046zink_set_blend_color(struct pipe_context *pctx,2047const struct pipe_blend_color *color)2048{2049struct zink_context *ctx = zink_context(pctx);2050memcpy(ctx->blend_constants, color->color, sizeof(float) * 4);2051}20522053static void2054zink_set_sample_mask(struct pipe_context *pctx, unsigned sample_mask)2055{2056struct zink_context *ctx = zink_context(pctx);2057ctx->gfx_pipeline_state.sample_mask = sample_mask;2058ctx->gfx_pipeline_state.dirty = true;2059}20602061static void2062zink_set_sample_locations(struct pipe_context *pctx, size_t size, const uint8_t *locations)2063{2064struct zink_context *ctx = zink_context(pctx);20652066ctx->gfx_pipeline_state.sample_locations_enabled = size && locations;2067ctx->sample_locations_changed = ctx->gfx_pipeline_state.sample_locations_enabled;2068if (size > sizeof(ctx->sample_locations))2069size = sizeof(ctx->sample_locations);2070memcpy(ctx->sample_locations, locations, size);2071}20722073static VkAccessFlags2074access_src_flags(VkImageLayout layout)2075{2076switch (layout) {2077case VK_IMAGE_LAYOUT_UNDEFINED:2078return 0;20792080case VK_IMAGE_LAYOUT_GENERAL:2081return VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;20822083case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:2084return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;2085case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:2086return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;20872088case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:2089case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:2090return VK_ACCESS_SHADER_READ_BIT;20912092case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:2093return VK_ACCESS_TRANSFER_READ_BIT;20942095case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:2096return VK_ACCESS_TRANSFER_WRITE_BIT;20972098case VK_IMAGE_LAYOUT_PREINITIALIZED:2099return VK_ACCESS_HOST_WRITE_BIT;21002101case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:2102return 0;21032104default:2105unreachable("unexpected layout");2106}2107}21082109static VkAccessFlags2110access_dst_flags(VkImageLayout layout)2111{2112switch (layout) {2113case VK_IMAGE_LAYOUT_UNDEFINED:2114return 0;21152116case VK_IMAGE_LAYOUT_GENERAL:2117return VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;21182119case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:2120return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;2121case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:2122return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;21232124case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:2125return VK_ACCESS_SHADER_READ_BIT;21262127case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:2128return VK_ACCESS_TRANSFER_READ_BIT;21292130case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:2131return VK_ACCESS_SHADER_READ_BIT;21322133case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:2134return VK_ACCESS_TRANSFER_WRITE_BIT;21352136case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:2137return 0;21382139default:2140unreachable("unexpected layout");2141}2142}21432144static VkPipelineStageFlags2145pipeline_dst_stage(VkImageLayout layout)2146{2147switch (layout) {2148case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:2149return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;2150case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:2151return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;21522153case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:2154return VK_PIPELINE_STAGE_TRANSFER_BIT;2155case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:2156return VK_PIPELINE_STAGE_TRANSFER_BIT;21572158case VK_IMAGE_LAYOUT_GENERAL:2159return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;21602161case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:2162case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:2163return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;21642165default:2166return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;2167}2168}21692170#define ALL_READ_ACCESS_FLAGS \2171(VK_ACCESS_INDIRECT_COMMAND_READ_BIT | \2172VK_ACCESS_INDEX_READ_BIT | \2173VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | \2174VK_ACCESS_UNIFORM_READ_BIT | \2175VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | \2176VK_ACCESS_SHADER_READ_BIT | \2177VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | \2178VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | \2179VK_ACCESS_TRANSFER_READ_BIT |\2180VK_ACCESS_HOST_READ_BIT |\2181VK_ACCESS_MEMORY_READ_BIT |\2182VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT |\2183VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT |\2184VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT |\2185VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR |\2186VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV |\2187VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT |\2188VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV |\2189VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV |\2190VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV)219121922193bool2194zink_resource_access_is_write(VkAccessFlags flags)2195{2196return (flags & ALL_READ_ACCESS_FLAGS) != flags;2197}21982199bool2200zink_resource_image_needs_barrier(struct zink_resource *res, VkImageLayout new_layout, VkAccessFlags flags, VkPipelineStageFlags pipeline)2201{2202if (!pipeline)2203pipeline = pipeline_dst_stage(new_layout);2204if (!flags)2205flags = access_dst_flags(new_layout);2206return res->layout != new_layout || (res->access_stage & pipeline) != pipeline ||2207(res->access & flags) != flags ||2208zink_resource_access_is_write(res->access) ||2209zink_resource_access_is_write(flags);2210}22112212bool2213zink_resource_image_barrier_init(VkImageMemoryBarrier *imb, struct zink_resource *res, VkImageLayout new_layout, VkAccessFlags flags, VkPipelineStageFlags pipeline)2214{2215if (!pipeline)2216pipeline = pipeline_dst_stage(new_layout);2217if (!flags)2218flags = access_dst_flags(new_layout);22192220VkImageSubresourceRange isr = {2221res->aspect,22220, VK_REMAINING_MIP_LEVELS,22230, VK_REMAINING_ARRAY_LAYERS2224};2225*imb = (VkImageMemoryBarrier){2226VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,2227NULL,2228res->access ? res->access : access_src_flags(res->layout),2229flags,2230res->layout,2231new_layout,2232VK_QUEUE_FAMILY_IGNORED,2233VK_QUEUE_FAMILY_IGNORED,2234res->obj->image,2235isr2236};2237return res->obj->needs_zs_evaluate || zink_resource_image_needs_barrier(res, new_layout, flags, pipeline);2238}22392240static inline bool2241is_shader_pipline_stage(VkPipelineStageFlags pipeline)2242{2243return pipeline & (VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |2244VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |2245VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT |2246VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT |2247VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);2248}22492250static void2251resource_check_defer_buffer_barrier(struct zink_context *ctx, struct zink_resource *res, VkPipelineStageFlags pipeline)2252{2253assert(res->obj->is_buffer);2254if (res->bind_count[0]) {2255if ((res->obj->is_buffer && res->vbo_bind_count && !(pipeline & VK_PIPELINE_STAGE_VERTEX_INPUT_BIT)) ||2256((!res->obj->is_buffer || res->vbo_bind_count != res->bind_count[0]) && !is_shader_pipline_stage(pipeline)))2257/* gfx rebind */2258_mesa_set_add(ctx->need_barriers[0], res);2259}2260if (res->bind_count[1] && !(pipeline & VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT))2261/* compute rebind */2262_mesa_set_add(ctx->need_barriers[1], res);2263}22642265static inline VkCommandBuffer2266get_cmdbuf(struct zink_context *ctx, struct zink_resource *res)2267{2268if ((res->access && !res->unordered_barrier) || !ctx->batch.in_rp) {2269struct zink_batch *batch = zink_batch_no_rp(ctx);2270assert(!batch->in_rp);2271res->unordered_barrier = false;2272return batch->state->cmdbuf;2273}2274res->unordered_barrier = true;2275ctx->batch.state->has_barriers = true;2276return ctx->batch.state->barrier_cmdbuf;2277}22782279static void2280resource_check_defer_image_barrier(struct zink_context *ctx, struct zink_resource *res, VkImageLayout layout, VkPipelineStageFlags pipeline)2281{2282assert(!res->obj->is_buffer);22832284bool is_compute = pipeline == VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;2285/* if this is a non-shader barrier and there are binds, always queue a shader barrier */2286bool is_shader = is_shader_pipline_stage(pipeline);2287if ((is_shader || !res->bind_count[is_compute]) &&2288/* if no layout change is needed between gfx and compute, do nothing */2289!res->bind_count[!is_compute] && (!is_compute || !res->fb_binds))2290return;22912292if (res->bind_count[!is_compute] && is_shader) {2293/* if the layout is the same between gfx and compute, do nothing */2294if (layout == zink_descriptor_util_image_layout_eval(res, !is_compute))2295return;2296}2297/* queue a layout change if a layout change will be needed */2298if (res->bind_count[!is_compute])2299_mesa_set_add(ctx->need_barriers[!is_compute], res);2300/* also queue a layout change if this is a non-shader layout */2301if (res->bind_count[is_compute] && !is_shader)2302_mesa_set_add(ctx->need_barriers[is_compute], res);2303}23042305void2306zink_resource_image_barrier(struct zink_context *ctx, struct zink_batch *batch, struct zink_resource *res,2307VkImageLayout new_layout, VkAccessFlags flags, VkPipelineStageFlags pipeline)2308{2309VkImageMemoryBarrier imb;2310if (!pipeline)2311pipeline = pipeline_dst_stage(new_layout);23122313if (!zink_resource_image_barrier_init(&imb, res, new_layout, flags, pipeline))2314return;2315/* only barrier if we're changing layout or doing something besides read -> read */2316VkCommandBuffer cmdbuf = get_cmdbuf(ctx, res);2317assert(new_layout);2318if (res->obj->needs_zs_evaluate)2319imb.pNext = &res->obj->zs_evaluate;2320res->obj->needs_zs_evaluate = false;2321vkCmdPipelineBarrier(2322cmdbuf,2323res->access_stage ? res->access_stage : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,2324pipeline,23250,23260, NULL,23270, NULL,23281, &imb2329);23302331resource_check_defer_image_barrier(ctx, res, new_layout, pipeline);23322333if (res->unordered_barrier) {2334res->access |= imb.dstAccessMask;2335res->access_stage |= pipeline;2336} else {2337res->access = imb.dstAccessMask;2338res->access_stage = pipeline;2339}2340res->layout = new_layout;2341}234223432344VkPipelineStageFlags2345zink_pipeline_flags_from_stage(VkShaderStageFlagBits stage)2346{2347switch (stage) {2348case VK_SHADER_STAGE_VERTEX_BIT:2349return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;2350case VK_SHADER_STAGE_FRAGMENT_BIT:2351return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;2352case VK_SHADER_STAGE_GEOMETRY_BIT:2353return VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;2354case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:2355return VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;2356case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:2357return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;2358case VK_SHADER_STAGE_COMPUTE_BIT:2359return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;2360default:2361unreachable("unknown shader stage bit");2362}2363}23642365ALWAYS_INLINE static VkPipelineStageFlags2366pipeline_access_stage(VkAccessFlags flags)2367{2368if (flags & (VK_ACCESS_UNIFORM_READ_BIT |2369VK_ACCESS_SHADER_READ_BIT |2370VK_ACCESS_SHADER_WRITE_BIT))2371return VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV |2372VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV |2373VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR |2374VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |2375VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |2376VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT |2377VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT |2378VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |2379VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;2380return VK_PIPELINE_STAGE_TRANSFER_BIT;2381}23822383ALWAYS_INLINE static bool2384zink_resource_buffer_needs_barrier(struct zink_resource *res, VkAccessFlags flags, VkPipelineStageFlags pipeline)2385{2386if (!res->access || !res->access_stage)2387return true;2388if (!pipeline)2389pipeline = pipeline_access_stage(flags);2390return zink_resource_access_is_write(res->access) ||2391zink_resource_access_is_write(flags) ||2392((res->access_stage & pipeline) != pipeline && !(res->access_stage & (pipeline - 1))) ||2393(res->access & flags) != flags;2394}23952396void2397zink_fake_buffer_barrier(struct zink_resource *res, VkAccessFlags flags, VkPipelineStageFlags pipeline)2398{2399res->access = flags;2400res->access_stage = pipeline;2401}24022403void2404zink_resource_buffer_barrier(struct zink_context *ctx, struct zink_batch *batch, struct zink_resource *res, VkAccessFlags flags, VkPipelineStageFlags pipeline)2405{2406VkMemoryBarrier bmb;2407if (!pipeline)2408pipeline = pipeline_access_stage(flags);2409if (!zink_resource_buffer_needs_barrier(res, flags, pipeline))2410return;24112412bmb.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;2413bmb.pNext = NULL;2414bmb.srcAccessMask = res->access;2415bmb.dstAccessMask = flags;2416VkCommandBuffer cmdbuf = get_cmdbuf(ctx, res);2417/* only barrier if we're changing layout or doing something besides read -> read */2418vkCmdPipelineBarrier(2419cmdbuf,2420res->access_stage ? res->access_stage : pipeline_access_stage(res->access),2421pipeline,24220,24231, &bmb,24240, NULL,24250, NULL2426);24272428resource_check_defer_buffer_barrier(ctx, res, pipeline);24292430if (res->unordered_barrier) {2431res->access |= bmb.dstAccessMask;2432res->access_stage |= pipeline;2433} else {2434res->access = bmb.dstAccessMask;2435res->access_stage = pipeline;2436}2437}24382439bool2440zink_resource_needs_barrier(struct zink_resource *res, VkImageLayout layout, VkAccessFlags flags, VkPipelineStageFlags pipeline)2441{2442if (res->base.b.target == PIPE_BUFFER)2443return zink_resource_buffer_needs_barrier(res, flags, pipeline);2444return zink_resource_image_needs_barrier(res, layout, flags, pipeline);2445}24462447void2448zink_resource_barrier(struct zink_context *ctx, struct zink_batch *batch, struct zink_resource *res, VkImageLayout layout, VkAccessFlags flags, VkPipelineStageFlags pipeline)2449{2450if (res->base.b.target == PIPE_BUFFER)2451zink_resource_buffer_barrier(ctx, batch, res, flags, pipeline);2452else2453zink_resource_image_barrier(ctx, batch, res, layout, flags, pipeline);2454}24552456VkShaderStageFlagBits2457zink_shader_stage(enum pipe_shader_type type)2458{2459VkShaderStageFlagBits stages[] = {2460[PIPE_SHADER_VERTEX] = VK_SHADER_STAGE_VERTEX_BIT,2461[PIPE_SHADER_FRAGMENT] = VK_SHADER_STAGE_FRAGMENT_BIT,2462[PIPE_SHADER_GEOMETRY] = VK_SHADER_STAGE_GEOMETRY_BIT,2463[PIPE_SHADER_TESS_CTRL] = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,2464[PIPE_SHADER_TESS_EVAL] = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,2465[PIPE_SHADER_COMPUTE] = VK_SHADER_STAGE_COMPUTE_BIT,2466};2467return stages[type];2468}24692470static uint32_t2471hash_gfx_program(const void *key)2472{2473return _mesa_hash_data(key, sizeof(struct zink_shader *) * (ZINK_SHADER_COUNT));2474}24752476static bool2477equals_gfx_program(const void *a, const void *b)2478{2479return memcmp(a, b, sizeof(struct zink_shader *) * (ZINK_SHADER_COUNT)) == 0;2480}24812482static void2483zink_flush(struct pipe_context *pctx,2484struct pipe_fence_handle **pfence,2485unsigned flags)2486{2487struct zink_context *ctx = zink_context(pctx);2488bool deferred = flags & PIPE_FLUSH_DEFERRED;2489bool deferred_fence = false;2490struct zink_batch *batch = &ctx->batch;2491struct zink_fence *fence = NULL;2492struct zink_screen *screen = zink_screen(ctx->base.screen);2493unsigned submit_count = 0;24942495/* triggering clears will force has_work */2496if (!deferred && ctx->clears_enabled)2497/* start rp to do all the clears */2498zink_begin_render_pass(ctx, batch);24992500if (!batch->has_work) {2501if (pfence) {2502/* reuse last fence */2503fence = ctx->last_fence;2504}2505if (!deferred) {2506struct zink_batch_state *last = zink_batch_state(ctx->last_fence);2507if (last) {2508sync_flush(ctx, last);2509if (last->is_device_lost)2510check_device_lost(ctx);2511}2512}2513tc_driver_internal_flush_notify(ctx->tc);2514} else {2515fence = &batch->state->fence;2516submit_count = batch->state->submit_count;2517if (deferred && !(flags & PIPE_FLUSH_FENCE_FD) && pfence)2518deferred_fence = true;2519else2520flush_batch(ctx, true);2521}25222523if (pfence) {2524struct zink_tc_fence *mfence;25252526if (flags & TC_FLUSH_ASYNC) {2527mfence = zink_tc_fence(*pfence);2528assert(mfence);2529} else {2530mfence = zink_create_tc_fence();25312532screen->base.fence_reference(&screen->base, pfence, NULL);2533*pfence = (struct pipe_fence_handle *)mfence;2534}25352536struct zink_batch_state *bs = zink_batch_state(fence);2537zink_batch_state_reference(screen, NULL, bs);2538mfence->fence = fence;2539if (fence)2540mfence->submit_count = submit_count;25412542if (deferred_fence) {2543assert(fence);2544mfence->deferred_ctx = pctx;2545assert(!ctx->deferred_fence || ctx->deferred_fence == fence);2546ctx->deferred_fence = fence;2547}25482549if (!fence || flags & TC_FLUSH_ASYNC) {2550if (!util_queue_fence_is_signalled(&mfence->ready))2551util_queue_fence_signal(&mfence->ready);2552}2553}2554if (fence) {2555if (!(flags & (PIPE_FLUSH_DEFERRED | PIPE_FLUSH_ASYNC)))2556sync_flush(ctx, zink_batch_state(fence));25572558if (flags & PIPE_FLUSH_END_OF_FRAME && !(flags & TC_FLUSH_ASYNC) && !deferred) {2559/* if the first frame has not yet occurred, we need an explicit fence here2560* in some cases in order to correctly draw the first frame, though it's2561* unknown at this time why this is the case2562*/2563if (!ctx->first_frame_done)2564zink_vkfence_wait(screen, fence, PIPE_TIMEOUT_INFINITE);2565ctx->first_frame_done = true;2566}2567}2568}25692570void2571zink_maybe_flush_or_stall(struct zink_context *ctx)2572{2573struct zink_screen *screen = zink_screen(ctx->base.screen);2574/* flush anytime our total batch memory usage is potentially >= 50% of total video memory */2575if (ctx->batch.state->resource_size >= screen->total_video_mem / 2 ||2576/* or if there's >100k draws+computes */2577ctx->batch.state->draw_count + ctx->batch.state->compute_count >= 100000)2578flush_batch(ctx, true);25792580if (ctx->resource_size >= screen->total_video_mem / 2 || _mesa_hash_table_num_entries(&ctx->batch_states) > 100) {2581sync_flush(ctx, zink_batch_state(ctx->last_fence));2582zink_vkfence_wait(screen, ctx->last_fence, PIPE_TIMEOUT_INFINITE);2583zink_batch_reset_all(ctx);2584}2585}25862587void2588zink_fence_wait(struct pipe_context *pctx)2589{2590struct zink_context *ctx = zink_context(pctx);25912592if (ctx->batch.has_work)2593pctx->flush(pctx, NULL, PIPE_FLUSH_HINT_FINISH);2594if (ctx->last_fence) {2595sync_flush(ctx, zink_batch_state(ctx->last_fence));2596zink_vkfence_wait(zink_screen(ctx->base.screen), ctx->last_fence, PIPE_TIMEOUT_INFINITE);2597zink_batch_reset_all(ctx);2598}2599}26002601void2602zink_wait_on_batch(struct zink_context *ctx, uint32_t batch_id)2603{2604struct zink_batch_state *bs = ctx->batch.state;2605assert(bs);2606if (!batch_id || bs->fence.batch_id == batch_id)2607/* not submitted yet */2608flush_batch(ctx, true);2609if (ctx->have_timelines) {2610if (!zink_screen_timeline_wait(zink_screen(ctx->base.screen), batch_id, UINT64_MAX))2611check_device_lost(ctx);2612return;2613}2614simple_mtx_lock(&ctx->batch_mtx);2615struct zink_fence *fence;26162617assert(batch_id || ctx->last_fence);2618if (ctx->last_fence && (!batch_id || batch_id == zink_batch_state(ctx->last_fence)->fence.batch_id))2619fence = ctx->last_fence;2620else {2621struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&ctx->batch_states, batch_id, (void*)(uintptr_t)batch_id);2622if (!he) {2623simple_mtx_unlock(&ctx->batch_mtx);2624/* if we can't find it, it either must have finished already or is on a different context */2625if (!zink_screen_check_last_finished(zink_screen(ctx->base.screen), batch_id)) {2626/* if it hasn't finished, it's on another context, so force a flush so there's something to wait on */2627ctx->batch.has_work = true;2628zink_fence_wait(&ctx->base);2629}2630return;2631}2632fence = he->data;2633}2634simple_mtx_unlock(&ctx->batch_mtx);2635assert(fence);2636sync_flush(ctx, zink_batch_state(fence));2637zink_vkfence_wait(zink_screen(ctx->base.screen), fence, PIPE_TIMEOUT_INFINITE);2638}26392640bool2641zink_check_batch_completion(struct zink_context *ctx, uint32_t batch_id)2642{2643assert(ctx->batch.state);2644if (!batch_id)2645/* not submitted yet */2646return false;26472648if (zink_screen_check_last_finished(zink_screen(ctx->base.screen), batch_id))2649return true;26502651if (ctx->have_timelines) {2652bool success = zink_screen_timeline_wait(zink_screen(ctx->base.screen), batch_id, 0);2653if (!success)2654check_device_lost(ctx);2655return success;2656}2657struct zink_fence *fence;26582659simple_mtx_lock(&ctx->batch_mtx);26602661if (ctx->last_fence && batch_id == zink_batch_state(ctx->last_fence)->fence.batch_id)2662fence = ctx->last_fence;2663else {2664struct hash_entry *he = _mesa_hash_table_search_pre_hashed(&ctx->batch_states, batch_id, (void*)(uintptr_t)batch_id);2665/* if we can't find it, it either must have finished already or is on a different context */2666if (!he) {2667simple_mtx_unlock(&ctx->batch_mtx);2668/* return compare against last_finished, since this has info from all contexts */2669return zink_screen_check_last_finished(zink_screen(ctx->base.screen), batch_id);2670}2671fence = he->data;2672}2673simple_mtx_unlock(&ctx->batch_mtx);2674assert(fence);2675if (zink_screen(ctx->base.screen)->threaded &&2676!util_queue_fence_is_signalled(&zink_batch_state(fence)->flush_completed))2677return false;2678return zink_vkfence_wait(zink_screen(ctx->base.screen), fence, 0);2679}26802681static void2682zink_texture_barrier(struct pipe_context *pctx, unsigned flags)2683{2684struct zink_context *ctx = zink_context(pctx);2685if (!ctx->framebuffer || !ctx->framebuffer->state.num_attachments)2686return;26872688VkMemoryBarrier bmb;2689bmb.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;2690bmb.pNext = NULL;2691bmb.srcAccessMask = 0;2692bmb.dstAccessMask = 0;2693struct zink_surface *surf = zink_surface(ctx->framebuffer->surfaces[ctx->framebuffer->state.num_attachments - 1]);2694struct zink_resource *res = zink_resource(surf->base.texture);2695zink_batch_no_rp(ctx);2696if (res->aspect != VK_IMAGE_ASPECT_COLOR_BIT) {2697VkMemoryBarrier dmb;2698dmb.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;2699dmb.pNext = NULL;2700dmb.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;2701dmb.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;2702vkCmdPipelineBarrier(2703ctx->batch.state->cmdbuf,2704VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,2705VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,27060,27071, &dmb,27080, NULL,27090, NULL2710);2711} else {2712bmb.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;2713bmb.dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;2714}2715if (ctx->framebuffer->state.num_attachments > 1) {2716bmb.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;2717bmb.dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;2718}2719if (bmb.srcAccessMask)2720vkCmdPipelineBarrier(2721ctx->batch.state->cmdbuf,2722VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,2723VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,27240,27251, &bmb,27260, NULL,27270, NULL2728);2729}27302731static inline void2732mem_barrier(struct zink_batch *batch, VkPipelineStageFlags src_stage, VkPipelineStageFlags dst_stage, VkAccessFlags src, VkAccessFlags dst)2733{2734VkMemoryBarrier mb;2735mb.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;2736mb.pNext = NULL;2737mb.srcAccessMask = src;2738mb.dstAccessMask = dst;2739vkCmdPipelineBarrier(batch->state->cmdbuf, src_stage, dst_stage, 0, 1, &mb, 0, NULL, 0, NULL);2740}27412742static void2743zink_memory_barrier(struct pipe_context *pctx, unsigned flags)2744{2745struct zink_context *ctx = zink_context(pctx);27462747VkPipelineStageFlags all_flags = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |2748VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |2749VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT |2750VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT |2751VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |2752VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;27532754if (!(flags & ~PIPE_BARRIER_UPDATE))2755return;27562757struct zink_batch *batch = &ctx->batch;2758zink_end_render_pass(ctx, batch);27592760if (flags & PIPE_BARRIER_MAPPED_BUFFER) {2761/* TODO: this should flush all persistent buffers in use as I think */2762}27632764if (flags & (PIPE_BARRIER_TEXTURE | PIPE_BARRIER_SHADER_BUFFER | PIPE_BARRIER_IMAGE))2765mem_barrier(batch, all_flags, all_flags, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);27662767if (flags & PIPE_BARRIER_QUERY_BUFFER)2768mem_barrier(batch, all_flags, VK_PIPELINE_STAGE_TRANSFER_BIT,2769VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT);27702771if (flags & PIPE_BARRIER_VERTEX_BUFFER)2772mem_barrier(batch, all_flags, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,2773VK_ACCESS_SHADER_WRITE_BIT,2774VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT);27752776if (flags & PIPE_BARRIER_INDEX_BUFFER)2777mem_barrier(batch, all_flags, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,2778VK_ACCESS_SHADER_WRITE_BIT,2779VK_ACCESS_INDEX_READ_BIT);27802781if (flags & PIPE_BARRIER_CONSTANT_BUFFER)2782mem_barrier(batch, all_flags, all_flags,2783VK_ACCESS_SHADER_WRITE_BIT,2784VK_ACCESS_UNIFORM_READ_BIT);27852786if (flags & PIPE_BARRIER_INDIRECT_BUFFER)2787mem_barrier(batch, all_flags, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,2788VK_ACCESS_SHADER_WRITE_BIT,2789VK_ACCESS_INDIRECT_COMMAND_READ_BIT);27902791if (flags & PIPE_BARRIER_FRAMEBUFFER)2792zink_texture_barrier(pctx, 0);2793if (flags & PIPE_BARRIER_STREAMOUT_BUFFER)2794mem_barrier(batch, all_flags,2795VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,2796VK_ACCESS_SHADER_WRITE_BIT,2797VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT |2798VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT);2799}28002801static void2802zink_flush_resource(struct pipe_context *pctx,2803struct pipe_resource *pres)2804{2805struct zink_context *ctx = zink_context(pctx);2806/* TODO: this is not futureproof and should be updated once proper2807* WSI support is added2808*/2809if (pres->bind & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT))2810pipe_resource_reference(&ctx->batch.state->flush_res, pres);2811}28122813void2814zink_copy_buffer(struct zink_context *ctx, struct zink_batch *batch, struct zink_resource *dst, struct zink_resource *src,2815unsigned dst_offset, unsigned src_offset, unsigned size)2816{2817VkBufferCopy region;2818region.srcOffset = src_offset;2819region.dstOffset = dst_offset;2820region.size = size;28212822if (!batch)2823batch = zink_batch_no_rp(ctx);2824assert(!batch->in_rp);2825zink_batch_reference_resource_rw(batch, src, false);2826zink_batch_reference_resource_rw(batch, dst, true);2827util_range_add(&dst->base.b, &dst->valid_buffer_range, dst_offset, dst_offset + size);2828zink_resource_buffer_barrier(ctx, batch, src, VK_ACCESS_TRANSFER_READ_BIT, 0);2829zink_resource_buffer_barrier(ctx, batch, dst, VK_ACCESS_TRANSFER_WRITE_BIT, 0);2830vkCmdCopyBuffer(batch->state->cmdbuf, src->obj->buffer, dst->obj->buffer, 1, ®ion);2831}28322833void2834zink_copy_image_buffer(struct zink_context *ctx, struct zink_batch *batch, struct zink_resource *dst, struct zink_resource *src,2835unsigned dst_level, unsigned dstx, unsigned dsty, unsigned dstz,2836unsigned src_level, const struct pipe_box *src_box, enum pipe_map_flags map_flags)2837{2838struct zink_resource *img = dst->base.b.target == PIPE_BUFFER ? src : dst;2839struct zink_resource *buf = dst->base.b.target == PIPE_BUFFER ? dst : src;28402841if (!batch)2842batch = zink_batch_no_rp(ctx);28432844bool buf2img = buf == src;28452846if (buf2img) {2847zink_resource_image_barrier(ctx, batch, img, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 0);2848zink_resource_buffer_barrier(ctx, batch, buf, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);2849} else {2850zink_resource_image_barrier(ctx, batch, img, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 0);2851zink_resource_buffer_barrier(ctx, batch, buf, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);2852util_range_add(&dst->base.b, &dst->valid_buffer_range, dstx, dstx + src_box->width);2853}28542855VkBufferImageCopy region = {0};2856region.bufferOffset = buf2img ? src_box->x : dstx;2857region.bufferRowLength = 0;2858region.bufferImageHeight = 0;2859region.imageSubresource.mipLevel = buf2img ? dst_level : src_level;2860switch (img->base.b.target) {2861case PIPE_TEXTURE_CUBE:2862case PIPE_TEXTURE_CUBE_ARRAY:2863case PIPE_TEXTURE_2D_ARRAY:2864case PIPE_TEXTURE_1D_ARRAY:2865/* these use layer */2866region.imageSubresource.baseArrayLayer = buf2img ? dstz : src_box->z;2867region.imageSubresource.layerCount = src_box->depth;2868region.imageOffset.z = 0;2869region.imageExtent.depth = 1;2870break;2871case PIPE_TEXTURE_3D:2872/* this uses depth */2873region.imageSubresource.baseArrayLayer = 0;2874region.imageSubresource.layerCount = 1;2875region.imageOffset.z = buf2img ? dstz : src_box->z;2876region.imageExtent.depth = src_box->depth;2877break;2878default:2879/* these must only copy one layer */2880region.imageSubresource.baseArrayLayer = 0;2881region.imageSubresource.layerCount = 1;2882region.imageOffset.z = 0;2883region.imageExtent.depth = 1;2884}2885region.imageOffset.x = buf2img ? dstx : src_box->x;2886region.imageOffset.y = buf2img ? dsty : src_box->y;28872888region.imageExtent.width = src_box->width;2889region.imageExtent.height = src_box->height;28902891zink_batch_reference_resource_rw(batch, img, buf2img);2892zink_batch_reference_resource_rw(batch, buf, !buf2img);28932894/* we're using u_transfer_helper_deinterleave, which means we'll be getting PIPE_MAP_* usage2895* to indicate whether to copy either the depth or stencil aspects2896*/2897unsigned aspects = 0;2898if (map_flags) {2899assert((map_flags & (PIPE_MAP_DEPTH_ONLY | PIPE_MAP_STENCIL_ONLY)) !=2900(PIPE_MAP_DEPTH_ONLY | PIPE_MAP_STENCIL_ONLY));2901if (map_flags & PIPE_MAP_DEPTH_ONLY)2902aspects = VK_IMAGE_ASPECT_DEPTH_BIT;2903else if (map_flags & PIPE_MAP_STENCIL_ONLY)2904aspects = VK_IMAGE_ASPECT_STENCIL_BIT;2905}2906if (!aspects)2907aspects = img->aspect;2908while (aspects) {2909int aspect = 1 << u_bit_scan(&aspects);2910region.imageSubresource.aspectMask = aspect;29112912/* this may or may not work with multisampled depth/stencil buffers depending on the driver implementation:2913*2914* srcImage must have a sample count equal to VK_SAMPLE_COUNT_1_BIT2915* - vkCmdCopyImageToBuffer spec2916*2917* dstImage must have a sample count equal to VK_SAMPLE_COUNT_1_BIT2918* - vkCmdCopyBufferToImage spec2919*/2920if (buf2img)2921vkCmdCopyBufferToImage(batch->state->cmdbuf, buf->obj->buffer, img->obj->image, img->layout, 1, ®ion);2922else2923vkCmdCopyImageToBuffer(batch->state->cmdbuf, img->obj->image, img->layout, buf->obj->buffer, 1, ®ion);2924}2925}29262927static void2928zink_resource_copy_region(struct pipe_context *pctx,2929struct pipe_resource *pdst,2930unsigned dst_level, unsigned dstx, unsigned dsty, unsigned dstz,2931struct pipe_resource *psrc,2932unsigned src_level, const struct pipe_box *src_box)2933{2934struct zink_resource *dst = zink_resource(pdst);2935struct zink_resource *src = zink_resource(psrc);2936struct zink_context *ctx = zink_context(pctx);2937if (dst->base.b.target != PIPE_BUFFER && src->base.b.target != PIPE_BUFFER) {2938VkImageCopy region = {0};2939if (util_format_get_num_planes(src->base.b.format) == 1 &&2940util_format_get_num_planes(dst->base.b.format) == 1) {2941/* If neither the calling command’s srcImage nor the calling command’s dstImage2942* has a multi-planar image format then the aspectMask member of srcSubresource2943* and dstSubresource must match2944*2945* -VkImageCopy spec2946*/2947assert(src->aspect == dst->aspect);2948} else2949unreachable("planar formats not yet handled");29502951zink_fb_clears_apply_or_discard(ctx, pdst, (struct u_rect){dstx, dstx + src_box->width, dsty, dsty + src_box->height}, false);2952zink_fb_clears_apply_region(ctx, psrc, zink_rect_from_box(src_box));29532954region.srcSubresource.aspectMask = src->aspect;2955region.srcSubresource.mipLevel = src_level;2956switch (src->base.b.target) {2957case PIPE_TEXTURE_CUBE:2958case PIPE_TEXTURE_CUBE_ARRAY:2959case PIPE_TEXTURE_2D_ARRAY:2960case PIPE_TEXTURE_1D_ARRAY:2961/* these use layer */2962region.srcSubresource.baseArrayLayer = src_box->z;2963region.srcSubresource.layerCount = src_box->depth;2964region.srcOffset.z = 0;2965region.extent.depth = 1;2966break;2967case PIPE_TEXTURE_3D:2968/* this uses depth */2969region.srcSubresource.baseArrayLayer = 0;2970region.srcSubresource.layerCount = 1;2971region.srcOffset.z = src_box->z;2972region.extent.depth = src_box->depth;2973break;2974default:2975/* these must only copy one layer */2976region.srcSubresource.baseArrayLayer = 0;2977region.srcSubresource.layerCount = 1;2978region.srcOffset.z = 0;2979region.extent.depth = 1;2980}29812982region.srcOffset.x = src_box->x;2983region.srcOffset.y = src_box->y;29842985region.dstSubresource.aspectMask = dst->aspect;2986region.dstSubresource.mipLevel = dst_level;2987switch (dst->base.b.target) {2988case PIPE_TEXTURE_CUBE:2989case PIPE_TEXTURE_CUBE_ARRAY:2990case PIPE_TEXTURE_2D_ARRAY:2991case PIPE_TEXTURE_1D_ARRAY:2992/* these use layer */2993region.dstSubresource.baseArrayLayer = dstz;2994region.dstSubresource.layerCount = src_box->depth;2995region.dstOffset.z = 0;2996break;2997case PIPE_TEXTURE_3D:2998/* this uses depth */2999region.dstSubresource.baseArrayLayer = 0;3000region.dstSubresource.layerCount = 1;3001region.dstOffset.z = dstz;3002break;3003default:3004/* these must only copy one layer */3005region.dstSubresource.baseArrayLayer = 0;3006region.dstSubresource.layerCount = 1;3007region.dstOffset.z = 0;3008}30093010region.dstOffset.x = dstx;3011region.dstOffset.y = dsty;3012region.extent.width = src_box->width;3013region.extent.height = src_box->height;30143015struct zink_batch *batch = zink_batch_no_rp(ctx);3016zink_batch_reference_resource_rw(batch, src, false);3017zink_batch_reference_resource_rw(batch, dst, true);30183019zink_resource_setup_transfer_layouts(ctx, src, dst);3020vkCmdCopyImage(batch->state->cmdbuf, src->obj->image, src->layout,3021dst->obj->image, dst->layout,30221, ®ion);3023} else if (dst->base.b.target == PIPE_BUFFER &&3024src->base.b.target == PIPE_BUFFER) {3025zink_copy_buffer(ctx, NULL, dst, src, dstx, src_box->x, src_box->width);3026} else3027zink_copy_image_buffer(ctx, NULL, dst, src, dst_level, dstx, dsty, dstz, src_level, src_box, 0);3028}30293030static struct pipe_stream_output_target *3031zink_create_stream_output_target(struct pipe_context *pctx,3032struct pipe_resource *pres,3033unsigned buffer_offset,3034unsigned buffer_size)3035{3036struct zink_so_target *t;3037t = CALLOC_STRUCT(zink_so_target);3038if (!t)3039return NULL;30403041/* using PIPE_BIND_CUSTOM here lets us create a custom pipe buffer resource,3042* which allows us to differentiate and use VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT3043* as we must for this case3044*/3045t->counter_buffer = pipe_buffer_create(pctx->screen, PIPE_BIND_STREAM_OUTPUT | PIPE_BIND_CUSTOM, PIPE_USAGE_DEFAULT, 4);3046if (!t->counter_buffer) {3047FREE(t);3048return NULL;3049}30503051t->base.reference.count = 1;3052t->base.context = pctx;3053pipe_resource_reference(&t->base.buffer, pres);3054t->base.buffer_offset = buffer_offset;3055t->base.buffer_size = buffer_size;30563057zink_resource(t->base.buffer)->bind_history |= ZINK_RESOURCE_USAGE_STREAMOUT;30583059return &t->base;3060}30613062static void3063zink_stream_output_target_destroy(struct pipe_context *pctx,3064struct pipe_stream_output_target *psot)3065{3066struct zink_so_target *t = (struct zink_so_target *)psot;3067pipe_resource_reference(&t->counter_buffer, NULL);3068pipe_resource_reference(&t->base.buffer, NULL);3069FREE(t);3070}30713072static void3073zink_set_stream_output_targets(struct pipe_context *pctx,3074unsigned num_targets,3075struct pipe_stream_output_target **targets,3076const unsigned *offsets)3077{3078struct zink_context *ctx = zink_context(pctx);30793080if (num_targets == 0) {3081for (unsigned i = 0; i < ctx->num_so_targets; i++)3082pipe_so_target_reference(&ctx->so_targets[i], NULL);3083ctx->num_so_targets = 0;3084} else {3085for (unsigned i = 0; i < num_targets; i++) {3086struct zink_so_target *t = zink_so_target(targets[i]);3087pipe_so_target_reference(&ctx->so_targets[i], targets[i]);3088if (!t)3089continue;3090struct zink_resource *res = zink_resource(t->counter_buffer);3091if (offsets[0] == (unsigned)-1)3092ctx->xfb_barrier |= zink_resource_buffer_needs_barrier(res,3093VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT,3094VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT);3095else3096ctx->xfb_barrier |= zink_resource_buffer_needs_barrier(res,3097VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT,3098VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT);3099}3100for (unsigned i = num_targets; i < ctx->num_so_targets; i++)3101pipe_so_target_reference(&ctx->so_targets[i], NULL);3102ctx->num_so_targets = num_targets;31033104/* TODO: possibly avoid rebinding on resume if resuming from same buffers? */3105ctx->dirty_so_targets = true;3106}3107}31083109void3110zink_rebind_framebuffer(struct zink_context *ctx, struct zink_resource *res)3111{3112if (!ctx->framebuffer)3113return;3114for (unsigned i = 0; i < ctx->framebuffer->state.num_attachments; i++) {3115if (!ctx->framebuffer->surfaces[i] ||3116zink_resource(ctx->framebuffer->surfaces[i]->texture) != res)3117continue;3118zink_rebind_surface(ctx, &ctx->framebuffer->surfaces[i]);3119zink_batch_no_rp(ctx);3120}3121if (rebind_fb_state(ctx, res, false))3122zink_batch_no_rp(ctx);3123}31243125static void3126rebind_buffer(struct zink_context *ctx, struct zink_resource *res)3127{3128const unsigned total_rebinds = res->bind_count[0] + res->bind_count[1];3129unsigned num_rebinds = 0, num_image_rebinds_remaining[2] = {res->image_bind_count[0], res->image_bind_count[1]};3130bool has_write = false;31313132if (res->vbo_bind_count) {3133ctx->vertex_buffers_dirty = true;3134num_rebinds += res->vbo_bind_count;3135}3136for (unsigned shader = 0; num_rebinds < total_rebinds && shader < PIPE_SHADER_TYPES; shader++) {3137u_foreach_bit(slot, res->ubo_bind_mask[shader]) {3138if (&res->base.b != ctx->ubos[shader][slot].buffer) //wrong context3139return;31403141update_descriptor_state_ubo(ctx, shader, slot);3142zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, shader, ZINK_DESCRIPTOR_TYPE_UBO, slot, 1);3143num_rebinds++;3144}3145u_foreach_bit(slot, res->ssbo_bind_mask[shader]) {3146struct pipe_shader_buffer *ssbo = &ctx->ssbos[shader][slot];3147if (&res->base.b != ssbo->buffer) //wrong context3148return;31493150has_write |= ctx->writable_ssbos[shader] & BITFIELD64_BIT(slot);3151util_range_add(&res->base.b, &res->valid_buffer_range, ssbo->buffer_offset,3152ssbo->buffer_offset + ssbo->buffer_size);3153update_descriptor_state_ssbo(ctx, shader, slot);3154zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, shader, ZINK_DESCRIPTOR_TYPE_SSBO, slot, 1);3155num_rebinds++;3156}3157u_foreach_bit(slot, res->sampler_binds[shader]) {3158struct zink_sampler_view *sampler_view = zink_sampler_view(ctx->sampler_views[shader][slot]);3159if (&res->base.b != sampler_view->base.texture) //wrong context3160return;31613162if (zink_batch_usage_exists(sampler_view->buffer_view->batch_uses))3163zink_batch_reference_bufferview(&ctx->batch, sampler_view->buffer_view);3164zink_buffer_view_reference(zink_screen(ctx->base.screen), &sampler_view->buffer_view, NULL);3165sampler_view->buffer_view = get_buffer_view(ctx, res, sampler_view->base.format,3166sampler_view->base.u.buf.offset, sampler_view->base.u.buf.size);3167update_descriptor_state_sampler(ctx, shader, slot);3168zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, shader, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW, slot, 1);3169num_rebinds++;3170}3171if (unlikely(num_image_rebinds_remaining[shader == PIPE_SHADER_COMPUTE])) {3172for (unsigned slot = 0; num_image_rebinds_remaining[shader == PIPE_SHADER_COMPUTE] &&3173slot < ctx->di.num_images[shader]; slot++) {3174struct zink_resource *cres = zink_get_resource_for_descriptor(ctx, ZINK_DESCRIPTOR_TYPE_IMAGE, shader, slot);3175if (res != cres)3176continue;31773178struct zink_image_view *image_view = &ctx->image_views[shader][slot];3179zink_descriptor_set_refs_clear(&image_view->buffer_view->desc_set_refs, image_view->buffer_view);3180if (zink_batch_usage_exists(image_view->buffer_view->batch_uses))3181zink_batch_reference_bufferview(&ctx->batch, image_view->buffer_view);3182zink_buffer_view_reference(zink_screen(ctx->base.screen), &image_view->buffer_view, NULL);3183if (!zink_resource_object_init_storage(ctx, res)) {3184debug_printf("couldn't create storage image!");3185continue;3186}3187has_write |= image_view->base.access & PIPE_IMAGE_ACCESS_WRITE;3188image_view->buffer_view = get_buffer_view(ctx, res, image_view->base.format,3189image_view->base.u.buf.offset, image_view->base.u.buf.size);3190assert(image_view->buffer_view);3191util_range_add(&res->base.b, &res->valid_buffer_range, image_view->base.u.buf.offset,3192image_view->base.u.buf.offset + image_view->base.u.buf.size);3193update_descriptor_state_image(ctx, shader, slot);3194zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, shader, ZINK_DESCRIPTOR_TYPE_IMAGE, slot, 1);3195num_image_rebinds_remaining[shader == PIPE_SHADER_COMPUTE]--;3196}3197}3198}3199zink_batch_resource_usage_set(&ctx->batch, res, has_write);3200}32013202static inline struct zink_screen **3203get_screen_ptr_for_commit(uint8_t *mem)3204{3205return (struct zink_screen**)(mem + sizeof(VkBindSparseInfo) + sizeof(VkSparseBufferMemoryBindInfo) + sizeof(VkSparseMemoryBind));3206}32073208static bool3209resource_commit(struct zink_screen *screen, VkBindSparseInfo *sparse)3210{3211VkQueue queue = screen->threaded ? screen->thread_queue : screen->queue;32123213VkResult ret = vkQueueBindSparse(queue, 1, sparse, VK_NULL_HANDLE);3214return zink_screen_handle_vkresult(screen, ret);3215}32163217static void3218submit_resource_commit(void *data, void *gdata, int thread_index)3219{3220struct zink_screen **screen = get_screen_ptr_for_commit(data);3221resource_commit(*screen, data);3222free(data);3223}32243225static bool3226zink_resource_commit(struct pipe_context *pctx, struct pipe_resource *pres, unsigned level, struct pipe_box *box, bool commit)3227{3228struct zink_context *ctx = zink_context(pctx);3229struct zink_resource *res = zink_resource(pres);3230struct zink_screen *screen = zink_screen(pctx->screen);32313232/* if any current usage exists, flush the queue */3233if (zink_batch_usage_is_unflushed(res->obj->reads) ||3234zink_batch_usage_is_unflushed(res->obj->writes))3235zink_flush_queue(ctx);32363237uint8_t *mem = malloc(sizeof(VkBindSparseInfo) + sizeof(VkSparseBufferMemoryBindInfo) + sizeof(VkSparseMemoryBind) + sizeof(void*));3238if (!mem)3239return false;3240VkBindSparseInfo *sparse = (void*)mem;3241sparse->sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO;3242sparse->pNext = NULL;3243sparse->waitSemaphoreCount = 0;3244sparse->bufferBindCount = 1;3245sparse->imageOpaqueBindCount = 0;3246sparse->imageBindCount = 0;3247sparse->signalSemaphoreCount = 0;32483249VkSparseBufferMemoryBindInfo *sparse_bind = (void*)(mem + sizeof(VkBindSparseInfo));3250sparse_bind->buffer = res->obj->buffer;3251sparse_bind->bindCount = 1;3252sparse->pBufferBinds = sparse_bind;32533254VkSparseMemoryBind *mem_bind = (void*)(mem + sizeof(VkBindSparseInfo) + sizeof(VkSparseBufferMemoryBindInfo));3255mem_bind->resourceOffset = box->x;3256mem_bind->size = box->width;3257mem_bind->memory = commit ? res->obj->mem : VK_NULL_HANDLE;3258/* currently sparse buffers allocate memory 1:1 for the max sparse size,3259* but probably it should dynamically allocate the committed regions;3260* if this ever changes, update the below line3261*/3262mem_bind->memoryOffset = box->x;3263mem_bind->flags = 0;3264sparse_bind->pBinds = mem_bind;32653266struct zink_screen **ptr = get_screen_ptr_for_commit(mem);3267*ptr = screen;32683269if (screen->threaded) {3270/* this doesn't need any kind of fencing because any access to this resource3271* will be automagically synchronized by queue dispatch */3272util_queue_add_job(&screen->flush_queue, mem, NULL, submit_resource_commit, NULL, 0);3273} else {3274bool ret = resource_commit(screen, sparse);3275if (!ret)3276check_device_lost(ctx);3277free(sparse);3278return ret;3279}3280return true;3281}32823283static void3284rebind_image(struct zink_context *ctx, struct zink_resource *res)3285{3286zink_rebind_framebuffer(ctx, res);3287if (!res->bind_count[0] && !res->bind_count[1])3288return;3289for (unsigned i = 0; i < PIPE_SHADER_TYPES; i++) {3290if (res->sampler_binds[i]) {3291for (unsigned j = 0; j < ctx->di.num_sampler_views[i]; j++) {3292struct zink_sampler_view *sv = zink_sampler_view(ctx->sampler_views[i][j]);3293if (sv && sv->base.texture == &res->base.b) {3294struct pipe_surface *psurf = &sv->image_view->base;3295zink_rebind_surface(ctx, &psurf);3296sv->image_view = zink_surface(psurf);3297zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, i, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW, j, 1);3298update_descriptor_state_sampler(ctx, i, j);3299}3300}3301}3302if (!res->image_bind_count[i == PIPE_SHADER_COMPUTE])3303continue;3304for (unsigned j = 0; j < ctx->di.num_images[i]; j++) {3305if (zink_resource(ctx->image_views[i][j].base.resource) == res) {3306zink_screen(ctx->base.screen)->context_invalidate_descriptor_state(ctx, i, ZINK_DESCRIPTOR_TYPE_IMAGE, j, 1);3307update_descriptor_state_sampler(ctx, i, j);3308_mesa_set_add(ctx->need_barriers[i == PIPE_SHADER_COMPUTE], res);3309}3310}3311}3312}33133314void3315zink_resource_rebind(struct zink_context *ctx, struct zink_resource *res)3316{3317if (res->bind_history & ZINK_RESOURCE_USAGE_STREAMOUT)3318ctx->dirty_so_targets = true;3319/* force counter buffer reset */3320res->bind_history &= ~ZINK_RESOURCE_USAGE_STREAMOUT;33213322if (!res->bind_count[0] && !res->bind_count[1])3323return;3324if (res->base.b.target == PIPE_BUFFER)3325rebind_buffer(ctx, res);3326else3327rebind_image(ctx, res);3328}33293330static void3331zink_context_replace_buffer_storage(struct pipe_context *pctx, struct pipe_resource *dst,3332struct pipe_resource *src, unsigned num_rebinds,3333uint32_t rebind_mask, uint32_t delete_buffer_id)3334{3335struct zink_resource *d = zink_resource(dst);3336struct zink_resource *s = zink_resource(src);33373338assert(d->internal_format == s->internal_format);3339util_idalloc_mt_free(&zink_screen(pctx->screen)->buffer_ids, delete_buffer_id);3340if (zink_batch_usage_is_unflushed(d->obj->reads) ||3341zink_batch_usage_is_unflushed(d->obj->writes))3342zink_batch_reference_resource(&zink_context(pctx)->batch, d);3343zink_resource_object_reference(zink_screen(pctx->screen), &d->obj, s->obj);3344d->access = s->access;3345d->access_stage = s->access_stage;3346d->unordered_barrier = s->unordered_barrier;3347zink_resource_rebind(zink_context(pctx), d);3348}33493350ALWAYS_INLINE static bool3351is_usage_completed(struct zink_screen *screen, const struct zink_batch_usage *u)3352{3353if (!zink_batch_usage_exists(u))3354return true;3355if (zink_batch_usage_is_unflushed(u))3356return false;3357/* check fastpath first */3358if (zink_screen_check_last_finished(screen, u->usage))3359return true;3360/* if we have timelines, do a quick check */3361if (screen->info.have_KHR_timeline_semaphore)3362return zink_screen_timeline_wait(screen, u->usage, 0);33633364/* otherwise assume busy */3365return false;3366}33673368static bool3369zink_context_is_resource_busy(struct pipe_screen *pscreen, struct pipe_resource *pres, unsigned usage)3370{3371struct zink_screen *screen = zink_screen(pscreen);3372struct zink_resource *res = zink_resource(pres);3373const struct zink_batch_usage *reads = NULL, *writes = NULL;3374if (((usage & (PIPE_MAP_READ | PIPE_MAP_WRITE)) == (PIPE_MAP_READ | PIPE_MAP_WRITE)) ||3375usage & PIPE_MAP_WRITE) {3376reads = res->obj->reads;3377writes = res->obj->writes;3378} else if (usage & PIPE_MAP_READ)3379writes = res->obj->writes;33803381return !is_usage_completed(screen, reads) || !is_usage_completed(screen, writes);3382}33833384static void3385zink_emit_string_marker(struct pipe_context *pctx,3386const char *string, int len)3387{3388struct zink_screen *screen = zink_screen(pctx->screen);3389struct zink_batch *batch = &zink_context(pctx)->batch;33903391/* make sure string is nul-terminated */3392char buf[512], *temp = NULL;3393if (len < ARRAY_SIZE(buf)) {3394memcpy(buf, string, len);3395buf[len] = '\0';3396string = buf;3397} else3398string = temp = strndup(string, len);33993400VkDebugUtilsLabelEXT label = {3401VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, NULL,3402string,3403{ 0 }3404};3405screen->vk.CmdInsertDebugUtilsLabelEXT(batch->state->cmdbuf, &label);3406free(temp);3407}34083409struct pipe_context *3410zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)3411{3412struct zink_screen *screen = zink_screen(pscreen);3413struct zink_context *ctx = rzalloc(NULL, struct zink_context);3414if (!ctx)3415goto fail;3416ctx->have_timelines = screen->info.have_KHR_timeline_semaphore;34173418ctx->gfx_pipeline_state.dirty = true;3419ctx->compute_pipeline_state.dirty = true;3420ctx->fb_changed = ctx->rp_changed = true;34213422ctx->base.screen = pscreen;3423ctx->base.priv = priv;34243425ctx->base.destroy = zink_context_destroy;3426ctx->base.get_device_reset_status = zink_get_device_reset_status;3427ctx->base.set_device_reset_callback = zink_set_device_reset_callback;34283429zink_context_state_init(&ctx->base);34303431ctx->base.create_sampler_state = zink_create_sampler_state;3432ctx->base.bind_sampler_states = zink_bind_sampler_states;3433ctx->base.delete_sampler_state = zink_delete_sampler_state;34343435ctx->base.create_sampler_view = zink_create_sampler_view;3436ctx->base.set_sampler_views = zink_set_sampler_views;3437ctx->base.sampler_view_destroy = zink_sampler_view_destroy;3438ctx->base.get_sample_position = zink_get_sample_position;3439ctx->base.set_sample_locations = zink_set_sample_locations;34403441zink_program_init(ctx);34423443ctx->base.set_polygon_stipple = zink_set_polygon_stipple;3444ctx->base.set_vertex_buffers = zink_set_vertex_buffers;3445ctx->base.set_viewport_states = zink_set_viewport_states;3446ctx->base.set_scissor_states = zink_set_scissor_states;3447ctx->base.set_inlinable_constants = zink_set_inlinable_constants;3448ctx->base.set_constant_buffer = zink_set_constant_buffer;3449ctx->base.set_shader_buffers = zink_set_shader_buffers;3450ctx->base.set_shader_images = zink_set_shader_images;3451ctx->base.set_framebuffer_state = zink_set_framebuffer_state;3452ctx->base.set_stencil_ref = zink_set_stencil_ref;3453ctx->base.set_clip_state = zink_set_clip_state;3454ctx->base.set_blend_color = zink_set_blend_color;3455ctx->base.set_tess_state = zink_set_tess_state;34563457ctx->base.set_sample_mask = zink_set_sample_mask;34583459ctx->base.clear = zink_clear;3460ctx->base.clear_texture = zink_clear_texture;3461ctx->base.clear_buffer = zink_clear_buffer;3462ctx->base.clear_render_target = zink_clear_render_target;3463ctx->base.clear_depth_stencil = zink_clear_depth_stencil;34643465ctx->base.draw_vbo = zink_draw_vbo;3466ctx->base.launch_grid = zink_launch_grid;3467ctx->base.fence_server_sync = zink_fence_server_sync;3468ctx->base.flush = zink_flush;3469ctx->base.memory_barrier = zink_memory_barrier;3470ctx->base.texture_barrier = zink_texture_barrier;3471ctx->base.evaluate_depth_buffer = zink_evaluate_depth_buffer;34723473ctx->base.resource_commit = zink_resource_commit;3474ctx->base.resource_copy_region = zink_resource_copy_region;3475ctx->base.blit = zink_blit;3476ctx->base.create_stream_output_target = zink_create_stream_output_target;3477ctx->base.stream_output_target_destroy = zink_stream_output_target_destroy;34783479ctx->base.set_stream_output_targets = zink_set_stream_output_targets;3480ctx->base.flush_resource = zink_flush_resource;34813482ctx->base.emit_string_marker = zink_emit_string_marker;34833484zink_context_surface_init(&ctx->base);3485zink_context_resource_init(&ctx->base);3486zink_context_query_init(&ctx->base);34873488_mesa_set_init(&ctx->update_barriers[0][0], ctx, _mesa_hash_pointer, _mesa_key_pointer_equal);3489_mesa_set_init(&ctx->update_barriers[1][0], ctx, _mesa_hash_pointer, _mesa_key_pointer_equal);3490_mesa_set_init(&ctx->update_barriers[0][1], ctx, _mesa_hash_pointer, _mesa_key_pointer_equal);3491_mesa_set_init(&ctx->update_barriers[1][1], ctx, _mesa_hash_pointer, _mesa_key_pointer_equal);3492ctx->need_barriers[0] = &ctx->update_barriers[0][0];3493ctx->need_barriers[1] = &ctx->update_barriers[1][0];34943495util_dynarray_init(&ctx->free_batch_states, ctx);3496_mesa_hash_table_init(&ctx->batch_states, ctx, NULL, _mesa_key_pointer_equal);34973498ctx->gfx_pipeline_state.have_EXT_extended_dynamic_state = screen->info.have_EXT_extended_dynamic_state;34993500slab_create_child(&ctx->transfer_pool, &screen->transfer_pool);3501slab_create_child(&ctx->transfer_pool_unsync, &screen->transfer_pool);35023503ctx->base.stream_uploader = u_upload_create_default(&ctx->base);3504ctx->base.const_uploader = u_upload_create_default(&ctx->base);3505for (int i = 0; i < ARRAY_SIZE(ctx->fb_clears); i++)3506util_dynarray_init(&ctx->fb_clears[i].clears, ctx);35073508ctx->blitter = util_blitter_create(&ctx->base);3509if (!ctx->blitter)3510goto fail;35113512ctx->program_cache = _mesa_hash_table_create(NULL,3513hash_gfx_program,3514equals_gfx_program);3515ctx->compute_program_cache = _mesa_hash_table_create(NULL,3516_mesa_hash_pointer,3517_mesa_key_pointer_equal);3518ctx->render_pass_cache = _mesa_hash_table_create(NULL,3519hash_render_pass_state,3520equals_render_pass_state);3521if (!ctx->program_cache || !ctx->compute_program_cache || !ctx->render_pass_cache)3522goto fail;35233524const uint8_t data[] = {0};3525ctx->dummy_vertex_buffer = pipe_buffer_create(&screen->base,3526PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_SHADER_IMAGE, PIPE_USAGE_IMMUTABLE, sizeof(data));3527if (!ctx->dummy_vertex_buffer)3528goto fail;3529ctx->dummy_xfb_buffer = pipe_buffer_create(&screen->base,3530PIPE_BIND_STREAM_OUTPUT, PIPE_USAGE_DEFAULT, sizeof(data));3531if (!ctx->dummy_xfb_buffer)3532goto fail;3533ctx->dummy_surface = zink_surface_create_null(ctx, PIPE_TEXTURE_2D, 1, 1, 1);3534if (!ctx->dummy_surface)3535goto fail;3536ctx->dummy_bufferview = get_buffer_view(ctx, zink_resource(ctx->dummy_vertex_buffer), PIPE_FORMAT_R8_UNORM, 0, sizeof(data));3537if (!ctx->dummy_bufferview)3538goto fail;35393540if (!zink_descriptor_layouts_init(ctx))3541goto fail;35423543if (!screen->descriptors_init(ctx)) {3544zink_screen_init_descriptor_funcs(screen, true);3545if (!screen->descriptors_init(ctx))3546goto fail;3547}35483549ctx->have_timelines = screen->info.have_KHR_timeline_semaphore;3550simple_mtx_init(&ctx->batch_mtx, mtx_plain);3551zink_start_batch(ctx, &ctx->batch);3552if (!ctx->batch.state)3553goto fail;35543555pipe_buffer_write(&ctx->base, ctx->dummy_vertex_buffer, 0, sizeof(data), data);3556pipe_buffer_write(&ctx->base, ctx->dummy_xfb_buffer, 0, sizeof(data), data);35573558for (unsigned i = 0; i < PIPE_SHADER_TYPES; i++) {3559/* need to update these based on screen config for null descriptors */3560for (unsigned j = 0; j < 32; j++) {3561update_descriptor_state_ubo(ctx, i, j);3562update_descriptor_state_sampler(ctx, i, j);3563update_descriptor_state_ssbo(ctx, i, j);3564update_descriptor_state_image(ctx, i, j);3565}3566}3567p_atomic_inc(&screen->base.num_contexts);35683569if (!(flags & PIPE_CONTEXT_PREFER_THREADED) || flags & PIPE_CONTEXT_COMPUTE_ONLY) {3570return &ctx->base;3571}35723573struct threaded_context *tc = (struct threaded_context*)threaded_context_create(&ctx->base, &screen->transfer_pool,3574zink_context_replace_buffer_storage,3575zink_create_tc_fence_for_tc,3576zink_context_is_resource_busy, true, &ctx->tc);35773578if (tc && (struct zink_context*)tc != ctx) {3579tc->bytes_mapped_limit = screen->total_mem / 4;3580ctx->base.set_context_param = zink_set_context_param;3581}35823583return (struct pipe_context*)tc;35843585fail:3586if (ctx)3587zink_context_destroy(&ctx->base);3588return NULL;3589}359035913592