Skip to content

Commit e638287

Browse files
committed
Initial commit
0 parents  commit e638287

25 files changed

+1698
-0
lines changed

.clang-format

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
BasedOnStyle: LLVM
2+
AllowShortIfStatementsOnASingleLine: WithoutElse
3+
ContinuationIndentWidth: 2
4+
SortIncludes: 'false'
5+
IndentPPDirectives: AfterHash

.gitignore

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Prerequisites
2+
*.d
3+
4+
# Compiled Object files
5+
*.slo
6+
*.lo
7+
*.o
8+
*.obj
9+
10+
# Precompiled Headers
11+
*.gch
12+
*.pch
13+
14+
# Compiled Dynamic libraries
15+
*.so
16+
*.dylib
17+
*.dll
18+
19+
# Fortran module files
20+
*.mod
21+
*.smod
22+
23+
# Compiled Static libraries
24+
*.lai
25+
*.la
26+
*.a
27+
*.lib
28+
29+
# Executables
30+
*.exe
31+
*.out
32+
*.app
33+
34+
#
35+
/build/*

CMakeLists.txt

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
cmake_minimum_required(VERSION 3.20)
2+
3+
if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
4+
set(CMAKE_TOOLCHAIN_FILE
5+
"$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
6+
CACHE STRING "")
7+
endif()
8+
message(STATUS "TOOLCHAIN: ${CMAKE_TOOLCHAIN_FILE}")
9+
10+
project(FrameGraph)
11+
if(PROJECT_BINARY_DIR STREQUAL PROJECT_SOURCE_DIR)
12+
message(
13+
FATAL_ERROR
14+
"In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there."
15+
)
16+
endif()
17+
18+
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
19+
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
20+
21+
set(CMAKE_CXX_STANDARD 20)
22+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
23+
set(CMAKE_CXX_EXTENSIONS OFF)
24+
25+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") # .lib
26+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") # .dll
27+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") # .exe
28+
29+
option(BUILD_SHARED_LIBS "Use shared libraries" OFF)
30+
set(BUILD_TESTING ON)
31+
endif()
32+
33+
add_library(
34+
FrameGraph
35+
"include/fg/TypeTraits.hpp"
36+
"include/fg/FrameGraphResource.hpp"
37+
"include/fg/FrameGraph.hpp"
38+
"include/fg/FrameGraph.inl"
39+
"include/fg/GraphNode.hpp"
40+
"include/fg/PassNode.hpp"
41+
"include/fg/PassEntry.hpp"
42+
"include/fg/ResourceNode.hpp"
43+
"include/fg/ResourceEntry.hpp"
44+
"include/fg/ResourceEntry.inl"
45+
"include/fg/Blackboard.hpp"
46+
"include/fg/Blackboard.inl"
47+
"src/FrameGraph.cpp"
48+
"src/GraphNode.cpp"
49+
"src/PassNode.cpp"
50+
"src/ResourceNode.cpp"
51+
"src/ResourceEntry.cpp")
52+
53+
target_include_directories(
54+
FrameGraph
55+
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
56+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
57+
58+
add_library(fg::FrameGraph ALIAS FrameGraph)
59+
60+
if(BUILD_TESTING)
61+
enable_testing()
62+
add_subdirectory(tests)
63+
endif()
64+
65+
include(GNUInstallDirs)
66+
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/fg
67+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Dawid Kurek
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# FrameGraph
2+
3+
[![CodeFactor](https://www.codefactor.io/repository/github/skaarj1989/framegraph/badge)](https://www.codefactor.io/repository/github/skaarj1989/framegraph)
4+
![GitHub](https://img.shields.io/github/license/skaarj1989/FrameGraph.svg)
5+
6+
This is a renderer agnostic implementation of **FrameGraph**, inspired by the **GDC** presentation:
7+
[_FrameGraph: Extensible Rendering Architecture in Frostbite_](https://www.gdcvault.com/play/1024045/FrameGraph-Extensible-Rendering-Architecture-in) by Yuriy O'Donnell
8+
9+
## How to use?
10+
11+
### Basic
12+
13+
```cpp
14+
#include "fg/FrameGraph.hpp"
15+
16+
void renderFrame() {
17+
FrameGraph fg;
18+
19+
struct PassData {
20+
FrameGraphResource target;
21+
};
22+
fg.addCallbackPass<PassData>("SimplePass",
23+
[&](FrameGraph::Builder &builder, PassData &data) {
24+
data.target = builder.create<FrameGraphTexture>("Foo", { 1280, 720 });
25+
data.target = builder.write(data.target);
26+
},
27+
[=](const PassData &data, FrameGraphPassResources &resources, void *) {
28+
auto &texture = resources.get<FrameGraphTexture>(data.target);
29+
// ...
30+
}
31+
);
32+
33+
fg.compile();
34+
fg.execute(&renderContext);
35+
}
36+
```
37+
38+
### Blackboard
39+
40+
Communication between modules
41+
42+
```cpp
43+
#include "fg/FrameGraph.hpp"
44+
#include "fg/Blackboard.hpp"
45+
46+
struct GBufferData {
47+
FrameGraphResource depth;
48+
FrameGraphResource normal;
49+
FrameGraphResource albedo;
50+
};
51+
GBufferPass::GBufferPass(FrameGraph &fg, FrameGraphBlackboard &blackboard,
52+
std::span<const Renderable> renderables) {
53+
blackboard.add<GBufferData>() = fg.addCallbackPass<GBufferData>(
54+
"GBuffer Pass",
55+
[&](FrameGraph::Builder &builder, GBufferData &data) {
56+
data.depth = builder.create<FrameGraphTexture>(
57+
"SceneDepth", {/* extent, pixelFormat ... */});
58+
data.depth = builder.write(data.depth);
59+
60+
data.normal = builder.create<FrameGraphTexture>("Normal", {});
61+
data.normal = builder.write(data.normal);
62+
63+
data.albedo = builder.create<FrameGraphTexture>("Albedo", {});
64+
data.albedo = builder.write(data.albedo);
65+
},
66+
[=](const GBufferData &data, FrameGraphPassResources &resources,
67+
void *ctx) {
68+
auto &rc = *static_cast<RenderContext *>(ctx);
69+
rc.beginRenderPass({
70+
resources.get<FrameGraphTexture>(data.depth),
71+
resources.get<FrameGraphTexture>(data.normal),
72+
resources.get<FrameGraphTexture>(data.albedo),
73+
});
74+
for (const auto &renderable : renderables)
75+
drawMesh(rc, renderable.mesh, renderable.material);
76+
rc.endRenderPass();
77+
});
78+
}
79+
80+
struct SceneColorData {
81+
FrameGraphResource hdr;
82+
};
83+
DeferredLightingPass::DeferredLightingPass(FrameGraph &fg,
84+
FrameGraphBlackboard &blackboard) {
85+
const auto &gBuffer = blackboard.get<GBufferData>();
86+
87+
blackboard.add<SceneColorData>() = fg.addCallbackPass<SceneColorData>(
88+
"GBuffer Pass",
89+
[&](FrameGraph::Builder &builder, SceneColorData &data) {
90+
builder.read(gBuffer.depth);
91+
builder.read(gBuffer.normal);
92+
builder.read(gBuffer.albedo);
93+
94+
data.hdr = builder.create<FrameGraphTexture>("SceneColor", {});
95+
data.hdr = builder.write(data.hdr);
96+
},
97+
[=](const SceneColorData &data, FrameGraphPassResources &resources,
98+
void *ctx) {
99+
auto &rc = *static_cast<RenderContext *>(ctx);
100+
rc.beginRenderPass({resources.get<FrameGraphTexture>(data.hdr)})
101+
.bindTextures({
102+
resources.get<FrameGraphTexture>(gBuffer.depth),
103+
resources.get<FrameGraphTexture>(gBuffer.normal),
104+
resources.get<FrameGraphTexture>(gBuffer.albedo),
105+
})
106+
.drawFullScreenQuad()
107+
.endRenderPass();
108+
});
109+
}
110+
111+
void renderFrame(std::span<const Renderable> renderables) {
112+
FrameGraph fg;
113+
FrameGraphBlackboard blackboard;
114+
115+
GBufferPass{fg, blackboard, renderables};
116+
DeferredLightingPass{fg, blackboard};
117+
118+
fg.compile();
119+
fg.execute(&renderContext);
120+
}
121+
```
122+
123+
### Visualization
124+
125+
```cpp
126+
std::ofstream{"fg.dot"} << fg;
127+
```
128+
129+
![graph](media/deferred_pipeline.svg)
130+
_(Graph created by one of tests)_
131+
132+
### Resources
133+
134+
To integrate a resource with **FrameGraph**, the following requirements should be met.
135+
**T** is a type meeting the requirements of **FrameGraph** resource.
136+
137+
| Expression | Type | Description |
138+
| --------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------- |
139+
| <pre lang="cpp">T{}</pre> | <pre lang="cpp">T</pre> | Is default/move constructible. |
140+
| <pre lang="cpp">T::Desc</pre> | <pre lang="cpp">struct</pre> | Resource descriptor. |
141+
| <pre lang="cpp">T::create</pre> | <pre lang="cpp">void(const T::Desc &, void \*)</pre> | A function used by implementation to create transient resource. |
142+
| <pre lang="cpp">T::destroy</pre> | <pre lang="cpp">void(const T::Dest &, void \*)</pre> | A function used by implementation to destroy transient resource. |
143+
| <pre lang="cpp">T::toString</pre> | <pre lang="cpp">std::string(const T::Desc &)<pre> | _(optional)_<br/>Static function used to embed resource descriptor inside graph node. |
144+
145+
## Installation
146+
147+
```bash
148+
git submodule init
149+
git submodule add https://github.com/skaarj1989/FrameGraph.git extern/FrameGraph
150+
```
151+
152+
```cmake
153+
add_subdirectory(extern/FrameGraph)
154+
target_link_libraries(YourProject PRIVATE fg::FrameGraph)
155+
```
156+
157+
Another possibility is to use [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html):
158+
159+
```cmake
160+
include(FetchContent)
161+
162+
FetchContent_Declare(
163+
FrameGraph
164+
GIT_REPOSITORY https://github.com/skaarj1989/FrameGraph.git
165+
GIT_TAG master)
166+
FetchContent_MakeAvailable(FrameGraph)
167+
168+
target_link_libraries(YourProject PRIVATE fg::FrameGraph)
169+
```
170+
171+
## Example
172+
173+
Coming soon ...
174+
175+
## License
176+
177+
[MIT](LICENSE)

include/fg/Blackboard.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#pragma once
2+
3+
#include <typeindex>
4+
#include <any>
5+
#include <unordered_map>
6+
7+
class FrameGraphBlackboard {
8+
public:
9+
FrameGraphBlackboard() = default;
10+
FrameGraphBlackboard(const FrameGraphBlackboard &) = delete;
11+
FrameGraphBlackboard(FrameGraphBlackboard &&) noexcept = default;
12+
~FrameGraphBlackboard() = default;
13+
14+
FrameGraphBlackboard &operator=(const FrameGraphBlackboard &) = delete;
15+
FrameGraphBlackboard &operator=(FrameGraphBlackboard &&) noexcept = default;
16+
17+
template <typename T, typename... Args> T &add(Args &&...args);
18+
19+
template <typename T> [[nodiscard]] T &get();
20+
template <typename T> [[nodiscard]] T *try_get();
21+
22+
template <typename T> [[nodiscard]] bool has() const;
23+
24+
private:
25+
std::unordered_map<std::type_index, std::any> m_storage;
26+
};
27+
28+
#include "fg/Blackboard.inl"

include/fg/Blackboard.inl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include <cassert>
2+
3+
template <typename T, typename... Args>
4+
inline T &FrameGraphBlackboard::add(Args &&...args) {
5+
assert(!has<T>());
6+
return m_storage[typeid(T)].emplace<T>(T{std::forward<Args>(args)...});
7+
}
8+
9+
template <typename T> inline T &FrameGraphBlackboard::get() {
10+
assert(has<T>());
11+
return std::any_cast<T &>(m_storage[typeid(T)]);
12+
}
13+
template <typename T> inline T *FrameGraphBlackboard::try_get() {
14+
auto it = m_storage.find(typeid(T));
15+
return it != m_storage.cend() ? std::any_cast<T>(&it->second) : nullptr;
16+
}
17+
18+
template <typename T> inline bool FrameGraphBlackboard::has() const {
19+
if constexpr (_HAS_CXX20)
20+
return m_storage.contains(typeid(T));
21+
else
22+
return m_storage.find(typeid(T)) != m_storage.cend();
23+
}

0 commit comments

Comments
 (0)