Vulkan: Reusing Textures from Pool

This PR solves an issue when using texture pools with textures that are not
natively supported by the device. In the previous implementation the
internal `Texture::format_` was changed. Any check if the texture could
be reused would fail as its format would be different that the requested one.

This PR fixes this by separating the requested format `Texture::format_` and
how it is stored on the GPU `VKTexture::device_format_`.

This solves the next artifacts:
* Workbench flickering artifacts on AMD/Intel GPUs
* Workbench TAA on AMD/Intel GPUs
* Overlays were not always drawn fully solid

Pull Request: https://projects.blender.org/blender/blender/pulls/114697
This commit is contained in:
Jeroen Bakker 2023-11-10 12:52:34 +01:00
parent 0c9433bf44
commit cc04bcd792
4 changed files with 43 additions and 22 deletions

@ -296,7 +296,7 @@ static void blit_aspect(VKCommandBuffers &command_buffer,
/* Prefer texture copy, as some platforms don't support using D32_SFLOAT_S8_UINT to be used as
* a blit destination. */
if (dst_offset_x == 0 && dst_offset_y == 0 &&
dst_texture.format_get() == src_texture.format_get() &&
dst_texture.device_format_get() == src_texture.device_format_get() &&
src_texture.width_get() == dst_texture.width_get() &&
src_texture.height_get() == dst_texture.height_get())
{

@ -40,10 +40,10 @@ VKImageView::VKImageView(VKTexture &texture,
const VkImageAspectFlags allowed_bits = VK_IMAGE_ASPECT_COLOR_BIT |
(use_stencil ? VK_IMAGE_ASPECT_STENCIL_BIT :
VK_IMAGE_ASPECT_DEPTH_BIT);
VkImageAspectFlags image_aspect = to_vk_image_aspect_flag_bits(texture.format_get()) &
allowed_bits;
eGPUTextureFormat device_format = texture.device_format_get();
VkImageAspectFlags image_aspect = to_vk_image_aspect_flag_bits(device_format) & allowed_bits;
vk_format_ = to_vk_format(texture.format_get());
vk_format_ = to_vk_format(device_format);
if (texture.format_flag_get() & GPU_FORMAT_SRGB && !use_srgb) {
vk_format_ = to_non_srgb_format(vk_format_);
}

@ -39,6 +39,7 @@ void VKTexture::init(VkImage vk_image, VkImageLayout layout, eGPUTextureFormat t
vk_image_ = vk_image;
current_layout_ = layout;
format_ = texture_format;
device_format_ = texture_format;
}
void VKTexture::generate_mipmap()
@ -91,14 +92,14 @@ void VKTexture::generate_mipmap()
VkImageBlit image_blit = {};
image_blit.srcOffsets[0] = {0, 0, 0};
image_blit.srcOffsets[1] = {src_size.x, src_size.y, src_size.z};
image_blit.srcSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_);
image_blit.srcSubresource.aspectMask = to_vk_image_aspect_flag_bits(device_format_);
image_blit.srcSubresource.mipLevel = src_mipmap;
image_blit.srcSubresource.baseArrayLayer = 0;
image_blit.srcSubresource.layerCount = vk_layer_count(1);
image_blit.dstOffsets[0] = {0, 0, 0};
image_blit.dstOffsets[1] = {dst_size.x, dst_size.y, dst_size.z};
image_blit.dstSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_);
image_blit.dstSubresource.aspectMask = to_vk_image_aspect_flag_bits(device_format_);
image_blit.dstSubresource.mipLevel = dst_mipmap;
image_blit.dstSubresource.baseArrayLayer = 0;
image_blit.dstSubresource.layerCount = vk_layer_count(1);
@ -148,11 +149,11 @@ void VKTexture::copy_to(Texture *tex)
VKTexture *src = this;
BLI_assert(dst);
BLI_assert(src->w_ == dst->w_ && src->h_ == dst->h_ && src->d_ == dst->d_);
BLI_assert(src->format_ == dst->format_);
BLI_assert(src->device_format_ == dst->device_format_);
BLI_assert(!is_texture_view());
UNUSED_VARS_NDEBUG(src);
copy_to(*dst, to_vk_image_aspect_flag_bits(format_));
copy_to(*dst, to_vk_image_aspect_flag_bits(device_format_));
}
void VKTexture::clear(eGPUDataFormat format, const void *data)
@ -163,7 +164,7 @@ void VKTexture::clear(eGPUDataFormat format, const void *data)
VKCommandBuffers &command_buffers = context.command_buffers_get();
VkClearColorValue clear_color = to_vk_clear_color_value(format, data);
VkImageSubresourceRange range = {0};
range.aspectMask = to_vk_image_aspect_flag_bits(format_);
range.aspectMask = to_vk_image_aspect_flag_bits(device_format_);
range.levelCount = VK_REMAINING_MIP_LEVELS;
range.layerCount = VK_REMAINING_ARRAY_LAYERS;
layout_ensure(context, VK_IMAGE_LAYOUT_GENERAL);
@ -223,7 +224,7 @@ void VKTexture::read_sub(
VKBuffer staging_buffer;
size_t sample_len = (region[2] - region[0]) * (region[3] - region[1]) * layers.size();
size_t device_memory_size = sample_len * to_bytesize(format_);
size_t device_memory_size = sample_len * to_bytesize(device_format_);
staging_buffer.create(device_memory_size, GPU_USAGE_DYNAMIC, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
@ -233,7 +234,7 @@ void VKTexture::read_sub(
buffer_image_copy.imageExtent.width = region[2];
buffer_image_copy.imageExtent.height = region[3];
buffer_image_copy.imageExtent.depth = 1;
buffer_image_copy.imageSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_);
buffer_image_copy.imageSubresource.aspectMask = to_vk_image_aspect_flag_bits(device_format_);
buffer_image_copy.imageSubresource.mipLevel = mip;
buffer_image_copy.imageSubresource.baseArrayLayer = layers.start();
buffer_image_copy.imageSubresource.layerCount = layers.size();
@ -242,7 +243,8 @@ void VKTexture::read_sub(
command_buffers.copy(staging_buffer, *this, Span<VkBufferImageCopy>(&buffer_image_copy, 1));
context.flush();
convert_device_to_host(r_data, staging_buffer.mapped_memory_get(), sample_len, format, format_);
convert_device_to_host(
r_data, staging_buffer.mapped_memory_get(), sample_len, format, device_format_);
}
void *VKTexture::read(int mip, eGPUDataFormat format)
@ -269,7 +271,7 @@ void VKTexture::update_sub(
int layers = vk_layer_count(1);
int3 extent = int3(extent_[0], max_ii(extent_[1], 1), max_ii(extent_[2], 1));
size_t sample_len = extent.x * extent.y * extent.z;
size_t device_memory_size = sample_len * to_bytesize(format_);
size_t device_memory_size = sample_len * to_bytesize(device_format_);
if (type_ & GPU_TEXTURE_1D) {
extent.y = 1;
@ -281,7 +283,8 @@ void VKTexture::update_sub(
VKBuffer staging_buffer;
staging_buffer.create(device_memory_size, GPU_USAGE_DYNAMIC, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
convert_host_to_device(staging_buffer.mapped_memory_get(), data, sample_len, format, format_);
convert_host_to_device(
staging_buffer.mapped_memory_get(), data, sample_len, format, device_format_);
VkBufferImageCopy region = {};
region.imageExtent.width = extent.x;
@ -291,7 +294,7 @@ void VKTexture::update_sub(
region.imageOffset.x = offset[0];
region.imageOffset.y = offset[1];
region.imageOffset.z = offset[2];
region.imageSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_);
region.imageSubresource.aspectMask = to_vk_image_aspect_flag_bits(device_format_);
region.imageSubresource.mipLevel = mip;
region.imageSubresource.layerCount = layers;
@ -320,11 +323,12 @@ bool VKTexture::init_internal()
{
const VKDevice &device = VKBackend::get().device_get();
const VKWorkarounds &workarounds = device.workarounds_get();
if (format_ == GPU_DEPTH_COMPONENT24 && workarounds.not_aligned_pixel_formats) {
format_ = GPU_DEPTH_COMPONENT32F;
device_format_ = format_;
if (device_format_ == GPU_DEPTH_COMPONENT24 && workarounds.not_aligned_pixel_formats) {
device_format_ = GPU_DEPTH_COMPONENT32F;
}
if (format_ == GPU_DEPTH24_STENCIL8 && workarounds.not_aligned_pixel_formats) {
format_ = GPU_DEPTH32F_STENCIL8;
if (device_format_ == GPU_DEPTH24_STENCIL8 && workarounds.not_aligned_pixel_formats) {
device_format_ = GPU_DEPTH32F_STENCIL8;
}
if (!allocate()) {
@ -346,7 +350,7 @@ bool VKTexture::init_internal(GPUVertBuf *vbo)
region.imageExtent.width = w_;
region.imageExtent.height = 1;
region.imageExtent.depth = 1;
region.imageSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_);
region.imageSubresource.aspectMask = to_vk_image_aspect_flag_bits(device_format_);
region.imageSubresource.mipLevel = 0;
region.imageSubresource.layerCount = 1;
@ -366,6 +370,7 @@ bool VKTexture::init_internal(GPUTexture *src, int mip_offset, int layer_offset,
VKTexture *texture = unwrap(unwrap(src));
source_texture_ = texture;
device_format_ = texture->device_format_;
mip_min_ = mip_offset;
mip_max_ = mip_offset;
layer_offset_ = layer_offset;
@ -454,7 +459,7 @@ bool VKTexture::allocate()
image_info.extent = vk_extent_3d(0);
image_info.mipLevels = max_ii(mipmaps_, 1);
image_info.arrayLayers = vk_layer_count(1);
image_info.format = to_vk_format(format_);
image_info.format = to_vk_format(device_format_);
/* Some platforms (NVIDIA) requires that attached textures are always tiled optimal.
*
* As image data are always accessed via an staging buffer we can enable optimal tiling for all
@ -581,7 +586,7 @@ void VKTexture::layout_ensure(VKContext &context,
barrier.srcAccessMask = src_access;
barrier.dstAccessMask = dst_access;
barrier.image = vk_image_;
barrier.subresourceRange.aspectMask = to_vk_image_aspect_flag_bits(format_);
barrier.subresourceRange.aspectMask = to_vk_image_aspect_flag_bits(device_format_);
barrier.subresourceRange.baseMipLevel = uint32_t(mipmap_range.start());
barrier.subresourceRange.levelCount = uint32_t(mipmap_range.size());
barrier.subresourceRange.baseArrayLayer = 0;

@ -19,6 +19,14 @@ namespace blender::gpu {
class VKSampler;
class VKTexture : public Texture, public VKBindableResource {
/**
* Texture format how the texture is stored on the device.
*
* This can be a different format then #Texture.format_ in case the texture format isn't natively
* supported by the device.
*/
eGPUTextureFormat device_format_ = (eGPUTextureFormat)-1;
/** When set the instance is considered to be a texture view from `source_texture_` */
VKTexture *source_texture_ = nullptr;
VkImage vk_image_ = VK_NULL_HANDLE;
@ -87,6 +95,14 @@ class VKTexture : public Texture, public VKBindableResource {
return vk_image_;
}
/**
* Get the texture format how the texture is stored on the device.
*/
eGPUTextureFormat device_format_get() const
{
return device_format_;
}
protected:
bool init_internal() override;
bool init_internal(GPUVertBuf *vbo) override;