Browse Source

Vk: store size in the Framebuffer and reuse it in RenderPassCreateInfo.

Since this is the most common use case, it makes sense.
pull/491/head
Vladimír Vondruš 5 years ago
parent
commit
9ad26feda0
  1. 24
      src/Magnum/Vk/Framebuffer.cpp
  2. 31
      src/Magnum/Vk/Framebuffer.h
  3. 3
      src/Magnum/Vk/FramebufferCreateInfo.h
  4. 6
      src/Magnum/Vk/RenderPass.cpp
  5. 8
      src/Magnum/Vk/RenderPass.h
  6. 7
      src/Magnum/Vk/Test/FramebufferVkTest.cpp
  7. 33
      src/Magnum/Vk/Test/RenderPassTest.cpp
  8. 2
      src/Magnum/Vk/Test/RenderPassVkTest.cpp

24
src/Magnum/Vk/Framebuffer.cpp

@ -92,21 +92,34 @@ FramebufferCreateInfo& FramebufferCreateInfo::operator=(FramebufferCreateInfo&&
return *this; return *this;
} }
Framebuffer Framebuffer::wrap(Device& device, const VkFramebuffer handle, const HandleFlags flags) { Framebuffer Framebuffer::wrap(Device& device, const VkFramebuffer handle, const Vector3i& size, const HandleFlags flags) {
Framebuffer out{NoCreate}; Framebuffer out{NoCreate};
out._device = &device; out._device = &device;
out._handle = handle; out._handle = handle;
out._flags = flags; out._flags = flags;
/* See the _size member for more information */
CORRADE_INTERNAL_ASSERT((size <= Vector3i{0xffff}).all());
out._size[0] = size.x();
out._size[1] = size.y();
out._size[2] = size.z();
return out; return out;
} }
Framebuffer::Framebuffer(Device& device, const FramebufferCreateInfo& info): _device{&device}, _flags{HandleFlag::DestroyOnDestruction} { Framebuffer::Framebuffer(Device& device, const FramebufferCreateInfo& info): _device{&device}, _flags{HandleFlag::DestroyOnDestruction} {
MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(device->CreateFramebuffer(device, info, nullptr, &_handle)); MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(device->CreateFramebuffer(device, info, nullptr, &_handle));
/* See the _size member for more information */
CORRADE_INTERNAL_ASSERT(info->width <= 0xffff && info->height <= 0xffff && info->layers <= 0xffff);
_size[0] = info->width;
_size[1] = info->height;
_size[2] = info->layers;
} }
Framebuffer::Framebuffer(NoCreateT): _device{}, _handle{} {} Framebuffer::Framebuffer(NoCreateT): _device{}, _handle{}, _size{} {}
Framebuffer::Framebuffer(Framebuffer&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags} { Framebuffer::Framebuffer(Framebuffer&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags}, _size{other._size[0], other._size[1], other._size[2]} {
other._handle = {}; other._handle = {};
} }
@ -120,9 +133,14 @@ Framebuffer& Framebuffer::operator=(Framebuffer&& other) noexcept {
swap(other._device, _device); swap(other._device, _device);
swap(other._handle, _handle); swap(other._handle, _handle);
swap(other._flags, _flags); swap(other._flags, _flags);
swap(other._size, _size);
return *this; return *this;
} }
Vector3i Framebuffer::size() const {
return {_size[0], _size[1], _size[2]};
}
VkFramebuffer Framebuffer::release() { VkFramebuffer Framebuffer::release() {
const VkFramebuffer handle = _handle; const VkFramebuffer handle = _handle;
_handle = {}; _handle = {};

31
src/Magnum/Vk/Framebuffer.h

@ -60,15 +60,22 @@ class MAGNUM_VK_EXPORT Framebuffer {
* @brief Wrap existing Vulkan handle * @brief Wrap existing Vulkan handle
* @param device Vulkan device the framebuffer is created on * @param device Vulkan device the framebuffer is created on
* @param handle The @type_vk{Framebuffer} handle * @param handle The @type_vk{Framebuffer} handle
* @param size Width, height and layer count of the
* framebuffer. Available through @ref size() afterwards.
* @param flags Handle flags * @param flags Handle flags
* *
* The @p handle is expected to be originating from @p device. Unlike * The @p handle is expected to be originating from @p device. The
* a framebuffer created using a constructor, the Vulkan framebuffer is * @p size parameter is used for convenience @ref RenderPass recording
* by default not deleted on destruction, use @p flags for different * later. If it's unknown, pass a default-constructed value --- you
* behavior. * will then be able to only being a render pass by specifying a
* concrete size in @ref RenderPassBeginInfo.
*
* Unlike a framebuffer created using a constructor, the Vulkan
* framebuffer is by default not deleted on destruction, use @p flags
* for different behavior.
* @see @ref release() * @see @ref release()
*/ */
static Framebuffer wrap(Device& device, VkFramebuffer handle, HandleFlags flags = {}); static Framebuffer wrap(Device& device, VkFramebuffer handle, const Vector3i& size, HandleFlags flags = {});
/** /**
* @brief Constructor * @brief Constructor
@ -118,6 +125,9 @@ class MAGNUM_VK_EXPORT Framebuffer {
/** @brief Handle flags */ /** @brief Handle flags */
HandleFlags handleFlags() const { return _flags; } HandleFlags handleFlags() const { return _flags; }
/** @brief Framebuffer size */
Vector3i size() const;
/** /**
* @brief Release the underlying Vulkan framebuffer * @brief Release the underlying Vulkan framebuffer
* *
@ -134,6 +144,17 @@ class MAGNUM_VK_EXPORT Framebuffer {
VkFramebuffer _handle; VkFramebuffer _handle;
HandleFlags _flags; HandleFlags _flags;
/* This is probably extremely stupid and will fire back later,
nevertheless -- on 64bit there's 7 padding bytes after flags, which
we can reuse to store framebuffer size. According to gpuinfo.org,
maxFramebufferWidth/Height is 32768 in late 2020, which fits into
16 bits, and a framebuffer of that size is 4 GB of memory. I don't
expect this growing over 64k (16 GB) anytime soon.
Additionally (which is probably also stupid), this is not using
Vector3us but instead a plain array to avoid the include
dependency. */
UnsignedShort _size[3];
}; };
}} }}

3
src/Magnum/Vk/FramebufferCreateInfo.h

@ -77,7 +77,8 @@ class MAGNUM_VK_EXPORT FramebufferCreateInfo {
* @param attachments Image views corresponding to all attachments * @param attachments Image views corresponding to all attachments
* listed in @ref RenderPassCreateInfo::setAttachments() * listed in @ref RenderPassCreateInfo::setAttachments()
* @param size Width, height and layer count of the * @param size Width, height and layer count of the
* framebuffer * framebuffer. Available through @ref Framebuffer::size()
* afterwards.
* @param flags Framebuffer creation flags * @param flags Framebuffer creation flags
* *
* The following @type_vk{FramebufferCreateInfo} fields are pre-filled * The following @type_vk{FramebufferCreateInfo} fields are pre-filled

6
src/Magnum/Vk/RenderPass.cpp

@ -33,6 +33,7 @@
#include "Magnum/Math/Color.h" #include "Magnum/Math/Color.h"
#include "Magnum/Vk/Assert.h" #include "Magnum/Vk/Assert.h"
#include "Magnum/Vk/Device.h" #include "Magnum/Vk/Device.h"
#include "Magnum/Vk/Framebuffer.h"
#include "Magnum/Vk/Handle.h" #include "Magnum/Vk/Handle.h"
#include "Magnum/Vk/Image.h" #include "Magnum/Vk/Image.h"
#include "Magnum/Vk/Integration.h" #include "Magnum/Vk/Integration.h"
@ -796,6 +797,11 @@ RenderPassBeginInfo::RenderPassBeginInfo(const VkRenderPass renderPass, const Vk
_info.renderArea = VkRect2D(renderArea); _info.renderArea = VkRect2D(renderArea);
} }
RenderPassBeginInfo::RenderPassBeginInfo(const VkRenderPass renderPass, Framebuffer& framebuffer): RenderPassBeginInfo{renderPass, framebuffer, {{}, framebuffer.size().xy()}} {
CORRADE_ASSERT(framebuffer.size().product(),
"Vk::RenderPassBeginInfo: the framebuffer has unknown size, you have to specify the render area explicitly", );
}
RenderPassBeginInfo::RenderPassBeginInfo(NoInitT) noexcept {} RenderPassBeginInfo::RenderPassBeginInfo(NoInitT) noexcept {}
RenderPassBeginInfo::RenderPassBeginInfo(const VkRenderPassBeginInfo& info): RenderPassBeginInfo::RenderPassBeginInfo(const VkRenderPassBeginInfo& info):

8
src/Magnum/Vk/RenderPass.h

@ -220,6 +220,14 @@ class MAGNUM_VK_EXPORT RenderPassBeginInfo {
*/ */
explicit RenderPassBeginInfo(VkRenderPass renderPass, VkFramebuffer framebuffer, const Range2Di& renderArea); explicit RenderPassBeginInfo(VkRenderPass renderPass, VkFramebuffer framebuffer, const Range2Di& renderArea);
/**
* @brief Construct for a render pass spanning the whole framebuffer area
*
* Equivalent to calling @ref RenderPassBeginInfo(VkRenderPass, VkFramebuffer, const Range2Di&)
* with @p renderArea spanning the whole @ref Framebuffer::size().
*/
explicit RenderPassBeginInfo(VkRenderPass renderPass, Framebuffer& framebuffer);
/** /**
* @brief Construct without initializing the contents * @brief Construct without initializing the contents
* *

7
src/Magnum/Vk/Test/FramebufferVkTest.cpp

@ -78,6 +78,7 @@ void FramebufferVkTest::construct() {
}, {256, 256}}}; }, {256, 256}}};
CORRADE_VERIFY(framebuffer.handle()); CORRADE_VERIFY(framebuffer.handle());
CORRADE_COMPARE(framebuffer.handleFlags(), HandleFlag::DestroyOnDestruction); CORRADE_COMPARE(framebuffer.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(framebuffer.size(), (Vector3i{256, 256, 1}));
} }
/* Shouldn't crash or anything */ /* Shouldn't crash or anything */
@ -102,6 +103,7 @@ void FramebufferVkTest::constructMove() {
CORRADE_VERIFY(!a.handle()); CORRADE_VERIFY(!a.handle());
CORRADE_COMPARE(b.handle(), handle); CORRADE_COMPARE(b.handle(), handle);
CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction); CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(b.size(), (Vector3i{256, 256, 1}));
Framebuffer c{NoCreate}; Framebuffer c{NoCreate};
c = std::move(b); c = std::move(b);
@ -109,6 +111,7 @@ void FramebufferVkTest::constructMove() {
CORRADE_COMPARE(b.handleFlags(), HandleFlags{}); CORRADE_COMPARE(b.handleFlags(), HandleFlags{});
CORRADE_COMPARE(c.handle(), handle); CORRADE_COMPARE(c.handle(), handle);
CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction); CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(c.size(), (Vector3i{256, 256, 1}));
CORRADE_VERIFY(std::is_nothrow_move_constructible<Framebuffer>::value); CORRADE_VERIFY(std::is_nothrow_move_constructible<Framebuffer>::value);
CORRADE_VERIFY(std::is_nothrow_move_assignable<Framebuffer>::value); CORRADE_VERIFY(std::is_nothrow_move_assignable<Framebuffer>::value);
@ -128,8 +131,10 @@ void FramebufferVkTest::wrap() {
FramebufferCreateInfo{renderPass, {colorView}, {256, 256}}, FramebufferCreateInfo{renderPass, {colorView}, {256, 256}},
nullptr, &framebuffer)), Result::Success); nullptr, &framebuffer)), Result::Success);
auto wrapped = Framebuffer::wrap(device(), framebuffer, HandleFlag::DestroyOnDestruction); /* The size is wrong, yes, but that's just for testing */
auto wrapped = Framebuffer::wrap(device(), framebuffer, {512, 384, 16}, HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(wrapped.handle(), framebuffer); CORRADE_COMPARE(wrapped.handle(), framebuffer);
CORRADE_COMPARE(wrapped.size(), (Vector3i{512, 384, 16}));
/* Release the handle again, destroy by hand */ /* Release the handle again, destroy by hand */
CORRADE_COMPARE(wrapped.release(), framebuffer); CORRADE_COMPARE(wrapped.release(), framebuffer);

33
src/Magnum/Vk/Test/RenderPassTest.cpp

@ -32,6 +32,8 @@
#include "Magnum/Math/Color.h" #include "Magnum/Math/Color.h"
#include "Magnum/Math/Range.h" #include "Magnum/Math/Range.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/Framebuffer.h"
#include "Magnum/Vk/Image.h" #include "Magnum/Vk/Image.h"
#include "Magnum/Vk/Integration.h" #include "Magnum/Vk/Integration.h"
#include "Magnum/Vk/RenderPassCreateInfo.h" #include "Magnum/Vk/RenderPassCreateInfo.h"
@ -97,6 +99,8 @@ struct RenderPassTest: TestSuite::Tester {
void constructCopy(); void constructCopy();
void beginInfoConstruct(); void beginInfoConstruct();
void beginInfoConstructImplicitSize();
void beginInfoConstructImplicitSizeUnknown();
void beginInfoConstructNoInit(); void beginInfoConstructNoInit();
void beginInfoConstructClears(); void beginInfoConstructClears();
void beginInfoConstructFromVk(); void beginInfoConstructFromVk();
@ -185,6 +189,8 @@ RenderPassTest::RenderPassTest() {
&RenderPassTest::constructCopy, &RenderPassTest::constructCopy,
&RenderPassTest::beginInfoConstruct, &RenderPassTest::beginInfoConstruct,
&RenderPassTest::beginInfoConstructImplicitSize,
&RenderPassTest::beginInfoConstructImplicitSizeUnknown,
&RenderPassTest::beginInfoConstructNoInit, &RenderPassTest::beginInfoConstructNoInit,
&RenderPassTest::beginInfoConstructClears, &RenderPassTest::beginInfoConstructClears,
&RenderPassTest::beginInfoConstructFromVk, &RenderPassTest::beginInfoConstructFromVk,
@ -1016,6 +1022,33 @@ void RenderPassTest::beginInfoConstruct() {
CORRADE_VERIFY(!info->pClearValues); CORRADE_VERIFY(!info->pClearValues);
} }
void RenderPassTest::beginInfoConstructImplicitSize() {
auto renderPass = reinterpret_cast<VkRenderPass>(0xbadbeef);
Device device{NoCreate};
auto framebuffer = Framebuffer::wrap(device, reinterpret_cast<VkFramebuffer>(0xdeadcafe), {256, 384, 16});
RenderPassBeginInfo info{renderPass, framebuffer};
CORRADE_COMPARE(info->renderPass, renderPass);
CORRADE_COMPARE(info->framebuffer, framebuffer.handle());
CORRADE_COMPARE(Range2Di{info->renderArea}, (Range2Di{{}, {256, 384}}));
CORRADE_COMPARE(info->clearValueCount, 0);
CORRADE_VERIFY(!info->pClearValues);
}
void RenderPassTest::beginInfoConstructImplicitSizeUnknown() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
Framebuffer framebuffer{NoCreate};
std::ostringstream out;
Error redirectError{&out};
RenderPassBeginInfo{VkRenderPass{}, framebuffer};
CORRADE_COMPARE(out.str(),
"Vk::RenderPassBeginInfo: the framebuffer has unknown size, you have to specify the render area explicitly\n");
}
void RenderPassTest::beginInfoConstructNoInit() { void RenderPassTest::beginInfoConstructNoInit() {
RenderPassBeginInfo info{NoInit}; RenderPassBeginInfo info{NoInit};
info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;

2
src/Magnum/Vk/Test/RenderPassVkTest.cpp

@ -179,7 +179,7 @@ void RenderPassVkTest::cmdBeginEnd() {
}, {256, 256}}}; }, {256, 256}}};
cmd.begin() cmd.begin()
.beginRenderPass(RenderPassBeginInfo{renderPass, framebuffer, {{}, {256, 256}}} .beginRenderPass(RenderPassBeginInfo{renderPass, framebuffer}
.clearColor(0, 0x1f1f1f_rgbf) .clearColor(0, 0x1f1f1f_rgbf)
.clearDepthStencil(1, 1.0f, 0)) .clearDepthStencil(1, 1.0f, 0))
.nextSubpass() .nextSubpass()

Loading…
Cancel
Save