{"id":18853717,"url":"https://github.com/skaarj1989/framegraph","last_synced_at":"2025-08-21T08:31:35.587Z","repository":{"id":50430336,"uuid":"457358340","full_name":"skaarj1989/FrameGraph","owner":"skaarj1989","description":"Renderer agnostic frame graph library","archived":false,"fork":false,"pushed_at":"2024-01-01T12:26:28.000Z","size":113,"stargazers_count":157,"open_issues_count":0,"forks_count":16,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-12-11T02:22:09.246Z","etag":null,"topics":["cpp20","framegraph","gamedev","graphics-programming","rendergraph","rendering"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skaarj1989.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-02-09T12:55:42.000Z","updated_at":"2024-12-09T08:32:58.000Z","dependencies_parsed_at":"2023-02-09T03:15:36.533Z","dependency_job_id":"478a46bd-0e50-46ed-ab6c-cb0552a35d95","html_url":"https://github.com/skaarj1989/FrameGraph","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skaarj1989%2FFrameGraph","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skaarj1989%2FFrameGraph/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skaarj1989%2FFrameGraph/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skaarj1989%2FFrameGraph/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skaarj1989","download_url":"https://codeload.github.com/skaarj1989/FrameGraph/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230501172,"owners_count":18236061,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp20","framegraph","gamedev","graphics-programming","rendergraph","rendering"],"created_at":"2024-11-08T03:45:24.255Z","updated_at":"2024-12-19T21:10:28.061Z","avatar_url":"https://github.com/skaarj1989.png","language":"C++","readme":"# FrameGraph\n\n[![CodeFactor](https://www.codefactor.io/repository/github/skaarj1989/framegraph/badge)](https://www.codefactor.io/repository/github/skaarj1989/framegraph)\n![GitHub](https://img.shields.io/github/license/skaarj1989/FrameGraph.svg)\n\nThis is a renderer agnostic implementation of **FrameGraph**, inspired by the **GDC** presentation:\n[_FrameGraph: Extensible Rendering Architecture in Frostbite_](https://www.gdcvault.com/play/1024045/FrameGraph-Extensible-Rendering-Architecture-in) by Yuriy O'Donnell\n\n## Table of contents\n\n- [FrameGraph](#framegraph)\n  - [Table of contents](#table-of-contents)\n  - [How to use?](#how-to-use)\n    - [Resources](#resources)\n    - [Basic](#basic)\n    - [Blackboard](#blackboard)\n    - [Automatic resource bindings and barriers](#automatic-resource-bindings-and-barriers)\n    - [Visualization](#visualization)\n      - [Custom writer](#custom-writer)\n      - [Visualization tool](#visualization-tool)\n  - [Installation](#installation)\n  - [Example](#example)\n  - [License](#license)\n\n## How to use?\n\n### Resources\n\nTo integrate a resource with **FrameGraph**, the following requirements should be met.\n**T** is a type meeting the requirements of **FrameGraph** resource.\n\n| Expression                        | Type                                                                        | Description                                                                           |\n| --------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |\n| \u003cpre lang=\"cpp\"\u003eT{}\u003c/pre\u003e         | \u003cpre lang=\"cpp\"\u003eT\u003c/pre\u003e                                                     | Is default/move constructible.                                                        |\n| \u003cpre lang=\"cpp\"\u003eT::Desc\u003c/pre\u003e     | \u003cpre lang=\"cpp\"\u003estruct\u003c/pre\u003e                                                | Resource descriptor.                                                                  |\n| \u003cpre lang=\"cpp\"\u003eT::create\u003c/pre\u003e   | \u003cpre lang=\"cpp\"\u003evoid(const T::Desc \u0026, void \\*)\u003c/pre\u003e                        | A function used by implementation to create transient resource.                       |\n| \u003cpre lang=\"cpp\"\u003eT::destroy\u003c/pre\u003e  | \u003cpre lang=\"cpp\"\u003evoid(const T::Desc \u0026, void \\*)\u003c/pre\u003e                        | A function used by implementation to destroy transient resource.                      |\n| \u003cpre lang=\"cpp\"\u003eT::preRead\u003c/pre\u003e  | \u003cpre lang=\"cpp\"\u003evoid(const T::Desc \u0026, uint32_t flags, void \\*context)\u003c/pre\u003e | _(optional)_\u003cbr/\u003eA function called before an execution lambda of a pass.              |\n| \u003cpre lang=\"cpp\"\u003eT::preWrite\u003c/pre\u003e | \u003cpre lang=\"cpp\"\u003evoid(const T::Desc \u0026, uint32_t flags, void \\*context)\u003c/pre\u003e | _(optional)_\u003cbr/\u003eA function called before an execution lambda of a pass.              |\n| \u003cpre lang=\"cpp\"\u003eT::toString\u003c/pre\u003e | \u003cpre lang=\"cpp\"\u003estd::string(const T::Desc \u0026)\u003cpre\u003e                           | _(optional)_\u003cbr/\u003eStatic function used to embed resource descriptor inside graph node. |\n\n### Basic\n\n```cpp\n#include \"fg/FrameGraph.hpp\"\n\nvoid renderFrame() {\n  FrameGraph fg;\n\n  struct PassData {\n    FrameGraphResource target;\n  };\n  fg.addCallbackPass\u003cPassData\u003e(\"SimplePass\",\n    [\u0026](FrameGraph::Builder \u0026builder, PassData \u0026data) {\n      data.target = builder.create\u003cFrameGraphTexture\u003e(\"Foo\", { 1280, 720 });\n      data.target = builder.write(data.target);\n    },\n    [=](const PassData \u0026data, FrameGraphPassResources \u0026resources, void *) {\n      auto \u0026texture = resources.get\u003cFrameGraphTexture\u003e(data.target);\n      // ...\n    }\n  );\n\n  fg.compile();\n  fg.execute(\u0026renderContext);\n}\n```\n\n### Blackboard\n\nCommunication between modules\n\n```cpp\n#include \"fg/FrameGraph.hpp\"\n#include \"fg/Blackboard.hpp\"\n\nstruct GBufferData {\n  FrameGraphResource depth;\n  FrameGraphResource normal;\n  FrameGraphResource albedo;\n};\nGBufferPass::GBufferPass(FrameGraph \u0026fg, FrameGraphBlackboard \u0026blackboard,\n                         std::span\u003cconst Renderable\u003e renderables) {\n  blackboard.add\u003cGBufferData\u003e() = fg.addCallbackPass\u003cGBufferData\u003e(\n    \"GBuffer Pass\",\n    [\u0026](FrameGraph::Builder \u0026builder, GBufferData \u0026data) {\n      data.depth = builder.create\u003cFrameGraphTexture\u003e(\n        \"SceneDepth\", {/* extent, pixelFormat ... */});\n      data.depth = builder.write(data.depth);\n\n      data.normal = builder.create\u003cFrameGraphTexture\u003e(\"Normal\", {});\n      data.normal = builder.write(data.normal);\n\n      data.albedo = builder.create\u003cFrameGraphTexture\u003e(\"Albedo\", {});\n      data.albedo = builder.write(data.albedo);\n    },\n    [=](const GBufferData \u0026data, FrameGraphPassResources \u0026resources,\n        void *ctx) {\n      auto \u0026rc = *static_cast\u003cRenderContext *\u003e(ctx);\n      rc.beginRenderPass({\n        resources.get\u003cFrameGraphTexture\u003e(data.depth),\n        resources.get\u003cFrameGraphTexture\u003e(data.normal),\n        resources.get\u003cFrameGraphTexture\u003e(data.albedo),\n      });\n      for (const auto \u0026renderable : renderables)\n        drawMesh(rc, renderable.mesh, renderable.material);\n      rc.endRenderPass();\n    });\n}\n\nstruct SceneColorData {\n  FrameGraphResource hdr;\n};\nDeferredLightingPass::DeferredLightingPass(FrameGraph \u0026fg,\n                                           FrameGraphBlackboard \u0026blackboard) {\n  const auto \u0026gBuffer = blackboard.get\u003cGBufferData\u003e();\n\n  blackboard.add\u003cSceneColorData\u003e() = fg.addCallbackPass\u003cSceneColorData\u003e(\n    \"GBuffer Pass\",\n    [\u0026](FrameGraph::Builder \u0026builder, SceneColorData \u0026data) {\n      builder.read(gBuffer.depth);\n      builder.read(gBuffer.normal);\n      builder.read(gBuffer.albedo);\n\n      data.hdr = builder.create\u003cFrameGraphTexture\u003e(\"SceneColor\", {});\n      data.hdr = builder.write(data.hdr);\n    },\n    [=](const SceneColorData \u0026data, FrameGraphPassResources \u0026resources,\n        void *ctx) {\n      auto \u0026rc = *static_cast\u003cRenderContext *\u003e(ctx);\n      rc.beginRenderPass({resources.get\u003cFrameGraphTexture\u003e(data.hdr)})\n        .bindTextures({\n          resources.get\u003cFrameGraphTexture\u003e(gBuffer.depth),\n          resources.get\u003cFrameGraphTexture\u003e(gBuffer.normal),\n          resources.get\u003cFrameGraphTexture\u003e(gBuffer.albedo),\n        })\n        .drawFullScreenQuad()\n        .endRenderPass();\n    });\n}\n\nvoid renderFrame(std::span\u003cconst Renderable\u003e renderables) {\n  FrameGraph fg;\n  FrameGraphBlackboard blackboard;\n\n  GBufferPass{fg, blackboard, renderables};\n  DeferredLightingPass{fg, blackboard};\n\n  fg.compile();\n  fg.execute(\u0026renderContext);\n}\n```\n\n### Automatic resource bindings and barriers\n\nImplement `preRead/preWrite` in a resource struct.\n\n_Code snippets taken from my Vulkan renderer_\n\n```cpp\n// For convenience, use an implicit conversion operator.\n\nstruct Attachment /* 21 bits */ {\n  uint32_t index{0};\n  std::optional\u003cuint32_t\u003e layer;\n  std::optional\u003cuint32_t\u003e face;\n  std::optional\u003cClearValue\u003e clearValue;\n\n  operator uint32_t() const;\n};\nAttachment decodeAttachment(uint32_t flags);\n\nstruct Location /* 7 bits */ {\n  uint32_t set{0};\n  uint32_t binding{0};\n\n  operator uint32_t() const;\n};\nLocation decodeLocation(uint32_t flags);\n\nstruct BindingInfo /* 13 bits */ {\n  Location location;\n  uint32_t pipelineStage{0};\n\n  operator uint32_t() const;\n};\nBindingInfo decodeBindingInfo(uint32_t flags);\n\nstruct TextureRead /* 15 bits */ {\n  BindingInfo binding;\n\n  enum class Type { CombinedImageSampler, SampledImage, StorageImage }; // 2 bits\n  Type type;\n\n  operator uint32_t() const;\n};\nTextureRead decodeTextureRead(uint32_t flags);\n```\n\n```cpp\nstruct FrameGraphTexture {\n  struct Desc { /* extent, pixel format ... */ };\n\n  void preRead(const Desc \u0026desc, uint32_t flags, void *ctx) {\n    auto \u0026rc = *static_cast\u003cRenderContext *\u003e(ctx);\n    // Decode flags, build DescriptorSet tables, insert barriers\n  }\n  void preWrite(const Desc \u0026desc, uint32_t flags, void *ctx) {\n    auto \u0026rc = *static_cast\u003cRenderContext *\u003e(ctx);\n    // Decode flags, build attachments (e.g VkRenderingInfo), insert barriers\n  }\n};\n```\n\n```cpp\nstruct Data {\n  FrameGraphResource output;\n};\nfg.addCallbackPass\u003cData\u003e(\n  \"FXAA\",\n  [\u0026](FrameGraph::Builder \u0026builder, Data \u0026data) {\n    builder.read(input, TextureRead{\n                          .binding =\n                            {\n                              .location = {.set = 2, .binding = 0},\n                              .pipelineStage = PipelineStage_FragmentShader,\n                            },\n                          .type = TextureRead::Type::CombinedImageSampler,\n                        });\n\n    const auto \u0026inputDesc = fg.getDescriptor\u003cFrameGraphTexture\u003e(input);\n    data.output = builder.create\u003cFrameGraphTexture\u003e(\"AA\", inputDesc);\n    data.output = builder.write(data.output, Attachment{.index = 0});\n  },\n  [=](const Data \u0026, const FrameGraphPassResources \u0026, void *ctx) {\n    auto \u0026rc = *static_cast\u003cRenderContext *\u003e(ctx);\n    renderFullScreenPostProcess(rc);\n  });\n```\n\n### Visualization\n\n```cpp\n// Built in graphviz writer.\nstd::ofstream{\"fg.dot\"} \u003c\u003c fg;\n```\n\n![graph](media/deferred_pipeline.svg)\n_(Graph created by one of tests)_\n\n#### Custom writer\n\nImplement a struct with the following methods:\n\n```cpp\nstruct JsonWriter {\n  nlohmann::json j;\n\n  void operator()(const PassNode \u0026node,\n                  const std::vector\u003cResourceNode\u003e \u0026resourceNodes) {\n    // ...\n  }\n  void operator()(const ResourceNode \u0026node, const ResourceEntry \u0026entry,\n                  const std::vector\u003cPassNode\u003e \u0026passNodes) {\n    // ...\n  }\n\n  void flush(std::ostream \u0026os) const { os \u003c\u003c std::setw(2) \u003c\u003c j \u003c\u003c \"\\n\"; }\n};\n```\n\n```cpp\nstd::ofstream f{\"fg.json\"};\nfg.debugOutput(f, JsonWriter{});\n```\n\n#### Visualization tool\n\nhttps://skaarj1989.github.io/FrameGraph/\n\n![viewer](media/viewer.png)\n_(see [viewer](https://github.com/skaarj1989/FrameGraph/tree/viewer) branch)_\n\n## Installation\n\n```bash\ngit submodule init\ngit submodule add https://github.com/skaarj1989/FrameGraph.git extern/FrameGraph\n```\n\n```cmake\nadd_subdirectory(extern/FrameGraph)\ntarget_link_libraries(YourProject PRIVATE fg::FrameGraph)\n```\n\nAnother possibility is to use [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html):\n\n```cmake\ninclude(FetchContent)\n\nFetchContent_Declare(\n  FrameGraph\n  GIT_REPOSITORY https://github.com/skaarj1989/FrameGraph.git\n  GIT_TAG master)\nFetchContent_MakeAvailable(FrameGraph)\n\ntarget_link_libraries(YourProject PRIVATE fg::FrameGraph)\n```\n\n## Example\n\nhttps://github.com/skaarj1989/FrameGraph-Example\n\n## License\n\n[MIT](LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskaarj1989%2Fframegraph","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskaarj1989%2Fframegraph","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskaarj1989%2Fframegraph/lists"}