This PR adds support for `GPU_framebuffer_blit` When used with `GPU_DEPTH_BIT`. The challenge with is that not all GPUs support using a depth texture as a blit destination. An AMD GPU doesn't support a depth buffer with stencil buffer as blit destination.  > NOTE: AMD GPUs don't support 24 bit unsigned normalized depth textures at all. In all cases when we use depth blitting we are blitting the whole texture and in stead we can use a texture copy. A negative effect is that we need to unbind the framebuffer when copying depth textures, but a positive effect is that we can use a data transfer function what should theoretically be faster. This should be revisited when we are investigating in areas to improve the performance of the Vulkan backend. Pull Request: https://projects.blender.org/blender/blender/pulls/112674
193 lines
6.0 KiB
C++
193 lines
6.0 KiB
C++
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup gpu
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "gpu_texture_private.hh"
|
|
|
|
#include "vk_bindable_resource.hh"
|
|
#include "vk_context.hh"
|
|
#include "vk_image_view.hh"
|
|
|
|
namespace blender::gpu {
|
|
|
|
class VKSampler;
|
|
|
|
class VKTexture : public Texture, public VKBindableResource {
|
|
/** When set the instance is considered to be a texture view from `source_texture_` */
|
|
VKTexture *source_texture_ = nullptr;
|
|
VkImage vk_image_ = VK_NULL_HANDLE;
|
|
VmaAllocation allocation_ = VK_NULL_HANDLE;
|
|
|
|
/* Image view when used in a shader. */
|
|
std::optional<VKImageView> image_view_;
|
|
|
|
/* Last image layout of the texture. Frame-buffer and barriers can alter/require the actual
|
|
* layout to be changed. During this it requires to set the current layout in order to know which
|
|
* conversion should happen. #current_layout_ keep track of the layout so the correct conversion
|
|
* can be done. */
|
|
VkImageLayout current_layout_ = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
int layer_offset_ = 0;
|
|
bool use_stencil_ = false;
|
|
|
|
VkComponentMapping vk_component_mapping_ = {VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
VK_COMPONENT_SWIZZLE_IDENTITY};
|
|
|
|
enum eDirtyFlags {
|
|
IMAGE_VIEW_DIRTY = (1 << 0),
|
|
};
|
|
|
|
int flags_ = IMAGE_VIEW_DIRTY;
|
|
|
|
public:
|
|
VKTexture(const char *name) : Texture(name) {}
|
|
|
|
virtual ~VKTexture() override;
|
|
|
|
void init(VkImage vk_image, VkImageLayout layout, eGPUTextureFormat texture_format);
|
|
|
|
void generate_mipmap() override;
|
|
void copy_to(Texture *tex) override;
|
|
void copy_to(VKTexture &dst_texture, VkImageAspectFlagBits vk_image_aspect);
|
|
void clear(eGPUDataFormat format, const void *data) override;
|
|
void clear_depth_stencil(const eGPUFrameBufferBits buffer,
|
|
float clear_depth,
|
|
uint clear_stencil);
|
|
void swizzle_set(const char swizzle_mask[4]) override;
|
|
void mip_range_set(int min, int max) override;
|
|
void *read(int mip, eGPUDataFormat format) override;
|
|
void read_sub(int mip, eGPUDataFormat format, const int area[4], void *r_data);
|
|
void update_sub(
|
|
int mip, int offset[3], int extent[3], eGPUDataFormat format, const void *data) override;
|
|
void update_sub(int offset[3],
|
|
int extent[3],
|
|
eGPUDataFormat format,
|
|
GPUPixelBuffer *pixbuf) override;
|
|
|
|
/* TODO(fclem): Legacy. Should be removed at some point. */
|
|
uint gl_bindcode_get() const override;
|
|
|
|
void bind(int location, shader::ShaderCreateInfo::Resource::BindType bind_type) override;
|
|
|
|
VkImage vk_image_handle() const
|
|
{
|
|
if (is_texture_view()) {
|
|
return source_texture_->vk_image_handle();
|
|
}
|
|
BLI_assert(vk_image_ != VK_NULL_HANDLE);
|
|
return vk_image_;
|
|
}
|
|
|
|
protected:
|
|
bool init_internal() override;
|
|
bool init_internal(GPUVertBuf *vbo) override;
|
|
bool init_internal(GPUTexture *src, int mip_offset, int layer_offset, bool use_stencil) override;
|
|
|
|
private:
|
|
/** Is this texture a view of another texture. */
|
|
bool is_texture_view() const;
|
|
|
|
/**
|
|
* Allocate the texture of the device. Result is `true` when texture is successfully allocated
|
|
* on the device.
|
|
*/
|
|
bool allocate();
|
|
|
|
VkImageViewType vk_image_view_type() const;
|
|
|
|
/**
|
|
* Determine the layerCount for vulkan based on the texture type. Will pass the
|
|
* #non_layered_value for non layered textures.
|
|
*/
|
|
int vk_layer_count(int non_layered_value) const;
|
|
|
|
/**
|
|
* Determine the VkExtent3D for the given mip_level.
|
|
*/
|
|
VkExtent3D vk_extent_3d(int mip_level) const;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Image Layout
|
|
* \{ */
|
|
public:
|
|
/**
|
|
* Update the current layout attribute, without actually changing the layout.
|
|
*
|
|
* Vulkan can change the layout of an image, when a command is being executed.
|
|
* The start of a render pass or the end of a render pass can also alter the
|
|
* actual layout of the image. This method allows to change the last known layout
|
|
* that the image is using.
|
|
*
|
|
* NOTE: When we add command encoding, this should partly being done inside
|
|
* the command encoder, as there is more accurate determination of the transition
|
|
* of the layout. Only the final transition should then be stored inside the texture
|
|
* to be used by as initial layout for the next set of commands.
|
|
*/
|
|
void current_layout_set(VkImageLayout new_layout);
|
|
VkImageLayout current_layout_get() const;
|
|
|
|
/**
|
|
* Ensure the layout of the texture. This also performs the conversion by adding a memory
|
|
* barrier to the active command buffer to perform the conversion.
|
|
*
|
|
* When texture is already in the requested layout, nothing will be done.
|
|
*/
|
|
void layout_ensure(VKContext &context, VkImageLayout requested_layout);
|
|
|
|
private:
|
|
/**
|
|
* Internal function to ensure the layout of a single mipmap level. Note that the caller is
|
|
* responsible to update the current_layout of the image at the end of the operation and make
|
|
* sure that all mipmap levels are in that given layout.
|
|
*/
|
|
void layout_ensure(VKContext &context,
|
|
IndexRange mipmap_range,
|
|
VkImageLayout current_layout,
|
|
VkImageLayout requested_layout);
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Image Views
|
|
* \{ */
|
|
public:
|
|
VKImageView &image_view_get()
|
|
{
|
|
image_view_ensure();
|
|
return *image_view_;
|
|
}
|
|
|
|
const VkComponentMapping &vk_component_mapping_get() const
|
|
{
|
|
return vk_component_mapping_;
|
|
}
|
|
|
|
private:
|
|
IndexRange mip_map_range() const;
|
|
IndexRange layer_range() const;
|
|
void image_view_ensure();
|
|
void image_view_update();
|
|
|
|
/** \} */
|
|
};
|
|
|
|
BLI_INLINE VKTexture *unwrap(Texture *tex)
|
|
{
|
|
return static_cast<VKTexture *>(tex);
|
|
}
|
|
|
|
BLI_INLINE Texture *wrap(VKTexture *texture)
|
|
{
|
|
return static_cast<Texture *>(texture);
|
|
}
|
|
|
|
} // namespace blender::gpu
|