Vulkan: Frame Buffer Flipping #107743
|
@ -31,22 +31,28 @@ VKContext::VKContext(void *ghost_window, void *ghost_context)
|
||||||
state_manager = new VKStateManager();
|
state_manager = new VKStateManager();
|
||||||
|
|
||||||
/* For off-screen contexts. Default frame-buffer is empty. */
|
/* For off-screen contexts. Default frame-buffer is empty. */
|
||||||
back_left = new VKFrameBuffer("back_left");
|
VKFrameBuffer *framebuffer = new VKFrameBuffer("back_left");
|
||||||
|
back_left = framebuffer;
|
||||||
|
active_fb = framebuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
VKContext::~VKContext() {}
|
VKContext::~VKContext() {}
|
||||||
|
|
||||||
void VKContext::activate()
|
void VKContext::sync_backbuffer()
|
||||||
{
|
{
|
||||||
if (ghost_window_) {
|
if (ghost_window_) {
|
||||||
VkImage image; /* TODO will be used for reading later... */
|
VkImage vk_image;
|
||||||
VkFramebuffer vk_framebuffer;
|
VkFramebuffer vk_framebuffer;
|
||||||
VkRenderPass render_pass;
|
VkRenderPass render_pass;
|
||||||
VkExtent2D extent;
|
VkExtent2D extent;
|
||||||
uint32_t fb_id;
|
uint32_t fb_id;
|
||||||
|
|
||||||
GHOST_GetVulkanBackbuffer(
|
GHOST_GetVulkanBackbuffer((GHOST_WindowHandle)ghost_window_,
|
||||||
(GHOST_WindowHandle)ghost_window_, &image, &vk_framebuffer, &render_pass, &extent, &fb_id);
|
&vk_image,
|
||||||
|
&vk_framebuffer,
|
||||||
|
&render_pass,
|
||||||
|
&extent,
|
||||||
|
&fb_id);
|
||||||
|
|
||||||
/* Recreate the gpu::VKFrameBuffer wrapper after every swap. */
|
/* Recreate the gpu::VKFrameBuffer wrapper after every swap. */
|
||||||
if (has_active_framebuffer()) {
|
if (has_active_framebuffer()) {
|
||||||
|
@ -55,22 +61,37 @@ void VKContext::activate()
|
||||||
delete back_left;
|
delete back_left;
|
||||||
|
|
||||||
VKFrameBuffer *framebuffer = new VKFrameBuffer(
|
VKFrameBuffer *framebuffer = new VKFrameBuffer(
|
||||||
"back_left", vk_framebuffer, render_pass, extent);
|
"back_left", vk_image, vk_framebuffer, render_pass, extent);
|
||||||
back_left = framebuffer;
|
back_left = framebuffer;
|
||||||
framebuffer->bind(false);
|
back_left->bind(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ghost_context_) {
|
||||||
|
VkCommandBuffer command_buffer = VK_NULL_HANDLE;
|
||||||
|
GHOST_GetVulkanCommandBuffer(static_cast<GHOST_ContextHandle>(ghost_context_),
|
||||||
|
&command_buffer);
|
||||||
|
VKDevice &device = VKBackend::get().device_;
|
||||||
|
command_buffer_.init(device.device_get(), device.queue_get(), command_buffer);
|
||||||
|
command_buffer_.begin_recording();
|
||||||
|
device.descriptor_pools_get().reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VKContext::activate()
|
||||||
|
{
|
||||||
|
/* Make sure no other context is already bound to this thread. */
|
||||||
|
BLI_assert(is_active_ == false);
|
||||||
|
|
||||||
|
is_active_ = true;
|
||||||
|
|
||||||
|
sync_backbuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKContext::deactivate() {}
|
void VKContext::deactivate() {}
|
||||||
|
|
||||||
void VKContext::begin_frame()
|
void VKContext::begin_frame()
|
||||||
{
|
{
|
||||||
VkCommandBuffer command_buffer = VK_NULL_HANDLE;
|
sync_backbuffer();
|
||||||
GHOST_GetVulkanCommandBuffer(static_cast<GHOST_ContextHandle>(ghost_context_), &command_buffer);
|
|
||||||
VKDevice &device = VKBackend::get().device_;
|
|
||||||
command_buffer_.init(device.device_get(), device.queue_get(), command_buffer);
|
|
||||||
command_buffer_.begin_recording();
|
|
||||||
device.descriptor_pools_get().reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKContext::end_frame()
|
void VKContext::end_frame()
|
||||||
|
@ -115,16 +136,23 @@ void VKContext::activate_framebuffer(VKFrameBuffer &framebuffer)
|
||||||
command_buffer_.begin_render_pass(framebuffer);
|
command_buffer_.begin_render_pass(framebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VKFrameBuffer *VKContext::active_framebuffer_get() const
|
||||||
|
{
|
||||||
|
return unwrap(active_fb);
|
||||||
|
}
|
||||||
|
|
||||||
bool VKContext::has_active_framebuffer() const
|
bool VKContext::has_active_framebuffer() const
|
||||||
{
|
{
|
||||||
return active_fb != nullptr;
|
return active_framebuffer_get() != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKContext::deactivate_framebuffer()
|
void VKContext::deactivate_framebuffer()
|
||||||
{
|
{
|
||||||
BLI_assert(active_fb != nullptr);
|
BLI_assert(active_fb != nullptr);
|
||||||
VKFrameBuffer *framebuffer = unwrap(active_fb);
|
VKFrameBuffer *framebuffer = active_framebuffer_get();
|
||||||
command_buffer_.end_render_pass(*framebuffer);
|
if (framebuffer->is_valid()) {
|
||||||
|
command_buffer_.end_render_pass(*framebuffer);
|
||||||
|
}
|
||||||
active_fb = nullptr;
|
active_fb = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,12 @@ class VKContext : public Context, NonCopyable {
|
||||||
bool debug_capture_scope_begin(void *scope) override;
|
bool debug_capture_scope_begin(void *scope) override;
|
||||||
void debug_capture_scope_end(void *scope) override;
|
void debug_capture_scope_end(void *scope) override;
|
||||||
|
|
||||||
|
bool has_active_framebuffer() const;
|
||||||
void activate_framebuffer(VKFrameBuffer &framebuffer);
|
void activate_framebuffer(VKFrameBuffer &framebuffer);
|
||||||
void deactivate_framebuffer();
|
void deactivate_framebuffer();
|
||||||
|
VKFrameBuffer *active_framebuffer_get() const;
|
||||||
|
|
||||||
|
void sync_backbuffer();
|
||||||
|
|
||||||
static VKContext *get(void)
|
static VKContext *get(void)
|
||||||
{
|
{
|
||||||
|
@ -59,9 +63,6 @@ class VKContext : public Context, NonCopyable {
|
||||||
}
|
}
|
||||||
|
|
||||||
const VKStateManager &state_manager_get() const;
|
const VKStateManager &state_manager_get() const;
|
||||||
|
|
||||||
private:
|
|
||||||
bool has_active_framebuffer() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blender::gpu
|
} // namespace blender::gpu
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "vk_framebuffer.hh"
|
#include "vk_framebuffer.hh"
|
||||||
#include "vk_backend.hh"
|
#include "vk_backend.hh"
|
||||||
|
#include "vk_context.hh"
|
||||||
#include "vk_memory.hh"
|
#include "vk_memory.hh"
|
||||||
#include "vk_texture.hh"
|
#include "vk_texture.hh"
|
||||||
|
|
||||||
|
@ -19,26 +20,28 @@ namespace blender::gpu {
|
||||||
VKFrameBuffer::VKFrameBuffer(const char *name) : FrameBuffer(name)
|
VKFrameBuffer::VKFrameBuffer(const char *name) : FrameBuffer(name)
|
||||||
{
|
{
|
||||||
immutable_ = false;
|
immutable_ = false;
|
||||||
|
flip_viewport_ = false;
|
||||||
|
size_set(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
VKFrameBuffer::VKFrameBuffer(const char *name,
|
VKFrameBuffer::VKFrameBuffer(const char *name,
|
||||||
|
VkImage vk_image,
|
||||||
VkFramebuffer vk_framebuffer,
|
VkFramebuffer vk_framebuffer,
|
||||||
VkRenderPass vk_render_pass,
|
VkRenderPass vk_render_pass,
|
||||||
VkExtent2D vk_extent)
|
VkExtent2D vk_extent)
|
||||||
: FrameBuffer(name)
|
: FrameBuffer(name)
|
||||||
{
|
{
|
||||||
immutable_ = true;
|
immutable_ = true;
|
||||||
|
flip_viewport_ = true;
|
||||||
/* Never update an internal frame-buffer. */
|
/* Never update an internal frame-buffer. */
|
||||||
dirty_attachments_ = false;
|
dirty_attachments_ = false;
|
||||||
width_ = vk_extent.width;
|
vk_image_ = vk_image;
|
||||||
height_ = vk_extent.height;
|
|
||||||
vk_framebuffer_ = vk_framebuffer;
|
vk_framebuffer_ = vk_framebuffer;
|
||||||
vk_render_pass_ = vk_render_pass;
|
vk_render_pass_ = vk_render_pass;
|
||||||
|
|
||||||
viewport_[0] = scissor_[0] = 0;
|
size_set(vk_extent.width, vk_extent.height);
|
||||||
viewport_[1] = scissor_[1] = 0;
|
viewport_reset();
|
||||||
viewport_[2] = scissor_[2] = width_;
|
scissor_reset();
|
||||||
viewport_[3] = scissor_[3] = height_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VKFrameBuffer::~VKFrameBuffer()
|
VKFrameBuffer::~VKFrameBuffer()
|
||||||
|
@ -52,12 +55,47 @@ VKFrameBuffer::~VKFrameBuffer()
|
||||||
|
|
||||||
void VKFrameBuffer::bind(bool /*enabled_srgb*/)
|
void VKFrameBuffer::bind(bool /*enabled_srgb*/)
|
||||||
{
|
{
|
||||||
|
VKContext &context = *VKContext::get();
|
||||||
|
/* Updating attachments can issue pipeline barriers, this should be done outside the render pass.
|
||||||
|
* When done inside a render pass there should be a self-dependency between sub-passes on the
|
||||||
|
* active render pass. As the active render pass isn't aware of the new render pass (and should
|
||||||
|
* not) it is better to deactivate it before updating the attachments. For more information check
|
||||||
|
* `VkSubpassDependency`. */
|
||||||
|
if (context.has_active_framebuffer()) {
|
||||||
|
context.deactivate_framebuffer();
|
||||||
|
}
|
||||||
|
|
||||||
update_attachments();
|
update_attachments();
|
||||||
|
|
||||||
VKContext &context = *VKContext::get();
|
|
||||||
context.activate_framebuffer(*this);
|
context.activate_framebuffer(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkViewport VKFrameBuffer::vk_viewport_get() const
|
||||||
|
{
|
||||||
|
VkViewport viewport;
|
||||||
|
int viewport_rect[4];
|
||||||
|
viewport_get(viewport_rect);
|
||||||
|
|
||||||
|
viewport.x = viewport_rect[0];
|
||||||
|
viewport.y = viewport_rect[1];
|
||||||
|
viewport.width = viewport_rect[2];
|
||||||
|
viewport.height = viewport_rect[3];
|
||||||
|
viewport.minDepth = 0.0f;
|
||||||
|
viewport.maxDepth = 1.0f;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vulkan has origin to the top left, Blender bottom left. We counteract this by using a negative
|
||||||
|
* viewport when flip_viewport_ is set. This flips the viewport making any draw/blit use the
|
||||||
|
* correct orientation.
|
||||||
|
*/
|
||||||
|
if (flip_viewport_) {
|
||||||
|
viewport.y = height_ - viewport_rect[1];
|
||||||
|
viewport.height = -viewport_rect[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
return viewport;
|
||||||
|
}
|
||||||
|
|
||||||
VkRect2D VKFrameBuffer::vk_render_area_get() const
|
VkRect2D VKFrameBuffer::vk_render_area_get() const
|
||||||
{
|
{
|
||||||
VkRect2D render_area = {};
|
VkRect2D render_area = {};
|
||||||
|
@ -82,7 +120,7 @@ VkRect2D VKFrameBuffer::vk_render_area_get() const
|
||||||
|
|
||||||
bool VKFrameBuffer::check(char /*err_out*/[256])
|
bool VKFrameBuffer::check(char /*err_out*/[256])
|
||||||
{
|
{
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKFrameBuffer::build_clear_attachments_depth_stencil(
|
void VKFrameBuffer::build_clear_attachments_depth_stencil(
|
||||||
|
@ -127,6 +165,9 @@ void VKFrameBuffer::build_clear_attachments_color(const float (*clear_colors)[4]
|
||||||
|
|
||||||
void VKFrameBuffer::clear(const Vector<VkClearAttachment> &attachments) const
|
void VKFrameBuffer::clear(const Vector<VkClearAttachment> &attachments) const
|
||||||
{
|
{
|
||||||
|
if (attachments.is_empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
VkClearRect clear_rect = {};
|
VkClearRect clear_rect = {};
|
||||||
clear_rect.rect = vk_render_area_get();
|
clear_rect.rect = vk_render_area_get();
|
||||||
clear_rect.baseArrayLayer = 0;
|
clear_rect.baseArrayLayer = 0;
|
||||||
|
@ -189,13 +230,43 @@ void VKFrameBuffer::attachment_set_loadstore_op(GPUAttachmentType /*type*/,
|
||||||
/** \name Read back
|
/** \name Read back
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
void VKFrameBuffer::read(eGPUFrameBufferBits /*planes*/,
|
void VKFrameBuffer::read(eGPUFrameBufferBits plane,
|
||||||
eGPUDataFormat /*format*/,
|
eGPUDataFormat format,
|
||||||
const int /*area*/[4],
|
const int /*area*/[4],
|
||||||
int /*channel_len*/,
|
int channel_len,
|
||||||
int /*slot*/,
|
int slot,
|
||||||
void * /*r_data*/)
|
void *r_data)
|
||||||
{
|
{
|
||||||
|
VKTexture *texture = nullptr;
|
||||||
|
switch (plane) {
|
||||||
|
case GPU_COLOR_BIT:
|
||||||
|
texture = unwrap(unwrap(attachments_[GPU_FB_COLOR_ATTACHMENT0 + slot].tex));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_assert_msg(texture,
|
||||||
|
"Trying to read back color texture from framebuffer, but no color texture is "
|
||||||
|
"available in requested slot.");
|
||||||
|
void *data = texture->read(0, format);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO:
|
||||||
|
* - Add support for area.
|
||||||
|
* - Add support for channel_len.
|
||||||
|
* Best option would be to add this to VKTexture so we don't over-allocate and reduce number of
|
||||||
|
* times copies are made.
|
||||||
|
*/
|
||||||
|
BLI_assert(format == GPU_DATA_FLOAT);
|
||||||
|
BLI_assert(channel_len == 4);
|
||||||
|
int mip_size[3] = {1, 1, 1};
|
||||||
|
texture->mip_size_get(0, mip_size);
|
||||||
|
const size_t mem_size = mip_size[0] * mip_size[1] * mip_size[2] * sizeof(float) * channel_len;
|
||||||
|
memcpy(r_data, data, mem_size);
|
||||||
|
MEM_freeN(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
@ -204,13 +275,76 @@ void VKFrameBuffer::read(eGPUFrameBufferBits /*planes*/,
|
||||||
/** \name Blit operations
|
/** \name Blit operations
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
void VKFrameBuffer::blit_to(eGPUFrameBufferBits /*planes*/,
|
void VKFrameBuffer::blit_to(eGPUFrameBufferBits planes,
|
||||||
int /*src_slot*/,
|
int src_slot,
|
||||||
FrameBuffer * /*dst*/,
|
FrameBuffer *dst,
|
||||||
int /*dst_slot*/,
|
int dst_slot,
|
||||||
int /*dst_offset_x*/,
|
int dst_offset_x,
|
||||||
int /*dst_offset_y*/)
|
int dst_offset_y)
|
||||||
{
|
{
|
||||||
|
BLI_assert(dst);
|
||||||
|
BLI_assert(planes == GPU_COLOR_BIT);
|
||||||
|
UNUSED_VARS_NDEBUG(planes);
|
||||||
|
|
||||||
|
VKContext &context = *VKContext::get();
|
||||||
|
if (!context.has_active_framebuffer()) {
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrieve source texture. */
|
||||||
|
const GPUAttachment &src_attachment = attachments_[GPU_FB_COLOR_ATTACHMENT0 + src_slot];
|
||||||
|
if (src_attachment.tex == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VKTexture &src_texture = *unwrap(unwrap(src_attachment.tex));
|
||||||
|
src_texture.layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
|
|
||||||
|
/* Retrieve destination texture. */
|
||||||
|
const VKFrameBuffer &dst_framebuffer = *unwrap(dst);
|
||||||
|
const GPUAttachment &dst_attachment =
|
||||||
|
dst_framebuffer.attachments_[GPU_FB_COLOR_ATTACHMENT0 + dst_slot];
|
||||||
|
VKTexture *dst_texture = nullptr;
|
||||||
|
VKTexture tmp_texture("FramebufferTexture");
|
||||||
|
if (dst_attachment.tex) {
|
||||||
|
dst_texture = unwrap(unwrap(dst_attachment.tex));
|
||||||
|
dst_texture->layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tmp_texture.init(dst_framebuffer.vk_image_get(), VK_IMAGE_LAYOUT_GENERAL);
|
||||||
|
dst_texture = &tmp_texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageBlit image_blit = {};
|
||||||
|
image_blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
image_blit.srcSubresource.mipLevel = 0;
|
||||||
|
image_blit.srcSubresource.baseArrayLayer = 0;
|
||||||
|
image_blit.srcSubresource.layerCount = 1;
|
||||||
|
image_blit.srcOffsets[0].x = 0;
|
||||||
|
image_blit.srcOffsets[0].y = 0;
|
||||||
|
image_blit.srcOffsets[0].z = 0;
|
||||||
|
image_blit.srcOffsets[1].x = src_texture.width_get();
|
||||||
|
image_blit.srcOffsets[1].y = src_texture.height_get();
|
||||||
|
image_blit.srcOffsets[1].z = 1;
|
||||||
|
|
||||||
|
image_blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
image_blit.dstSubresource.mipLevel = 0;
|
||||||
|
image_blit.dstSubresource.baseArrayLayer = 0;
|
||||||
|
image_blit.dstSubresource.layerCount = 1;
|
||||||
|
image_blit.dstOffsets[0].x = dst_offset_x;
|
||||||
|
image_blit.dstOffsets[0].y = dst_offset_y;
|
||||||
|
image_blit.dstOffsets[0].z = 0;
|
||||||
|
image_blit.dstOffsets[1].x = dst_offset_x + src_texture.width_get();
|
||||||
|
image_blit.dstOffsets[1].y = dst_offset_x + src_texture.height_get();
|
||||||
|
image_blit.dstOffsets[1].z = 1;
|
||||||
|
|
||||||
|
const bool should_flip = flip_viewport_ != dst_framebuffer.flip_viewport_;
|
||||||
|
if (should_flip) {
|
||||||
|
image_blit.dstOffsets[0].y = dst_framebuffer.height_ - dst_offset_y;
|
||||||
|
image_blit.dstOffsets[1].y = dst_framebuffer.height_ - dst_offset_y - src_texture.height_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
context.command_buffer_get().blit(*dst_texture, src_texture, Span<VkImageBlit>(&image_blit, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
@ -248,10 +382,6 @@ void VKFrameBuffer::render_pass_create()
|
||||||
std::array<VkAttachmentDescription, GPU_FB_MAX_ATTACHMENT> attachment_descriptions;
|
std::array<VkAttachmentDescription, GPU_FB_MAX_ATTACHMENT> attachment_descriptions;
|
||||||
std::array<VkImageView, GPU_FB_MAX_ATTACHMENT> image_views;
|
std::array<VkImageView, GPU_FB_MAX_ATTACHMENT> image_views;
|
||||||
std::array<VkAttachmentReference, GPU_FB_MAX_ATTACHMENT> attachment_references;
|
std::array<VkAttachmentReference, GPU_FB_MAX_ATTACHMENT> attachment_references;
|
||||||
#if 0
|
|
||||||
Vector<VkAttachmentReference> color_attachments;
|
|
||||||
VkAttachmentReference depth_attachment = {};
|
|
||||||
#endif
|
|
||||||
bool has_depth_attachment = false;
|
bool has_depth_attachment = false;
|
||||||
bool found_attachment = false;
|
bool found_attachment = false;
|
||||||
int depth_location = -1;
|
int depth_location = -1;
|
||||||
|
@ -289,7 +419,7 @@ void VKFrameBuffer::render_pass_create()
|
||||||
attachment_description.flags = 0;
|
attachment_description.flags = 0;
|
||||||
attachment_description.format = to_vk_format(texture.format_get());
|
attachment_description.format = to_vk_format(texture.format_get());
|
||||||
attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
|
attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||||
attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
|
@ -321,7 +451,8 @@ void VKFrameBuffer::render_pass_create()
|
||||||
size_set(size[0], size[1]);
|
size_set(size[0], size[1]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this->size_set(0, 0);
|
/* A framebuffer should at least be 1 by 1.*/
|
||||||
|
this->size_set(1, 1);
|
||||||
}
|
}
|
||||||
viewport_reset();
|
viewport_reset();
|
||||||
scissor_reset();
|
scissor_reset();
|
||||||
|
|
|
@ -25,11 +25,21 @@ class VKFrameBuffer : public FrameBuffer {
|
||||||
VkDevice vk_device_ = VK_NULL_HANDLE;
|
VkDevice vk_device_ = VK_NULL_HANDLE;
|
||||||
/* Base render pass used for framebuffer creation. */
|
/* Base render pass used for framebuffer creation. */
|
||||||
VkRenderPass vk_render_pass_ = VK_NULL_HANDLE;
|
VkRenderPass vk_render_pass_ = VK_NULL_HANDLE;
|
||||||
|
VkImage vk_image_ = VK_NULL_HANDLE;
|
||||||
/* Number of layers if the attachments are layered textures. */
|
/* Number of layers if the attachments are layered textures. */
|
||||||
int depth_ = 1;
|
int depth_ = 1;
|
||||||
/** Internal frame-buffers are immutable. */
|
/** Internal frame-buffers are immutable. */
|
||||||
bool immutable_;
|
bool immutable_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should we flip the viewport to match Blenders coordinate system. We flip the viewport for
|
||||||
|
* offscreen framebuffers.
|
||||||
|
*
|
||||||
|
* When two framebuffers are blitted we also check if the coordinate system should be flipped
|
||||||
|
* during blitting.
|
||||||
|
*/
|
||||||
|
bool flip_viewport_ = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Create a conventional framebuffer to attach texture to.
|
* Create a conventional framebuffer to attach texture to.
|
||||||
|
@ -41,6 +51,7 @@ class VKFrameBuffer : public FrameBuffer {
|
||||||
* This just act as a wrapper, the actual allocations are done by GHOST_ContextVK.
|
* This just act as a wrapper, the actual allocations are done by GHOST_ContextVK.
|
||||||
**/
|
**/
|
||||||
VKFrameBuffer(const char *name,
|
VKFrameBuffer(const char *name,
|
||||||
|
VkImage vk_image,
|
||||||
VkFramebuffer vk_framebuffer,
|
VkFramebuffer vk_framebuffer,
|
||||||
VkRenderPass vk_render_pass,
|
VkRenderPass vk_render_pass,
|
||||||
VkExtent2D vk_extent);
|
VkExtent2D vk_extent);
|
||||||
|
@ -76,6 +87,11 @@ class VKFrameBuffer : public FrameBuffer {
|
||||||
int dst_offset_x,
|
int dst_offset_x,
|
||||||
int dst_offset_y) override;
|
int dst_offset_y) override;
|
||||||
|
|
||||||
|
bool is_valid() const
|
||||||
|
{
|
||||||
|
return vk_framebuffer_ != VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
VkFramebuffer vk_framebuffer_get() const
|
VkFramebuffer vk_framebuffer_get() const
|
||||||
{
|
{
|
||||||
BLI_assert(vk_framebuffer_ != VK_NULL_HANDLE);
|
BLI_assert(vk_framebuffer_ != VK_NULL_HANDLE);
|
||||||
|
@ -87,7 +103,13 @@ class VKFrameBuffer : public FrameBuffer {
|
||||||
BLI_assert(vk_render_pass_ != VK_NULL_HANDLE);
|
BLI_assert(vk_render_pass_ != VK_NULL_HANDLE);
|
||||||
return vk_render_pass_;
|
return vk_render_pass_;
|
||||||
}
|
}
|
||||||
|
VkViewport vk_viewport_get() const;
|
||||||
VkRect2D vk_render_area_get() const;
|
VkRect2D vk_render_area_get() const;
|
||||||
|
VkImage vk_image_get() const
|
||||||
|
{
|
||||||
|
BLI_assert(vk_image_ != VK_NULL_HANDLE);
|
||||||
|
return vk_image_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void update_attachments();
|
void update_attachments();
|
||||||
|
|
|
@ -24,10 +24,17 @@ namespace blender::gpu {
|
||||||
VKTexture::~VKTexture()
|
VKTexture::~VKTexture()
|
||||||
{
|
{
|
||||||
VK_ALLOCATION_CALLBACKS
|
VK_ALLOCATION_CALLBACKS
|
||||||
|
if (is_allocated()) {
|
||||||
|
const VKDevice &device = VKBackend::get().device_get();
|
||||||
|
vmaDestroyImage(device.mem_allocator_get(), vk_image_, allocation_);
|
||||||
|
vkDestroyImageView(device.device_get(), vk_image_view_, vk_allocation_callbacks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const VKDevice &device = VKBackend::get().device_get();
|
void VKTexture::init(VkImage vk_image, VkImageLayout layout)
|
||||||
vmaDestroyImage(device.mem_allocator_get(), vk_image_, allocation_);
|
{
|
||||||
vkDestroyImageView(device.device_get(), vk_image_view_, vk_allocation_callbacks);
|
vk_image_ = vk_image;
|
||||||
|
current_layout_ = layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKTexture::generate_mipmap() {}
|
void VKTexture::generate_mipmap() {}
|
||||||
|
|
|
@ -27,6 +27,8 @@ class VKTexture : public Texture {
|
||||||
VKTexture(const char *name) : Texture(name) {}
|
VKTexture(const char *name) : Texture(name) {}
|
||||||
virtual ~VKTexture() override;
|
virtual ~VKTexture() override;
|
||||||
|
|
||||||
|
void init(VkImage vk_image, VkImageLayout layout);
|
||||||
|
|
||||||
void generate_mipmap() override;
|
void generate_mipmap() override;
|
||||||
void copy_to(Texture *tex) override;
|
void copy_to(Texture *tex) override;
|
||||||
void clear(eGPUDataFormat format, const void *data) override;
|
void clear(eGPUDataFormat format, const void *data) override;
|
||||||
|
@ -47,7 +49,7 @@ class VKTexture : public Texture {
|
||||||
void image_bind(int location);
|
void image_bind(int location);
|
||||||
VkImage vk_image_handle() const
|
VkImage vk_image_handle() const
|
||||||
{
|
{
|
||||||
BLI_assert(is_allocated());
|
BLI_assert(vk_image_ != VK_NULL_HANDLE);
|
||||||
return vk_image_;
|
return vk_image_;
|
||||||
}
|
}
|
||||||
VkImageView vk_image_view_handle() const
|
VkImageView vk_image_view_handle() const
|
||||||
|
|
Loading…
Reference in New Issue