Cycles uses pixel buffers to update the display. Due to making things work the vulkan backend downloaded the GPU allocated pixel buffer to the CPU, Copied it to a GPU allocated staging buffer and update the display texture using the staging buffer. Needless to say that a (CPU->)GPU->CPU->GPU roundtrip is a bottleneck. This PR fixes this by allowing the pixel buffer to act as a staging buffer as well. Viewport and final image rendering performance is now also similar. | **Render** | **GPU Backend** | **Path tracing** | **Display** | | ---------- | --------------- | ---------------- | ----------- | | Viewport | OpenGL | 2.7 | 0.06 | | Viewport | Vulkan | 2.7 | 0.04 | | Image | OpenGL | 3.9 | 0.02 | | Image | Vulkan | 3.9 | 0.02 | Tested on: ``` Operating system: Linux-6.8.0-49-generic-x86_64-with-glibc2.39 64 Bits, X11 UI Graphics card: AMD Radeon Pro W7700 (RADV NAVI32) Advanced Micro Devices radv Mesa 24.3.1 - kisak-mesa PPA Vulkan Backend ``` Pull Request: https://projects.blender.org/blender/blender/pulls/133485
191 lines
5.8 KiB
C++
191 lines
5.8 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_context.hh"
|
|
#include "vk_image_view.hh"
|
|
|
|
namespace blender::gpu {
|
|
|
|
class VKSampler;
|
|
class VKDescriptorSetTracker;
|
|
class VKVertexBuffer;
|
|
class VKPixelBuffer;
|
|
|
|
/** Additional modifiers when requesting image views. */
|
|
enum class VKImageViewFlags {
|
|
DEFAULT = 0,
|
|
NO_SWIZZLING = 1 << 0,
|
|
};
|
|
ENUM_OPERATORS(VKImageViewFlags, VKImageViewFlags::NO_SWIZZLING)
|
|
|
|
class VKTexture : public Texture {
|
|
friend class VKDescriptorSetTracker;
|
|
|
|
/**
|
|
* 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;
|
|
|
|
/**
|
|
* Store of source vertex buffer. Related to `GPU_texture_create_from_vertbuf`.
|
|
*
|
|
* In vulkan a texel buffer is a buffer and not a texture. Calls will be forwarded to the vertex
|
|
* buffer in this case. GPU_texture_create_from_vertbuf should be phased out (currently only used
|
|
* by particle hair).
|
|
*/
|
|
VKVertexBuffer *source_buffer_ = nullptr;
|
|
VkImage vk_image_ = VK_NULL_HANDLE;
|
|
VmaAllocation allocation_ = VK_NULL_HANDLE;
|
|
|
|
/**
|
|
* Image views are owned by VKTexture. When a specific image view is needed it will be created
|
|
* and stored here. Image view can be requested by calling `image_view_get` method.
|
|
*/
|
|
Vector<VKImageView> image_views_;
|
|
|
|
/* 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;
|
|
|
|
char swizzle_[4] = {'r', 'g', 'b', 'a'};
|
|
VKImageViewInfo image_view_info_ = {eImageViewUsage::ShaderBinding,
|
|
IndexRange(0, VK_REMAINING_ARRAY_LAYERS),
|
|
IndexRange(0, VK_REMAINING_MIP_LEVELS),
|
|
{{'r', 'g', 'b', 'a'}},
|
|
false,
|
|
false,
|
|
VKImageViewArrayed::DONT_CARE};
|
|
|
|
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, VkImageAspectFlags 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 region[6], IndexRange layers, void *r_data);
|
|
void update_sub(int mip,
|
|
int offset[3],
|
|
int extent[3],
|
|
eGPUDataFormat format,
|
|
const void *data,
|
|
VKPixelBuffer *pixel_buffer);
|
|
|
|
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;
|
|
|
|
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_;
|
|
}
|
|
|
|
/**
|
|
* Get the texture format how the texture is stored on the device.
|
|
*/
|
|
eGPUTextureFormat device_format_get() const
|
|
{
|
|
return device_format_;
|
|
}
|
|
|
|
/**
|
|
* Get a specific image view for this texture. The specification of the image view are passed
|
|
* inside the `info` parameter.
|
|
*/
|
|
const VKImageView &image_view_get(const VKImageViewInfo &info);
|
|
|
|
/**
|
|
* Get the current image view for this texture.
|
|
*/
|
|
const VKImageView &image_view_get(VKImageViewArrayed arrayed, VKImageViewFlags flags);
|
|
|
|
protected:
|
|
bool init_internal() override;
|
|
bool init_internal(VertBuf *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();
|
|
|
|
/**
|
|
* 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 Views
|
|
* \{ */
|
|
|
|
private:
|
|
IndexRange mip_map_range() const;
|
|
IndexRange layer_range() const;
|
|
|
|
/** \} */
|
|
};
|
|
|
|
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
|