Skip to content

Commit c61e078

Browse files
authoredJul 31, 2024··
Merge pull request #100 from cg-tuwien/development
Auto-Vk v0.99
2 parents 6b104f1 + 3d2206f commit c61e078

11 files changed

+1259
-297
lines changed
 

‎.github/workflows/build.yml

+132-31
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ env:
1616
jobs:
1717
linux:
1818
name: ${{ matrix.config.name }}, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }}
19-
runs-on: ubuntu-20.04
19+
runs-on: ubuntu-22.04
2020
strategy:
2121
fail-fast: false
2222
matrix:
@@ -28,37 +28,47 @@ jobs:
2828
#}
2929
- {
3030
name: "linux: gcc",
31-
cc: "gcc-10",
32-
cxx: "g++-10"
31+
cc: "gcc-13",
32+
cxx: "g++-13"
3333
}
3434
# note: if a specific vulkan version (e.g. 1.1.x, or < 1.2.135) needs testing, you can add it here:
3535
# (not that ubuntu-latest (20.04) only supports >= v1.2.148 via apt)
36-
vulkan-sdk: ["latest", "1.2.176"]
37-
vma: ["OFF"]
36+
vulkan-sdk: ["latest", "1.3.243"]
37+
vma: ["ON", "OFF"]
38+
exclude: # exclude combinations that are known to fail
39+
- vulkan-sdk: "1.2.198"
40+
vma: "ON"
3841

3942
steps:
40-
- uses: actions/checkout@v2
43+
- uses: actions/checkout@v3
4144

4245
- name: Create Build Environment
4346
shell: bash
4447
# Some projects don't allow in-source building, so create a separate build directory
4548
# We'll use this as our working directory for all subsequent commands
4649
run: |
4750
# Add lunarg apt sources
51+
sudo sed -i -e 's|disco|jammy|g' /etc/apt/sources.list
52+
sudo apt update
4853
wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
4954
if [ "${{ matrix.vulkan-sdk }}" = "latest" ]; then
50-
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-focal.list https://packages.lunarg.com/vulkan/lunarg-vulkan-focal.list
55+
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-jammy.list https://packages.lunarg.com/vulkan/lunarg-vulkan-jammy.list
5156
else
52-
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-${{ matrix.vulkan-sdk }}-focal.list https://packages.lunarg.com/vulkan/${{ matrix.vulkan-sdk }}/lunarg-vulkan-${{ matrix.vulkan-sdk }}-focal.list
57+
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-${{ matrix.vulkan-sdk }}-jammy.list https://packages.lunarg.com/vulkan/${{ matrix.vulkan-sdk }}/lunarg-vulkan-${{ matrix.vulkan-sdk }}-jammy.list
5358
fi
5459
60+
# For GCC-13
61+
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
62+
5563
# Update package lists
5664
sudo apt-get update -qq
5765
5866
# Install dependencies
5967
sudo apt-get install -y \
60-
vulkan-sdk
61-
68+
vulkan-sdk \
69+
g++-13 \
70+
gcc-13
71+
6272
# clang does not yet (<= 12) support "Down with typename" (P0634R3), which is used in libstdc++ >= 11 in the ranges-header
6373
if [ "${{ matrix.config.cc }}" = "clang" ]; then
6474
sudo apt remove libgcc-11-dev gcc-11
@@ -85,8 +95,85 @@ jobs:
8595
# Execute the build. You can specify a specific target with "--target <NAME>"
8696
run: cmake --build .
8797

88-
windows:
98+
linux-old:
8999
name: ${{ matrix.config.name }}, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }}
100+
runs-on: ubuntu-20.04
101+
strategy:
102+
fail-fast: false
103+
matrix:
104+
config:
105+
#- {
106+
# name: "linux: clang",
107+
# cc: "clang",
108+
# cxx: "clang++"
109+
#}
110+
- {
111+
name: "linux: gcc",
112+
cc: "gcc-13",
113+
cxx: "g++-13"
114+
}
115+
# note: if a specific vulkan version (e.g. 1.1.x, or < 1.2.135) needs testing, you can add it here:
116+
# (not that ubuntu-latest (20.04) only supports >= v1.2.148 via apt)
117+
vulkan-sdk: ["1.2.198"]
118+
vma: ["ON", "OFF"]
119+
exclude: # exclude combinations that are known to fail
120+
- vulkan-sdk: "1.2.198"
121+
vma: "ON"
122+
123+
steps:
124+
- uses: actions/checkout@v3
125+
126+
- name: Create Build Environment
127+
shell: bash
128+
# Some projects don't allow in-source building, so create a separate build directory
129+
# We'll use this as our working directory for all subsequent commands
130+
run: |
131+
# Add lunarg apt sources
132+
sudo sed -i -e 's|disco|focal|g' /etc/apt/sources.list
133+
sudo apt update
134+
wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
135+
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-${{ matrix.vulkan-sdk }}-focal.list https://packages.lunarg.com/vulkan/${{ matrix.vulkan-sdk }}/lunarg-vulkan-${{ matrix.vulkan-sdk }}-focal.list
136+
137+
# For GCC-13
138+
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
139+
140+
# Update package lists
141+
sudo apt-get update -qq
142+
143+
# Install dependencies
144+
sudo apt-get install -y \
145+
vulkan-sdk \
146+
g++-13 \
147+
gcc-13
148+
149+
# clang does not yet (<= 12) support "Down with typename" (P0634R3), which is used in libstdc++ >= 11 in the ranges-header
150+
if [ "${{ matrix.config.cc }}" = "clang" ]; then
151+
sudo apt remove libgcc-11-dev gcc-11
152+
fi
153+
154+
cmake -E make_directory ${{ runner.workspace }}/build
155+
156+
- name: Configure CMake
157+
# Use a bash shell so we can use the same syntax for environment variable
158+
# access regardless of the host operating system
159+
shell: bash
160+
working-directory: ${{ runner.workspace }}/build
161+
# Note the current convention is to use the -S and -B options here to specify source
162+
# and build directories, but this is only available with CMake 3.13 and higher.
163+
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
164+
run: |
165+
export CC=${{ matrix.config.cc }}
166+
export CXX=${{ matrix.config.cxx }}
167+
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -Davk_LibraryType=STATIC $GITHUB_WORKSPACE -Davk_UseVMA=${{ matrix.vma }}
168+
169+
- name: Build
170+
shell: bash
171+
working-directory: ${{ runner.workspace }}/build
172+
# Execute the build. You can specify a specific target with "--target <NAME>"
173+
run: cmake --build .
174+
175+
windows:
176+
name: ${{ matrix.config.name }}, windows-2019, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }}
90177
runs-on: windows-2019
91178
env:
92179
vulkan_sdk: "$GITHUB_WORKSPACE/vulkan_sdk/"
@@ -99,16 +186,19 @@ jobs:
99186
cc: "cl",
100187
cxx: "cl"
101188
}
102-
# note: if a specific vulkan version (e.g. 1.1.x, or < 1.2.135) needs testing, you can add it here:
103-
vulkan-sdk: ["latest", "1.2.176.1"]
104-
vma: ["OFF"]
189+
# note: if a specific vulkan version needs testing, you can add it here:
190+
vulkan-sdk: ["latest", "1.3.243.0", "1.2.198.1"]
191+
vma: ["ON", "OFF"]
192+
exclude: # exclude combinations that are known to fail
193+
- vulkan-sdk: "1.2.198.1"
194+
vma: "ON"
105195

106196
steps:
107-
# apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows
108-
- uses: actions/checkout@v2
197+
# apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows
198+
- uses: actions/checkout@v3
109199

110200
- name: Create Build Environment
111-
# apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows
201+
# apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows
112202
working-directory: ${{ runner.workspace }}/${{ github.event.repository.name }}
113203
shell: pwsh
114204
# Some projects don't allow in-source building, so create a separate build directory
@@ -121,6 +211,8 @@ jobs:
121211
curl -LS -o vulkan-sdk.exe https://sdk.lunarg.com/sdk/download/${{ matrix.vulkan-sdk }}/windows/VulkanSDK-${{ matrix.vulkan-sdk }}-Installer.exe
122212
}
123213
7z x vulkan-sdk.exe -o"${{ env.vulkan_sdk }}"
214+
mkdir "${{ env.vulkan_sdk }}Include/vma/"
215+
curl -LS -o "${{ env.vulkan_sdk }}Include/vma/vk_mem_alloc.h" https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/blob/master/include/vk_mem_alloc.h?raw=true
124216
125217
# apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows
126218
cmake -E make_directory ${{ runner.workspace }}/${{ github.event.repository.name }}/build
@@ -138,19 +230,22 @@ jobs:
138230
$env:CC="${{ matrix.config.cc }}"
139231
$env:CXX="${{ matrix.config.cxx }}"
140232
$env:Path += ";${{ env.vulkan_sdk }}\;${{ env.vulkan_sdk }}\Bin\"
233+
$env:VULKAN_SDK="${{ env.vulkan_sdk }}"
234+
$env:Vulkan_LIBRARY="${{ env.vulkan_sdk }}/Bin"
235+
$env:Vulkan_INCLUDE_DIR="${{ env.vulkan_sdk }}/Include"
141236
142237
# apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows
143238
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -Davk_LibraryType=STATIC ${{ runner.workspace }}/${{ github.event.repository.name }} -Davk_UseVMA=${{ matrix.vma }} -G "Visual Studio 16 2019" -A x64
144239
145240
- name: Build
146241
shell: bash
147-
# apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows
242+
# apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows
148243
working-directory: ${{ runner.workspace }}/${{ github.event.repository.name }}/build
149244
# Execute the build. You can specify a specific target with "--target <NAME>"
150-
run: cmake --build .
245+
run: VULKAN_SDK=${{ env.vulkan_sdk }} cmake --build . --config $BUILD_TYPE
151246

152247
windows-latest:
153-
name: ${{ matrix.config.name }}, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }}
248+
name: ${{ matrix.config.name }}, windows-latest, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }}
154249
runs-on: windows-latest
155250
env:
156251
vulkan_sdk: "$GITHUB_WORKSPACE/vulkan_sdk/"
@@ -163,16 +258,19 @@ jobs:
163258
cc: "cl",
164259
cxx: "cl"
165260
}
166-
# note: if a specific vulkan version (e.g. 1.1.x, or < 1.2.135) needs testing, you can add it here:
167-
vulkan-sdk: ["latest", "1.2.176.1"]
168-
vma: ["OFF"]
261+
# note: if a specific vulkan version needs testing, you can add it here:
262+
vulkan-sdk: ["latest", "1.3.243.0", "1.2.198.1"]
263+
vma: ["ON", "OFF"]
264+
exclude: # exclude combinations that are known to fail
265+
- vulkan-sdk: "1.2.198.1"
266+
vma: "ON"
169267

170268
steps:
171-
# apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows
172-
- uses: actions/checkout@v2
269+
# apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows
270+
- uses: actions/checkout@v3
173271

174272
- name: Create Build Environment
175-
# apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows
273+
# apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows
176274
working-directory: ${{ runner.workspace }}/${{ github.event.repository.name }}
177275
shell: pwsh
178276
# Some projects don't allow in-source building, so create a separate build directory
@@ -185,8 +283,10 @@ jobs:
185283
curl -LS -o vulkan-sdk.exe https://sdk.lunarg.com/sdk/download/${{ matrix.vulkan-sdk }}/windows/VulkanSDK-${{ matrix.vulkan-sdk }}-Installer.exe
186284
}
187285
7z x vulkan-sdk.exe -o"${{ env.vulkan_sdk }}"
286+
mkdir "${{ env.vulkan_sdk }}Include/vma/"
287+
curl -LS -o "${{ env.vulkan_sdk }}Include/vma/vk_mem_alloc.h" https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/blob/master/include/vk_mem_alloc.h?raw=true
188288
189-
# apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows
289+
# apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows
190290
cmake -E make_directory ${{ runner.workspace }}/${{ github.event.repository.name }}/build
191291
192292
- name: Configure CMake
@@ -201,14 +301,15 @@ jobs:
201301
run: |
202302
$env:CC="${{ matrix.config.cc }}"
203303
$env:CXX="${{ matrix.config.cxx }}"
304+
$env:VULKAN_SDK="${{ env.vulkan_sdk }}"
305+
$env:Vulkan_LIBRARY="${{ env.vulkan_sdk }}/Bin"
306+
$env:Vulkan_INCLUDE_DIR="${{ env.vulkan_sdk }}/Include"
204307
$env:Path += ";${{ env.vulkan_sdk }}\;${{ env.vulkan_sdk }}\Bin\"
205-
206-
# apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows
207308
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -Davk_LibraryType=STATIC ${{ runner.workspace }}/${{ github.event.repository.name }} -Davk_UseVMA=${{ matrix.vma }} -G "Visual Studio 17 2022" -A x64
208309
209310
- name: Build
210311
shell: bash
211-
# apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows
312+
# apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows
212313
working-directory: ${{ runner.workspace }}/${{ github.event.repository.name }}/build
213314
# Execute the build. You can specify a specific target with "--target <NAME>"
214-
run: cmake --build .
315+
run: cmake --build . --config $BUILD_TYPE

‎CMakeLists.txt

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
cmake_minimum_required(VERSION 3.13)
1+
cmake_minimum_required(VERSION 3.16)
22
project(avk)
33

44
if (MSVC)
55
# <ranges> support requires /std:c++latest on MSVC
6-
set(CMAKE_CXX_STANDARD 23)
7-
add_compile_options(/bigobj)
6+
set(CMAKE_CXX_STANDARD 20)
87
else (MSVC)
98
set(CMAKE_CXX_STANDARD 20)
109
endif (MSVC)

‎README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Auto-Vk v0.98.1
1+
# Auto-Vk v0.99
22

33
_Auto-Vk_ is a low-level convenience and productivity layer for the best graphics API there is, namely
44
<p align="center">
@@ -13,7 +13,7 @@ I.e., the big, important concepts, which make Vulkan as performant as it can be-
1313
# Setup
1414

1515
_Auto-Vk_ requires
16-
* A Vulkan 1.2 SDK or a Vulkan 1.3 SDK
16+
* A Vulkan 1.3 SDK
1717
* [Vulkan-Hpp](https://github.com/KhronosGroup/Vulkan-Hpp)
1818
* A C++20 compiler
1919

@@ -79,7 +79,7 @@ avk::framebuffer framebuffer = myRoot.create_framebuffer(...);
7979
avk::semaphore imageAvailableSemaphore = ...;
8080

8181
mRoot.record({
82-
avk::command::render_pass(graphicsPipeline->renderpass_reference(), framebuffer.as_reference(), {
82+
avk::command::render_pass(graphicsPipeline->renderpass_reference().value(), framebuffer.as_reference(), {
8383
avk::command::bind_pipeline(graphicsPipeline.as_reference()),
8484
avk::command::draw(3u, 1u, 0u, 0u)
8585
})

‎include/avk/attachment.hpp

+32
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,35 @@ namespace avk
6060
*/
6161
static attachment declare_for(const image_view_t& aImageView, attachment_load_config aLoadOp, subpass_usages aUsageInSubpasses, attachment_store_config aStoreOp);
6262

63+
/** Declare multisampled format of an attachment for a dynamic rendering pipeline. This attachment can only be used with pipeline that has dynamic rendering enabled.
64+
* It has fewer parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass
65+
* as opposed to being declared beforehand..
66+
* @param aFormatAndSamples Multisampled format definition: A tuple with the format of the attachment in its first element, and with the number of samples in its second element.
67+
* @param aUsage How is this attachment being used in the renderpass? In contrast to non-dynamic attachments, this usage can only contain a single subpass as such
68+
* Possible values in namespace avk::usage::
69+
* Usages for different subpasses can be defined by concatenating them using operator>>.
70+
* Example 1: avk::usage::color(0) // Indicates that this attachment is used as color attachment at location=0 in the renderpass
71+
* Example 2: avk::usage::color(2) + usage::resolve_to(3) // Indicates that this attachment is used as color attachment at location=2 in the renderpass
72+
* // Additionally, at the end of renderpass, its contents are resolved into the attachment at index 3.
73+
* Example 3: usage::unused // Indicates that this attachment is unused in the renderpass (it will only be used as a resolve target for example)
74+
*/
75+
static attachment declare_dynamic(std::tuple<vk::Format, vk::SampleCountFlagBits> aFormatAndSamples, subpass_usages aUsage);
76+
77+
/** Declare multisampled format of an attachment for a dynamic rendering pipeline. This attachment can only be used with pipeline that has dynamic rendering enabled.
78+
* It has fewer parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass
79+
* as opposed to being declared beforehand..
80+
* @param aFormat The format of the attachment
81+
*/
82+
static attachment declare_dynamic(vk::Format aFormat, subpass_usages aUsage);
83+
84+
/** Declare multisampled format of an attachment for a dynamic rendering pipeline. This attachment can only be used with pipeline that has dynamic rendering enabled.
85+
* It has fewer parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass
86+
* as opposed to being declared beforehand..
87+
* @param aImageView The format of the attachment is copied from the given image view.
88+
*/
89+
static attachment declare_dynamic_for(const image_view_t& aImageView, subpass_usages aUsage);
90+
91+
6392
attachment& set_clear_color(std::array<float, 4> aColor) { mColorClearValue = aColor; return *this; }
6493
attachment& set_depth_clear_value(float aDepthClear) { mDepthClearValue = aDepthClear; return *this; }
6594
attachment& set_stencil_clear_value(uint32_t aStencilClear) { mStencilClearValue = aStencilClear; return *this; }
@@ -88,6 +117,8 @@ namespace avk
88117
auto sample_count() const { return mSampleCount; }
89118
/** True if a multisample resolve pass shall be set up. */
90119
auto is_to_be_resolved() const { return mSubpassUsages.contains_resolve(); }
120+
/** True if this attachment is declared for dynamic rendering pipelines ie. using one of the dynamic declare functions*/
121+
bool is_for_dynamic_rendering() const { return mDynamicRenderingAttachment; }
91122

92123
/** Returns the stencil load operation */
93124
auto get_stencil_load_op() const { return mStencilLoadOperation.value_or(mLoadOperation); }
@@ -108,5 +139,6 @@ namespace avk
108139
std::array<float, 4> mColorClearValue;
109140
float mDepthClearValue;
110141
uint32_t mStencilClearValue;
142+
bool mDynamicRenderingAttachment;
111143
};
112144
}

‎include/avk/avk.hpp

+47-12
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,6 @@ namespace avk
239239
#include "avk/input_description.hpp"
240240
#include "avk/push_constants.hpp"
241241

242-
243242
#include "avk/buffer_view.hpp"
244243
#include "avk/vertex_index_buffer_pair.hpp"
245244
#include "avk/subpass_dependency.hpp"
@@ -271,6 +270,17 @@ namespace avk
271270
#include "avk/commands.hpp"
272271
#include "avk/queue.hpp"
273272

273+
// Provide the implementation of buffer_t::read (declared in buffer.hpp)
274+
namespace avk {
275+
template<typename Ret>
276+
[[nodiscard]] Ret buffer_t::read(size_t aMetaDataIndex) {
277+
auto memProps = memory_properties();
278+
Ret result;
279+
read_into(static_cast<void*>(&result), aMetaDataIndex);
280+
return result;
281+
}
282+
}
283+
274284
namespace avk
275285
{
276286
// T must provide:
@@ -711,11 +721,12 @@ namespace avk
711721
* @param aAlterConfigBeforeCreation Optional custom callback function which can be used to alter the new pipeline's config right before it is being created on the device.
712722
* @return A new graphics pipeline instance.
713723
*/
714-
graphics_pipeline create_graphics_pipeline_from_template(const graphics_pipeline_t& aTemplate, renderpass aNewRenderpass, std::optional<cfg::subpass_index> aSubpassIndex = {}, std::function<void(graphics_pipeline_t&)> aAlterConfigBeforeCreation = {});
724+
graphics_pipeline create_graphics_pipeline_from_template(const graphics_pipeline_t& aTemplate, std::optional<renderpass> aNewRenderpass, std::optional<cfg::subpass_index> aSubpassIndex = {}, std::function<void(graphics_pipeline_t&)> aAlterConfigBeforeCreation = {});
715725

716-
/** Creates a graphics pipeline based on another graphics pipeline, which serves as a template,
717-
* which either uses the same renderpass (if it has shared ownership enabled) or creates a new
718-
* renderpass internally using create_renderpass_from_template with the template's renderpass.
726+
/** Creates a graphics pipeline based on another graphics pipeline, which serves as a template, which either:
727+
* - uses the same renderpass (if it has shared ownership enabled)
728+
* - creates a new renderpass internally using create_renderpass_from_template with the template's renderpass
729+
* - uses dynamic rendering and thus does not need to create new renderpass
719730
* @param aTemplate Another, already existing graphics pipeline, which serves as a template for the newly created graphics pipeline.
720731
* @param aAlterConfigBeforeCreation Optional custom callback function which can be used to alter the new pipeline's config right before it is being created on the device.
721732
* @return A new graphics pipeline instance.
@@ -728,6 +739,7 @@ namespace avk
728739
* - cfg::pipeline_settings (flags)
729740
* - renderpass
730741
* - avk::attachment (use either attachments or renderpass!)
742+
* - avk::dynamic_rendering_attachment (only use if dynamic_rendering::enabled)
731743
* - input_binding_location_data (vertex input)
732744
* - cfg::primitive_topology
733745
* - shader_info
@@ -736,6 +748,7 @@ namespace avk
736748
* - cfg::depth_write
737749
* - cfg::viewport_depth_scissors_config
738750
* - cfg::culling_mode
751+
* - cfg::dynamic_rendering
739752
* - cfg::front_face
740753
* - cfg::polygon_drawing
741754
* - cfg::rasterizer_geometry_mode
@@ -759,17 +772,39 @@ namespace avk
759772
std::function<void(graphics_pipeline_t&)> alterConfigFunction;
760773
graphics_pipeline_config config;
761774
add_config(config, renderPassAttachments, alterConfigFunction, std::move(args)...);
762-
763-
// Check if render pass attachments are in renderPassAttachments XOR config => only in that case, it is clear how to proceed, fail in other cases
764-
if (renderPassAttachments.size() > 0 == (config.mRenderPassSubpass.has_value() && static_cast<bool>(std::get<renderpass>(*config.mRenderPassSubpass)->handle()))) {
765-
if (renderPassAttachments.size() == 0) {
766-
throw avk::runtime_error("No renderpass config provided! Please provide a renderpass or attachments!");
775+
bool hasRenderPassAttachments = false;
776+
bool hasDynamicRenderingAttachments = false;
777+
for(const auto & attachment : renderPassAttachments)
778+
{
779+
if(attachment.is_for_dynamic_rendering())
780+
{
781+
hasDynamicRenderingAttachments = true;
782+
} else {
783+
hasRenderPassAttachments = true;
767784
}
768-
throw avk::runtime_error("Ambiguous renderpass config! Either set a renderpass XOR provide attachments!");
769785
}
786+
787+
const bool hasValidRenderPass = config.mRenderPassSubpass.has_value() && static_cast<bool>(std::get<renderpass>(*config.mRenderPassSubpass)->handle());
788+
const bool isDynamicRenderingSet = config.mDynamicRendering == avk::cfg::dynamic_rendering::enabled;
789+
// Check all invalid configurations when dynamic rendering is set
790+
if (isDynamicRenderingSet )
791+
{
792+
if(hasValidRenderPass) { throw avk::runtime_error("Dynamic rendering does not accept renderpasses! They are set dynamically during rendering!"); }
793+
if(hasRenderPassAttachments) { throw avk::runtime_error("Only avk::attachments created by declare_dynamic(_for) functions are allowed when dynamic rendering is enabled!"); }
794+
if(!hasDynamicRenderingAttachments) { throw avk::runtime_error("Dynamic rendering enabled but no avk::attachmenst created by declare_dynamic(_for) functions provided! Please provide at least one attachment!"); }
795+
}
796+
// Check all invalid configurations when normal rendering (with renderpasses) is used
797+
else
798+
{
799+
if(hasValidRenderPass && hasRenderPassAttachments) { throw avk::runtime_error("Ambiguous renderpass config! Either set a renderpass OR provide attachments but not both at the same time!"); }
800+
if(!(hasValidRenderPass || hasRenderPassAttachments)) { throw avk::runtime_error("No renderpass config provided! Please provide a renderpass or attachments!"); }
801+
}
802+
770803
// ^ that was the sanity check. See if we have to build the renderpass from the attachments:
771-
if (renderPassAttachments.size() > 0) {
804+
if (hasRenderPassAttachments) {
772805
add_config(config, renderPassAttachments, alterConfigFunction, create_renderpass(std::move(renderPassAttachments)));
806+
} else {
807+
config.mDynamicRenderingAttachments = std::move(renderPassAttachments);
773808
}
774809

775810
// 2. CREATE PIPELINE according to the config

‎include/avk/buffer.hpp

+33-32
Original file line numberDiff line numberDiff line change
@@ -226,19 +226,6 @@ namespace avk
226226
*/
227227
command::action_type_command fill(const void* aDataPtr, size_t aMetaDataIndex) const;
228228

229-
// TODO: Maybe the following overload could be re-enabled after command/commands refactoring?!
230-
///** Fill buffer with data according to the meta data of the given type Meta.
231-
// * The buffer's size is determined from its metadata
232-
// * @param aDataPtr Pointer to the data to copy to the buffer. MUST point to at least enough data to fill the buffer entirely.
233-
// * @param aMetaDataSkip How often a meta data of type Meta shall be skipped. I.e. values != 0 only make sense if there ar multiple meta data entries of type Meta.
234-
// */
235-
//template <typename Meta>
236-
//std::optional<command_buffer> fill(const void* aDataPtr, size_t aMetaDataSkip, old_sync aSyncHandler)
237-
//{
238-
// assert(has_meta<Meta>(aMetaDataSkip));
239-
// return fill(aDataPtr, index_of_meta<Meta>(aMetaDataSkip), std::move(aSyncHandler));
240-
//}
241-
242229
/** Fill buffer partially with data.
243230
*
244231
* @param aDataPtr Pointer to the data to copy to the buffer
@@ -248,31 +235,45 @@ namespace avk
248235
*/
249236
command::action_type_command fill(const void* aDataPtr, size_t aMetaDataIndex, size_t aOffsetInBytes, size_t aDataSizeInBytes) const;
250237

251-
/** Read data from buffer back to the CPU-side, into some given memory.
252-
* @param aDataPtr Target memory where to write read-back data into
253-
* @param aMetaDataIndex Index of the meta data index which is used for the buffer's read-back data (size and stuff)
254-
*/
238+
/** Reads values from a buffer back into some host-side memory.
239+
* @param aDataPtr Where to store the read-back memory into.
240+
* @param aMetaDataIndex Which meta data index shall be used to determine the data size to be read back.
241+
* @return An avk::command is returned which you, generally, must send to a queue to be executed.
242+
* It could be that the returned command is empty. This will happen if the buffer's memory
243+
* is stored in a host visible memory region.
244+
*
245+
* @example Read an uint64_t back to host memory from a buffer that is backed by device-local memory,
246+
* and wait with a fence until the operation has completed:
247+
*
248+
* avk::buffer mMyBuffer = ...;
249+
* uint32_t mMyReadBackData;
250+
* context().record_and_submit_with_fence({
251+
* mMyBuffer->read_into(&mMyReadBackData, 0)
252+
* }, *mQueue)->wait_until_signalled();
253+
*/
255254
avk::command::action_type_command read_into(void* aDataPtr, size_t aMetaDataIndex) const;
256255

257256
/**
258-
* Read back data from a buffer.
257+
* Read back data from a buffer that is backed by host-visible memory.
258+
* This is a convenience overload to avk::read, and is mostly intended to be used for small amounts of data,
259+
* because the data container is allocated on the stack and returned to the caller.
260+
* Technically, every data type that can be copy-constructed is fine.
261+
* Attention: This does not support read backs from buffers backed by device-local memory, since the
262+
* result of avk::read_into is discarded.
259263
*
260-
* This is a convenience overload to avk::read.
261-
*
262-
* Example usage:
263-
* uint32_t readData = avk::read<uint32_t>(mMySsbo, avk::old_sync::not_required());
264-
* // ^ given that mMySsbo is a host-coherent buffer. If it is not, sync is required.
265-
*
266-
* @tparam Ret Specify the type of data that shall be read from the buffer (this is `uint32_t` in the example above).
267-
* @returns A value of type `Ret` which is returned by value.
264+
* @tparam Ret Specify the type of data that shall be read from the buffer
265+
* @param aMetaDataIndex Which meta data index shall be used to determine the data size to be read back.
266+
* @return The value that has been read back from the buffer's host visible memory.
267+
* The value's size is of size `Ret` and is returned by value.
268+
*
269+
* @example Read back one uint32_t value:
270+
*
271+
* avk::buffer mMyBuffer = ...;
272+
* uint32_t myData = mMyBuffer->read<uint32_t>(0);
273+
* // ^ given that mMyBuffer is a buffer backed by host visible memory and hence, does not require commands to be executed.
268274
*/
269275
template<typename Ret>
270-
[[nodiscard]] Ret read(size_t aMetaDataIndex) {
271-
auto memProps = memory_properties();
272-
Ret result;
273-
read_into(static_cast<void*>(&result), aMetaDataIndex);
274-
return result;
275-
}
276+
[[nodiscard]] Ret read(size_t aMetaDataIndex);
276277

277278
[[nodiscard]] const auto* root_ptr() const { return mRoot; }
278279

‎include/avk/commands.hpp

+460-90
Large diffs are not rendered by default.

‎include/avk/cpp_utils.hpp

+15-26
Original file line numberDiff line numberDiff line change
@@ -69,39 +69,28 @@ namespace avk
6969
}
7070

7171
/** Load a binary file into memory.
72-
* Adapted from: http://www.cplusplus.com/reference/istream/istream/read/
72+
* Adapted from: https://coniferproductions.com/posts/2022/10/25/reading-binary-files-cpp/
7373
*/
7474
static std::vector<char> load_binary_file(std::string path)
7575
{
76-
std::vector<char> buffer;
77-
std::ifstream is(path.c_str(), std::ifstream::binary);
78-
if (!is) {
79-
throw avk::runtime_error("Couldn't load file '" + path + "'");
76+
try {
77+
std::filesystem::path inputFilePath{path};
78+
auto length = std::filesystem::file_size(inputFilePath);
79+
if (length == 0) {
80+
throw avk::runtime_error("Couldn't load file '" + path + "'. It appears to be empty.");
81+
}
82+
std::vector<char> buffer(((length + 3) / 4) * 4);
83+
std::ifstream inputFile(path, std::ios_base::binary);
84+
inputFile.read(reinterpret_cast<char*>(buffer.data()), length);
85+
inputFile.close();
86+
return buffer;
8087
}
81-
82-
// get length of file:
83-
is.seekg(0, is.end);
84-
size_t length = is.tellg();
85-
is.seekg(0, is.beg);
86-
87-
buffer.resize(length);
88-
89-
// read data as a block:
90-
is.read(buffer.data(), length);
91-
92-
if (!is) {
93-
is.close();
94-
throw avk::runtime_error(
95-
"Couldn't read file '" + path + "' into buffer. " +
96-
"load_binary_file could only read " + std::to_string(is.gcount()) + " bytes instead of " + std::to_string(length)
97-
);
88+
catch (std::filesystem::filesystem_error& e)
89+
{
90+
throw avk::runtime_error("Couldn't load file '" + path + "'. Reason: " + e.what());
9891
}
99-
100-
is.close();
101-
return buffer;
10292
}
10393

104-
10594
static std::string trim_spaces(std::string_view s)
10695
{
10796
if (s.empty()) {

‎include/avk/graphics_pipeline.hpp

+21-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22
#include "avk/avk.hpp"
3+
#include <functional>
34

45
namespace avk
56
{
@@ -16,10 +17,22 @@ namespace avk
1617
graphics_pipeline_t& operator=(const graphics_pipeline_t&) = delete;
1718
~graphics_pipeline_t() = default;
1819

19-
[[nodiscard]] avk::renderpass renderpass() const { return mRenderPass; }
20-
[[nodiscard]] const avk::renderpass_t& renderpass_reference() const { return mRenderPass.get(); }
21-
auto renderpass_handle() const { return mRenderPass->handle(); }
22-
auto subpass_id() const { return mSubpassIndex; }
20+
[[nodiscard]] auto renderpass() const { return mRenderPass; }
21+
[[nodiscard]] auto renderpass_reference() const -> std::optional<std::reference_wrapper<const avk::renderpass_t>>
22+
{
23+
if(mRenderPass.has_value()) { return std::cref(mRenderPass.value().get()); }
24+
else { return std::nullopt; }
25+
}
26+
auto renderpass_handle() const -> std::optional<vk::RenderPass>
27+
{
28+
if(mRenderPass.has_value()) {return mRenderPass.value()->handle();}
29+
else {return std::nullopt;}
30+
}
31+
auto subpass_id() const -> std::optional<uint32_t>
32+
{
33+
if(mRenderPass.has_value()) {return mSubpassIndex;}
34+
else {return std::nullopt;}
35+
};
2336
auto& vertex_input_binding_descriptions() { return mOrderedVertexInputBindingDescriptions; }
2437
auto& vertex_input_attribute_descriptions() { return mVertexInputAttributeDescriptions; }
2538
auto& vertex_input_state_create_info() { return mPipelineVertexInputStateCreateInfo; }
@@ -69,7 +82,7 @@ namespace avk
6982
const auto& handle() const { return mPipeline.get(); }
7083

7184
private:
72-
avk::renderpass mRenderPass;
85+
std::optional<avk::renderpass> mRenderPass;
7386
uint32_t mSubpassIndex;
7487
// The vertex input data:
7588
std::vector<vk::VertexInputBindingDescription> mOrderedVertexInputBindingDescriptions;
@@ -85,6 +98,9 @@ namespace avk
8598
std::vector<vk::Viewport> mViewports;
8699
std::vector<vk::Rect2D> mScissors;
87100
vk::PipelineViewportStateCreateInfo mViewportStateCreateInfo;
101+
// Dynamic rendering state
102+
std::vector<vk::Format> mDynamicRenderingColorFormats;
103+
std::optional<vk::PipelineRenderingCreateInfoKHR> mRenderingCreateInfo;
88104
// Rasterization state:
89105
vk::PipelineRasterizationStateCreateInfo mRasterizationStateCreateInfo;
90106
// Depth stencil config:

‎include/avk/graphics_pipeline_config.hpp

+18-1
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ namespace avk
164164
bool mDynamicScissorEnabled;
165165
};
166166

167+
/** Dyanmic rendering*/
168+
enum struct dynamic_rendering
169+
{
170+
disabled,
171+
enabled
172+
};
173+
167174
/** Pipeline configuration data: Culling Mode */
168175
enum struct culling_mode
169176
{
@@ -609,13 +616,15 @@ namespace avk
609616

610617
cfg::pipeline_settings mPipelineSettings; // TODO: Handle settings!
611618
std::optional<std::tuple<renderpass, uint32_t>> mRenderPassSubpass;
619+
std::optional<std::vector<avk::attachment>> mDynamicRenderingAttachments;
612620
std::vector<input_binding_to_location_mapping> mInputBindingLocations;
613621
cfg::primitive_topology mPrimitiveTopology;
614622
std::vector<shader_info> mShaderInfos;
615623
std::vector<cfg::viewport_depth_scissors_config> mViewportDepthConfig;
616624
cfg::rasterizer_geometry_mode mRasterizerGeometryMode;
617625
cfg::polygon_drawing mPolygonDrawingModeAndConfig;
618626
cfg::culling_mode mCullingMode;
627+
cfg::dynamic_rendering mDynamicRendering;
619628
cfg::front_face mFrontFaceWindingOrder;
620629
cfg::depth_clamp_bias mDepthClampBiasConfig;
621630
cfg::depth_test mDepthTestConfig;
@@ -672,7 +681,7 @@ namespace avk
672681
add_config(aConfig, aAttachments, aFunc, std::move(args)...);
673682
}
674683

675-
// Add a renderpass attachment to the (temporary) attachments vector and build renderpass afterwards
684+
// Add a renderpass attachment to the (temporary) attachments vector and later build renderpass from them
676685
template <typename... Ts>
677686
void add_config(graphics_pipeline_config& aConfig, std::vector<avk::attachment>& aAttachments, std::function<void(graphics_pipeline_t&)>& aFunc, avk::attachment aAttachment, Ts... args)
678687
{
@@ -752,6 +761,14 @@ namespace avk
752761
add_config(aConfig, aAttachments, aFunc, std::move(args)...);
753762
}
754763

764+
// Set dynamic rendering
765+
template <typename... Ts>
766+
void add_config(graphics_pipeline_config& aConfig, std::vector<avk::attachment>& aAttachments, std::function<void(graphics_pipeline_t&)>& aFunc, cfg::dynamic_rendering aDynamicRendering, Ts... args)
767+
{
768+
aConfig.mDynamicRendering = aDynamicRendering;
769+
add_config(aConfig, aAttachments, aFunc, std::move(args)...);
770+
}
771+
755772
// Set the definition of front faces in the pipeline config
756773
template <typename... Ts>
757774
void add_config(graphics_pipeline_config& aConfig, std::vector<avk::attachment>& aAttachments, std::function<void(graphics_pipeline_t&)>& aFunc, cfg::front_face aFrontFace, Ts... args)

‎src/avk.cpp

+496-94
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.