https://github.com/skaarj1989/framegraph
Renderer agnostic frame graph library
https://github.com/skaarj1989/framegraph
cpp20 framegraph gamedev graphics-programming rendergraph rendering
Last synced: about 2 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 (over 3 years ago)
- Default Branch: master
- Last Pushed: 2024-01-01T12:26:28.000Z (almost 2 years ago)
- Last Synced: 2024-12-11T02:22:09.246Z (10 months 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)