diff --git a/src/Magnum/Vk/Framebuffer.cpp b/src/Magnum/Vk/Framebuffer.cpp index 798755c7d..276f67ff0 100644 --- a/src/Magnum/Vk/Framebuffer.cpp +++ b/src/Magnum/Vk/Framebuffer.cpp @@ -92,21 +92,34 @@ FramebufferCreateInfo& FramebufferCreateInfo::operator=(FramebufferCreateInfo&& 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}; out._device = &device; out._handle = handle; 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; } Framebuffer::Framebuffer(Device& device, const FramebufferCreateInfo& info): _device{&device}, _flags{HandleFlag::DestroyOnDestruction} { 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 = {}; } @@ -120,9 +133,14 @@ Framebuffer& Framebuffer::operator=(Framebuffer&& other) noexcept { swap(other._device, _device); swap(other._handle, _handle); swap(other._flags, _flags); + swap(other._size, _size); return *this; } +Vector3i Framebuffer::size() const { + return {_size[0], _size[1], _size[2]}; +} + VkFramebuffer Framebuffer::release() { const VkFramebuffer handle = _handle; _handle = {}; diff --git a/src/Magnum/Vk/Framebuffer.h b/src/Magnum/Vk/Framebuffer.h index 0eec02533..6f82207b7 100644 --- a/src/Magnum/Vk/Framebuffer.h +++ b/src/Magnum/Vk/Framebuffer.h @@ -60,15 +60,22 @@ class MAGNUM_VK_EXPORT Framebuffer { * @brief Wrap existing Vulkan handle * @param device Vulkan device the framebuffer is created on * @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 * - * The @p handle is expected to be originating from @p device. Unlike - * a framebuffer created using a constructor, the Vulkan framebuffer is - * by default not deleted on destruction, use @p flags for different - * behavior. + * The @p handle is expected to be originating from @p device. The + * @p size parameter is used for convenience @ref RenderPass recording + * later. If it's unknown, pass a default-constructed value --- you + * 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() */ - static Framebuffer wrap(Device& device, VkFramebuffer handle, HandleFlags flags = {}); + static Framebuffer wrap(Device& device, VkFramebuffer handle, const Vector3i& size, HandleFlags flags = {}); /** * @brief Constructor @@ -118,6 +125,9 @@ class MAGNUM_VK_EXPORT Framebuffer { /** @brief Handle flags */ HandleFlags handleFlags() const { return _flags; } + /** @brief Framebuffer size */ + Vector3i size() const; + /** * @brief Release the underlying Vulkan framebuffer * @@ -134,6 +144,17 @@ class MAGNUM_VK_EXPORT Framebuffer { VkFramebuffer _handle; 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]; }; }} diff --git a/src/Magnum/Vk/FramebufferCreateInfo.h b/src/Magnum/Vk/FramebufferCreateInfo.h index e6312e3b9..3000872f2 100644 --- a/src/Magnum/Vk/FramebufferCreateInfo.h +++ b/src/Magnum/Vk/FramebufferCreateInfo.h @@ -77,7 +77,8 @@ class MAGNUM_VK_EXPORT FramebufferCreateInfo { * @param attachments Image views corresponding to all attachments * listed in @ref RenderPassCreateInfo::setAttachments() * @param size Width, height and layer count of the - * framebuffer + * framebuffer. Available through @ref Framebuffer::size() + * afterwards. * @param flags Framebuffer creation flags * * The following @type_vk{FramebufferCreateInfo} fields are pre-filled diff --git a/src/Magnum/Vk/RenderPass.cpp b/src/Magnum/Vk/RenderPass.cpp index ebd4a368c..5d49bf3e9 100644 --- a/src/Magnum/Vk/RenderPass.cpp +++ b/src/Magnum/Vk/RenderPass.cpp @@ -33,6 +33,7 @@ #include "Magnum/Math/Color.h" #include "Magnum/Vk/Assert.h" #include "Magnum/Vk/Device.h" +#include "Magnum/Vk/Framebuffer.h" #include "Magnum/Vk/Handle.h" #include "Magnum/Vk/Image.h" #include "Magnum/Vk/Integration.h" @@ -796,6 +797,11 @@ RenderPassBeginInfo::RenderPassBeginInfo(const VkRenderPass renderPass, const Vk _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(const VkRenderPassBeginInfo& info): diff --git a/src/Magnum/Vk/RenderPass.h b/src/Magnum/Vk/RenderPass.h index 9115b4ffe..f56580a36 100644 --- a/src/Magnum/Vk/RenderPass.h +++ b/src/Magnum/Vk/RenderPass.h @@ -220,6 +220,14 @@ class MAGNUM_VK_EXPORT RenderPassBeginInfo { */ 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 * diff --git a/src/Magnum/Vk/Test/FramebufferVkTest.cpp b/src/Magnum/Vk/Test/FramebufferVkTest.cpp index 83725ff34..f0727ba9b 100644 --- a/src/Magnum/Vk/Test/FramebufferVkTest.cpp +++ b/src/Magnum/Vk/Test/FramebufferVkTest.cpp @@ -78,6 +78,7 @@ void FramebufferVkTest::construct() { }, {256, 256}}}; CORRADE_VERIFY(framebuffer.handle()); CORRADE_COMPARE(framebuffer.handleFlags(), HandleFlag::DestroyOnDestruction); + CORRADE_COMPARE(framebuffer.size(), (Vector3i{256, 256, 1})); } /* Shouldn't crash or anything */ @@ -102,6 +103,7 @@ void FramebufferVkTest::constructMove() { CORRADE_VERIFY(!a.handle()); CORRADE_COMPARE(b.handle(), handle); CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction); + CORRADE_COMPARE(b.size(), (Vector3i{256, 256, 1})); Framebuffer c{NoCreate}; c = std::move(b); @@ -109,6 +111,7 @@ void FramebufferVkTest::constructMove() { CORRADE_COMPARE(b.handleFlags(), HandleFlags{}); CORRADE_COMPARE(c.handle(), handle); CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction); + CORRADE_COMPARE(c.size(), (Vector3i{256, 256, 1})); CORRADE_VERIFY(std::is_nothrow_move_constructible::value); CORRADE_VERIFY(std::is_nothrow_move_assignable::value); @@ -128,8 +131,10 @@ void FramebufferVkTest::wrap() { FramebufferCreateInfo{renderPass, {colorView}, {256, 256}}, 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.size(), (Vector3i{512, 384, 16})); /* Release the handle again, destroy by hand */ CORRADE_COMPARE(wrapped.release(), framebuffer); diff --git a/src/Magnum/Vk/Test/RenderPassTest.cpp b/src/Magnum/Vk/Test/RenderPassTest.cpp index 069898a90..39f2c848e 100644 --- a/src/Magnum/Vk/Test/RenderPassTest.cpp +++ b/src/Magnum/Vk/Test/RenderPassTest.cpp @@ -32,6 +32,8 @@ #include "Magnum/Math/Color.h" #include "Magnum/Math/Range.h" +#include "Magnum/Vk/Device.h" +#include "Magnum/Vk/Framebuffer.h" #include "Magnum/Vk/Image.h" #include "Magnum/Vk/Integration.h" #include "Magnum/Vk/RenderPassCreateInfo.h" @@ -97,6 +99,8 @@ struct RenderPassTest: TestSuite::Tester { void constructCopy(); void beginInfoConstruct(); + void beginInfoConstructImplicitSize(); + void beginInfoConstructImplicitSizeUnknown(); void beginInfoConstructNoInit(); void beginInfoConstructClears(); void beginInfoConstructFromVk(); @@ -185,6 +189,8 @@ RenderPassTest::RenderPassTest() { &RenderPassTest::constructCopy, &RenderPassTest::beginInfoConstruct, + &RenderPassTest::beginInfoConstructImplicitSize, + &RenderPassTest::beginInfoConstructImplicitSizeUnknown, &RenderPassTest::beginInfoConstructNoInit, &RenderPassTest::beginInfoConstructClears, &RenderPassTest::beginInfoConstructFromVk, @@ -1016,6 +1022,33 @@ void RenderPassTest::beginInfoConstruct() { CORRADE_VERIFY(!info->pClearValues); } +void RenderPassTest::beginInfoConstructImplicitSize() { + auto renderPass = reinterpret_cast(0xbadbeef); + Device device{NoCreate}; + auto framebuffer = Framebuffer::wrap(device, reinterpret_cast(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() { RenderPassBeginInfo info{NoInit}; info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; diff --git a/src/Magnum/Vk/Test/RenderPassVkTest.cpp b/src/Magnum/Vk/Test/RenderPassVkTest.cpp index dca80f064..07919854e 100644 --- a/src/Magnum/Vk/Test/RenderPassVkTest.cpp +++ b/src/Magnum/Vk/Test/RenderPassVkTest.cpp @@ -179,7 +179,7 @@ void RenderPassVkTest::cmdBeginEnd() { }, {256, 256}}}; cmd.begin() - .beginRenderPass(RenderPassBeginInfo{renderPass, framebuffer, {{}, {256, 256}}} + .beginRenderPass(RenderPassBeginInfo{renderPass, framebuffer} .clearColor(0, 0x1f1f1f_rgbf) .clearDepthStencil(1, 1.0f, 0)) .nextSubpass()