FrameGraph API change

Resources are now single textures (generally buffers in the future),
but no longer a render target + a set of texture.
Instead, render target need to be declared and are associated to a pass.
This commit is contained in:
Mathias Agopian
2019-01-22 19:03:20 -08:00
committed by Mathias Agopian
parent be18155996
commit ac679e0da4
7 changed files with 431 additions and 347 deletions

View File

@@ -194,24 +194,28 @@ FrameGraphResource PostProcessManager::msaa(FrameGraph& fg,
struct PostProcessMSAA {
FrameGraphResource input;
FrameGraphResource output;
FrameGraphRenderTarget inRenderTarget;
FrameGraphRenderTarget outRenderTarget;
};
auto& ppMSAA = fg.addPass<PostProcessMSAA>("msaa",
[&](FrameGraph::Builder& builder, PostProcessMSAA& data) {
auto const* inputDesc = fg.getDescriptor(input);
data.input = builder.blit(input);
data.inRenderTarget = builder.declareRenderTarget(data.input);
FrameGraphResource::Descriptor outputDesc{
.width = inputDesc->width,
.height = inputDesc->height,
.format = outFormat
};
data.output = builder.write(builder.createResource("msaa output", outputDesc));
data.output = builder.write(builder.declareTexture("msaa output", outputDesc));
data.outRenderTarget = builder.declareRenderTarget(data.output);
},
[=](FrameGraphPassResources const& resources,
PostProcessMSAA const& data, DriverApi& driver) {
auto in = resources.getRenderTarget(data.input);
auto out = resources.getRenderTarget(data.output);
auto in = resources.getRenderTarget(data.inRenderTarget);
auto out = resources.getRenderTarget(data.outRenderTarget);
auto const& desc = resources.getDescriptor(data.input);
driver.blit(TargetBufferFlags::COLOR,
out.target, 0, 0, desc.width, desc.height,
@@ -230,6 +234,7 @@ FrameGraphResource PostProcessManager::toneMapping(FrameGraph& fg,
struct PostProcessToneMapping {
FrameGraphResource input;
FrameGraphResource output;
FrameGraphRenderTarget outRenderTarget;
};
Handle<HwProgram> toneMappingProgram = engine->getPostProcessProgram(
translucent ? PostProcessStage::TONE_MAPPING_TRANSLUCENT
@@ -246,7 +251,8 @@ FrameGraphResource PostProcessManager::toneMapping(FrameGraph& fg,
.format = outFormat
};
data.output = builder.write(
builder.createResource("tonemapping output", outputDesc));
builder.declareTexture("tonemapping output", outputDesc));
data.outRenderTarget = builder.declareRenderTarget(data.output);
},
[=](FrameGraphPassResources const& resources,
PostProcessToneMapping const& data, DriverApi& driver) {
@@ -258,10 +264,10 @@ FrameGraphResource PostProcessManager::toneMapping(FrameGraph& fg,
auto const& targetDesc = resources.getDescriptor(data.output);
auto const& textureDesc = resources.getDescriptor(data.input);
auto const& texture = resources.getTexture(data.input, TextureUsage::COLOR_ATTACHMENT);
auto const& texture = resources.getTexture(data.input);
setSource(targetDesc.width, targetDesc.height, texture, textureDesc.width, textureDesc.height);
auto const& target = resources.getRenderTarget(data.output);
auto const& target = resources.getRenderTarget(data.outRenderTarget);
driver.beginRenderPass(target.target, target.params);
driver.draw(pipeline, fullScreenRenderPrimitive);
driver.endRenderPass();
@@ -279,6 +285,7 @@ FrameGraphResource PostProcessManager::fxaa(FrameGraph& fg,
struct PostProcessFXAA {
FrameGraphResource input;
FrameGraphResource output;
FrameGraphRenderTarget outRenderTarget;
};
Handle<HwProgram> antiAliasingProgram = engine->getPostProcessProgram(
@@ -296,7 +303,8 @@ FrameGraphResource PostProcessManager::fxaa(FrameGraph& fg,
.height = inputDesc->height,
.format = outFormat
};
data.output = builder.write(builder.createResource("fxaa output", outputDesc));
data.output = builder.write(builder.declareTexture("fxaa output", outputDesc));
data.outRenderTarget = builder.declareRenderTarget(data.output);
},
[=](FrameGraphPassResources const& resources,
PostProcessFXAA const& data, DriverApi& driver) {
@@ -308,10 +316,10 @@ FrameGraphResource PostProcessManager::fxaa(FrameGraph& fg,
auto const& targetDesc = resources.getDescriptor(data.output);
auto const& textureDesc = resources.getDescriptor(data.input);
auto const& texture = resources.getTexture(data.input, TextureUsage::COLOR_ATTACHMENT);
auto const& texture = resources.getTexture(data.input);
setSource(targetDesc.width, targetDesc.height, texture, textureDesc.width, textureDesc.height);
auto const& target = resources.getRenderTarget(data.output);
auto const& target = resources.getRenderTarget(data.outRenderTarget);
driver.beginRenderPass(target.target, target.params);
driver.draw(pipeline, fullScreenRenderPrimitive);
driver.endRenderPass();
@@ -327,24 +335,28 @@ FrameGraphResource PostProcessManager::dynamicScaling(FrameGraph& fg,
struct PostProcessScaling {
FrameGraphResource input;
FrameGraphResource output;
FrameGraphRenderTarget inRenderTarget;
FrameGraphRenderTarget outRenderTarget;
};
auto& ppScaling = fg.addPass<PostProcessScaling>("scaling",
[&](FrameGraph::Builder& builder, PostProcessScaling& data) {
auto* inputDesc = fg.getDescriptor(input);
data.input = builder.blit(input);
data.inRenderTarget = builder.declareRenderTarget(data.input);
FrameGraphResource::Descriptor outputDesc{
.width = inputDesc->width,
.height = inputDesc->height,
.format = outFormat
};
data.output = builder.write(builder.createResource("scale output", outputDesc));
data.output = builder.write(builder.declareTexture("scale output", outputDesc));
data.outRenderTarget = builder.declareRenderTarget(data.output);
},
[=](FrameGraphPassResources const& resources,
PostProcessScaling const& data, DriverApi& driver) {
auto in = resources.getRenderTarget(data.input);
auto out = resources.getRenderTarget(data.output);
auto in = resources.getRenderTarget(data.inRenderTarget);
auto out = resources.getRenderTarget(data.outRenderTarget);
auto const& inDesc = resources.getDescriptor(data.input);
driver.blit(TargetBufferFlags::COLOR,
out.target, outViewport.left, outViewport.bottom, outViewport.width,

View File

@@ -247,17 +247,14 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
.width = colorTarget->w,
.height= colorTarget->h,
.format= colorTarget->format,
.samples= colorTarget->samples
};
FrameGraphResource input = fg.importResource("colorTarget",
colorDesc, colorTarget->texture);
FrameGraphResource::Descriptor viewRenderTargetDesc{
FrameGraphRenderTarget::Descriptor viewRenderTargetDesc{
.width = vp.width,
.height= vp.height
.height= vp.height,
};
FrameGraphResource input = fg.importResource("colorTarget", colorDesc,
colorTarget->target, colorTarget->texture);
FrameGraphResource output = fg.importResource("viewRenderTarget",
viewRenderTargetDesc, viewRenderTarget);
@@ -273,7 +270,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
}
fg.moveResource(output, input);
fg.present(output, FrameGraph::Builder::COLOR);
fg.present(output);
fg.compile();
//fg.export_graphviz(slog.d);

View File

@@ -38,12 +38,22 @@ using namespace fg;
namespace fg {
struct Alias {
FrameGraphResource from, to;
};
struct TargetFlags {
uint8_t clear = 0;
uint8_t discardStart = 0;
uint8_t discardEnd = 0;
uint8_t dependencies = 0;
};
struct Resource {
explicit Resource(const char* name, bool imported) noexcept;
Resource(const char* name, bool imported) noexcept;
Resource(Resource const&) = delete;
Resource(Resource&&) = default;
Resource& operator=(Resource const&) = delete;
~Resource() noexcept;
// constants
@@ -51,25 +61,34 @@ struct Resource {
bool imported;
// computed during compile()
PassNode* writer = nullptr; // last writer to this resource
PassNode* first = nullptr; // pass that needs to instantiate the resource
PassNode* last = nullptr; // pass that can destroy the resource
uint32_t writerCount = 0; // # of passes writing to this resource
uint32_t readerCount = 0; // # of passes reading from this resource
PassNode* writer = nullptr; // last writer to this resource
PassNode* first = nullptr; // pass that needs to instantiate the resource
PassNode* last = nullptr; // pass that can destroy the resource
uint32_t writerCount = 0; // # of passes writing to this resource
uint32_t readerCount = 0; // # of passes reading from this resource
enum Type {
TEXTURE,
IMPORTED_RENDER_TARGET
};
Type type = TEXTURE;
FrameGraphResource::Descriptor desc;
FrameGraph::Builder::RWFlags readFlags = 0;
FrameGraph::Builder::RWFlags writeFlags = 0;
// concrete resource -- set when the resource is created
void create(DriverApi& driver) noexcept;
void destroy(DriverApi& driver) noexcept;
Handle<HwTexture> textures[2] = {}; // color, depth
FrameGraphPassResources::RenderTarget target;
// can't use union without implementing the move ctor manually. not a problem right now.
//union {
Handle<HwTexture> texture;
uint16_t renderTargetIndex;
//};
};
struct ResourceNode {
ResourceNode(const char* name, FrameGraphResource::Descriptor const& desc, bool imported,
uint16_t index) noexcept
ResourceNode(const char* name,
FrameGraphResource::Descriptor const& desc, bool imported, uint16_t index) noexcept
: name(name), imported(imported), index(index), desc(desc) {
}
ResourceNode(ResourceNode const&) = delete;
@@ -82,9 +101,7 @@ struct ResourceNode {
// updated by the builder
uint8_t version = 0;
FrameGraphResource::Descriptor desc;
FrameGraph::Builder::RWFlags readFlags = 0;
FrameGraph::Builder::RWFlags writeFlags = 0;
FrameGraphResource::Descriptor desc; // FIXME: it's a shame we store this twice (in Resource too)
// set during compile()
union {
@@ -93,6 +110,100 @@ struct ResourceNode {
};
};
struct RenderTarget {
RenderTarget(const char* name,
FrameGraphRenderTarget::Descriptor const& desc, bool imported, uint16_t index) noexcept
: name(name), imported(imported), index(index), desc(desc) {
}
// constants
const char* const name; // for debugging
bool imported;
uint16_t index;
FrameGraphRenderTarget::Descriptor desc;
void create(FrameGraph& fg, DriverApi& driver, TargetFlags const& targetFlags) noexcept {
const auto& resourceNodes = fg.mResourceNodes;
auto& renderTargets = fg.mRenderTargets;
uint32_t width = desc.width;
uint32_t height = desc.height;
TextureFormat colorFormat = TextureFormat::RGBA8; // only used for the color attachment when not specified
if (!imported) {
uint32_t attachments = 0;
Handle<HwTexture> color;
Handle<HwTexture> depth;
fg::RenderTarget* importedRenderTarget = nullptr;
if (desc.attachments.depth.isValid()) {
ResourceNode const& depthNode = resourceNodes[desc.attachments.depth.index];
Resource const* pDepthResource = depthNode.resource;
assert(pDepthResource);
if (pDepthResource->type == Resource::IMPORTED_RENDER_TARGET) {
importedRenderTarget = &renderTargets[pDepthResource->renderTargetIndex];
} else {
width = pDepthResource->desc.width;
height = pDepthResource->desc.height;
depth = pDepthResource->texture;
attachments |= uint32_t(TargetBufferFlags::DEPTH);
}
}
if (desc.attachments.color.isValid()) {
ResourceNode const& colorNode = resourceNodes[desc.attachments.color.index];
Resource const* pColorResource = colorNode.resource;
assert(pColorResource);
if (pColorResource->type == Resource::IMPORTED_RENDER_TARGET) {
importedRenderTarget = &renderTargets[pColorResource->renderTargetIndex];
} else {
width = pColorResource->desc.width;
height = pColorResource->desc.height;
colorFormat = pColorResource->desc.format;
color = pColorResource->texture;
attachments |= uint32_t(TargetBufferFlags::COLOR);
}
}
if (importedRenderTarget) {
// this rendertarget is created from an imported resource
assert(!attachments);
assert(importedRenderTarget->imported);
imported = true;
desc = importedRenderTarget->desc;
targetInfo.target = importedRenderTarget->targetInfo.target;
width = desc.width;
height = desc.height;
} else if (attachments) {
targetInfo.target = driver.createRenderTarget(TargetBufferFlags(attachments),
width, height, desc.samples, colorFormat,
{ color }, { depth }, {});
}
}
targetInfo.params = {};
targetInfo.params.clear = targetFlags.clear;
targetInfo.params.discardStart = targetFlags.discardStart;
targetInfo.params.discardEnd = targetFlags.discardEnd;
targetInfo.params.dependencies = targetFlags.dependencies;
targetInfo.params.left = 0;
targetInfo.params.bottom = 0;
targetInfo.params.width = width;
targetInfo.params.height = height;
}
void destroy(DriverApi& driver) noexcept {
if (!imported) {
if (targetInfo.target) {
driver.destroyRenderTarget(targetInfo.target);
}
}
}
FrameGraphPassResources::RenderTargetInfo targetInfo;
};
struct PassNode {
template <typename T>
using Vector = FrameGraph::Vector<T>;
@@ -101,29 +212,25 @@ struct PassNode {
: name(name), id(id), base(base),
reads(fg.getArena()),
writes(fg.getArena()),
renderTargets(fg.getArena()),
targetFlags(fg.getArena()),
devirtualize(fg.getArena()),
destroy(fg.getArena()) {
}
PassNode(PassNode const&) = delete;
PassNode(PassNode&& rhs) noexcept
: name(rhs.name), id(rhs.id), base(rhs.base),
reads(std::move(rhs.reads)),
writes(std::move(rhs.writes)),
targetFlags(std::move(rhs.targetFlags)),
devirtualize(std::move(rhs.devirtualize)),
destroy(std::move(rhs.destroy)),
refCount(rhs.refCount) {
rhs.base = nullptr;
}
PassNode(PassNode&& rhs) noexcept = default;
PassNode& operator=(PassNode const&) = delete;
PassNode& operator=(PassNode&&) = delete;
~PassNode() { delete base; }
~PassNode() = default;
// for Builder
FrameGraphResource read(ResourceNode const& resource, FrameGraph::Builder::RWFlags flags) {
void declareRenderTarget(RenderTarget& renderTarget) noexcept {
renderTargets.push_back(renderTarget.index);
}
FrameGraphResource read(ResourceNode const& resource) {
// don't allow multiple reads of the same resource -- it's just redundant.
auto pos = std::find_if(reads.begin(), reads.end(),
[&resource](FrameGraphResource cur) { return resource.index == cur.index; });
@@ -131,7 +238,9 @@ struct PassNode {
return *pos;
}
FrameGraphResource r{ resource.index, resource.version, flags };
FrameGraphResource r{ resource.index, resource.version };
// FIXME: it shouldn't be allowed to READ + WRITE from the same pass (but: what about atomic buffers?)
// now figure out if we already recorded a write to this resource, and if so, use the
// previous version number to record the read. i.e. pretend the read() was recorded first.
@@ -152,7 +261,7 @@ struct PassNode {
return (pos != reads.end());
}
FrameGraphResource write(ResourceNode& resource, FrameGraph::Builder::RWFlags flags) {
FrameGraphResource write(ResourceNode& resource) {
// don't allow multiple writes of the same resource -- it's just redundant.
auto pos = std::find_if(writes.begin(), writes.end(),
[&resource](FrameGraphResource cur) { return resource.index == cur.index; });
@@ -179,32 +288,27 @@ struct PassNode {
hasSideEffect = true;
}
// record the write
FrameGraphResource r{ resource.index, resource.version, flags };
FrameGraphResource r{ resource.index, resource.version };
writes.push_back(r);
return r;
}
bool isWritingTo(FrameGraphResource resource) const noexcept {
auto pos = std::find_if(writes.begin(), writes.end(),
[resource](FrameGraphResource cur) { return resource.index == cur.index; });
return (pos != writes.end());
bool isWritingTo(FrameGraphRenderTarget const& renderTarget) const noexcept {
auto pos = std::find_if(renderTargets.begin(), renderTargets.end(),
[index = renderTarget.index](uint16_t cur) { return index == cur; });
return (pos != renderTargets.end());
}
// constants
const char* const name; // our name
const uint32_t id; // a unique id (only for debugging)
FrameGraphPassExecutor* base = nullptr; // type eraser for calling execute()
const char* const name; // our name
const uint32_t id; // a unique id (only for debugging)
std::unique_ptr<FrameGraphPassExecutor> base; // type eraser for calling execute()
// set by the builder
Vector<FrameGraphResource> reads; // resources we're reading from
Vector<FrameGraphResource> writes; // resources we're writing to
Vector<uint16_t> renderTargets; // declared renderTargets
struct TargetFlags {
uint8_t clear = 0;
uint8_t discardStart = 0;
uint8_t discardEnd = 0;
uint8_t dependencies = 0;
};
Vector<TargetFlags> targetFlags;
bool hasSideEffect = false; // whether this pass has side effects
@@ -215,19 +319,6 @@ struct PassNode {
uint32_t refCount = 0; // count resources that have a reference to us
};
struct Alias {
FrameGraphResource from, to;
};
Resource::~Resource() noexcept {
if (!imported) {
assert(!textures[0]);
assert(!textures[1]);
assert(!target.target);
}
}
// ------------------------------------------------------------------------------------------------
// out-of-line definitions
// ------------------------------------------------------------------------------------------------
@@ -236,65 +327,33 @@ Resource::Resource(const char* name, bool imported) noexcept
: name(name), imported(imported) {
}
Resource::~Resource() noexcept {
if (!imported) {
assert(!texture);
}
}
void Resource::create(DriverApi& driver) noexcept {
// some sanity check
if (readerCount) assert(readFlags);
if (writerCount) assert(writeFlags);
// technically this doesn't need to be initialized if we're not a rendertarget.
target.params = {};
target.params.left = 0;
target.params.bottom = 0;
target.params.width = desc.width;
target.params.height = desc.height;
if (!imported) {
if (readFlags & FrameGraph::Builder::COLOR) {
textures[0] = driver.createTexture(desc.type, desc.levels,
desc.format, 1,
if (readerCount) {
// Don't create the texture handle if this resource is never read
// (it means it's only used as an attachment for a rendertarget)
texture = driver.createTexture(desc.type, desc.levels, desc.format, 1,
desc.width, desc.height, desc.depth,
TextureUsage::COLOR_ATTACHMENT);
}
if (readFlags & FrameGraph::Builder::DEPTH) {
textures[1] = driver.createTexture(desc.type, desc.levels,
TextureFormat::DEPTH24, 1,
desc.width, desc.height, desc.depth,
TextureUsage::DEPTH_ATTACHMENT);
}
// Note: if the resource is a source of a blit, it needs a rendertarget (because that's how
// blits work) -- in that case, the resource would have been declared with Builder::blit()
// access, and its write flags here would be set.
uint32_t attachments = 0;
if (writeFlags & FrameGraph::Builder::COLOR) {
attachments |= uint32_t(TargetBufferFlags::COLOR);
}
if (writeFlags & FrameGraph::Builder::DEPTH) {
attachments |= TargetBufferFlags::DEPTH;
}
if (attachments) {
target.target = driver.createRenderTarget(TargetBufferFlags(attachments),
desc.width, desc.height, desc.samples, desc.format,
{ textures[0] }, { textures[1] }, {});
TextureUsage::COLOR_ATTACHMENT); // FIXME: this should be calculated automatically
}
}
}
void Resource::destroy(DriverApi& driver) noexcept {
// we don't own the handles of imported resources
if (imported) return;
for (auto& texture : textures) {
if (!imported) {
if (texture) {
driver.destroyTexture(texture);
texture.clear(); // needed because of noop driver
}
}
if (target.target) {
driver.destroyRenderTarget(target.target);
target.target.clear(); // needed because of noop driver
}
}
@@ -313,41 +372,53 @@ FrameGraph::Builder::Builder(FrameGraph& fg, PassNode& pass) noexcept
FrameGraph::Builder::~Builder() noexcept = default;
FrameGraphResource FrameGraph::Builder::createResource(
FrameGraphResource FrameGraph::Builder::declareTexture(
const char* name, FrameGraphResource::Descriptor const& desc) noexcept {
FrameGraph& frameGraph = mFrameGraph;
ResourceNode& resource = frameGraph.createResource(name, desc, false);
ResourceNode& resource = mFrameGraph.createResource(name, desc, false);
return { resource.index, resource.version };
}
FrameGraphResource FrameGraph::Builder::read(FrameGraphResource const& input, RWFlags readFlags) {
FrameGraphRenderTarget FrameGraph::Builder::declareRenderTarget(
const char* name, FrameGraphRenderTarget::Descriptor const& desc) noexcept {
RenderTarget& renderTarget = mFrameGraph.createRenderTarget(name, desc, false);
// TODO: check that desc.attachments.* are being written by this pass
mPass.declareRenderTarget(renderTarget);
return FrameGraphRenderTarget{ renderTarget.index };
}
FrameGraphRenderTarget FrameGraph::Builder::declareRenderTarget(FrameGraphResource texture) noexcept {
ResourceNode* resource = mFrameGraph.getResource(texture);
FrameGraphRenderTarget::Descriptor desc {
.width = resource->desc.width,
.height = resource->desc.height,
.samples = 1,
.attachments.color = texture
};
return declareRenderTarget(resource->name, desc);
}
FrameGraphResource FrameGraph::Builder::read(FrameGraphResource const& input) {
ResourceNode* resource = mFrameGraph.getResource(input);
if (!resource) {
return {};
}
resource->readFlags |= readFlags;
return mPass.read(*resource, readFlags);
return mPass.read(*resource);
}
FrameGraphResource
FrameGraph::Builder::blit(FrameGraphResource const& input, FrameGraph::Builder::RWFlags readFlags) {
FrameGraphResource FrameGraph::Builder::blit(FrameGraphResource const& input) {
ResourceNode* resource = mFrameGraph.getResource(input);
if (!resource) {
return {};
}
resource->readFlags |= readFlags;
// resource used in a blit, it needs a rendertarget, so we set its write flags.
resource->writeFlags |= readFlags;
return mPass.read(*resource, readFlags);
return mPass.read(*resource);
}
FrameGraphResource FrameGraph::Builder::write(FrameGraphResource const& output, RWFlags writeFlags) {
FrameGraphResource FrameGraph::Builder::write(FrameGraphResource const& output) {
ResourceNode* resource = mFrameGraph.getResource(output);
if (!resource) {
return {};
}
resource->writeFlags |= writeFlags;
return mPass.write(*resource, writeFlags);
return mPass.write(*resource);
}
FrameGraph::Builder& FrameGraph::Builder::sideEffect() noexcept {
@@ -358,26 +429,10 @@ FrameGraph::Builder& FrameGraph::Builder::sideEffect() noexcept {
// ------------------------------------------------------------------------------------------------
FrameGraphPassResources::FrameGraphPassResources(FrameGraph& fg, fg::PassNode const& pass) noexcept
: mFrameGraph(fg), mPass(pass) {
// copy the target flags for each render target of this pass
auto const& resourceNodes = fg.mResourceNodes;
for (size_t i = 0, c = pass.writes.size(); i < c; i++) {
auto const& r = pass.writes[i];
Resource* const pResource = resourceNodes[r.index].resource;
assert(pResource);
RenderPassParams& targetFlags = pResource->target.params;
const PassNode::TargetFlags& passTargetFlags = pass.targetFlags[i];
targetFlags.clear = passTargetFlags.clear;
targetFlags.discardStart = passTargetFlags.discardStart;
targetFlags.discardEnd = passTargetFlags.discardEnd;
targetFlags.dependencies = passTargetFlags.dependencies;
}
: mFrameGraph(fg), mPass(pass) {
}
Handle<HwTexture> FrameGraphPassResources::getTexture(
FrameGraphResource r, TextureUsage attachment) const noexcept {
Handle <HwTexture> FrameGraphPassResources::getTexture(FrameGraphResource r) const noexcept {
Resource const* const pResource = mFrameGraph.mResourceNodes[r.index].resource;
assert(pResource);
@@ -386,66 +441,26 @@ Handle<HwTexture> FrameGraphPassResources::getTexture(
"Pass \"%s\" doesn't declare reads to resource \"%s\" -- expect graphic corruptions",
mPass.name, pResource->name);
const char* requested = "unknown";
Handle<HwTexture> h;
switch (attachment) {
case TextureUsage::DEFAULT:
if (pResource->readFlags == FrameGraph::Builder::DEPTH) {
h = pResource->textures[1];
requested = "depth";
break;
}
[[clang::fallthrough]];
case TextureUsage::COLOR_ATTACHMENT:
h = pResource->textures[0];
requested = "color";
break;
case TextureUsage::DEPTH_ATTACHMENT:
h = pResource->textures[1];
requested = "depth";
break;
}
if (pResource->imported) {
ASSERT_POSTCONDITION_NON_FATAL(h,
"Imported resource \"%s\" (id=%u) doesn't have a %s texture",
pResource->name, r.index, requested);
} else {
// for non imported resources that shouldn't happen.
// FIXME: is it true though? couldn't it happen if user didn't declare dependencies right?
assert(h);
}
return h;
return pResource->texture;
}
FrameGraphPassResources::RenderTarget const&
FrameGraphPassResources::getRenderTarget(FrameGraphResource r) const noexcept {
Resource const* const pResource = mFrameGraph.mResourceNodes[r.index].resource;
assert(pResource);
FrameGraphPassResources::RenderTargetInfo const&
FrameGraphPassResources::getRenderTarget(FrameGraphRenderTarget r) const noexcept {
fg::RenderTarget& renderTarget = mFrameGraph.mRenderTargets[r.index];
// We need to check the resource in read or written by this pass (as opposed to written only),
// because a render target is needed for blit operations, which might be what the caller
// is doing.
ASSERT_POSTCONDITION_NON_FATAL(mPass.isWritingTo(r) || mPass.isReadingFrom(r),
"Pass \"%s\" doesn't declare writes to resource \"%s\" -- expect graphic corruptions",
mPass.name, pResource->name);
// check that this FrameGraphRenderTarget is indeed declared by this pass
ASSERT_POSTCONDITION_NON_FATAL(mPass.isWritingTo(r),
"Pass \"%s\" doesn't declare rendertarget \"%s\" -- expect graphic corruptions",
mPass.name, renderTarget.name);
assert(pResource->target.target);
assert(renderTarget.targetInfo.target);
if (pResource->imported) {
ASSERT_POSTCONDITION_NON_FATAL(pResource->target.target,
"Imported resource \"%s\" (id=%u) doesn't have a render target",
pResource->name, r.index);
}
// slog.d << mPass.name << ": resource = \"" << pResource->name << "\", flags = "
// slog.d << mPass.name << ": resource = \"" << renderTarget.name << "\", flags = "
// << io::hex
// << pResource->target.params.discardStart << ", "
// << pResource->target.params.discardEnd << io::endl;
// << renderTarget.targetInfo.params.discardStart << ", "
// << renderTarget.targetInfo.params.discardEnd << io::endl;
return pResource->target;
return renderTarget.targetInfo;
}
FrameGraphResource::Descriptor const& FrameGraphPassResources::getDescriptor(
@@ -463,6 +478,7 @@ FrameGraph::FrameGraph()
: mArena("FrameGraph Arena", 16384), // TODO: the Area will eventually come from outside
mPassNodes(mArena),
mResourceNodes(mArena),
mRenderTargets(mArena),
mResourceRegistry(mArena),
mAliases(mArena) {
// some default size to avoid wasting space with the std::vector<>
@@ -489,12 +505,12 @@ bool FrameGraph::moveResource(FrameGraphResource from, FrameGraphResource to) {
return true;
}
void FrameGraph::present(FrameGraphResource input, Builder::RWFlags sideEffects) {
void FrameGraph::present(FrameGraphResource input) {
struct Dummy {
};
addPass<Dummy>("Present",
[&](Builder& builder, Dummy& data) {
builder.read(input, sideEffects);
builder.read(input);
builder.sideEffect();
},
[](FrameGraphPassResources const& resources, Dummy const& data, DriverApi&) {
@@ -508,6 +524,14 @@ PassNode& FrameGraph::createPass(const char* name, FrameGraphPassExecutor* base)
return frameGraphPasses.back();
}
fg::RenderTarget& FrameGraph::createRenderTarget(const char* name,
FrameGraphRenderTarget::Descriptor const& desc, bool imported) noexcept {
auto& renderTargets = mRenderTargets;
const uint16_t id = (uint16_t)renderTargets.size();
renderTargets.emplace_back(name, desc, imported, id);
return renderTargets.back();
}
ResourceNode& FrameGraph::createResource(
const char* name, FrameGraphResource::Descriptor const& desc, bool imported) noexcept {
auto& registry = mResourceNodes;
@@ -541,30 +565,50 @@ FrameGraphResource::Descriptor* FrameGraph::getDescriptor(FrameGraphResource r)
}
FrameGraphResource FrameGraph::importResource(
const char* name, FrameGraphResource::Descriptor const& descriptor,
Handle <HwRenderTarget> target) {
return importResource(name, descriptor, target, {}, {});
const char* name, FrameGraphRenderTarget::Descriptor const& descriptor,
Handle<HwRenderTarget> target) {
// Importing a render target is a bit involved. We first create the render target as well
// as a frame graph resource. The frame graph resource references the render target for
// later use.
// TODO: can we do better with the discard flags? Maybe pass has parameter.
RenderTarget& renderTarget = createRenderTarget(name, descriptor, true);
renderTarget.targetInfo.target = target;
renderTarget.targetInfo.params.discardStart = TargetBufferFlags::NONE;
renderTarget.targetInfo.params.discardEnd = TargetBufferFlags::NONE;
// create the resource that will be returned to the user
FrameGraphResource::Descriptor desc {
.width = descriptor.width,
.height = descriptor.height,
};
ResourceNode& node = createResource(name, desc, true);
// imported resources are created immediately
auto& resourceRegistry = mResourceRegistry;
resourceRegistry.emplace_back(name, true);
Resource& resource = resourceRegistry.back();
resource.type = Resource::IMPORTED_RENDER_TARGET;
resource.renderTargetIndex = renderTarget.index;
// we store the offset into the array (instead of the pointer) because the storage might
// move between now and compile().
node.offset = &resource - resourceRegistry.data();
return { node.index, node.version };
}
FrameGraphResource FrameGraph::importResource(
const char* name, FrameGraphResource::Descriptor const& descriptor,
Handle<HwTexture> color, Handle<HwTexture> depth) {
return importResource(name, descriptor, {}, color, depth);
}
FrameGraphResource FrameGraph::importResource(
const char* name, FrameGraphResource::Descriptor const& descriptor,
Handle <HwRenderTarget> target,
Handle <HwTexture> color, Handle <HwTexture> depth) {
Handle<HwTexture> color) {
ResourceNode& node = createResource(name, descriptor, true);
// imported resources are created immediately
auto& resourceRegistry = mResourceRegistry;
resourceRegistry.emplace_back(name, true);
Resource& resource = resourceRegistry.back();
resource.textures[0] = color;
resource.textures[1] = depth;
resource.target.target = target;
resource.texture = color;
// we store the offset into the array (instead of the pointer) because the storage might
// move between now and compile().
@@ -576,7 +620,9 @@ FrameGraphResource FrameGraph::importResource(
FrameGraph& FrameGraph::compile() noexcept {
auto& passNodes = mPassNodes;
auto& resourceNodes = mResourceNodes;
auto const& renderTargets = mRenderTargets;
auto& resourceRegistry = mResourceRegistry;
resourceRegistry.reserve(resourceNodes.size());
// create the sub-resources
@@ -588,8 +634,6 @@ FrameGraph& FrameGraph::compile() noexcept {
node.resource = &resourceRegistry.back();
}
node.resource->desc = node.desc;
node.resource->readFlags = node.readFlags;
node.resource->writeFlags = node.writeFlags;
}
// remap them
@@ -604,13 +648,6 @@ FrameGraph& FrameGraph::compile() noexcept {
pass.writes.erase(pos);
}
}
// read flags are combined
from.resource->readFlags |= to.resource->readFlags;
// write flags are set to the "to" resource, since writers are disconnected from the "from"
from.resource->writeFlags = to.resource->writeFlags;
// alias "to" to "from"
to.resource = from.resource;
}
@@ -673,13 +710,11 @@ FrameGraph& FrameGraph::compile() noexcept {
}
// compute first/last users for active passes
auto first = passNodes.begin();
auto last = passNodes.end();
while (first != last) {
PassNode& pass = *first;
auto const first = passNodes.data();
auto const last = passNodes.data() + passNodes.size();
for (PassNode& pass : passNodes) {
if (!pass.refCount) {
assert(!pass.hasSideEffect);
++first;
continue;
}
for (FrameGraphResource resource : pass.reads) {
@@ -689,85 +724,41 @@ FrameGraph& FrameGraph::compile() noexcept {
// figure out which is the last pass to need this resource
subResource->last = &pass;
}
pass.targetFlags.resize(pass.writes.size());
for (size_t i = 0, c = pass.writes.size(); i < c; i++) {
FrameGraphResource resource = pass.writes[i];
for (FrameGraphResource resource : pass.writes) {
Resource* subResource = resourceNodes[resource.index].resource;
// figure out which is the first pass to need this resource
subResource->first = subResource->first ? subResource->first : &pass;
// figure out which is the last pass to need this resource
subResource->last = &pass;
// compute this resource discard flag for this pass
PassNode::TargetFlags& targetFlags = pass.targetFlags[i];
}
// FIXME: the discard flags must be updated for each attachement
uint8_t discardStart = TargetBufferFlags::ALL;
uint8_t discardEnd = TargetBufferFlags::ALL;
// does anyone reads this resource after us...
auto curr = first;
while (++curr != last) {
PassNode& futurePass = *curr;
pass.targetFlags.resize(pass.renderTargets.size());
// TODO: maybe find a more efficient way of figuring this out
for (size_t i = 0, c = pass.renderTargets.size(); i < c; ++i) {
RenderTarget const& renderTarget = renderTargets[pass.renderTargets[i]];
// compute this resource discard flag for this pass for this resource
auto pos = std::find_if(
futurePass.reads.begin(), futurePass.reads.end(),
[subResource, &resourceNodes](FrameGraphResource cur) {
return subResource == resourceNodes[cur.index].resource;
});
// does anyone writes to this resource before us -- if so, don't discard those buffers on enter
// (i.e. if nobody wrote, no need to load from memory)
uint8_t discardStart = computeDiscardFlags(
DiscardPhase::START, first, &pass, renderTarget);
const bool isFuturePassReadingFromUs = pos != futurePass.reads.end();
// does anyone reads this resource after us -- if so, don't discard those buffers on exit
// (i.e. if noboddy is going to read, no need to write back to memory)
uint8_t discardEnd = computeDiscardFlags(
DiscardPhase::END, &pass + 1, last, renderTarget);
if (isFuturePassReadingFromUs) {
// if a future pass is reading from us, we can't discard when we're done
if (pos->flags & Builder::COLOR) {
discardEnd &= ~TargetBufferFlags::COLOR;
}
if (pos->flags & Builder::DEPTH) {
discardEnd &= ~TargetBufferFlags::DEPTH;
}
break;
}
}
// does anyone write this resource before us
curr = passNodes.begin();
while (curr != first) {
PassNode& pastPass = *curr++;
// TODO: maybe find a more efficient way of figuring this out
auto pos = std::find_if(
pastPass.writes.begin(), pastPass.writes.end(),
[subResource, &resourceNodes](FrameGraphResource cur) {
return subResource == resourceNodes[cur.index].resource;
});
const bool isPastPassWritingToUs = pos != pastPass.writes.end();
if (isPastPassWritingToUs) {
// if a past pass is writing to us, we can't discard
if (pos->flags & Builder::COLOR) {
discardStart &= ~TargetBufferFlags::COLOR;
}
if (pos->flags & Builder::DEPTH) {
discardStart &= ~TargetBufferFlags::DEPTH;
}
break;
}
}
TargetFlags& targetFlags = pass.targetFlags[i];
targetFlags.clear = 0;
targetFlags.discardStart = discardStart;
targetFlags.discardEnd = discardEnd;
targetFlags.dependencies = 0;
}
++first;
}
// add resource to devirtualize or destroy to the corresponding list for each active pass
for (size_t index = 0, c = resourceRegistry.size() ; index < c ; index++) {
auto& resource = resourceRegistry[index];
Resource& resource = resourceRegistry[index];
assert(!resource.first == !resource.last);
if (resource.readerCount && resource.first && resource.last) {
resource.first->devirtualize.push_back((uint16_t)index);
@@ -778,6 +769,34 @@ FrameGraph& FrameGraph::compile() noexcept {
return *this;
}
uint8_t FrameGraph::computeDiscardFlags(DiscardPhase phase,
PassNode const* curr, PassNode const* first,
RenderTarget const& renderTarget) {
auto& resourceNodes = mResourceNodes;
uint8_t discardFlags = TargetBufferFlags::ALL;
// for each pass...
while (discardFlags && curr != first) {
PassNode const& pass = *curr++;
// TODO: maybe find a more efficient way of figuring this out
// for each resource written or read...
for (FrameGraphResource cur : ((phase == DiscardPhase::START) ? pass.writes : pass.reads)) {
// for all possible attachments...
if (resourceNodes[cur.index].resource ==
resourceNodes[renderTarget.desc.attachments.color.index].resource) {
discardFlags &= ~TargetBufferFlags::COLOR;
}
if (resourceNodes[cur.index].resource ==
resourceNodes[renderTarget.desc.attachments.depth.index].resource) {
discardFlags &= ~TargetBufferFlags::DEPTH;
}
if (!discardFlags) {
break;
}
}
}
return discardFlags;
}
void FrameGraph::execute(DriverApi& driver) noexcept {
auto& resourceRegistry = mResourceRegistry;
for (PassNode const& node : mPassNodes) {
@@ -789,10 +808,22 @@ void FrameGraph::execute(DriverApi& driver) noexcept {
resourceRegistry[id].create(driver);
}
// FIXME: this should work like resource, we need to know their lifetime
// create the rendertargets
for (size_t i = 0, c = node.renderTargets.size(); i < c; ++i) {
mRenderTargets[node.renderTargets[i]].create(*this, driver, node.targetFlags[i]);
}
// execute the pass
FrameGraphPassResources resources(*this, node);
node.base->execute(resources, driver);
// FIXME: use a cache or something
// destroy the rendertargets
for (size_t id : node.renderTargets) {
mRenderTargets[id].destroy(driver);
}
// destroy concrete resources
for (uint32_t id : node.destroy) {
resourceRegistry[id].destroy(driver);

View File

@@ -43,6 +43,7 @@ namespace filament {
namespace fg {
struct Resource;
struct ResourceNode;
struct RenderTarget;
struct PassNode;
struct Alias;
} // namespace fg
@@ -57,27 +58,29 @@ public:
Builder(Builder const&) = delete;
Builder& operator=(Builder const&) = delete;
// create a resource
using RWFlags = uint8_t;
static constexpr RWFlags NONE = 0x0;
static constexpr RWFlags COLOR = 0x1; // COLOR buffer access
static constexpr RWFlags DEPTH = 0x2; // DEPTH buffer access
// TODO: should this always register a write? If the GPU doesn't write into the resource
// what's the point of creating it?
// Create a virtual resource that can eventually turn into a concrete texture or
// render target
FrameGraphResource createResource(const char* name,
FrameGraphResource declareTexture(const char* name,
FrameGraphResource::Descriptor const& desc = {}) noexcept;
FrameGraphRenderTarget declareRenderTarget(const char* name,
FrameGraphRenderTarget::Descriptor const& desc = {}) noexcept;
FrameGraphRenderTarget declareRenderTarget(FrameGraphResource texture) noexcept;
// Read from a resource (i.e. add a reference to that resource)
FrameGraphResource read(FrameGraphResource const& input, RWFlags readFlags = COLOR);
FrameGraphResource read(FrameGraphResource const& input);
// The resource will be used as a source of a blit()
FrameGraphResource blit(FrameGraphResource const& input, RWFlags readFlags = COLOR);
FrameGraphResource blit(FrameGraphResource const& input);
// TODO: should write be replaced by declareRenderTarget()?
// Write to a resource (i.e. add a reference to the pass that's doing the writing))
// Writing to a resource makes its handle invalid.
// Writing to an imported resources adds a side-effect (see sideEffect() below).
FrameGraphResource write(FrameGraphResource const& output, RWFlags writeFlags = COLOR);
FrameGraphResource write(FrameGraphResource const& output);
// Declare that this pass has side effects outside the framegraph (i.e. it can't be culled)
// Calling write() on an imported resource automatically adds a side-effect.
@@ -122,8 +125,7 @@ public:
}
// Adds a reference to 'input', preventing it from being culled.
void present(FrameGraphResource input,
Builder::RWFlags sideEffects = Builder::COLOR | Builder::DEPTH);
void present(FrameGraphResource input);
// Returns whether the resource handle is valid. A resource handle becomes invalid after
// it's used to declare a resource write (see Builder::write()).
@@ -135,21 +137,14 @@ public:
// Import a write-only render target from outside the framegraph and returns a handle to it.
FrameGraphResource importResource(
const char* name, FrameGraphResource::Descriptor const& descriptor,
const char* name, FrameGraphRenderTarget::Descriptor const& descriptor,
Handle<HwRenderTarget> target);
// Import a read-only render target from outside the framegraph and returns a handle to it.
FrameGraphResource importResource(
const char* name, FrameGraphResource::Descriptor const& descriptor,
Handle<HwTexture> color,
Handle<HwTexture> depth = {});
Handle<HwTexture> color);
// Import a read/write render target from outside the framegraph and returns a handle to it.
FrameGraphResource importResource(
const char* name, FrameGraphResource::Descriptor const& descriptor,
Handle<HwRenderTarget> target,
Handle<HwTexture> color,
Handle<HwTexture> depth = {});
// Moves the resource associated to the handle 'from' to the handle 'to'. After this call,
// all handles referring to the resource 'to' are redirected to the resource 'from'
@@ -170,6 +165,7 @@ public:
private:
friend class FrameGraphPassResources;
friend struct fg::PassNode;
friend struct fg::RenderTarget;
template <typename T>
using Allocator = utils::STLAllocator<T, details::LinearAllocatorArena>;
@@ -184,10 +180,19 @@ private:
FrameGraphResource::Descriptor const& desc, bool imported) noexcept;
fg::ResourceNode* getResource(FrameGraphResource r);
fg::RenderTarget& createRenderTarget(const char* name,
FrameGraphRenderTarget::Descriptor const& desc, bool imported) noexcept;
enum class DiscardPhase { START, END };
uint8_t computeDiscardFlags(DiscardPhase phase,
fg::PassNode const* curr, fg::PassNode const* first,
fg::RenderTarget const& renderTarget);
details::LinearAllocatorArena mArena;
Vector<fg::PassNode> mPassNodes; // list of frame graph passes
Vector<fg::ResourceNode> mResourceNodes;
Vector<fg::RenderTarget> mRenderTargets;
Vector<fg::Resource> mResourceRegistry; // frame graph concrete resources
Vector<fg::Alias> mAliases;
};

View File

@@ -33,15 +33,14 @@ class FrameGraphResource;
class FrameGraphPassResources {
public:
struct RenderTarget {
struct RenderTargetInfo {
Handle<HwRenderTarget> target;
driver::RenderPassParams params;
};
Handle<HwTexture> getTexture(FrameGraphResource r,
driver::TextureUsage attachment = driver::TextureUsage::DEFAULT) const noexcept;
Handle <HwTexture> getTexture(FrameGraphResource r) const noexcept;
RenderTarget const& getRenderTarget(FrameGraphResource r) const noexcept;
RenderTargetInfo const& getRenderTarget(FrameGraphRenderTarget r) const noexcept;
FrameGraphResource::Descriptor const& getDescriptor(FrameGraphResource r) const noexcept;

View File

@@ -27,6 +27,7 @@ namespace filament {
namespace fg {
struct PassNode;
struct RenderTarget;
} // namespace fg
class FrameGraph;
@@ -42,13 +43,11 @@ class FrameGraphResource {
friend class FrameGraph;
friend class FrameGraphPassResources;
friend struct fg::PassNode;
friend struct fg::RenderTarget;
FrameGraphResource(uint16_t index, uint8_t version) noexcept
: index(index), version(version) {}
FrameGraphResource(uint16_t index, uint8_t version, uint8_t flags) noexcept
: index(index), version(version), flags(flags) {}
static constexpr uint16_t UNINITIALIZED = std::numeric_limits<uint16_t>::max();
// index to the resource handle
uint16_t index = UNINITIALIZED;
@@ -56,9 +55,6 @@ class FrameGraphResource {
// resource handle's version, this resource has become invalid.
uint8_t version = 0;
// buffers accessed for either read or write
uint8_t flags = 0;
public:
FrameGraphResource() noexcept = default;
@@ -67,7 +63,6 @@ public:
uint32_t height = 1; // height of resource in pixel
uint32_t depth = 1; // # of images for 3D textures
uint8_t levels = 1; // # of levels for textures
uint8_t samples = 1; // # of sample for render targets
driver::SamplerType type = driver::SamplerType::SAMPLER_2D; // texture target type
driver::TextureFormat format = driver::TextureFormat::RGBA8; // resource internal format
};
@@ -87,6 +82,47 @@ public:
}
};
class FrameGraphRenderTarget {
friend class FrameGraph;
friend class FrameGraphPassResources;
friend struct fg::PassNode;
explicit FrameGraphRenderTarget(uint16_t index) noexcept : index(index) {}
static constexpr uint16_t UNINITIALIZED = std::numeric_limits<uint16_t>::max();
// index to the resource handle
uint16_t index = UNINITIALIZED;
public:
FrameGraphRenderTarget() noexcept = default;
struct Descriptor {
uint32_t width = 1; // width of resource in pixel
uint32_t height = 1; // height of resource in pixel
uint8_t samples = 1; // # of samples
struct {
FrameGraphResource color; // color attachment
FrameGraphResource depth; // depth attachment
} attachments;
};
bool isValid() const noexcept { return index != UNINITIALIZED; }
bool operator < (const FrameGraphRenderTarget& rhs) const noexcept {
return (index < rhs.index);
}
bool operator == (const FrameGraphRenderTarget& rhs) const noexcept {
return (index == rhs.index);
}
bool operator != (const FrameGraphRenderTarget& rhs) const noexcept {
return !operator==(rhs);
}
};
} // namespace filament
#endif //TNT_FILAMENT_FRAMEGRAPHRESOURCE_H

View File

@@ -35,6 +35,7 @@ TEST(FrameGraphTest, SimpleRenderPass) {
struct RenderPassData {
FrameGraphResource output;
FrameGraphRenderTarget outRenderTarget;
};
auto& renderPass = fg.addPass<RenderPassData>("Render",
@@ -42,7 +43,8 @@ TEST(FrameGraphTest, SimpleRenderPass) {
FrameGraphResource::Descriptor desc {
.format = driver::TextureFormat::RGBA16F
};
data.output = builder.write(builder.createResource("renderTarget", desc));
data.output = builder.write(builder.declareTexture("renderTarget", desc));
data.outRenderTarget = builder.declareRenderTarget(data.output);
EXPECT_TRUE(data.output.isValid());
EXPECT_TRUE(fg.isValid(data.output));
},
@@ -51,7 +53,7 @@ TEST(FrameGraphTest, SimpleRenderPass) {
RenderPassData const& data,
driver::DriverApi& driver) {
renderPassExecuted = true;
EXPECT_TRUE(resources.getRenderTarget(data.output).target);
EXPECT_TRUE(resources.getRenderTarget(data.outRenderTarget).target);
});
@@ -74,7 +76,7 @@ TEST(FrameGraphTest, SimpleRenderPassReadWrite) {
auto& renderPass = fg.addPass<RenderPassData>("Render",
[&](FrameGraph::Builder& builder, RenderPassData& data) {
auto r = builder.createResource("renderTarget", {});
auto r = builder.declareTexture("renderTarget", {});
data.output = builder.write(r);
data.input = builder.read(data.output);
},
@@ -99,6 +101,7 @@ TEST(FrameGraphTest, SimpleRenderAndPostProcessPasses) {
struct RenderPassData {
FrameGraphResource output;
FrameGraphRenderTarget outRenderTarget;
};
auto& renderPass = fg.addPass<RenderPassData>("Render",
@@ -106,7 +109,8 @@ TEST(FrameGraphTest, SimpleRenderAndPostProcessPasses) {
FrameGraphResource::Descriptor desc {
.format = driver::TextureFormat::RGBA16F
};
data.output = builder.write(builder.createResource("renderTarget", desc));
data.output = builder.write(builder.declareTexture("renderTarget", desc));
data.outRenderTarget = builder.declareRenderTarget(data.output);
EXPECT_TRUE(data.output.isValid());
EXPECT_TRUE(fg.isValid(data.output));
},
@@ -115,7 +119,7 @@ TEST(FrameGraphTest, SimpleRenderAndPostProcessPasses) {
RenderPassData const& data,
driver::DriverApi& driver) {
renderPassExecuted = true;
EXPECT_TRUE(resources.getRenderTarget(data.output).target);
EXPECT_TRUE(resources.getRenderTarget(data.outRenderTarget).target);
});
@@ -175,7 +179,7 @@ TEST(FrameGraphTest, SimplePassCulling) {
auto& renderPass = fg.addPass<RenderPassData>("Render",
[&](FrameGraph::Builder& builder, RenderPassData& data) {
data.output = builder.write(builder.createResource("renderTarget"));
data.output = builder.write(builder.declareTexture("renderTarget"));
},
[=, &renderPassExecuted](
FrameGraphPassResources const& resources,
@@ -193,7 +197,7 @@ TEST(FrameGraphTest, SimplePassCulling) {
auto& postProcessPass = fg.addPass<PostProcessPassData>("PostProcess",
[&](FrameGraph::Builder& builder, PostProcessPassData& data) {
data.input = builder.read(renderPass.getData().output);
data.output = builder.write(builder.createResource("postprocess-renderTarget"));
data.output = builder.write(builder.declareTexture("postprocess-renderTarget"));
},
[=, &postProcessPassExecuted](
FrameGraphPassResources const& resources,
@@ -211,7 +215,7 @@ TEST(FrameGraphTest, SimplePassCulling) {
auto& culledPass = fg.addPass<CulledPassData>("CulledPass",
[&](FrameGraph::Builder& builder, CulledPassData& data) {
data.input = builder.read(renderPass.getData().output);
data.output = builder.write(builder.createResource("unused-rendertarget"));
data.output = builder.write(builder.declareTexture("unused-rendertarget"));
},
[=, &culledPassExecuted](
FrameGraphPassResources const& resources,
@@ -266,7 +270,7 @@ TEST(FrameGraphTest, BadGraph) {
auto& R0 = fg.addPass<R0Data>("R1",
[&](FrameGraph::Builder& builder, R0Data& data) {
data.output = builder.write(builder.createResource("A"));
data.output = builder.write(builder.declareTexture("A"));
},
[=, &R0exec](FrameGraphPassResources const&, R0Data const&, driver::DriverApi&) {
R0exec = true;
@@ -317,7 +321,7 @@ TEST(FrameGraphTest, ComplexGraph) {
};
auto& depthPass = fg.addPass<DepthPassData>("Depth pass",
[&](FrameGraph::Builder& builder, DepthPassData& data) {
data.output = builder.write(builder.createResource("Depth Buffer"));
data.output = builder.write(builder.declareTexture("Depth Buffer"));
},
[=](FrameGraphPassResources const&, DepthPassData const&, driver::DriverApi&) {
});
@@ -332,7 +336,7 @@ TEST(FrameGraphTest, ComplexGraph) {
auto& buggyPass = fg.addPass<BuffyPassData>("Bug",
[&](FrameGraph::Builder& builder, BuffyPassData& data) {
data.input = builder.read(depthPass.getData().output);
data.output = builder.write(builder.createResource("Buggy output"));
data.output = builder.write(builder.declareTexture("Buggy output"));
},
[&](FrameGraphPassResources const&, BuffyPassData const&, driver::DriverApi&) {
});
@@ -349,9 +353,9 @@ TEST(FrameGraphTest, ComplexGraph) {
[&](FrameGraph::Builder& builder, GBufferPassData& data) {
data.input = builder.read(depthPass.getData().output);
data.output = builder.write(data.input);
data.gbuffers[0] = builder.write(builder.createResource("Gbuffer 1"));
data.gbuffers[1] = builder.write(builder.createResource("Gbuffer 2"));
data.gbuffers[2] = builder.write(builder.createResource("Gbuffer 3"));
data.gbuffers[0] = builder.write(builder.declareTexture("Gbuffer 1"));
data.gbuffers[1] = builder.write(builder.declareTexture("Gbuffer 2"));
data.gbuffers[2] = builder.write(builder.declareTexture("Gbuffer 3"));
},
[=](FrameGraphPassResources const&, GBufferPassData const&, driver::DriverApi&) {
});
@@ -367,7 +371,7 @@ TEST(FrameGraphTest, ComplexGraph) {
data.input[1] = builder.read(gbufferPass.getData().gbuffers[0]);
data.input[2] = builder.read(gbufferPass.getData().gbuffers[1]);
data.input[3] = builder.read(gbufferPass.getData().gbuffers[2]);
data.output = builder.write(builder.createResource("Lighting buffer"));
data.output = builder.write(builder.declareTexture("Lighting buffer"));
},
[=](FrameGraphPassResources const&, LightingPassData const&, driver::DriverApi&) {
});
@@ -380,7 +384,7 @@ TEST(FrameGraphTest, ComplexGraph) {
auto& convolutionPass = fg.addPass<ConvolutionPassData>("Convolution",
[&](FrameGraph::Builder& builder, ConvolutionPassData& data) {
data.input = builder.read(gbufferPass.getData().gbuffers[2]); //builder.createTexture("Cubemap", Builder::READ, {});
data.output = builder.write(builder.createResource("Reflection probe"));
data.output = builder.write(builder.declareTexture("Reflection probe"));
},
[=](FrameGraphPassResources const&, ConvolutionPassData const&, driver::DriverApi&) {
});
@@ -405,7 +409,7 @@ TEST(FrameGraphTest, MoveResource) {
auto& renderPass = fg.addPass<RenderPassData>("Render",
[&](FrameGraph::Builder& builder, RenderPassData& data) {
data.input = builder.read(builder.createResource("render-inout"));
data.input = builder.read(builder.declareTexture("render-inout"));
data.output = builder.write(data.input);
},
[=](FrameGraphPassResources const& resources, RenderPassData const& data, driver::DriverApi&) {
@@ -414,7 +418,7 @@ TEST(FrameGraphTest, MoveResource) {
auto& debugPass = fg.addPass<RenderPassData>("Debug",
[&](FrameGraph::Builder& builder, RenderPassData& data) {
data.input = builder.read(builder.createResource("debug-inout"));
data.input = builder.read(builder.declareTexture("debug-inout"));
data.output = builder.write(data.input);
},
[=](FrameGraphPassResources const& resources, RenderPassData const& data, driver::DriverApi&) {