https://github.com/skaarj1989/framegraph
Renderer agnostic frame graph library
https://github.com/skaarj1989/framegraph
cpp20 framegraph gamedev graphics-programming rendergraph rendering
Last synced: 7 months ago
JSON representation
Renderer agnostic frame graph library
- Host: GitHub
- URL: https://github.com/skaarj1989/framegraph
- Owner: skaarj1989
- License: mit
- Created: 2022-02-09T12:55:42.000Z (about 4 years ago)
- Default Branch: master
- Last Pushed: 2024-01-01T12:26:28.000Z (about 2 years ago)
- Last Synced: 2024-12-11T02:22:09.246Z (over 1 year ago)
- Topics: cpp20, framegraph, gamedev, graphics-programming, rendergraph, rendering
- Language: C++
- Homepage:
- Size: 110 KB
- Stars: 157
- Watchers: 4
- Forks: 16
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# FrameGraph
[](https://www.codefactor.io/repository/github/skaarj1989/framegraph)

This is a renderer agnostic implementation of **FrameGraph**, inspired by the **GDC** presentation:
[_FrameGraph: Extensible Rendering Architecture in Frostbite_](https://www.gdcvault.com/play/1024045/FrameGraph-Extensible-Rendering-Architecture-in) by Yuriy O'Donnell
## Table of contents
- [FrameGraph](#framegraph)
- [Table of contents](#table-of-contents)
- [How to use?](#how-to-use)
- [Resources](#resources)
- [Basic](#basic)
- [Blackboard](#blackboard)
- [Automatic resource bindings and barriers](#automatic-resource-bindings-and-barriers)
- [Visualization](#visualization)
- [Custom writer](#custom-writer)
- [Visualization tool](#visualization-tool)
- [Installation](#installation)
- [Example](#example)
- [License](#license)
## How to use?
### Resources
To integrate a resource with **FrameGraph**, the following requirements should be met.
**T** is a type meeting the requirements of **FrameGraph** resource.
| Expression | Type | Description |
| --------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
T{} | T
| Is default/move constructible. |
| T::Desc
| struct
| Resource descriptor. |
| T::create
| void(const T::Desc &, void \*)
| A function used by implementation to create transient resource. |
| T::destroy
| void(const T::Desc &, void \*)
| A function used by implementation to destroy transient resource. |
| T::preRead
| void(const T::Desc &, uint32_t flags, void \*context)
| _(optional)_
A function called before an execution lambda of a pass. |
| T::preWrite
| void(const T::Desc &, uint32_t flags, void \*context)
| _(optional)_
A function called before an execution lambda of a pass. |
| T::toString
| std::string(const T::Desc &) | _(optional)_
Static function used to embed resource descriptor inside graph node. |
### Basic
```cpp
#include "fg/FrameGraph.hpp"
void renderFrame() {
FrameGraph fg;
struct PassData {
FrameGraphResource target;
};
fg.addCallbackPass("SimplePass",
[&](FrameGraph::Builder &builder, PassData &data) {
data.target = builder.create("Foo", { 1280, 720 });
data.target = builder.write(data.target);
},
[=](const PassData &data, FrameGraphPassResources &resources, void *) {
auto &texture = resources.get(data.target);
// ...
}
);
fg.compile();
fg.execute(&renderContext);
}
```
### Blackboard
Communication between modules
```cpp
#include "fg/FrameGraph.hpp"
#include "fg/Blackboard.hpp"
struct GBufferData {
FrameGraphResource depth;
FrameGraphResource normal;
FrameGraphResource albedo;
};
GBufferPass::GBufferPass(FrameGraph &fg, FrameGraphBlackboard &blackboard,
std::span renderables) {
blackboard.add() = fg.addCallbackPass(
"GBuffer Pass",
[&](FrameGraph::Builder &builder, GBufferData &data) {
data.depth = builder.create(
"SceneDepth", {/* extent, pixelFormat ... */});
data.depth = builder.write(data.depth);
data.normal = builder.create("Normal", {});
data.normal = builder.write(data.normal);
data.albedo = builder.create("Albedo", {});
data.albedo = builder.write(data.albedo);
},
[=](const GBufferData &data, FrameGraphPassResources &resources,
void *ctx) {
auto &rc = *static_cast(ctx);
rc.beginRenderPass({
resources.get(data.depth),
resources.get(data.normal),
resources.get(data.albedo),
});
for (const auto &renderable : renderables)
drawMesh(rc, renderable.mesh, renderable.material);
rc.endRenderPass();
});
}
struct SceneColorData {
FrameGraphResource hdr;
};
DeferredLightingPass::DeferredLightingPass(FrameGraph &fg,
FrameGraphBlackboard &blackboard) {
const auto &gBuffer = blackboard.get();
blackboard.add() = fg.addCallbackPass(
"GBuffer Pass",
[&](FrameGraph::Builder &builder, SceneColorData &data) {
builder.read(gBuffer.depth);
builder.read(gBuffer.normal);
builder.read(gBuffer.albedo);
data.hdr = builder.create("SceneColor", {});
data.hdr = builder.write(data.hdr);
},
[=](const SceneColorData &data, FrameGraphPassResources &resources,
void *ctx) {
auto &rc = *static_cast(ctx);
rc.beginRenderPass({resources.get(data.hdr)})
.bindTextures({
resources.get(gBuffer.depth),
resources.get(gBuffer.normal),
resources.get(gBuffer.albedo),
})
.drawFullScreenQuad()
.endRenderPass();
});
}
void renderFrame(std::span renderables) {
FrameGraph fg;
FrameGraphBlackboard blackboard;
GBufferPass{fg, blackboard, renderables};
DeferredLightingPass{fg, blackboard};
fg.compile();
fg.execute(&renderContext);
}
```
### Automatic resource bindings and barriers
Implement `preRead/preWrite` in a resource struct.
_Code snippets taken from my Vulkan renderer_
```cpp
// For convenience, use an implicit conversion operator.
struct Attachment /* 21 bits */ {
uint32_t index{0};
std::optional layer;
std::optional face;
std::optional clearValue;
operator uint32_t() const;
};
Attachment decodeAttachment(uint32_t flags);
struct Location /* 7 bits */ {
uint32_t set{0};
uint32_t binding{0};
operator uint32_t() const;
};
Location decodeLocation(uint32_t flags);
struct BindingInfo /* 13 bits */ {
Location location;
uint32_t pipelineStage{0};
operator uint32_t() const;
};
BindingInfo decodeBindingInfo(uint32_t flags);
struct TextureRead /* 15 bits */ {
BindingInfo binding;
enum class Type { CombinedImageSampler, SampledImage, StorageImage }; // 2 bits
Type type;
operator uint32_t() const;
};
TextureRead decodeTextureRead(uint32_t flags);
```
```cpp
struct FrameGraphTexture {
struct Desc { /* extent, pixel format ... */ };
void preRead(const Desc &desc, uint32_t flags, void *ctx) {
auto &rc = *static_cast(ctx);
// Decode flags, build DescriptorSet tables, insert barriers
}
void preWrite(const Desc &desc, uint32_t flags, void *ctx) {
auto &rc = *static_cast(ctx);
// Decode flags, build attachments (e.g VkRenderingInfo), insert barriers
}
};
```
```cpp
struct Data {
FrameGraphResource output;
};
fg.addCallbackPass(
"FXAA",
[&](FrameGraph::Builder &builder, Data &data) {
builder.read(input, TextureRead{
.binding =
{
.location = {.set = 2, .binding = 0},
.pipelineStage = PipelineStage_FragmentShader,
},
.type = TextureRead::Type::CombinedImageSampler,
});
const auto &inputDesc = fg.getDescriptor(input);
data.output = builder.create("AA", inputDesc);
data.output = builder.write(data.output, Attachment{.index = 0});
},
[=](const Data &, const FrameGraphPassResources &, void *ctx) {
auto &rc = *static_cast(ctx);
renderFullScreenPostProcess(rc);
});
```
### Visualization
```cpp
// Built in graphviz writer.
std::ofstream{"fg.dot"} << fg;
```

_(Graph created by one of tests)_
#### Custom writer
Implement a struct with the following methods:
```cpp
struct JsonWriter {
nlohmann::json j;
void operator()(const PassNode &node,
const std::vector &resourceNodes) {
// ...
}
void operator()(const ResourceNode &node, const ResourceEntry &entry,
const std::vector &passNodes) {
// ...
}
void flush(std::ostream &os) const { os << std::setw(2) << j << "\n"; }
};
```
```cpp
std::ofstream f{"fg.json"};
fg.debugOutput(f, JsonWriter{});
```
#### Visualization tool
https://skaarj1989.github.io/FrameGraph/

_(see [viewer](https://github.com/skaarj1989/FrameGraph/tree/viewer) branch)_
## Installation
```bash
git submodule init
git submodule add https://github.com/skaarj1989/FrameGraph.git extern/FrameGraph
```
```cmake
add_subdirectory(extern/FrameGraph)
target_link_libraries(YourProject PRIVATE fg::FrameGraph)
```
Another possibility is to use [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html):
```cmake
include(FetchContent)
FetchContent_Declare(
FrameGraph
GIT_REPOSITORY https://github.com/skaarj1989/FrameGraph.git
GIT_TAG master)
FetchContent_MakeAvailable(FrameGraph)
target_link_libraries(YourProject PRIVATE fg::FrameGraph)
```
## Example
https://github.com/skaarj1989/FrameGraph-Example
## License
[MIT](LICENSE)