static void radv_make_buffer_descriptor(struct radv_device *device, struct radv_buffer *buffer, VkFormat vk_format, unsigned offset, unsigned range, uint32_t *state) { const struct vk_format_description *desc; unsigned stride; uint64_t gpu_address = device->ws->buffer_get_va(buffer->bo); uint64_t va = gpu_address + buffer->offset; unsigned num_format, data_format; int first_non_void; desc = vk_format_description(vk_format); first_non_void = vk_format_get_first_non_void_channel(vk_format); stride = desc->block.bits / 8; num_format = radv_translate_buffer_numformat(desc, first_non_void); data_format = radv_translate_buffer_dataformat(desc, first_non_void); va += offset; state[0] = va; state[1] = S_008F04_BASE_ADDRESS_HI(va >> 32) | S_008F04_STRIDE(stride); state[2] = range; state[3] = S_008F0C_DST_SEL_X(radv_map_swizzle(desc->swizzle[0])) | S_008F0C_DST_SEL_Y(radv_map_swizzle(desc->swizzle[1])) | S_008F0C_DST_SEL_Z(radv_map_swizzle(desc->swizzle[2])) | S_008F0C_DST_SEL_W(radv_map_swizzle(desc->swizzle[3])) | S_008F0C_NUM_FORMAT(num_format) | S_008F0C_DATA_FORMAT(data_format); }
unsigned radv_translate_colorswap(VkFormat format, bool do_endian_swap) { const struct vk_format_description *desc = vk_format_description(format); #define HAS_SWIZZLE(chan,swz) (desc->swizzle[chan] == VK_SWIZZLE_##swz) if (format == VK_FORMAT_B10G11R11_UFLOAT_PACK32) return V_0280A0_SWAP_STD; if (desc->layout != VK_FORMAT_LAYOUT_PLAIN) return ~0U; switch (desc->nr_channels) { case 1: if (HAS_SWIZZLE(0,X)) return V_0280A0_SWAP_STD; /* X___ */ else if (HAS_SWIZZLE(3,X)) return V_0280A0_SWAP_ALT_REV; /* ___X */ break; case 2: if ((HAS_SWIZZLE(0,X) && HAS_SWIZZLE(1,Y)) || (HAS_SWIZZLE(0,X) && HAS_SWIZZLE(1,NONE)) || (HAS_SWIZZLE(0,NONE) && HAS_SWIZZLE(1,Y))) return V_0280A0_SWAP_STD; /* XY__ */ else if ((HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(1,X)) || (HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(1,NONE)) || (HAS_SWIZZLE(0,NONE) && HAS_SWIZZLE(1,X))) /* YX__ */ return (do_endian_swap ? V_0280A0_SWAP_STD : V_0280A0_SWAP_STD_REV); else if (HAS_SWIZZLE(0,X) && HAS_SWIZZLE(3,Y)) return V_0280A0_SWAP_ALT; /* X__Y */ else if (HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(3,X)) return V_0280A0_SWAP_ALT_REV; /* Y__X */ break; case 3: if (HAS_SWIZZLE(0,X)) return (do_endian_swap ? V_0280A0_SWAP_STD_REV : V_0280A0_SWAP_STD); else if (HAS_SWIZZLE(0,Z)) return V_0280A0_SWAP_STD_REV; /* ZYX */ break; case 4: /* check the middle channels, the 1st and 4th channel can be NONE */ if (HAS_SWIZZLE(1,Y) && HAS_SWIZZLE(2,Z)) { return V_0280A0_SWAP_STD; /* XYZW */ } else if (HAS_SWIZZLE(1,Z) && HAS_SWIZZLE(2,Y)) { return V_0280A0_SWAP_STD_REV; /* WZYX */ } else if (HAS_SWIZZLE(1,Y) && HAS_SWIZZLE(2,X)) { return V_0280A0_SWAP_ALT; /* ZYXW */ } else if (HAS_SWIZZLE(1,Z) && HAS_SWIZZLE(2,W)) { /* YZWX */ if (desc->is_array) return V_0280A0_SWAP_ALT_REV; else return (do_endian_swap ? V_0280A0_SWAP_ALT : V_0280A0_SWAP_ALT_REV); } break; } return ~0U; }
static bool radv_is_storage_image_format_supported(struct radv_physical_device *physical_device, VkFormat format) { const struct vk_format_description *desc = vk_format_description(format); unsigned data_format, num_format; if (!desc || format == VK_FORMAT_UNDEFINED) return false; data_format = radv_translate_tex_dataformat(format, desc, vk_format_get_first_non_void_channel(format)); num_format = radv_translate_tex_numformat(format, desc, vk_format_get_first_non_void_channel(format)); if(data_format == ~0 || num_format == ~0) return false; /* Extracted from the GCN3 ISA document. */ switch(num_format) { case V_008F14_IMG_NUM_FORMAT_UNORM: case V_008F14_IMG_NUM_FORMAT_SNORM: case V_008F14_IMG_NUM_FORMAT_UINT: case V_008F14_IMG_NUM_FORMAT_SINT: case V_008F14_IMG_NUM_FORMAT_FLOAT: break; default: return false; } switch(data_format) { case V_008F14_IMG_DATA_FORMAT_8: case V_008F14_IMG_DATA_FORMAT_16: case V_008F14_IMG_DATA_FORMAT_8_8: case V_008F14_IMG_DATA_FORMAT_32: case V_008F14_IMG_DATA_FORMAT_16_16: case V_008F14_IMG_DATA_FORMAT_10_11_11: case V_008F14_IMG_DATA_FORMAT_11_11_10: case V_008F14_IMG_DATA_FORMAT_10_10_10_2: case V_008F14_IMG_DATA_FORMAT_2_10_10_10: case V_008F14_IMG_DATA_FORMAT_8_8_8_8: case V_008F14_IMG_DATA_FORMAT_32_32: case V_008F14_IMG_DATA_FORMAT_16_16_16_16: case V_008F14_IMG_DATA_FORMAT_32_32_32_32: case V_008F14_IMG_DATA_FORMAT_5_6_5: case V_008F14_IMG_DATA_FORMAT_1_5_5_5: case V_008F14_IMG_DATA_FORMAT_5_5_5_1: case V_008F14_IMG_DATA_FORMAT_4_4_4_4: /* TODO: FMASK formats. */ return true; default: return false; } }
static bool radv_is_sampler_format_supported(VkFormat format, bool *linear_sampling) { const struct vk_format_description *desc = vk_format_description(format); uint32_t num_format; if (!desc || format == VK_FORMAT_UNDEFINED) return false; num_format = radv_translate_tex_numformat(format, desc, vk_format_get_first_non_void_channel(format)); if (num_format == V_008F14_IMG_NUM_FORMAT_USCALED || num_format == V_008F14_IMG_NUM_FORMAT_SSCALED) return false; if (num_format == V_008F14_IMG_NUM_FORMAT_UNORM || num_format == V_008F14_IMG_NUM_FORMAT_SNORM || num_format == V_008F14_IMG_NUM_FORMAT_FLOAT || num_format == V_008F14_IMG_NUM_FORMAT_SRGB) *linear_sampling = true; else *linear_sampling = false; return radv_translate_tex_dataformat(format, vk_format_description(format), vk_format_get_first_non_void_channel(format)) != ~0U; }
static bool radv_is_buffer_format_supported(VkFormat format) { const struct vk_format_description *desc = vk_format_description(format); unsigned data_format, num_format; if (!desc || format == VK_FORMAT_UNDEFINED) return false; data_format = radv_translate_buffer_dataformat(desc, vk_format_get_first_non_void_channel(format)); num_format = radv_translate_buffer_numformat(desc, vk_format_get_first_non_void_channel(format)); return data_format != V_008F0C_BUF_DATA_FORMAT_INVALID && num_format != ~0; }
bool radv_is_colorbuffer_format_supported(VkFormat format, bool *blendable) { const struct vk_format_description *desc = vk_format_description(format); uint32_t color_format = radv_translate_colorformat(format); uint32_t color_swap = radv_translate_colorswap(format, false); uint32_t color_num_format = radv_translate_color_numformat(format, desc, vk_format_get_first_non_void_channel(format)); if (color_num_format == V_028C70_NUMBER_UINT || color_num_format == V_028C70_NUMBER_SINT || color_format == V_028C70_COLOR_8_24 || color_format == V_028C70_COLOR_24_8 || color_format == V_028C70_COLOR_X24_8_32_FLOAT) { *blendable = false; } else *blendable = true; return color_format != V_028C70_COLOR_INVALID && color_swap != ~0U && color_num_format != ~0; }
static uint32_t tu6_sp_2d_src_format(VkFormat format) { const struct vk_format_description *desc = vk_format_description(format); uint32_t reg = 0xf000 | A6XX_SP_2D_SRC_FORMAT_COLOR_FORMAT(tu6_get_native_format(format)->rb); int channel = vk_format_get_first_non_void_channel(format); if (channel < 0) { /* TODO special format. */ return reg; } if (desc->channel[channel].normalized) { if (desc->channel[channel].type == VK_FORMAT_TYPE_SIGNED) reg |= A6XX_SP_2D_SRC_FORMAT_SINT; reg |= A6XX_SP_2D_SRC_FORMAT_NORM; } else if (desc->channel[channel].pure_integer) { if (desc->channel[channel].type == VK_FORMAT_TYPE_SIGNED) reg |= A6XX_SP_2D_SRC_FORMAT_SINT; else reg |= A6XX_SP_2D_SRC_FORMAT_UINT; } return reg; }
static int radv_init_surface(struct radv_device *device, struct radeon_surf *surface, const struct radv_image_create_info *create_info) { const VkImageCreateInfo *pCreateInfo = create_info->vk_info; unsigned array_mode = radv_choose_tiling(device, create_info); const struct vk_format_description *desc = vk_format_description(pCreateInfo->format); bool is_depth, is_stencil; is_depth = vk_format_has_depth(desc); is_stencil = vk_format_has_stencil(desc); surface->blk_w = vk_format_get_blockwidth(pCreateInfo->format); surface->blk_h = vk_format_get_blockheight(pCreateInfo->format); surface->bpe = vk_format_get_blocksize(vk_format_depth_only(pCreateInfo->format)); /* align byte per element on dword */ if (surface->bpe == 3) { surface->bpe = 4; } surface->flags = RADEON_SURF_SET(array_mode, MODE); switch (pCreateInfo->imageType){ case VK_IMAGE_TYPE_1D: if (pCreateInfo->arrayLayers > 1) surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D_ARRAY, TYPE); else surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D, TYPE); break; case VK_IMAGE_TYPE_2D: if (pCreateInfo->arrayLayers > 1) surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D_ARRAY, TYPE); else surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); break; case VK_IMAGE_TYPE_3D: surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_3D, TYPE); break; default: unreachable("unhandled image type"); } if (is_depth) { surface->flags |= RADEON_SURF_ZBUFFER; if (radv_use_tc_compat_htile_for_image(device, pCreateInfo)) surface->flags |= RADEON_SURF_TC_COMPATIBLE_HTILE; } if (is_stencil) surface->flags |= RADEON_SURF_SBUFFER; surface->flags |= RADEON_SURF_OPTIMIZE_FOR_SPACE; if (!radv_use_dcc_for_image(device, create_info, pCreateInfo)) surface->flags |= RADEON_SURF_DISABLE_DCC; if (create_info->scanout) surface->flags |= RADEON_SURF_SCANOUT; return 0; }
static int radv_init_surface(struct radv_device *device, struct radeon_surf *surface, const struct radv_image_create_info *create_info) { const VkImageCreateInfo *pCreateInfo = create_info->vk_info; unsigned array_mode = radv_choose_tiling(device, create_info); const struct vk_format_description *desc = vk_format_description(pCreateInfo->format); bool is_depth, is_stencil, blendable; is_depth = vk_format_has_depth(desc); is_stencil = vk_format_has_stencil(desc); surface->npix_x = pCreateInfo->extent.width; surface->npix_y = pCreateInfo->extent.height; surface->npix_z = pCreateInfo->extent.depth; surface->blk_w = vk_format_get_blockwidth(pCreateInfo->format); surface->blk_h = vk_format_get_blockheight(pCreateInfo->format); surface->blk_d = 1; surface->array_size = pCreateInfo->arrayLayers; surface->last_level = pCreateInfo->mipLevels - 1; surface->bpe = vk_format_get_blocksize(pCreateInfo->format); /* align byte per element on dword */ if (surface->bpe == 3) { surface->bpe = 4; } surface->nsamples = pCreateInfo->samples ? pCreateInfo->samples : 1; surface->flags = RADEON_SURF_SET(array_mode, MODE); switch (pCreateInfo->imageType){ case VK_IMAGE_TYPE_1D: if (pCreateInfo->arrayLayers > 1) surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D_ARRAY, TYPE); else surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D, TYPE); break; case VK_IMAGE_TYPE_2D: if (pCreateInfo->arrayLayers > 1) surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D_ARRAY, TYPE); else surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); break; case VK_IMAGE_TYPE_3D: surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_3D, TYPE); break; default: unreachable("unhandled image type"); } if (is_depth) { surface->flags |= RADEON_SURF_ZBUFFER; } if (is_stencil) surface->flags |= RADEON_SURF_SBUFFER | RADEON_SURF_HAS_SBUFFER_MIPTREE; surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; if ((pCreateInfo->usage & (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT)) || (pCreateInfo->flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) || (pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR) || device->instance->physicalDevice.rad_info.chip_class < VI || create_info->scanout || !device->allow_dcc || !radv_is_colorbuffer_format_supported(pCreateInfo->format, &blendable)) surface->flags |= RADEON_SURF_DISABLE_DCC; if (create_info->scanout) surface->flags |= RADEON_SURF_SCANOUT; return 0; }
static VkExtent3D meta_image_block_size(const struct radv_image *image) { const struct vk_format_description *desc = vk_format_description(image->vk_format); return (VkExtent3D) { desc->block.width, desc->block.height, 1 }; }
bool radv_format_pack_clear_color(VkFormat format, uint32_t clear_vals[2], VkClearColorValue *value) { uint8_t r = 0, g = 0, b = 0, a = 0; const struct vk_format_description *desc = vk_format_description(format); if (vk_format_get_component_bits(format, VK_FORMAT_COLORSPACE_RGB, 0) <= 8) { if (desc->colorspace == VK_FORMAT_COLORSPACE_RGB) { r = float_to_ubyte(value->float32[0]); g = float_to_ubyte(value->float32[1]); b = float_to_ubyte(value->float32[2]); a = float_to_ubyte(value->float32[3]); } else if (desc->colorspace == VK_FORMAT_COLORSPACE_SRGB) { r = util_format_linear_float_to_srgb_8unorm(value->float32[0]); g = util_format_linear_float_to_srgb_8unorm(value->float32[1]); b = util_format_linear_float_to_srgb_8unorm(value->float32[2]); a = float_to_ubyte(value->float32[3]); } } switch (format) { case VK_FORMAT_R8_UNORM: case VK_FORMAT_R8_SRGB: clear_vals[0] = r; clear_vals[1] = 0; break; case VK_FORMAT_R8G8_UNORM: case VK_FORMAT_R8G8_SRGB: clear_vals[0] = r | g << 8; clear_vals[1] = 0; break; case VK_FORMAT_R8G8B8A8_SRGB: case VK_FORMAT_R8G8B8A8_UNORM: clear_vals[0] = r | g << 8 | b << 16 | a << 24; clear_vals[1] = 0; break; case VK_FORMAT_B8G8R8A8_SRGB: case VK_FORMAT_B8G8R8A8_UNORM: clear_vals[0] = b | g << 8 | r << 16 | a << 24; clear_vals[1] = 0; break; case VK_FORMAT_A8B8G8R8_UNORM_PACK32: case VK_FORMAT_A8B8G8R8_SRGB_PACK32: clear_vals[0] = r | g << 8 | b << 16 | a << 24; clear_vals[1] = 0; break; case VK_FORMAT_R8_UINT: clear_vals[0] = value->uint32[0] & 0xff; clear_vals[1] = 0; break; case VK_FORMAT_R16_UINT: clear_vals[0] = value->uint32[0] & 0xffff; clear_vals[1] = 0; break; case VK_FORMAT_R8G8_UINT: clear_vals[0] = value->uint32[0] & 0xff; clear_vals[0] |= (value->uint32[1] & 0xff) << 8; clear_vals[1] = 0; break; case VK_FORMAT_R8G8B8A8_UINT: clear_vals[0] = value->uint32[0] & 0xff; clear_vals[0] |= (value->uint32[1] & 0xff) << 8; clear_vals[0] |= (value->uint32[2] & 0xff) << 16; clear_vals[0] |= (value->uint32[3] & 0xff) << 24; clear_vals[1] = 0; break; case VK_FORMAT_A8B8G8R8_UINT_PACK32: clear_vals[0] = value->uint32[0] & 0xff; clear_vals[0] |= (value->uint32[1] & 0xff) << 8; clear_vals[0] |= (value->uint32[2] & 0xff) << 16; clear_vals[0] |= (value->uint32[3] & 0xff) << 24; clear_vals[1] = 0; break; case VK_FORMAT_R16G16_UINT: clear_vals[0] = value->uint32[0] & 0xffff; clear_vals[0] |= (value->uint32[1] & 0xffff) << 16; clear_vals[1] = 0; break; case VK_FORMAT_R16G16B16A16_UINT: clear_vals[0] = value->uint32[0] & 0xffff; clear_vals[0] |= (value->uint32[1] & 0xffff) << 16; clear_vals[1] = value->uint32[2] & 0xffff; clear_vals[1] |= (value->uint32[3] & 0xffff) << 16; break; case VK_FORMAT_R32_UINT: clear_vals[0] = value->uint32[0]; clear_vals[1] = 0; break; case VK_FORMAT_R32G32_UINT: clear_vals[0] = value->uint32[0]; clear_vals[1] = value->uint32[1]; break; case VK_FORMAT_R32_SINT: clear_vals[0] = value->int32[0]; clear_vals[1] = 0; break; case VK_FORMAT_R16_SFLOAT: clear_vals[0] = util_float_to_half(value->float32[0]); clear_vals[1] = 0; break; case VK_FORMAT_R16G16_SFLOAT: clear_vals[0] = util_float_to_half(value->float32[0]); clear_vals[0] |= (uint32_t)util_float_to_half(value->float32[1]) << 16; clear_vals[1] = 0; break; case VK_FORMAT_R16G16B16A16_SFLOAT: clear_vals[0] = util_float_to_half(value->float32[0]); clear_vals[0] |= (uint32_t)util_float_to_half(value->float32[1]) << 16; clear_vals[1] = util_float_to_half(value->float32[2]); clear_vals[1] |= (uint32_t)util_float_to_half(value->float32[3]) << 16; break; case VK_FORMAT_R16_UNORM: clear_vals[0] = ((uint16_t)util_iround(CLAMP(value->float32[0], 0.0f, 1.0f) * 0xffff)) & 0xffff; clear_vals[1] = 0; break; case VK_FORMAT_R16G16_UNORM: clear_vals[0] = ((uint16_t)util_iround(CLAMP(value->float32[0], 0.0f, 1.0f) * 0xffff)) & 0xffff; clear_vals[0] |= ((uint16_t)util_iround(CLAMP(value->float32[1], 0.0f, 1.0f) * 0xffff)) << 16; clear_vals[1] = 0; break; case VK_FORMAT_R16G16B16A16_UNORM: clear_vals[0] = ((uint16_t)util_iround(CLAMP(value->float32[0], 0.0f, 1.0f) * 0xffff)) & 0xffff; clear_vals[0] |= ((uint16_t)util_iround(CLAMP(value->float32[1], 0.0f, 1.0f) * 0xffff)) << 16; clear_vals[1] = ((uint16_t)util_iround(CLAMP(value->float32[2], 0.0f, 1.0f) * 0xffff)) & 0xffff; clear_vals[1] |= ((uint16_t)util_iround(CLAMP(value->float32[3], 0.0f, 1.0f) * 0xffff)) << 16; break; case VK_FORMAT_A2B10G10R10_UNORM_PACK32: /* TODO */ return false; case VK_FORMAT_R32G32_SFLOAT: clear_vals[0] = fui(value->float32[0]); clear_vals[1] = fui(value->float32[1]); break; case VK_FORMAT_R32_SFLOAT: clear_vals[1] = 0; clear_vals[0] = fui(value->float32[0]); break; default: fprintf(stderr, "failed to fast clear %d\n", format); return false; } return true; }
uint32_t radv_translate_colorformat(VkFormat format) { const struct vk_format_description *desc = vk_format_description(format); #define HAS_SIZE(x,y,z,w) \ (desc->channel[0].size == (x) && desc->channel[1].size == (y) && \ desc->channel[2].size == (z) && desc->channel[3].size == (w)) if (format == VK_FORMAT_B10G11R11_UFLOAT_PACK32) /* isn't plain */ return V_028C70_COLOR_10_11_11; if (desc->layout != VK_FORMAT_LAYOUT_PLAIN) return V_028C70_COLOR_INVALID; /* hw cannot support mixed formats (except depth/stencil, since * stencil is not written to). */ if (desc->is_mixed && desc->colorspace != VK_FORMAT_COLORSPACE_ZS) return V_028C70_COLOR_INVALID; switch (desc->nr_channels) { case 1: switch (desc->channel[0].size) { case 8: return V_028C70_COLOR_8; case 16: return V_028C70_COLOR_16; case 32: return V_028C70_COLOR_32; } break; case 2: if (desc->channel[0].size == desc->channel[1].size) { switch (desc->channel[0].size) { case 8: return V_028C70_COLOR_8_8; case 16: return V_028C70_COLOR_16_16; case 32: return V_028C70_COLOR_32_32; } } else if (HAS_SIZE(8,24,0,0)) { return V_028C70_COLOR_24_8; } else if (HAS_SIZE(24,8,0,0)) { return V_028C70_COLOR_8_24; } break; case 3: if (HAS_SIZE(5,6,5,0)) { return V_028C70_COLOR_5_6_5; } else if (HAS_SIZE(32,8,24,0)) { return V_028C70_COLOR_X24_8_32_FLOAT; } break; case 4: if (desc->channel[0].size == desc->channel[1].size && desc->channel[0].size == desc->channel[2].size && desc->channel[0].size == desc->channel[3].size) { switch (desc->channel[0].size) { case 4: return V_028C70_COLOR_4_4_4_4; case 8: return V_028C70_COLOR_8_8_8_8; case 16: return V_028C70_COLOR_16_16_16_16; case 32: return V_028C70_COLOR_32_32_32_32; } } else if (HAS_SIZE(5,5,5,1)) { return V_028C70_COLOR_1_5_5_5; } else if (HAS_SIZE(1,5,5,5)) { return V_028C70_COLOR_5_5_5_1; } else if (HAS_SIZE(10,10,10,2)) { return V_028C70_COLOR_2_10_10_10; } break; } return V_028C70_COLOR_INVALID; }
static void radv_physical_device_get_format_properties(struct radv_physical_device *physical_device, VkFormat format, VkFormatProperties *out_properties) { VkFormatFeatureFlags linear = 0, tiled = 0, buffer = 0; const struct vk_format_description *desc = vk_format_description(format); bool blendable; if (!desc) { out_properties->linearTilingFeatures = linear; out_properties->optimalTilingFeatures = tiled; out_properties->bufferFeatures = buffer; return; } if (radv_is_storage_image_format_supported(physical_device, format)) { tiled |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; linear |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; } if (radv_is_buffer_format_supported(format)) { buffer |= VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT | VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT; } if (vk_format_is_depth_or_stencil(format)) { if (radv_is_zs_format_supported(format)) tiled |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; tiled |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; tiled |= VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; } else { bool linear_sampling; if (radv_is_sampler_format_supported(format, &linear_sampling)) { linear |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT; tiled |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT; if (linear_sampling) { linear |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; tiled |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; } } if (radv_is_colorbuffer_format_supported(format, &blendable)) { linear |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; tiled |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; if (blendable) { linear |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; tiled |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; } } } if (format == VK_FORMAT_R32_UINT || format == VK_FORMAT_R32_SINT) { buffer |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT; linear |= VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT; tiled |= VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT; } out_properties->linearTilingFeatures = linear; out_properties->optimalTilingFeatures = tiled; out_properties->bufferFeatures = buffer; }