diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index c40783e026..19e75c395b 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -194,24 +194,28 @@ FrameGraphResource PostProcessManager::msaa(FrameGraph& fg, struct PostProcessMSAA { FrameGraphResource input; FrameGraphResource output; + FrameGraphRenderTarget inRenderTarget; + FrameGraphRenderTarget outRenderTarget; }; auto& ppMSAA = fg.addPass("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 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 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("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, diff --git a/filament/src/Renderer.cpp b/filament/src/Renderer.cpp index 9bf3488992..e972c6b6e2 100644 --- a/filament/src/Renderer.cpp +++ b/filament/src/Renderer.cpp @@ -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); diff --git a/filament/src/fg/FrameGraph.cpp b/filament/src/fg/FrameGraph.cpp index 5e06256055..b9760a0dad 100644 --- a/filament/src/fg/FrameGraph.cpp +++ b/filament/src/fg/FrameGraph.cpp @@ -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 textures[2] = {}; // color, depth - FrameGraphPassResources::RenderTarget target; + + // can't use union without implementing the move ctor manually. not a problem right now. + //union { + Handle 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 color; + Handle 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 using Vector = FrameGraph::Vector; @@ -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 base; // type eraser for calling execute() // set by the builder Vector reads; // resources we're reading from Vector writes; // resources we're writing to + Vector renderTargets; // declared renderTargets - struct TargetFlags { - uint8_t clear = 0; - uint8_t discardStart = 0; - uint8_t discardEnd = 0; - uint8_t dependencies = 0; - }; Vector 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 FrameGraphPassResources::getTexture( - FrameGraphResource r, TextureUsage attachment) const noexcept { - +Handle FrameGraphPassResources::getTexture(FrameGraphResource r) const noexcept { Resource const* const pResource = mFrameGraph.mResourceNodes[r.index].resource; assert(pResource); @@ -386,66 +441,26 @@ Handle FrameGraphPassResources::getTexture( "Pass \"%s\" doesn't declare reads to resource \"%s\" -- expect graphic corruptions", mPass.name, pResource->name); - - const char* requested = "unknown"; - Handle 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("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 target) { - return importResource(name, descriptor, target, {}, {}); + const char* name, FrameGraphRenderTarget::Descriptor const& descriptor, + Handle 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 color, Handle depth) { - return importResource(name, descriptor, {}, color, depth); -} - -FrameGraphResource FrameGraph::importResource( - const char* name, FrameGraphResource::Descriptor const& descriptor, - Handle target, - Handle color, Handle depth) { + Handle 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); diff --git a/filament/src/fg/FrameGraph.h b/filament/src/fg/FrameGraph.h index f5a1e16b65..434c6a4e79 100644 --- a/filament/src/fg/FrameGraph.h +++ b/filament/src/fg/FrameGraph.h @@ -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 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 color, - Handle depth = {}); + Handle 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 target, - Handle color, - Handle 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 using Allocator = utils::STLAllocator; @@ -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 mPassNodes; // list of frame graph passes Vector mResourceNodes; + Vector mRenderTargets; Vector mResourceRegistry; // frame graph concrete resources Vector mAliases; }; diff --git a/filament/src/fg/FrameGraphPassResources.h b/filament/src/fg/FrameGraphPassResources.h index d14052533c..300b38ed24 100644 --- a/filament/src/fg/FrameGraphPassResources.h +++ b/filament/src/fg/FrameGraphPassResources.h @@ -33,15 +33,14 @@ class FrameGraphResource; class FrameGraphPassResources { public: - struct RenderTarget { + struct RenderTargetInfo { Handle target; driver::RenderPassParams params; }; - Handle getTexture(FrameGraphResource r, - driver::TextureUsage attachment = driver::TextureUsage::DEFAULT) const noexcept; + Handle 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; diff --git a/filament/src/fg/FrameGraphResource.h b/filament/src/fg/FrameGraphResource.h index ad5f7b4b10..ad1d4a8a3f 100644 --- a/filament/src/fg/FrameGraphResource.h +++ b/filament/src/fg/FrameGraphResource.h @@ -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::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::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 diff --git a/filament/test/filament_framegraph_test.cpp b/filament/test/filament_framegraph_test.cpp index 311b163f4b..acc536d09a 100644 --- a/filament/test/filament_framegraph_test.cpp +++ b/filament/test/filament_framegraph_test.cpp @@ -35,6 +35,7 @@ TEST(FrameGraphTest, SimpleRenderPass) { struct RenderPassData { FrameGraphResource output; + FrameGraphRenderTarget outRenderTarget; }; auto& renderPass = fg.addPass("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("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("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("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("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("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("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("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("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("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("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("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&) {