Browse Source

Vk: implement a Framebuffer wrapper.

EZ, for once.
pull/491/head
Vladimír Vondruš 5 years ago
parent
commit
71af6a034c
  1. 34
      doc/snippets/MagnumVk.cpp
  2. 4
      doc/vulkan-mapping.dox
  3. 3
      src/Magnum/Vk/CMakeLists.txt
  4. 132
      src/Magnum/Vk/Framebuffer.cpp
  5. 141
      src/Magnum/Vk/Framebuffer.h
  6. 163
      src/Magnum/Vk/FramebufferCreateInfo.h
  7. 2
      src/Magnum/Vk/RenderPass.h
  8. 4
      src/Magnum/Vk/Test/CMakeLists.txt
  9. 175
      src/Magnum/Vk/Test/FramebufferTest.cpp
  10. 142
      src/Magnum/Vk/Test/FramebufferVkTest.cpp
  11. 2
      src/Magnum/Vk/Vk.h

34
doc/snippets/MagnumVk.cpp

@ -38,6 +38,7 @@
#include "Magnum/Vk/DeviceProperties.h" #include "Magnum/Vk/DeviceProperties.h"
#include "Magnum/Vk/Extensions.h" #include "Magnum/Vk/Extensions.h"
#include "Magnum/Vk/ExtensionProperties.h" #include "Magnum/Vk/ExtensionProperties.h"
#include "Magnum/Vk/FramebufferCreateInfo.h"
#include "Magnum/Vk/InstanceCreateInfo.h" #include "Magnum/Vk/InstanceCreateInfo.h"
#include "Magnum/Vk/Integration.h" #include "Magnum/Vk/Integration.h"
#include "Magnum/Vk/ImageCreateInfo.h" #include "Magnum/Vk/ImageCreateInfo.h"
@ -291,6 +292,39 @@ if(device.isExtensionEnabled<Vk::Extensions::EXT::index_type_uint8>()) {
/* [Device-isExtensionEnabled] */ /* [Device-isExtensionEnabled] */
} }
{
Vk::Device device{DOXYGEN_IGNORE(NoCreate)};
Vector2i size;
/* The include should be a no-op here since it was already included above */
/* [Framebuffer-creation] */
#include <Magnum/Vk/FramebufferCreateInfo.h>
DOXYGEN_IGNORE()
Vk::Image color{device, Vk::ImageCreateInfo2D{ /* created before */
Vk::ImageUsage::ColorAttachment,
VK_FORMAT_R8G8B8A8_UNORM, size, 1}, DOXYGEN_IGNORE(NoAllocate)};
Vk::Image depth{device, Vk::ImageCreateInfo2D{
Vk::ImageUsage::DepthStencilAttachment,
VK_FORMAT_D24_UNORM_S8_UINT, size, 1}, DOXYGEN_IGNORE(NoAllocate)};
Vk::ImageView colorView{device, Vk::ImageViewCreateInfo2D{color}};
Vk::ImageView depthView{device, Vk::ImageViewCreateInfo2D{depth}};
Vk::RenderPass renderPass{device, Vk::RenderPassCreateInfo{} /* created before */
.setAttachments({
color.format(),
depth.format()
})
DOXYGEN_IGNORE()
};
Vk::Framebuffer framebuffer{device, Vk::FramebufferCreateInfo{renderPass, {
colorView,
depthView
}, size}};
/* [Framebuffer-creation] */
}
{ {
Vk::Device device{NoCreate}; Vk::Device device{NoCreate};
/* The include should be a no-op here since it was already included above */ /* The include should be a no-op here since it was already included above */

4
doc/vulkan-mapping.dox

@ -150,7 +150,7 @@ Vulkan function | Matching API
@fn_vk{CreateDevice}, \n @fn_vk{DestroyDevice} | @ref Device constructor and destructor @fn_vk{CreateDevice}, \n @fn_vk{DestroyDevice} | @ref Device constructor and destructor
@fn_vk{CreateEvent}, \n @fn_vk{DestroyEvent} | | @fn_vk{CreateEvent}, \n @fn_vk{DestroyEvent} | |
@fn_vk{CreateFence}, \n @fn_vk{DestroyFence} | | @fn_vk{CreateFence}, \n @fn_vk{DestroyFence} | |
@fn_vk{CreateFramebuffer}, \n @fn_vk{DestroyFramebuffer} | | @fn_vk{CreateFramebuffer}, \n @fn_vk{DestroyFramebuffer} | @ref Framebuffer constructor and destructor
@fn_vk{CreateImage}, \n @fn_vk{DestroyImage} | @ref Image constructor and destructor @fn_vk{CreateImage}, \n @fn_vk{DestroyImage} | @ref Image constructor and destructor
@fn_vk{CreateImageView}, \n @fn_vk{DestroyImageView} | @ref ImageView constructor and destructor @fn_vk{CreateImageView}, \n @fn_vk{DestroyImageView} | @ref ImageView constructor and destructor
@fn_vk{CreateInstance}, \n @fn_vk{DestroyInstance} | @ref Instance constructor and destructor @fn_vk{CreateInstance}, \n @fn_vk{DestroyInstance} | @ref Instance constructor and destructor
@ -471,7 +471,7 @@ Vulkan structure | Matching API
@type_vk{FormatProperties}, \n @type_vk{FormatProperties2} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @type_vk{FormatProperties}, \n @type_vk{FormatProperties2} @m_class{m-label m-flat m-success} **KHR, 1.1** | |
@type_vk{FramebufferAttachmentsCreateInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{FramebufferAttachmentsCreateInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{FramebufferAttachmentImageInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{FramebufferAttachmentImageInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{FramebufferCreateInfo} | | @type_vk{FramebufferCreateInfo} | @ref FramebufferCreateInfo
@subsection vulkan-mapping-structures-g G @subsection vulkan-mapping-structures-g G

3
src/Magnum/Vk/CMakeLists.txt

@ -30,6 +30,7 @@ set(MagnumVk_SRCS
CommandBuffer.cpp CommandBuffer.cpp
CommandPool.cpp CommandPool.cpp
Extensions.cpp Extensions.cpp
Framebuffer.cpp
Handle.cpp Handle.cpp
Instance.cpp Instance.cpp
Result.cpp Result.cpp
@ -67,6 +68,8 @@ set(MagnumVk_HEADERS
Enums.h Enums.h
Extensions.h Extensions.h
ExtensionProperties.h ExtensionProperties.h
Framebuffer.h
FramebufferCreateInfo.h
Handle.h Handle.h
Image.h Image.h
ImageCreateInfo.h ImageCreateInfo.h

132
src/Magnum/Vk/Framebuffer.cpp

@ -0,0 +1,132 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "Framebuffer.h"
#include "FramebufferCreateInfo.h"
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/Reference.h>
#include "Magnum/Math/Vector3.h"
#include "Magnum/Vk/Assert.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/ImageView.h"
namespace Magnum { namespace Vk {
struct FramebufferCreateInfo::State {
Containers::Array<VkImageView> attachments;
};
FramebufferCreateInfo::FramebufferCreateInfo(const VkRenderPass renderPass, const Containers::ArrayView<const Containers::Reference<ImageView>> attachments, const Vector3i& size, const Flags flags): _info{}, _state{Containers::InPlaceInit} {
_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
_info.flags = VkFramebufferCreateFlags(flags);
_info.renderPass = renderPass;
_info.width = size.x();
_info.height = size.y();
_info.layers = size.z();
/* Allocate an array with VkImageView handles */
/** @todo combine the state and array allocations into one (could use
ArrayTuple, however that one includes ArrayView so not much better than
including Array directly in the header which I don't want to do) */
_state->attachments = Containers::Array<VkImageView>{Containers::NoInit, attachments.size()};
for(std::size_t i = 0; i != attachments.size(); ++i)
_state->attachments[i] = *attachments[i];
_info.attachmentCount = _state->attachments.size();
_info.pAttachments = _state->attachments;
}
FramebufferCreateInfo::FramebufferCreateInfo(const VkRenderPass renderPass, const std::initializer_list<Containers::Reference<ImageView>> attachments, const Vector3i& size, const Flags flags): FramebufferCreateInfo{renderPass, Containers::arrayView(attachments), size, flags} {}
FramebufferCreateInfo::FramebufferCreateInfo(const VkRenderPass renderPass, const Containers::ArrayView<const Containers::Reference<ImageView>> attachments, const Vector2i& size, const Flags flags): FramebufferCreateInfo{renderPass, attachments, {size, 1}, flags} {}
FramebufferCreateInfo::FramebufferCreateInfo(const VkRenderPass renderPass, const std::initializer_list<Containers::Reference<ImageView>> attachments, const Vector2i& size, const Flags flags): FramebufferCreateInfo{renderPass, Containers::arrayView(attachments), size, flags} {}
FramebufferCreateInfo::FramebufferCreateInfo(NoInitT) noexcept {}
FramebufferCreateInfo::FramebufferCreateInfo(const VkFramebufferCreateInfo& info):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(info) {}
FramebufferCreateInfo::FramebufferCreateInfo(FramebufferCreateInfo&& other) noexcept:
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(other._info),
_state{std::move(other._state)}
{
/* Ensure the previous instance doesn't reference state that's now ours */
other._info.attachmentCount = 0;
other._info.pAttachments = nullptr;
}
FramebufferCreateInfo::~FramebufferCreateInfo() = default;
FramebufferCreateInfo& FramebufferCreateInfo::operator=(FramebufferCreateInfo&& other) noexcept {
using std::swap;
swap(other._info, _info);
swap(other._state, _state);
return *this;
}
Framebuffer Framebuffer::wrap(Device& device, const VkFramebuffer handle, const HandleFlags flags) {
Framebuffer out{NoCreate};
out._device = &device;
out._handle = handle;
out._flags = flags;
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));
}
Framebuffer::Framebuffer(NoCreateT): _device{}, _handle{} {}
Framebuffer::Framebuffer(Framebuffer&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags} {
other._handle = {};
}
Framebuffer::~Framebuffer() {
if(_handle && (_flags & HandleFlag::DestroyOnDestruction))
(**_device).DestroyFramebuffer(*_device, _handle, nullptr);
}
Framebuffer& Framebuffer::operator=(Framebuffer&& other) noexcept {
using std::swap;
swap(other._device, _device);
swap(other._handle, _handle);
swap(other._flags, _flags);
return *this;
}
VkFramebuffer Framebuffer::release() {
const VkFramebuffer handle = _handle;
_handle = {};
return handle;
}
}}

141
src/Magnum/Vk/Framebuffer.h

@ -0,0 +1,141 @@
#ifndef Magnum_Vk_Framebuffer_h
#define Magnum_Vk_Framebuffer_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/** @file
* @brief Class @ref Magnum::Vk::Framebuffer
* @m_since_latest
*/
#include "Magnum/Magnum.h"
#include "Magnum/Tags.h"
#include "Magnum/Vk/Handle.h"
#include "Magnum/Vk/Vk.h"
#include "Magnum/Vk/Vulkan.h"
#include "Magnum/Vk/visibility.h"
namespace Magnum { namespace Vk {
/**
@brief Framebuffer
@m_since_latest
Wraps a @type_vk_keyword{Framebuffer}, which connects a @ref RenderPass
together with concrete @ref ImageView "ImageViews" for attachments.
@section Vk-Framebuffer-creation Framebuffer creation
A framebuffer is created using @ref FramebufferCreateInfo that takes a
previously-created @ref RenderPass together with @ref ImageView "ImageViews"
onto @ref Image "Images" of desired sizes and compatible formats for all its attachments:
@snippet MagnumVk.cpp Framebuffer-creation
*/
class MAGNUM_VK_EXPORT Framebuffer {
public:
/**
* @brief Wrap existing Vulkan handle
* @param device Vulkan device the framebuffer is created on
* @param handle The @type_vk{Framebuffer} handle
* @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.
* @see @ref release()
*/
static Framebuffer wrap(Device& device, VkFramebuffer handle, HandleFlags flags = {});
/**
* @brief Constructor
* @param device Vulkan device to create the image on
* @param info Image creation info
*
* @see @fn_vk_keyword{CreateFramebuffer}
*/
explicit Framebuffer(Device& device, const FramebufferCreateInfo& info);
/**
* @brief Construct without creating the image
*
* The constructed instance is equivalent to moved-from state. Useful
* in cases where you will overwrite the instance later anyway. Move
* another object over it to make it useful.
*/
explicit Framebuffer(NoCreateT);
/** @brief Copying is not allowed */
Framebuffer(const Framebuffer&) = delete;
/** @brief Move constructor */
Framebuffer(Framebuffer&& other) noexcept;
/**
* @brief Destructor
*
* Destroys associated @type_vk{Framebuffer} handle, unless the
* instance was created using @ref wrap() without
* @ref HandleFlag::DestroyOnDestruction specified.
* @see @fn_vk_keyword{DestroyFramebuffer}, @ref release()
*/
~Framebuffer();
/** @brief Copying is not allowed */
Framebuffer& operator=(const Framebuffer&) = delete;
/** @brief Move assignment */
Framebuffer& operator=(Framebuffer&& other) noexcept;
/** @brief Underlying @type_vk{Framebuffer} handle */
VkFramebuffer handle() { return _handle; }
/** @overload */
operator VkFramebuffer() { return _handle; }
/** @brief Handle flags */
HandleFlags handleFlags() const { return _flags; }
/**
* @brief Release the underlying Vulkan framebuffer
*
* Releases ownership of the Vulkan framebuffer and returns its handle
* so @fn_vk{DestroyFramebuffer} is not called on destruction. The
* internal state is then equivalent to moved-from state.
* @see @ref wrap()
*/
VkFramebuffer release();
private:
/* Can't be a reference because of the NoCreate constructor */
Device* _device;
VkFramebuffer _handle;
HandleFlags _flags;
};
}}
#endif

163
src/Magnum/Vk/FramebufferCreateInfo.h

@ -0,0 +1,163 @@
#ifndef Magnum_Vk_FramebufferCreateInfo_h
#define Magnum_Vk_FramebufferCreateInfo_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/** @file
* @brief Class @ref Magnum::Vk::FramebufferCreateInfo
* @m_since_latest
*/
#include <Corrade/Containers/Pointer.h>
#include <Corrade/Containers/EnumSet.h>
#include "Magnum/Magnum.h"
#include "Magnum/Tags.h"
#include "Magnum/Vk/visibility.h"
#include "Magnum/Vk/Vk.h"
#include "Magnum/Vk/Vulkan.h"
namespace Magnum { namespace Vk {
/**
@brief Framebuffer creation info
@m_since_latest
Wraps a @type_vk{FramebufferCreateInfo}. See
@ref Vk-Framebuffer-creation "Framebuffer creation" for usage information.
*/
class MAGNUM_VK_EXPORT FramebufferCreateInfo {
public:
/**
* @brief Framebuffer creation flag
*
* Wraps @type_vk_keyword{FramebufferCreateFlagBits}.
* @see @ref Flags, @ref FramebufferCreateInfo(VkRenderPass, Containers::ArrayView<const Containers::Reference<ImageView>>, const Vector3i&, Flags)
* @m_enum_values_as_keywords
*/
enum class Flag: UnsignedInt {
/** @todo VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, 1.2, plus a
dedicated attachment-less constructor enabling that implicitly */
};
/**
* @brief Framebuffer creation flags
*
* Type-safe wrapper for @type_vk_keyword{FramebufferCreateFlags}.
* @see @ref FramebufferCreateInfo(VkRenderPass, Containers::ArrayView<const Containers::Reference<ImageView>>, const Vector3i&, Flags)
*/
typedef Containers::EnumSet<Flag> Flags;
/**
* @brief Construct a multi-layer framebuffer
* @param renderPass A @ref RenderPass or a raw Vulkan render pass
* handle the framebuffer is compatible with
* @param attachments Image views corresponding to all attachments
* listed in @ref RenderPassCreateInfo::setAttachments()
* @param size Width, height and layer count of the
* framebuffer
* @param flags Framebuffer creation flags
*
* The following @type_vk{FramebufferCreateInfo} fields are pre-filled
* in addition to `sType`, everything else is zero-filled:
*
* - `flags`
* - `renderPass`
* - `attachmentCount` and `pAttachments` to @p attachments
* - `width`, `height` and `layers` to @p size
*/
explicit FramebufferCreateInfo(VkRenderPass renderPass, Containers::ArrayView<const Containers::Reference<ImageView>> attachments, const Vector3i& size, Flags flags = {});
/** @overload */
explicit FramebufferCreateInfo(VkRenderPass renderPass, std::initializer_list<Containers::Reference<ImageView>> attachments, const Vector3i& size, Flags flags = {});
/**
* @brief Construct a single-layer framebuffer
*
* Equivalent to calling @ref FramebufferCreateInfo(VkRenderPass, Containers::ArrayView<const Containers::Reference<ImageView>>, const Vector3i&, Flags)
* with the last dimension set to @cpp 1 @ce.
*/
explicit FramebufferCreateInfo(VkRenderPass renderPass, Containers::ArrayView<const Containers::Reference<ImageView>> attachments, const Vector2i& size, Flags flags = {});
/** @overload */
explicit FramebufferCreateInfo(VkRenderPass renderPass, std::initializer_list<Containers::Reference<ImageView>> attachments, const Vector2i& size, Flags flags = {});
/**
* @brief Construct without initializing the contents
*
* Note that not even the `sType` field is set --- the structure has to
* be fully initialized afterwards in order to be usable.
*/
explicit FramebufferCreateInfo(NoInitT) noexcept;
/**
* @brief Construct from existing data
*
* Copies the existing values verbatim, pointers are kept unchanged
* without taking over the ownership. Modifying the newly created
* instance will not modify the original data nor the pointed-to data.
*/
explicit FramebufferCreateInfo(const VkFramebufferCreateInfo& info);
/** @brief Copying is not allowed */
FramebufferCreateInfo(const FramebufferCreateInfo&) = delete;
/** @brief Move constructor */
FramebufferCreateInfo(FramebufferCreateInfo&& other) noexcept;
~FramebufferCreateInfo();
/** @brief Copying is not allowed */
FramebufferCreateInfo& operator=(const FramebufferCreateInfo&) = delete;
/** @brief Move assignment */
FramebufferCreateInfo& operator=(FramebufferCreateInfo&& other) noexcept;
/** @brief Underlying @type_vk{FramebufferCreateInfo} structure */
VkFramebufferCreateInfo& operator*() { return _info; }
/** @overload */
const VkFramebufferCreateInfo& operator*() const { return _info; }
/** @overload */
VkFramebufferCreateInfo* operator->() { return &_info; }
/** @overload */
const VkFramebufferCreateInfo* operator->() const { return &_info; }
/** @overload */
operator const VkFramebufferCreateInfo*() const { return &_info; }
private:
VkFramebufferCreateInfo _info;
struct State;
Containers::Pointer<State> _state;
};
CORRADE_ENUMSET_OPERATORS(FramebufferCreateInfo::Flags)
}}
/* Make the definition complete -- it doesn't make sense to have a CreateInfo
without the corresponding object anyway. */
#include "Magnum/Vk/Framebuffer.h"
#endif

2
src/Magnum/Vk/RenderPass.h

@ -47,7 +47,7 @@ namespace Implementation { struct DeviceState; }
Wraps a @type_vk_keyword{RenderPass}, represents a collection of attachment Wraps a @type_vk_keyword{RenderPass}, represents a collection of attachment
descriptions, subpasses and their dependencies. The render pass description is descriptions, subpasses and their dependencies. The render pass description is
independent of any specific image views used for attachments, these two are independent of any specific image views used for attachments, these two are
connected together in a framebuffer. connected together in a @ref Framebuffer.
@section Vk-RenderPass-creation Render pass creation @section Vk-RenderPass-creation Render pass creation

4
src/Magnum/Vk/Test/CMakeLists.txt

@ -33,6 +33,7 @@ corrade_add_test(VkDeviceFeaturesTest DeviceFeaturesTest.cpp LIBRARIES MagnumVk)
corrade_add_test(VkEnumsTest EnumsTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkEnumsTest EnumsTest.cpp LIBRARIES MagnumVkTestLib)
corrade_add_test(VkExtensionsTest ExtensionsTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkExtensionsTest ExtensionsTest.cpp LIBRARIES MagnumVk)
corrade_add_test(VkExtensionPropertiesTest ExtensionPropertiesTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkExtensionPropertiesTest ExtensionPropertiesTest.cpp LIBRARIES MagnumVk)
corrade_add_test(VkFramebufferTest FramebufferTest.cpp LIBRARIES MagnumVk)
corrade_add_test(VkHandleTest HandleTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkHandleTest HandleTest.cpp LIBRARIES MagnumVk)
corrade_add_test(VkImageTest ImageTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkImageTest ImageTest.cpp LIBRARIES MagnumVkTestLib)
corrade_add_test(VkImageViewTest ImageViewTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkImageViewTest ImageViewTest.cpp LIBRARIES MagnumVkTestLib)
@ -122,6 +123,7 @@ set_target_properties(
VkEnumsTest VkEnumsTest
VkExtensionsTest VkExtensionsTest
VkExtensionPropertiesTest VkExtensionPropertiesTest
VkFramebufferTest
VkHandleTest VkHandleTest
VkImageTest VkImageTest
VkImageViewTest VkImageViewTest
@ -152,6 +154,7 @@ if(BUILD_VK_TESTS)
corrade_add_test(VkDeviceVkTest DeviceVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester) corrade_add_test(VkDeviceVkTest DeviceVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester)
corrade_add_test(VkDevicePropertiesVkTest DevicePropertiesVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester) corrade_add_test(VkDevicePropertiesVkTest DevicePropertiesVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester)
corrade_add_test(VkExtensionPropertiesVkTest ExtensionPropertiesVkTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkExtensionPropertiesVkTest ExtensionPropertiesVkTest.cpp LIBRARIES MagnumVkTestLib)
corrade_add_test(VkFramebufferVkTest FramebufferVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkLayerPropertiesVkTest LayerPropertiesVkTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkLayerPropertiesVkTest LayerPropertiesVkTest.cpp LIBRARIES MagnumVkTestLib)
corrade_add_test(VkImageVkTest ImageVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester) corrade_add_test(VkImageVkTest ImageVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkImageViewVkTest ImageViewVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester) corrade_add_test(VkImageViewVkTest ImageViewVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
@ -169,6 +172,7 @@ if(BUILD_VK_TESTS)
VkDeviceVkTest VkDeviceVkTest
VkDevicePropertiesVkTest VkDevicePropertiesVkTest
VkExtensionPropertiesVkTest VkExtensionPropertiesVkTest
VkFramebufferVkTest
VkLayerPropertiesVkTest VkLayerPropertiesVkTest
VkImageVkTest VkImageVkTest
VkImageViewVkTest VkImageViewVkTest

175
src/Magnum/Vk/Test/FramebufferTest.cpp

@ -0,0 +1,175 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <new>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Containers/Reference.h>
#include "Magnum/Math/Vector3.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/FramebufferCreateInfo.h"
#include "Magnum/Vk/ImageView.h"
namespace Magnum { namespace Vk { namespace Test { namespace {
struct FramebufferTest: TestSuite::Tester {
explicit FramebufferTest();
void createInfoConstruct();
void createInfoConstructLayered();
void createInfoConstructNoInit();
void createInfoConstructFromVk();
void createInfoConstructCopy();
void createInfoConstructMove();
void constructNoCreate();
void constructCopy();
};
FramebufferTest::FramebufferTest() {
addTests({&FramebufferTest::createInfoConstruct,
&FramebufferTest::createInfoConstructLayered,
&FramebufferTest::createInfoConstructNoInit,
&FramebufferTest::createInfoConstructFromVk,
&FramebufferTest::createInfoConstructCopy,
&FramebufferTest::createInfoConstructMove,
&FramebufferTest::constructNoCreate,
&FramebufferTest::constructCopy});
}
void FramebufferTest::createInfoConstruct() {
Device device{NoCreate};
auto renderPass = reinterpret_cast<VkRenderPass>(0xdeadbeef);
auto a = ImageView::wrap(device, reinterpret_cast<VkImageView>(0xcafe1), {});
auto b = ImageView::wrap(device, reinterpret_cast<VkImageView>(0xcafe2), {});
auto c = ImageView::wrap(device, reinterpret_cast<VkImageView>(0xcafe3), {});
/** @todo use a real flag once it exists */
FramebufferCreateInfo info{renderPass, {a, b, c}, {256, 512}, FramebufferCreateInfo::Flag(0xbadda9)};
CORRADE_COMPARE(info->flags, 0xbadda9);
CORRADE_COMPARE(info->renderPass, reinterpret_cast<VkRenderPass>(0xdeadbeef));
CORRADE_COMPARE(info->attachmentCount, 3);
CORRADE_VERIFY(info->pAttachments);
CORRADE_COMPARE(info->pAttachments[0], reinterpret_cast<VkImageView>(0xcafe1));
CORRADE_COMPARE(info->pAttachments[1], reinterpret_cast<VkImageView>(0xcafe2));
CORRADE_COMPARE(info->pAttachments[2], reinterpret_cast<VkImageView>(0xcafe3));
CORRADE_COMPARE(info->width, 256);
CORRADE_COMPARE(info->height, 512);
CORRADE_COMPARE(info->layers, 1);
}
void FramebufferTest::createInfoConstructLayered() {
Device device{NoCreate};
auto renderPass = reinterpret_cast<VkRenderPass>(0xdeadbeef);
auto a = ImageView::wrap(device, reinterpret_cast<VkImageView>(0xcafe1), {});
auto b = ImageView::wrap(device, reinterpret_cast<VkImageView>(0xcafe2), {});
auto c = ImageView::wrap(device, reinterpret_cast<VkImageView>(0xcafe3), {});
/** @todo use a real flag once it exists */
FramebufferCreateInfo info{renderPass, {a, b, c}, {256, 512, 5}, FramebufferCreateInfo::Flag(0xbadda9)};
CORRADE_COMPARE(info->flags, 0xbadda9);
CORRADE_COMPARE(info->renderPass, reinterpret_cast<VkRenderPass>(0xdeadbeef));
CORRADE_COMPARE(info->attachmentCount, 3);
CORRADE_VERIFY(info->pAttachments);
CORRADE_COMPARE(info->pAttachments[0], reinterpret_cast<VkImageView>(0xcafe1));
CORRADE_COMPARE(info->pAttachments[1], reinterpret_cast<VkImageView>(0xcafe2));
CORRADE_COMPARE(info->pAttachments[2], reinterpret_cast<VkImageView>(0xcafe3));
CORRADE_COMPARE(info->width, 256);
CORRADE_COMPARE(info->height, 512);
CORRADE_COMPARE(info->layers, 5);
}
void FramebufferTest::createInfoConstructNoInit() {
FramebufferCreateInfo info{NoInit};
info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&info) FramebufferCreateInfo{NoInit};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY((std::is_nothrow_constructible<FramebufferCreateInfo, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, FramebufferCreateInfo>::value));
}
void FramebufferTest::createInfoConstructFromVk() {
VkFramebufferCreateInfo vkInfo;
vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
FramebufferCreateInfo info{vkInfo};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
}
void FramebufferTest::createInfoConstructCopy() {
CORRADE_VERIFY(!(std::is_copy_constructible<FramebufferCreateInfo>{}));
CORRADE_VERIFY(!(std::is_copy_assignable<FramebufferCreateInfo>{}));
}
void FramebufferTest::createInfoConstructMove() {
Device device{NoCreate};
auto renderPass = reinterpret_cast<VkRenderPass>(0xdeadbeef);
auto view = ImageView::wrap(device, reinterpret_cast<VkImageView>(0xcafe), {});
FramebufferCreateInfo a{renderPass, {view}, {256, 512}};
FramebufferCreateInfo b = std::move(a);
CORRADE_COMPARE(a->attachmentCount, 0);
CORRADE_VERIFY(!a->pAttachments);
CORRADE_COMPARE(b->renderPass, reinterpret_cast<VkRenderPass>(0xdeadbeef));
CORRADE_COMPARE(b->attachmentCount, 1);
CORRADE_VERIFY(b->pAttachments);
CORRADE_COMPARE(b->pAttachments[0], reinterpret_cast<VkImageView>(0xcafe));
FramebufferCreateInfo c{VkFramebufferCreateInfo{}};
c = std::move(b);
CORRADE_COMPARE(b->attachmentCount, 0);
CORRADE_VERIFY(!b->pAttachments);
CORRADE_COMPARE(c->renderPass, reinterpret_cast<VkRenderPass>(0xdeadbeef));
CORRADE_COMPARE(c->attachmentCount, 1);
CORRADE_VERIFY(c->pAttachments);
CORRADE_COMPARE(c->pAttachments[0], reinterpret_cast<VkImageView>(0xcafe));
CORRADE_VERIFY(std::is_nothrow_move_constructible<FramebufferCreateInfo>::value);
CORRADE_VERIFY(std::is_nothrow_move_assignable<FramebufferCreateInfo>::value);
}
void FramebufferTest::constructNoCreate() {
{
Framebuffer view{NoCreate};
CORRADE_VERIFY(!view.handle());
}
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoCreateT, Framebuffer>::value));
}
void FramebufferTest::constructCopy() {
CORRADE_VERIFY(!std::is_copy_constructible<Framebuffer>{});
CORRADE_VERIFY(!std::is_copy_assignable<Framebuffer>{});
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::FramebufferTest)

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

@ -0,0 +1,142 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <Corrade/Containers/Reference.h>
#include "Magnum/Vk/FramebufferCreateInfo.h"
#include "Magnum/Vk/ImageCreateInfo.h"
#include "Magnum/Vk/ImageViewCreateInfo.h"
#include "Magnum/Vk/RenderPassCreateInfo.h"
#include "Magnum/Vk/Result.h"
#include "Magnum/Vk/VulkanTester.h"
namespace Magnum { namespace Vk { namespace Test { namespace {
struct FramebufferVkTest: VulkanTester {
explicit FramebufferVkTest();
void construct();
void constructMove();
void wrap();
};
FramebufferVkTest::FramebufferVkTest() {
addTests({&FramebufferVkTest::construct,
&FramebufferVkTest::constructMove,
&FramebufferVkTest::wrap});
}
void FramebufferVkTest::construct() {
/* Using a depth attachment as well even though not strictly necessary to
catch potential unexpected bugs */
Image color{device(), ImageCreateInfo2D{ImageUsage::ColorAttachment,
VK_FORMAT_R8G8B8A8_UNORM, {256, 256}, 1}, MemoryFlag::DeviceLocal};
Image depth{device(), ImageCreateInfo2D{ImageUsage::DepthStencilAttachment,
VK_FORMAT_D24_UNORM_S8_UINT, {256, 256}, 1}, MemoryFlag::DeviceLocal};
ImageView colorView{device(), ImageViewCreateInfo2D{color}};
ImageView depthView{device(), ImageViewCreateInfo2D{depth}};
RenderPass renderPass{device(), RenderPassCreateInfo{}
.setAttachments({
color.format(),
depth.format()
})
.addSubpass(SubpassDescription{}
.setColorAttachments({0})
.setDepthStencilAttachment(1)
)
};
{
Framebuffer framebuffer{device(), FramebufferCreateInfo{renderPass, {
colorView,
depthView
}, {256, 256}}};
CORRADE_VERIFY(framebuffer.handle());
CORRADE_COMPARE(framebuffer.handleFlags(), HandleFlag::DestroyOnDestruction);
}
/* Shouldn't crash or anything */
CORRADE_VERIFY(true);
}
void FramebufferVkTest::constructMove() {
Image color{device(), ImageCreateInfo2D{ImageUsage::ColorAttachment,
VK_FORMAT_R8G8B8A8_UNORM, {256, 256}, 1}, MemoryFlag::DeviceLocal};
ImageView colorView{device(), ImageViewCreateInfo2D{color}};
RenderPass renderPass{device(), RenderPassCreateInfo{}
.setAttachments({color.format()})
.addSubpass(SubpassDescription{}.setColorAttachments({0}))
};
Framebuffer a{device(), FramebufferCreateInfo{renderPass, {
colorView
}, {256, 256}}};
VkFramebuffer handle = a.handle();
Framebuffer b = std::move(a);
CORRADE_VERIFY(!a.handle());
CORRADE_COMPARE(b.handle(), handle);
CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction);
Framebuffer c{NoCreate};
c = std::move(b);
CORRADE_VERIFY(!b.handle());
CORRADE_COMPARE(b.handleFlags(), HandleFlags{});
CORRADE_COMPARE(c.handle(), handle);
CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_VERIFY(std::is_nothrow_move_constructible<Framebuffer>::value);
CORRADE_VERIFY(std::is_nothrow_move_assignable<Framebuffer>::value);
}
void FramebufferVkTest::wrap() {
Image color{device(), ImageCreateInfo2D{ImageUsage::ColorAttachment,
VK_FORMAT_R8G8B8A8_UNORM, {256, 256}, 1}, MemoryFlag::DeviceLocal};
ImageView colorView{device(), ImageViewCreateInfo2D{color}};
RenderPass renderPass{device(), RenderPassCreateInfo{}
.setAttachments({color.format()})
.addSubpass(SubpassDescription{}.setColorAttachments({0}))
};
VkFramebuffer framebuffer{};
CORRADE_COMPARE(Result(device()->CreateFramebuffer(device(),
FramebufferCreateInfo{renderPass, {colorView}, {256, 256}},
nullptr, &framebuffer)), Result::Success);
auto wrapped = Framebuffer::wrap(device(), framebuffer, HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(wrapped.handle(), framebuffer);
/* Release the handle again, destroy by hand */
CORRADE_COMPARE(wrapped.release(), framebuffer);
CORRADE_VERIFY(!wrapped.handle());
device()->DestroyFramebuffer(device(), framebuffer, nullptr);
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::FramebufferVkTest)

2
src/Magnum/Vk/Vk.h

@ -49,6 +49,8 @@ class DeviceProperties;
enum class DeviceType: Int; enum class DeviceType: Int;
class Extension; class Extension;
class ExtensionProperties; class ExtensionProperties;
class Framebuffer;
class FramebufferCreateInfo;
enum class HandleFlag: UnsignedByte; enum class HandleFlag: UnsignedByte;
typedef Containers::EnumSet<HandleFlag> HandleFlags; typedef Containers::EnumSet<HandleFlag> HandleFlags;
class Image; class Image;

Loading…
Cancel
Save