renderpass rebuild
This commit is contained in:
parent
44bf81dcfe
commit
fcf226ff3f
@ -1,48 +0,0 @@
|
||||
#include "asset/res/resource_handle.h"
|
||||
#include "math/vector2.h"
|
||||
#include "render_enum.h"
|
||||
namespace api {
|
||||
/*
|
||||
class Texture;
|
||||
struct Attachment
|
||||
{
|
||||
re::LoadOp load_op{};
|
||||
re::StoreOp store_op{};
|
||||
re::LoadOp stencil_load_op{};
|
||||
re::StoreOp stencil_store_op{};
|
||||
bool own_buffer = false;
|
||||
RscHandle<Texture> buffer;
|
||||
RscHandle<Texture> operator*()const { return buffer; }
|
||||
operator RscHandle<Texture>()const { return buffer; }
|
||||
const RscHandle<Texture>* operator->()const { return &buffer; }
|
||||
Attachment() = default;
|
||||
Attachment(const Attachment&) = delete;
|
||||
Attachment(Attachment&& rhs) : own_buffer{ rhs.own_buffer }, buffer{ rhs.buffer }
|
||||
{
|
||||
rhs.own_buffer = false;
|
||||
rhs.buffer = {};
|
||||
}
|
||||
Attachment& operator=(const Attachment&) = delete;
|
||||
Attachment& operator=(Attachment&&) = default;
|
||||
virtual ~Attachment();
|
||||
};
|
||||
struct TextureDesc
|
||||
{
|
||||
string name;
|
||||
Vector2 size;
|
||||
re::Format format;
|
||||
static TextureDesc Make() {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
struct AttachmentDesc
|
||||
{
|
||||
re::LoadOp load_op;
|
||||
re::StoreOp store_op;
|
||||
re::LoadOp stencil_load_op;
|
||||
re::StoreOp stencil_store_op;
|
||||
static AttachmentDesc Make() {
|
||||
return {};
|
||||
}
|
||||
};*/
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
#include <cstdint>
|
||||
namespace api::re {
|
||||
enum class StoreOp : uint8_t
|
||||
{
|
||||
eDontCare,
|
||||
eStore
|
||||
};
|
||||
enum class LoadOp : uint8_t
|
||||
{
|
||||
eDontCare,
|
||||
eClear,
|
||||
eLoad
|
||||
};
|
||||
enum AttachmentType : uint8_t
|
||||
{
|
||||
eColor,
|
||||
eDepth,
|
||||
eStencil,
|
||||
eDepth3D,
|
||||
eSizeAT
|
||||
};
|
||||
enum class Format : uint16_t {
|
||||
|
||||
};
|
||||
}
|
||||
@ -1,12 +1,11 @@
|
||||
#pragma once
|
||||
#include "asset/asset.h"
|
||||
#include "render/type.h"
|
||||
#include "render/render_type.h"
|
||||
namespace api {
|
||||
class Texture : public Resource<Texture>
|
||||
{
|
||||
public:
|
||||
TextureDesc mDesc;
|
||||
void* mPtr;
|
||||
public:
|
||||
Texture(TextureDesc& desc);
|
||||
};
|
||||
|
||||
@ -1,18 +1,23 @@
|
||||
#pragma once
|
||||
#include "type.h"
|
||||
#include "frame_graph_node.h"
|
||||
namespace api {
|
||||
struct FRenderView;
|
||||
using pmr::Tag;
|
||||
class FrameGraph
|
||||
{
|
||||
public:
|
||||
uint32_t mSurfaceID{0};
|
||||
table<TextureSampler, void*> mTextureSamplerPool;
|
||||
table<Tag, uint32_t> mTextureTagMap;
|
||||
table<TextureKey, uint32_t> mTextureKeyMap;
|
||||
std::vector<TextureDesc> mTexturePool;
|
||||
table<TextureViewKey, ImageViewPtr> mTextureViewPool;
|
||||
pmr::vector<FrameGraphNodePtr> mNodes{FramePool()};
|
||||
struct TextureID{
|
||||
uint32_t id;
|
||||
uint32_t tick;
|
||||
};
|
||||
uint32_t mTickStamp{1};
|
||||
uint32_t mSurfaceID{0};
|
||||
table<TextureSampler, void*> mTextureSamplerPool;
|
||||
table<Tag, uint32_t> mTextureTagMap;
|
||||
table<TextureKey, std::vector<TextureID>> mTextureKeyMap;//一张图不够用了
|
||||
std::vector<TextureDesc> mTexturePool;
|
||||
table<TextureViewKey, ImageViewPtr> mTextureViewPool;
|
||||
pmr::vector<FrameGraphNodePtr> mNodes{FramePool()};
|
||||
RenderPassNode* mFirstInputNode{ nullptr };
|
||||
RenderPassNode* mLastOutputNode{ nullptr };
|
||||
inline static Name NameSurface{ "surface" };
|
||||
@ -39,16 +44,16 @@ namespace api {
|
||||
TextureDesc& GetRenderSurface();
|
||||
void TransitionState(TextureDesc& desc, ResourceState state);
|
||||
bool ResolveState(TextureDesc& desc, ResourceState& srcstart, ResourceState& dststate);
|
||||
bool ResolveState(AttachmentDesc& desc, ResourceState& srcstart, ResourceState& dststate);
|
||||
bool ResolveState(BufferDesc& desc, ResourceState& srcstart, ResourceState& dststate);
|
||||
TextureDesc& ResolveTexture(uint32_t id);
|
||||
TextureDesc ResourceTexture(Name name, int num);
|
||||
ImageViewPtr ResolveTextureView(TextureDesc& desc);
|
||||
ImageViewPtr ResolveTextureView(TextureViewKey key);
|
||||
void* ResolveTextureSampler(TextureSampler sampler);
|
||||
void ResourceTexture(TextureDesc& desc);
|
||||
void SetResourceTexture(TextureDesc texture, Name name, int num = 0);
|
||||
uint32_t GetTextureID(Name name, int num);
|
||||
void AcquireTexture(TextureDesc& desc);
|
||||
void RealeaseTexture(TextureDesc& desc);
|
||||
public:
|
||||
void ExecutePresentPass(FRenderView& view);
|
||||
void ExecuteRenderPass(RenderPassNode* node, FRenderView& view);
|
||||
@ -58,4 +63,3 @@ namespace api {
|
||||
static void ExecuteResourceBarriers(RenderPassNode* node, RenderPassType type);
|
||||
};
|
||||
}
|
||||
#include "frame_graph_builder.inl"
|
||||
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
namespace api {
|
||||
struct RenderPassBuilder {
|
||||
FrameGraph& graph;
|
||||
FrameGraphNodePtr node;
|
||||
FrameResource* resource{nullptr};
|
||||
public:
|
||||
RenderPassBuilder(FrameGraph* graph) noexcept
|
||||
: graph(*graph), node() {};
|
||||
RenderPassBuilder(FrameGraph* graph, FrameGraphNodePtr& node) noexcept
|
||||
: graph(*graph) , node(node) {};
|
||||
RenderPassBuilder& Name(pmr::Name name);
|
||||
RenderPassBuilder& Type(RenderPassNodeType type,RenderPassNodeFlag flag = RenderPassNodeFlag::None);
|
||||
RenderPassBuilder& Read(TextureDesc desc, ResourceState state, pmr::Name name = {});
|
||||
RenderPassBuilder& Write(AttachmentDesc desc, ResourceState state, pmr::Name name = {});
|
||||
RenderPassBuilder& Dependency(RenderPassNode* rely) { node->dependencies.push_back(rely); return *this;}
|
||||
};
|
||||
}
|
||||
@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
#include "asset/asset.h"
|
||||
#include "render/type.h"
|
||||
#include <functional>
|
||||
namespace api {
|
||||
class FrameGraph;
|
||||
#include "meta/enum.h"
|
||||
#include "render/render_type.h"
|
||||
namespace api{
|
||||
class FrameGraph;
|
||||
class RenderPassBuilder;
|
||||
struct RenderPassNode;
|
||||
struct RenderContext;
|
||||
@ -37,7 +36,7 @@ namespace api {
|
||||
}
|
||||
};
|
||||
struct FrameResource {
|
||||
using Resource = std::variant<TextureDesc, BufferDesc, AttachmentDesc>;
|
||||
using Resource = std::variant<TextureDesc, BufferDesc>;
|
||||
Name name;
|
||||
Resource res;
|
||||
FrameResource() noexcept = default;
|
||||
@ -46,9 +45,6 @@ namespace api {
|
||||
T& CastTo() {
|
||||
return std::get<T>(res);
|
||||
}
|
||||
bool IsAttachment() const {
|
||||
return std::holds_alternative<AttachmentDesc>(res);
|
||||
}
|
||||
bool IsTexture() const{
|
||||
return std::holds_alternative<TextureDesc>(res);
|
||||
}
|
||||
@ -60,18 +56,6 @@ namespace api {
|
||||
}
|
||||
};
|
||||
using FrameGraphEdgePtr = FrameResource*;
|
||||
enum class RenderPassNodeType : uint8_t {
|
||||
None,
|
||||
Scene,
|
||||
Imgui,
|
||||
};
|
||||
enum class RenderPassNodeFlag : uint8_t
|
||||
{
|
||||
None = 0,
|
||||
Output = 0x01,
|
||||
FirstInput = 0x02,
|
||||
LastOutput = 0x04,
|
||||
};
|
||||
using RenderPassEdgeIterFn = std::function<void(FrameResource*)>;
|
||||
struct RenderPassNode {
|
||||
Name name;
|
||||
@ -79,6 +63,7 @@ namespace api {
|
||||
RenderPassNodeType type{0};
|
||||
RenderPassNodeFlag flag{0};
|
||||
bool isActive{ false };
|
||||
RenderPassParams params{};
|
||||
RenderPassSetupFunction setup;
|
||||
RenderPassNodeExecuteFn executor;
|
||||
pmr::vector<RenderPassNode*> dependencies{ FramePool() };
|
||||
@ -113,4 +98,20 @@ namespace api {
|
||||
{
|
||||
return node->hash;
|
||||
}
|
||||
struct RenderPassBuilder {
|
||||
FrameGraph& graph;
|
||||
FrameGraphNodePtr node;
|
||||
FrameResource* resource{ nullptr };
|
||||
public:
|
||||
RenderPassBuilder(FrameGraph* graph) noexcept
|
||||
: graph(*graph), node() {};
|
||||
RenderPassBuilder(FrameGraph* graph, FrameGraphNodePtr& node) noexcept
|
||||
: graph(*graph), node(node) {};
|
||||
RenderPassBuilder& Name(pmr::Name name);
|
||||
RenderPassBuilder& Type(RenderPassNodeType type, RenderPassNodeFlag flag = RenderPassNodeFlag::None);
|
||||
RenderPassBuilder& Read(TextureDesc desc, ResourceState state, pmr::Name name = {});
|
||||
RenderPassBuilder& Write(TextureDesc desc, ResourceState state, pmr::Name name = {});
|
||||
RenderPassBuilder& Dependency(RenderPassNode* rely) { node->dependencies.push_back(rely); return *this; }
|
||||
RenderPassBuilder& Attachment(AttachmentFlag flag);
|
||||
};
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "type.h"
|
||||
#include "render_type.h"
|
||||
namespace api {
|
||||
struct RenderContext;
|
||||
struct FRenderView {
|
||||
|
||||
365
engine/modules/engine/render/include/render/render_type.h
Normal file
365
engine/modules/engine/render/include/render/render_type.h
Normal file
@ -0,0 +1,365 @@
|
||||
#pragma once
|
||||
#include "tinyimageformat/tinyimageformat_base.h"
|
||||
#include "math/vector2.h"
|
||||
#include "math/vector4.h"
|
||||
#include "asset/asset.h"
|
||||
#include <functional>
|
||||
namespace api {
|
||||
enum class RenderPassType : uint8_t {
|
||||
Render,
|
||||
Present,
|
||||
Compute,
|
||||
Copy
|
||||
};
|
||||
enum class AttachmentFlag : uint8_t {
|
||||
None = 0,
|
||||
Clear = 0x01,
|
||||
DiscardStart = 0x02,
|
||||
DiscardEnd = 0x04,
|
||||
DepthStencil = 0x08,
|
||||
MainPass = 0x10,
|
||||
Subpass = 0x20,
|
||||
Sample = 0x40,
|
||||
};
|
||||
enum class RenderPassNodeType : uint8_t {
|
||||
None,
|
||||
Scene,
|
||||
Imgui,
|
||||
};
|
||||
enum class RenderPassNodeFlag : uint8_t
|
||||
{
|
||||
None = 0,
|
||||
Output = 0x01,
|
||||
FirstInput = 0x02,
|
||||
LastOutput = 0x04,
|
||||
};
|
||||
enum class BufferUsage : uint8_t {
|
||||
STATIC = 0x01, //!< content modified once, used many times
|
||||
DYNAMIC = 0x02, //!< content modified frequently, used many times
|
||||
VERTEX = 0x04,
|
||||
UNIFORM = 0x08,
|
||||
SHADER_STORAGE = 0x10
|
||||
};
|
||||
enum class ResourceMemoryUsage : uint8_t
|
||||
{
|
||||
/// No intended memory usage specified.
|
||||
UNKNOWN = 0,
|
||||
/// Memory will be used on device only, no need to be mapped on host.
|
||||
GPU_ONLY = 1,
|
||||
/// Memory will be mapped on host. Could be used for transfer to device.
|
||||
CPU_ONLY = 2,
|
||||
/// Memory will be used for frequent (dynamic) updates from host and reads on device.
|
||||
CPU_TO_GPU = 3,
|
||||
/// Memory will be used for writing on device and readback on host.
|
||||
GPU_TO_CPU = 4,
|
||||
COUNT,
|
||||
};
|
||||
enum SampleCount : uint8_t
|
||||
{
|
||||
SAMPLE_COUNT_1 = 1,
|
||||
SAMPLE_COUNT_2 = 2,
|
||||
SAMPLE_COUNT_4 = 4,
|
||||
SAMPLE_COUNT_8 = 8,
|
||||
SAMPLE_COUNT_16 = 16,
|
||||
SAMPLE_COUNT_COUNT = 5,
|
||||
};
|
||||
enum class ResourceState : uint8_t
|
||||
{
|
||||
// The initial layout after the creation of the VkImage. We use this to denote the state before
|
||||
// any transition.
|
||||
UNDEFINED,
|
||||
// Fragment/vertex shader accessible layout for reading and writing.
|
||||
READ_WRITE,
|
||||
// Fragment/vertex shader accessible layout for reading only.
|
||||
READ_ONLY,
|
||||
// For the source of a copy operation.
|
||||
TRANSFER_SRC,
|
||||
// For the destination of a copy operation.
|
||||
TRANSFER_DST,
|
||||
// For using a depth texture as an attachment.
|
||||
DEPTH_ATTACHMENT,
|
||||
// For using a depth texture both as an attachment and as a sampler.
|
||||
DEPTH_SAMPLER,
|
||||
// For swapchain images that will be presented.
|
||||
PRESENT,
|
||||
// For color attachments, but also used when the image is a sampler.
|
||||
// TODO: explore separate layout policies for attachment+sampling and just attachment.
|
||||
COLOR_ATTACHMENT,
|
||||
};
|
||||
enum class TextureUsage :uint16_t {
|
||||
NONE = 0x0000,
|
||||
COLOR_ATTACHMENT = 0x0001, //!< Texture can be used as a color attachment
|
||||
DEPTH_ATTACHMENT = 0x0002, //!< Texture can be used as a depth attachment
|
||||
STENCIL_ATTACHMENT = 0x0004, //!< Texture can be used as a stencil attachment
|
||||
UPLOADABLE = 0x0008, //!< Data can be uploaded into this texture (default)
|
||||
SAMPLEABLE = 0x0010, //!< Texture can be sampled (default)
|
||||
SUBPASS_INPUT = 0x0020, //!< Texture can be used as a subpass input
|
||||
BLIT_SRC = 0x0040, //!< Texture can be used the source of a blit()
|
||||
BLIT_DST = 0x0080, //!< Texture can be used the destination of a blit()
|
||||
PROTECTED = 0x0100, //!< Texture can be used for protected content
|
||||
DEFAULT = UPLOADABLE | SAMPLEABLE //!< Default texture usage
|
||||
};
|
||||
enum class TextureDimension : uint8_t
|
||||
{
|
||||
TEX_NULL = 0,
|
||||
TEX_1D = 0x01,
|
||||
TEX_2D = 0x02,
|
||||
TEX_3D = 0x04,
|
||||
TEX_CUBE = 0x08,
|
||||
};
|
||||
//! Sampler Wrap mode
|
||||
enum class SamplerWrapMode : uint8_t {
|
||||
CLAMP_TO_EDGE, //!< clamp-to-edge. The edge of the texture extends to infinity.
|
||||
REPEAT, //!< repeat. The texture infinitely repeats in the wrap direction.
|
||||
MIRRORED_REPEAT, //!< mirrored-repeat. The texture infinitely repeats and mirrors in the wrap direction.
|
||||
};
|
||||
|
||||
//! Sampler minification filter
|
||||
enum class SamplerMinFilter : uint8_t {
|
||||
// don't change the enums values
|
||||
NEAREST = 0, //!< No filtering. Nearest neighbor is used.
|
||||
LINEAR = 1, //!< Box filtering. Weighted average of 4 neighbors is used.
|
||||
NEAREST_MIPMAP_NEAREST = 2, //!< Mip-mapping is activated. But no filtering occurs.
|
||||
LINEAR_MIPMAP_NEAREST = 3, //!< Box filtering within a mip-map level.
|
||||
NEAREST_MIPMAP_LINEAR = 4, //!< Mip-map levels are interpolated, but no other filtering occurs.
|
||||
LINEAR_MIPMAP_LINEAR = 5 //!< Both interpolated Mip-mapping and linear filtering are used.
|
||||
};
|
||||
|
||||
//! Sampler magnification filter
|
||||
enum class SamplerMagFilter : uint8_t {
|
||||
// don't change the enums values
|
||||
NEAREST = 0, //!< No filtering. Nearest neighbor is used.
|
||||
LINEAR = 1, //!< Box filtering. Weighted average of 4 neighbors is used.
|
||||
};
|
||||
|
||||
//! Sampler compare mode
|
||||
enum class SamplerCompareMode : uint8_t {
|
||||
// don't change the enums values
|
||||
NONE = 0,
|
||||
COMPARE_TO_TEXTURE = 1
|
||||
};
|
||||
|
||||
//! comparison function for the depth / stencil sampler
|
||||
enum class SamplerCompareFunc : uint8_t {
|
||||
// don't change the enums values
|
||||
LE = 0, //!< Less or equal
|
||||
GE, //!< Greater or equal
|
||||
L, //!< Strictly less than
|
||||
G, //!< Strictly greater than
|
||||
E, //!< Equal
|
||||
NE, //!< Not equal
|
||||
A, //!< Always. Depth / stencil testing is deactivated.
|
||||
N //!< Never. The depth / stencil test always fails.
|
||||
};
|
||||
using SamplerPtr = void*;
|
||||
//! Sampler parameters
|
||||
struct TextureSampler { // NOLINT
|
||||
SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST)
|
||||
SamplerMinFilter filterMin : 3; //!< minification filter (NEAREST)
|
||||
SamplerWrapMode wrapS : 2; //!< s-coordinate wrap mode (CLAMP_TO_EDGE)
|
||||
SamplerWrapMode wrapT : 2; //!< t-coordinate wrap mode (CLAMP_TO_EDGE)
|
||||
|
||||
SamplerWrapMode wrapR : 2; //!< r-coordinate wrap mode (CLAMP_TO_EDGE)
|
||||
uint8_t anisotropyLog2 : 3; //!< anisotropy level (0)
|
||||
SamplerCompareMode compareMode : 1; //!< sampler compare mode (NONE)
|
||||
uint8_t padding0 : 2; //!< reserved. must be 0.
|
||||
|
||||
SamplerCompareFunc compareFunc : 3; //!< sampler comparison function (LE)
|
||||
uint8_t padding1 : 5; //!< reserved. must be 0.
|
||||
uint8_t padding2 : 8; //!< reserved. must be 0.
|
||||
struct EqualTo {
|
||||
bool operator()(TextureSampler lhs, TextureSampler rhs) const noexcept {
|
||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||
return *pLhs == *pRhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct LessThan {
|
||||
bool operator()(TextureSampler lhs, TextureSampler rhs) const noexcept {
|
||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||
return *pLhs == *pRhs;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
friend inline bool operator < (TextureSampler lhs, TextureSampler rhs) noexcept {
|
||||
return TextureSampler::LessThan{}(lhs, rhs);
|
||||
}
|
||||
public:
|
||||
friend inline bool operator== (TextureSampler lhs, TextureSampler rhs) noexcept {
|
||||
return TextureSampler::EqualTo{}(lhs, rhs);
|
||||
}
|
||||
};
|
||||
using ImagePtr = void*;
|
||||
using ImageViewPtr = void*;
|
||||
using BufferPtr = void*;
|
||||
struct BufferBarrier;
|
||||
struct TextureBarrier;
|
||||
struct BufferDesc {
|
||||
BufferPtr buffer;
|
||||
void* mappingAddr;
|
||||
uint32_t size;
|
||||
BufferUsage usage;
|
||||
ResourceMemoryUsage memoryUsage;
|
||||
static BufferDesc Make() {
|
||||
return {};
|
||||
}
|
||||
BufferBarrier ToBarrier(ResourceState from, ResourceState to)const;
|
||||
};
|
||||
struct TextureViewKey {
|
||||
ImagePtr image;
|
||||
TinyImageFormat format;
|
||||
TextureDimension dimension;
|
||||
uint8_t baseArrayLayer;
|
||||
uint8_t layerCount;
|
||||
uint8_t baseMipLevel;
|
||||
uint8_t levelCount;
|
||||
friend inline bool operator==(const TextureViewKey& k1, const TextureViewKey& k2) {
|
||||
if (k1.image != k2.image) return false;
|
||||
if (k1.format != k2.format) return false;
|
||||
if (k1.dimension != k2.dimension) return false;
|
||||
if (k1.baseArrayLayer != k2.baseArrayLayer) return false;
|
||||
if (k1.layerCount != k2.layerCount) return false;
|
||||
if (k1.baseMipLevel != k2.baseMipLevel) return false;
|
||||
if (k1.levelCount != k2.levelCount) return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct TextureKey {
|
||||
uint32_t id;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t depth;
|
||||
TinyImageFormat format;
|
||||
SampleCount sampleCount;
|
||||
TextureDimension dimension;
|
||||
uint8_t mipLevel;
|
||||
uint8_t arraySize;
|
||||
friend inline bool operator==(const TextureKey& k1, const TextureKey& k2) {
|
||||
if (k1.format != k2.format) return false;
|
||||
if (k1.dimension != k2.dimension) return false;
|
||||
if (k1.width != k2.width) return false;
|
||||
if (k1.height != k2.height) return false;
|
||||
if (k1.arraySize != k2.arraySize) return false;
|
||||
if (k1.mipLevel != k2.mipLevel) return false;
|
||||
if (k1.sampleCount != k2.sampleCount) return false;
|
||||
if (k1.depth != k2.depth) return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct TextureDesc : TextureKey {
|
||||
ImagePtr image;
|
||||
void* pData;//api数据 比如 vulkan 包含了内存信息,删除图像时要用到
|
||||
ResourceState state;
|
||||
TextureUsage usage;//这个字段是包含关系,即使不同,也可以指向相同的图像
|
||||
//MSAA 多重采样解析纹理
|
||||
TextureDesc Resolve(uint32_t id = 0) {
|
||||
TextureDesc resolve{ *(TextureKey*)this };
|
||||
resolve.id = id;
|
||||
resolve.sampleCount = SampleCount::SAMPLE_COUNT_1;
|
||||
return resolve;
|
||||
}
|
||||
TextureViewKey ToTextureView() const {
|
||||
TextureViewKey desc{};
|
||||
desc.image = image;
|
||||
desc.format = format;
|
||||
desc.baseArrayLayer = 0;
|
||||
desc.baseMipLevel = 0;
|
||||
desc.layerCount = 1;
|
||||
desc.levelCount = 1;
|
||||
desc.dimension = dimension;
|
||||
return desc;
|
||||
}
|
||||
TextureBarrier ToBarrier(ResourceState from, ResourceState to)const;
|
||||
};
|
||||
struct TextureBarrier
|
||||
{
|
||||
TextureDesc mTexture;
|
||||
ResourceState mSrcState;
|
||||
ResourceState mDstState;
|
||||
uint8_t mBeginOnly : 1;
|
||||
uint8_t mEndOnly : 1;
|
||||
uint8_t mAcquire : 1;
|
||||
uint8_t mRelease : 1;
|
||||
uint8_t mQueueType : 5;
|
||||
/// Specifiy whether following barrier targets particular subresource
|
||||
uint8_t mSubresourceBarrier : 1;
|
||||
/// Following values are ignored if mSubresourceBarrier is false
|
||||
uint8_t mMipLevel : 7;
|
||||
uint16_t mArrayLayer;
|
||||
};
|
||||
typedef struct BufferBarrier
|
||||
{
|
||||
//Buffer* pBuffer;
|
||||
ResourceState mSrcState;
|
||||
ResourceState mDstState;
|
||||
uint8_t mBeginOnly : 1;
|
||||
uint8_t mEndOnly : 1;
|
||||
} BufferBarrier;
|
||||
inline BufferBarrier BufferDesc::ToBarrier(ResourceState from, ResourceState to)const
|
||||
{
|
||||
BufferBarrier barrier{};
|
||||
barrier.mSrcState = from;
|
||||
barrier.mDstState = to;
|
||||
return barrier;
|
||||
}
|
||||
inline TextureBarrier TextureDesc::ToBarrier(ResourceState from, ResourceState to)const
|
||||
{
|
||||
TextureBarrier barrier{};
|
||||
barrier.mSrcState = from;
|
||||
barrier.mDstState = to;
|
||||
barrier.mTexture = *this;
|
||||
return barrier;
|
||||
}
|
||||
struct ResourceBarrierDesc {
|
||||
RenderPassType type;
|
||||
const BufferBarrier* pBufferBarriers;
|
||||
uint32_t bufferBarriersCount;
|
||||
const TextureBarrier* pTextureBarriers;
|
||||
uint32_t textureBarriersCount;
|
||||
};
|
||||
/**
|
||||
* Parameters of a render pass.
|
||||
*/
|
||||
struct RenderPassParams {
|
||||
uint8_t passMask;
|
||||
uint8_t subpassMask;
|
||||
uint8_t sampleMask;
|
||||
uint8_t clear;
|
||||
uint8_t discardStart;//不关心加载内容
|
||||
uint8_t discardEnd;//数据存储在访问最快的地方,只能在RenderPass内部用,后面就找不到了(不在附件里)
|
||||
Vector2 depthRange{ 0.f, 1.f }; //!< depth range for this pass
|
||||
Vector4 clearColor = { 0.f, 0.f, 0.f, 1.f };
|
||||
float clearDepth;
|
||||
uint32_t clearStencil;
|
||||
};
|
||||
}
|
||||
#include "meta/hash.h"
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<api::TextureViewKey>
|
||||
{
|
||||
size_t operator()(const api::TextureViewKey& key) const noexcept
|
||||
{
|
||||
return meta::MurmurHashFn(key);
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct hash<api::TextureKey>
|
||||
{
|
||||
size_t operator()(const api::TextureKey& key) const noexcept
|
||||
{
|
||||
return meta::MurmurHashFn(key);
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct hash<api::TextureSampler>
|
||||
{
|
||||
size_t operator()(const api::TextureSampler& key) const noexcept
|
||||
{
|
||||
return std::hash<int>{}(*(int*)&key);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1,116 +1,9 @@
|
||||
#pragma once
|
||||
#include "meta/enum.h"
|
||||
#include "refl/pch.h"
|
||||
#include "tinyimageformat/tinyimageformat_base.h"
|
||||
#include <cstdint>
|
||||
//#include <algorithm>
|
||||
namespace api {
|
||||
using pmr::Name;
|
||||
enum class GraphicsAPI : uint8_t
|
||||
{
|
||||
OpenGL,
|
||||
Vulkan,
|
||||
D3D12
|
||||
};
|
||||
enum class RenderPassType : uint8_t {
|
||||
Render,
|
||||
Present,
|
||||
Compute,
|
||||
Copy
|
||||
};
|
||||
enum class BufferUsage : uint8_t {
|
||||
STATIC = 0x01, //!< content modified once, used many times
|
||||
DYNAMIC = 0x02, //!< content modified frequently, used many times
|
||||
VERTEX = 0x04,
|
||||
UNIFORM = 0x08,
|
||||
SHADER_STORAGE = 0x10
|
||||
};
|
||||
enum class ResourceMemoryUsage : uint8_t
|
||||
{
|
||||
/// No intended memory usage specified.
|
||||
UNKNOWN = 0,
|
||||
/// Memory will be used on device only, no need to be mapped on host.
|
||||
GPU_ONLY = 1,
|
||||
/// Memory will be mapped on host. Could be used for transfer to device.
|
||||
CPU_ONLY = 2,
|
||||
/// Memory will be used for frequent (dynamic) updates from host and reads on device.
|
||||
CPU_TO_GPU = 3,
|
||||
/// Memory will be used for writing on device and readback on host.
|
||||
GPU_TO_CPU = 4,
|
||||
COUNT,
|
||||
};
|
||||
enum SampleCount : uint8_t
|
||||
{
|
||||
SAMPLE_COUNT_1 = 1,
|
||||
SAMPLE_COUNT_2 = 2,
|
||||
SAMPLE_COUNT_4 = 4,
|
||||
SAMPLE_COUNT_8 = 8,
|
||||
SAMPLE_COUNT_16 = 16,
|
||||
SAMPLE_COUNT_COUNT = 5,
|
||||
};
|
||||
enum class TargetBufferFlags : uint32_t {
|
||||
NONE = 0x0u, //!< No buffer selected.
|
||||
COLOR0 = 0x00000001u, //!< Color buffer selected.
|
||||
COLOR1 = 0x00000002u, //!< Color buffer selected.
|
||||
COLOR2 = 0x00000004u, //!< Color buffer selected.
|
||||
COLOR3 = 0x00000008u, //!< Color buffer selected.
|
||||
COLOR4 = 0x00000010u, //!< Color buffer selected.
|
||||
COLOR5 = 0x00000020u, //!< Color buffer selected.
|
||||
COLOR6 = 0x00000040u, //!< Color buffer selected.
|
||||
COLOR7 = 0x00000080u, //!< Color buffer selected.
|
||||
|
||||
COLOR = COLOR0, //!< \deprecated
|
||||
COLOR_ALL = COLOR0 | COLOR1 | COLOR2 | COLOR3 | COLOR4 | COLOR5 | COLOR6 | COLOR7,
|
||||
DEPTH = 0x10000000u, //!< Depth buffer selected.
|
||||
STENCIL = 0x20000000u, //!< Stencil buffer selected.
|
||||
DEPTH_AND_STENCIL = DEPTH | STENCIL, //!< depth and stencil buffer selected.
|
||||
ALL = COLOR_ALL | DEPTH | STENCIL //!< Color, depth and stencil buffer selected.
|
||||
};
|
||||
enum class ResourceState : uint8_t
|
||||
{
|
||||
// The initial layout after the creation of the VkImage. We use this to denote the state before
|
||||
// any transition.
|
||||
UNDEFINED,
|
||||
// Fragment/vertex shader accessible layout for reading and writing.
|
||||
READ_WRITE,
|
||||
// Fragment/vertex shader accessible layout for reading only.
|
||||
READ_ONLY,
|
||||
// For the source of a copy operation.
|
||||
TRANSFER_SRC,
|
||||
// For the destination of a copy operation.
|
||||
TRANSFER_DST,
|
||||
// For using a depth texture as an attachment.
|
||||
DEPTH_ATTACHMENT,
|
||||
// For using a depth texture both as an attachment and as a sampler.
|
||||
DEPTH_SAMPLER,
|
||||
// For swapchain images that will be presented.
|
||||
PRESENT,
|
||||
// For color attachments, but also used when the image is a sampler.
|
||||
// TODO: explore separate layout policies for attachment+sampling and just attachment.
|
||||
COLOR_ATTACHMENT,
|
||||
};
|
||||
enum class TextureUsage :uint16_t {
|
||||
NONE = 0x0000,
|
||||
COLOR_ATTACHMENT = 0x0001, //!< Texture can be used as a color attachment
|
||||
DEPTH_ATTACHMENT = 0x0002, //!< Texture can be used as a depth attachment
|
||||
STENCIL_ATTACHMENT = 0x0004, //!< Texture can be used as a stencil attachment
|
||||
UPLOADABLE = 0x0008, //!< Data can be uploaded into this texture (default)
|
||||
SAMPLEABLE = 0x0010, //!< Texture can be sampled (default)
|
||||
SUBPASS_INPUT = 0x0020, //!< Texture can be used as a subpass input
|
||||
BLIT_SRC = 0x0040, //!< Texture can be used the source of a blit()
|
||||
BLIT_DST = 0x0080, //!< Texture can be used the destination of a blit()
|
||||
PROTECTED = 0x0100, //!< Texture can be used for protected content
|
||||
DEFAULT = UPLOADABLE | SAMPLEABLE //!< Default texture usage
|
||||
};
|
||||
enum class TextureDimension : uint8_t
|
||||
{
|
||||
TEX_NULL = 0,
|
||||
TEX_1D = 0x01,
|
||||
TEX_2D = 0x02,
|
||||
TEX_3D = 0x04,
|
||||
TEX_CUBE = 0x08,
|
||||
};
|
||||
enum class ShaderDescriptorType : uint8_t{
|
||||
enum class ShaderDescriptorType : uint8_t {
|
||||
UNIFORM_BUFFER,
|
||||
SAMPLER,
|
||||
};
|
||||
@ -119,91 +12,12 @@ namespace api {
|
||||
VERTEX = 0x1,
|
||||
FRAGMENT = 0x2,
|
||||
};
|
||||
//! Sampler Wrap mode
|
||||
enum class SamplerWrapMode : uint8_t {
|
||||
CLAMP_TO_EDGE, //!< clamp-to-edge. The edge of the texture extends to infinity.
|
||||
REPEAT, //!< repeat. The texture infinitely repeats in the wrap direction.
|
||||
MIRRORED_REPEAT, //!< mirrored-repeat. The texture infinitely repeats and mirrors in the wrap direction.
|
||||
};
|
||||
|
||||
//! Sampler minification filter
|
||||
enum class SamplerMinFilter : uint8_t {
|
||||
// don't change the enums values
|
||||
NEAREST = 0, //!< No filtering. Nearest neighbor is used.
|
||||
LINEAR = 1, //!< Box filtering. Weighted average of 4 neighbors is used.
|
||||
NEAREST_MIPMAP_NEAREST = 2, //!< Mip-mapping is activated. But no filtering occurs.
|
||||
LINEAR_MIPMAP_NEAREST = 3, //!< Box filtering within a mip-map level.
|
||||
NEAREST_MIPMAP_LINEAR = 4, //!< Mip-map levels are interpolated, but no other filtering occurs.
|
||||
LINEAR_MIPMAP_LINEAR = 5 //!< Both interpolated Mip-mapping and linear filtering are used.
|
||||
};
|
||||
|
||||
//! Sampler magnification filter
|
||||
enum class SamplerMagFilter : uint8_t {
|
||||
// don't change the enums values
|
||||
NEAREST = 0, //!< No filtering. Nearest neighbor is used.
|
||||
LINEAR = 1, //!< Box filtering. Weighted average of 4 neighbors is used.
|
||||
};
|
||||
|
||||
//! Sampler compare mode
|
||||
enum class SamplerCompareMode : uint8_t {
|
||||
// don't change the enums values
|
||||
NONE = 0,
|
||||
COMPARE_TO_TEXTURE = 1
|
||||
};
|
||||
|
||||
//! comparison function for the depth / stencil sampler
|
||||
enum class SamplerCompareFunc : uint8_t {
|
||||
// don't change the enums values
|
||||
LE = 0, //!< Less or equal
|
||||
GE, //!< Greater or equal
|
||||
L, //!< Strictly less than
|
||||
G, //!< Strictly greater than
|
||||
E, //!< Equal
|
||||
NE, //!< Not equal
|
||||
A, //!< Always. Depth / stencil testing is deactivated.
|
||||
N //!< Never. The depth / stencil test always fails.
|
||||
};
|
||||
using SamplerPtr = void*;
|
||||
//! Sampler parameters
|
||||
struct TextureSampler { // NOLINT
|
||||
SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST)
|
||||
SamplerMinFilter filterMin : 3; //!< minification filter (NEAREST)
|
||||
SamplerWrapMode wrapS : 2; //!< s-coordinate wrap mode (CLAMP_TO_EDGE)
|
||||
SamplerWrapMode wrapT : 2; //!< t-coordinate wrap mode (CLAMP_TO_EDGE)
|
||||
|
||||
SamplerWrapMode wrapR : 2; //!< r-coordinate wrap mode (CLAMP_TO_EDGE)
|
||||
uint8_t anisotropyLog2 : 3; //!< anisotropy level (0)
|
||||
SamplerCompareMode compareMode : 1; //!< sampler compare mode (NONE)
|
||||
uint8_t padding0 : 2; //!< reserved. must be 0.
|
||||
|
||||
SamplerCompareFunc compareFunc : 3; //!< sampler comparison function (LE)
|
||||
uint8_t padding1 : 5; //!< reserved. must be 0.
|
||||
uint8_t padding2 : 8; //!< reserved. must be 0.
|
||||
struct EqualTo {
|
||||
bool operator()(TextureSampler lhs, TextureSampler rhs) const noexcept {
|
||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||
return *pLhs == *pRhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct LessThan {
|
||||
bool operator()(TextureSampler lhs, TextureSampler rhs) const noexcept {
|
||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||
return *pLhs == *pRhs;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
friend inline bool operator < (TextureSampler lhs, TextureSampler rhs) noexcept {
|
||||
return TextureSampler::LessThan{}(lhs, rhs);
|
||||
}
|
||||
public:
|
||||
friend inline bool operator== (TextureSampler lhs, TextureSampler rhs) noexcept {
|
||||
return TextureSampler::EqualTo{}(lhs, rhs);
|
||||
}
|
||||
};
|
||||
enum class GraphicsAPI : uint8_t
|
||||
{
|
||||
OpenGL,
|
||||
Vulkan,
|
||||
D3D12
|
||||
};
|
||||
struct MaterialResource {
|
||||
Name name;
|
||||
bool isDirty;
|
||||
@ -270,170 +84,4 @@ namespace api {
|
||||
ShaderStage stageFlags;
|
||||
};
|
||||
using ShaderDescriptorSet = pmr::vector<ShaderDescriptorLayout>;
|
||||
using ImagePtr = void*;
|
||||
using ImageViewPtr = void*;
|
||||
using BufferPtr = void*;
|
||||
struct BufferBarrier;
|
||||
struct TextureBarrier;
|
||||
struct BufferDesc {
|
||||
BufferPtr buffer;
|
||||
void* mappingAddr;
|
||||
uint32_t size;
|
||||
BufferUsage usage;
|
||||
ResourceMemoryUsage memoryUsage;
|
||||
static BufferDesc Make() {
|
||||
return {};
|
||||
}
|
||||
BufferBarrier ToBarrier(ResourceState from, ResourceState to)const;
|
||||
};
|
||||
struct TextureViewKey {
|
||||
ImagePtr image;
|
||||
TinyImageFormat format;
|
||||
TextureDimension dimension;
|
||||
uint8_t baseArrayLayer;
|
||||
uint8_t layerCount;
|
||||
uint8_t baseMipLevel;
|
||||
uint8_t levelCount;
|
||||
friend inline bool operator==(const TextureViewKey& k1, const TextureViewKey& k2) {
|
||||
if (k1.image != k2.image) return false;
|
||||
if (k1.format != k2.format) return false;
|
||||
if (k1.dimension != k2.dimension) return false;
|
||||
if (k1.baseArrayLayer != k2.baseArrayLayer) return false;
|
||||
if (k1.layerCount != k2.layerCount) return false;
|
||||
if (k1.baseMipLevel != k2.baseMipLevel) return false;
|
||||
if (k1.levelCount != k2.levelCount) return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct TextureKey {
|
||||
uint32_t id;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t depth;
|
||||
TinyImageFormat format;
|
||||
SampleCount sampleCount;
|
||||
TextureDimension dimension;
|
||||
uint8_t mipLevel;
|
||||
uint8_t arraySize;
|
||||
friend inline bool operator==(const TextureKey& k1, const TextureKey& k2) {
|
||||
if (k1.format != k2.format) return false;
|
||||
if (k1.dimension != k2.dimension) return false;
|
||||
if (k1.width != k2.width) return false;
|
||||
if (k1.height != k2.height) return false;
|
||||
if (k1.arraySize != k2.arraySize) return false;
|
||||
if (k1.mipLevel != k2.mipLevel) return false;
|
||||
if (k1.sampleCount != k2.sampleCount) return false;
|
||||
if (k1.depth != k2.depth) return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct TextureDesc : TextureKey {
|
||||
ImagePtr image;
|
||||
void* pData;//api数据 比如 vulkan 包含了内存信息,删除图像时要用到
|
||||
ResourceState state;
|
||||
TextureUsage usage;//这个字段是包含关系,即使不同,也可以指向相同的图像
|
||||
TextureViewKey ToTextureView() const{
|
||||
TextureViewKey desc{};
|
||||
desc.image = image;
|
||||
desc.format = format;
|
||||
desc.baseArrayLayer = 0;
|
||||
desc.baseMipLevel = 0;
|
||||
desc.layerCount = 1;
|
||||
desc.levelCount = 1;
|
||||
desc.dimension = dimension;
|
||||
return desc;
|
||||
}
|
||||
TextureBarrier ToBarrier(ResourceState from, ResourceState to)const;
|
||||
};
|
||||
struct AttachmentDesc {
|
||||
TextureDesc texture;
|
||||
ImageViewPtr imageView;
|
||||
AttachmentDesc() :texture(), imageView(nullptr) {};
|
||||
AttachmentDesc(const TextureDesc& desc): texture(desc), imageView(nullptr){}
|
||||
TextureViewKey ToTextureView() const {
|
||||
return texture.ToTextureView();
|
||||
}
|
||||
TextureBarrier ToBarrier(ResourceState from, ResourceState to)const;
|
||||
};
|
||||
struct TextureBarrier
|
||||
{
|
||||
TextureDesc mTexture;
|
||||
ResourceState mSrcState;
|
||||
ResourceState mDstState;
|
||||
uint8_t mBeginOnly : 1;
|
||||
uint8_t mEndOnly : 1;
|
||||
uint8_t mAcquire : 1;
|
||||
uint8_t mRelease : 1;
|
||||
uint8_t mQueueType : 5;
|
||||
/// Specifiy whether following barrier targets particular subresource
|
||||
uint8_t mSubresourceBarrier : 1;
|
||||
/// Following values are ignored if mSubresourceBarrier is false
|
||||
uint8_t mMipLevel : 7;
|
||||
uint16_t mArrayLayer;
|
||||
};
|
||||
typedef struct BufferBarrier
|
||||
{
|
||||
//Buffer* pBuffer;
|
||||
ResourceState mSrcState;
|
||||
ResourceState mDstState;
|
||||
uint8_t mBeginOnly : 1;
|
||||
uint8_t mEndOnly : 1;
|
||||
} BufferBarrier;
|
||||
struct ResourceBarrierDesc {
|
||||
RenderPassType type;
|
||||
const BufferBarrier* pBufferBarriers;
|
||||
uint32_t bufferBarriersCount;
|
||||
const TextureBarrier* pTextureBarriers;
|
||||
uint32_t textureBarriersCount;
|
||||
};
|
||||
inline BufferBarrier BufferDesc::ToBarrier(ResourceState from, ResourceState to)const
|
||||
{
|
||||
BufferBarrier barrier{};
|
||||
barrier.mSrcState = from;
|
||||
barrier.mDstState = to;
|
||||
return barrier;
|
||||
}
|
||||
inline TextureBarrier TextureDesc::ToBarrier(ResourceState from, ResourceState to)const
|
||||
{
|
||||
TextureBarrier barrier{};
|
||||
barrier.mSrcState = from;
|
||||
barrier.mDstState = to;
|
||||
barrier.mTexture = *this;
|
||||
return barrier;
|
||||
}
|
||||
inline TextureBarrier AttachmentDesc::ToBarrier(ResourceState from, ResourceState to)const
|
||||
{
|
||||
TextureBarrier barrier{};
|
||||
barrier.mSrcState = from;
|
||||
barrier.mDstState = to;
|
||||
barrier.mTexture = texture;
|
||||
return barrier;
|
||||
}
|
||||
}
|
||||
#include "meta/hash.h"
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<api::TextureViewKey>
|
||||
{
|
||||
size_t operator()(const api::TextureViewKey& key) const noexcept
|
||||
{
|
||||
return meta::MurmurHashFn(key);
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct hash<api::TextureKey>
|
||||
{
|
||||
size_t operator()(const api::TextureKey& key) const noexcept
|
||||
{
|
||||
return meta::MurmurHashFn(key);
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct hash<api::TextureSampler>
|
||||
{
|
||||
size_t operator()(const api::TextureSampler& key) const noexcept
|
||||
{
|
||||
return std::hash<int>{}(*(int*)&key);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -142,6 +142,7 @@ namespace api {
|
||||
mNodes.clear();
|
||||
mFirstInputNode = nullptr;
|
||||
mLastOutputNode = nullptr;
|
||||
mTickStamp++;
|
||||
}
|
||||
void FrameGraph::ExecuteRenderPass(RenderPassNode* node, FRenderView& view)
|
||||
{
|
||||
@ -224,10 +225,6 @@ namespace api {
|
||||
desc.image = texture.image;
|
||||
return srcstart == dststate;
|
||||
}
|
||||
bool FrameGraph::ResolveState(AttachmentDesc& desc, ResourceState& srcstart, ResourceState& dststate)
|
||||
{
|
||||
return ResolveState(desc.texture, srcstart, dststate);
|
||||
}
|
||||
bool FrameGraph::ResolveState(BufferDesc& desc, ResourceState& srcstart, ResourceState& dststate)
|
||||
{
|
||||
return true;
|
||||
@ -278,18 +275,6 @@ namespace api {
|
||||
}
|
||||
return mTexturePool[0];
|
||||
}
|
||||
void FrameGraph::ResourceTexture(TextureDesc& desc)
|
||||
{
|
||||
auto it = mTextureKeyMap.find(desc);
|
||||
if (it != mTextureKeyMap.end()) {
|
||||
desc.id = it->second;
|
||||
}
|
||||
else {
|
||||
desc.id = mTexturePool.size() + 1;
|
||||
mTextureKeyMap[desc] = desc.id;
|
||||
mTexturePool.push_back(desc);
|
||||
}
|
||||
}
|
||||
uint32_t FrameGraph::GetTextureID(Name name, int num)
|
||||
{
|
||||
Tag tag(name, num);
|
||||
@ -299,6 +284,35 @@ namespace api {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void FrameGraph::AcquireTexture(TextureDesc& desc)
|
||||
{
|
||||
auto it = mTextureKeyMap.find(desc);
|
||||
if (it != mTextureKeyMap.end()) {
|
||||
for (auto& id : it->second) {
|
||||
if (id.tick != mTickStamp) {
|
||||
desc.id = id.id;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
desc.id = mTexturePool.size() + 1;
|
||||
TextureID id{ desc.id , mTickStamp };
|
||||
mTexturePool.push_back(desc);
|
||||
mTextureKeyMap[desc].push_back(id);
|
||||
}
|
||||
void FrameGraph::RealeaseTexture(TextureDesc& desc)
|
||||
{
|
||||
auto it = mTextureKeyMap.find(desc);
|
||||
if (it != mTextureKeyMap.end()) {
|
||||
for (auto& id : it->second) {
|
||||
if (id.id == desc.id) {
|
||||
id.tick = mTickStamp - 1;
|
||||
desc.id = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void FrameGraph::SetResourceTexture(TextureDesc desc, Name name, int num)
|
||||
{
|
||||
Tag tag(name, num);
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
#include "render/graph/frame_graph.h"
|
||||
#include "render/pass/render_pass.h"
|
||||
namespace api {
|
||||
RenderPassBuilder& RenderPassBuilder::Name(pmr::Name name)
|
||||
{
|
||||
node->name = name;
|
||||
return *this;
|
||||
}
|
||||
RenderPassBuilder& RenderPassBuilder::Type(RenderPassNodeType type, RenderPassNodeFlag flag)
|
||||
{
|
||||
node->type = type;
|
||||
node->flag = flag;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RenderPassBuilder& RenderPassBuilder::Read(TextureDesc desc, ResourceState state, pmr::Name name)
|
||||
{
|
||||
desc.state = state;
|
||||
FrameGraphEdgePtr edge = FrameResource::Make(name, desc);
|
||||
node->inEdges.push_back(edge);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RenderPassBuilder& RenderPassBuilder::Write(AttachmentDesc desc, ResourceState state, pmr::Name name)
|
||||
{
|
||||
desc.texture.state = state;
|
||||
FrameGraphEdgePtr edge = FrameResource::Make(name, desc);
|
||||
node->outEdges.push_back(edge);
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
73
engine/modules/engine/render/src/graph/frame_graph_node.cpp
Normal file
73
engine/modules/engine/render/src/graph/frame_graph_node.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
#include "render/graph/frame_graph.h"
|
||||
#include "render/pass/render_pass.h"
|
||||
namespace api {
|
||||
void RenderPassNode::ForeachEdge(RenderPassEdgeIterFn fn) {
|
||||
for (auto& edge : inEdges) {
|
||||
fn(edge);
|
||||
}
|
||||
for (auto& edge : outEdges) {
|
||||
fn(edge);
|
||||
}
|
||||
}
|
||||
FrameGraphNodePtr::FrameGraphNodePtr(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor, NodeType type) : type(type)
|
||||
{
|
||||
node = new (FramePool()) RenderPassNode();
|
||||
node->setup = setup;
|
||||
node->executor = executor;
|
||||
}
|
||||
RenderPassBuilder& RenderPassBuilder::Name(pmr::Name name)
|
||||
{
|
||||
node->name = name;
|
||||
return *this;
|
||||
}
|
||||
RenderPassBuilder& RenderPassBuilder::Type(RenderPassNodeType type, RenderPassNodeFlag flag)
|
||||
{
|
||||
node->type = type;
|
||||
node->flag = flag;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RenderPassBuilder& RenderPassBuilder::Read(TextureDesc desc, ResourceState state, pmr::Name name)
|
||||
{
|
||||
desc.state = state;
|
||||
FrameGraphEdgePtr edge = FrameResource::Make(name, desc);
|
||||
node->inEdges.push_back(edge);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RenderPassBuilder& RenderPassBuilder::Write(TextureDesc desc, ResourceState state, pmr::Name name)
|
||||
{
|
||||
desc.state = state;
|
||||
FrameGraphEdgePtr edge = FrameResource::Make(name, desc);
|
||||
node->outEdges.push_back(edge);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RenderPassBuilder& RenderPassBuilder::Attachment(AttachmentFlag flag)
|
||||
{
|
||||
uint32_t mask = node->outEdges.size();
|
||||
if (mask && any(flag)) {
|
||||
mask = 1 << (mask - 1);
|
||||
if (any(flag & AttachmentFlag::Clear)) {
|
||||
node->params.clear |= mask;
|
||||
}
|
||||
if (any(flag & AttachmentFlag::DiscardStart)) {
|
||||
node->params.discardStart |= mask;
|
||||
}
|
||||
if (any(flag & AttachmentFlag::DiscardEnd)) {
|
||||
node->params.discardEnd |= mask;
|
||||
}
|
||||
if (any(flag & AttachmentFlag::Sample)) {
|
||||
node->params.sampleMask |= mask;
|
||||
}
|
||||
if (any(flag & AttachmentFlag::MainPass)) {
|
||||
node->params.passMask |= mask;
|
||||
}
|
||||
if (any(flag & AttachmentFlag::Subpass)) {
|
||||
node->params.subpassMask |= mask;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
#include "render/graph/type.h"
|
||||
#include "render/renderapi.h"
|
||||
namespace api {
|
||||
void RenderPassNode::ForeachEdge(RenderPassEdgeIterFn fn) {
|
||||
for (auto& edge : inEdges) {
|
||||
fn(edge);
|
||||
}
|
||||
for (auto& edge : outEdges) {
|
||||
fn(edge);
|
||||
}
|
||||
}
|
||||
FrameGraphNodePtr::FrameGraphNodePtr(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor, NodeType type) : type(type)
|
||||
{
|
||||
node = new (FramePool()) RenderPassNode();
|
||||
node->setup = setup;
|
||||
node->executor = executor;
|
||||
}
|
||||
}
|
||||
@ -11,10 +11,10 @@ namespace api {
|
||||
static RscHandle<Mesh> mesh;
|
||||
void DemoPass::Setup(FrameGraph& graph, RenderPassBuilder& builder)
|
||||
{
|
||||
AttachmentDesc surface{ graph.GetSurface()};
|
||||
builder.Name("MiniPass")
|
||||
.Type(RenderPassNodeType::Scene, RenderPassNodeFlag::Output)
|
||||
.Write(surface, ResourceState::COLOR_ATTACHMENT);
|
||||
.Write(graph.GetSurface(), ResourceState::COLOR_ATTACHMENT)
|
||||
.Attachment(AttachmentFlag::Clear);
|
||||
}
|
||||
void DemoPass::Execute(FrameGraph& graph, RenderPassContext& ctx)
|
||||
{
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
#pragma once
|
||||
#include "pmr/frame_allocator.h"
|
||||
#include "pmr/name.h"
|
||||
#include <Windows.h>
|
||||
#include <functional>
|
||||
#define VK_NO_PROTOTYPES
|
||||
#include "volk/volk.h"
|
||||
#include "vma/vk_mem_alloc.h"
|
||||
#include "render/render_type.h"
|
||||
#include "render/type.h"
|
||||
#define Z_RENDER_DEBUG 1
|
||||
namespace vkn {
|
||||
@ -16,7 +15,6 @@ namespace vkn {
|
||||
class CommandBuffer;
|
||||
using voidFn = std::function<void()>;
|
||||
using commandFn = std::function<void(CommandBuffer& cmd)>;
|
||||
using api::TargetBufferFlags;
|
||||
using api::ResourceBarrierDesc;
|
||||
using api::TextureViewKey;
|
||||
using api::ImageViewPtr;
|
||||
@ -50,28 +48,26 @@ namespace vkn {
|
||||
VmaAllocation indexAllocation;
|
||||
VmaAllocation vertexAllocation;
|
||||
};
|
||||
//不需要支持所有,只要支持常见的就行
|
||||
struct RenderPassKey {
|
||||
VkRenderPass pass;
|
||||
VkFormat colorFormat[8];
|
||||
VkFormat depthFormat;
|
||||
VkSampleCountFlagBits samples;
|
||||
TargetBufferFlags clear; // 4 bytes
|
||||
TargetBufferFlags discardStart; // 4 bytes
|
||||
TargetBufferFlags discardEnd; // 4 bytes
|
||||
TinyImageFormat colorFormat[MAX_SUPPORTED_RENDER_TARGET_COUNT];
|
||||
uint8_t depthMask;
|
||||
uint8_t clear; // 1 bytes
|
||||
uint8_t discardStart; // 1 bytes
|
||||
uint8_t discardEnd; // 1 bytes
|
||||
SampleCount samples;
|
||||
uint8_t sampleMask;// 1 byte
|
||||
uint8_t passMask;// 1 byte
|
||||
uint8_t subpassMask;// 1 byte
|
||||
uint8_t initialColorLayoutMask;// 1 byte
|
||||
uint8_t needsResolveMask; // 1 byte
|
||||
operator size_t() const{
|
||||
return meta::MurmurHashFn(this);
|
||||
}
|
||||
};
|
||||
struct RenderPassInfo {
|
||||
VkRenderPass pass;
|
||||
RenderPassKey config;
|
||||
vector<VkSemaphore> semaphores;
|
||||
vector<VkCommandBuffer> commands;
|
||||
VkRenderPass Pass() {
|
||||
return config.pass;
|
||||
}
|
||||
};
|
||||
struct FramebufferKey {
|
||||
VkRenderPass pass;
|
||||
|
||||
@ -16,6 +16,7 @@ namespace vkn {
|
||||
using api::MaterialInstance;
|
||||
using api::RenderPassNode;
|
||||
using api::RenderPassType;
|
||||
using api::RenderPassParams;
|
||||
class VULKAN_API VulkanAPI final : public api::RenderAPI{
|
||||
private:
|
||||
VulkanWindow& window;
|
||||
|
||||
@ -18,6 +18,7 @@ namespace vkn {
|
||||
void DrawIndexed(uint32_t index_count, uint32_t first_index, uint32_t first_vertex) override;
|
||||
void ExecuteSurfaceBarriers(const ResourceBarrierDesc& desc) override;
|
||||
|
||||
void ClearSurface(VkClearColorValue clearValue);
|
||||
void BeginRecord(VkCommandBufferUsageFlags flag);
|
||||
void EndRecord(VkQueue queue);
|
||||
};
|
||||
|
||||
@ -89,7 +89,7 @@ namespace vkn {
|
||||
if (itPass == RenderPassCache.end()) {
|
||||
return;
|
||||
}
|
||||
VkRenderPass renderpass = itPass->second.Pass();
|
||||
VkRenderPass renderpass = itPass->second.pass;
|
||||
pmr::vector<VkPipelineShaderStageCreateInfo> shaderStages;
|
||||
std::map<VkShaderStageFlagBits, VkShaderModule> shaderModules;
|
||||
auto& device = backend.GetDevice();
|
||||
@ -365,35 +365,56 @@ namespace vkn {
|
||||
}
|
||||
void VulkanAPI::BeginRenderPass(RenderPassNode* node, FnEnterRenderPass callback)
|
||||
{
|
||||
RenderPassKey config{};
|
||||
FramebufferKey frameKey{.layers = 1};
|
||||
VkClearValue clearValues[2 * MAX_SUPPORTED_RENDER_TARGET_COUNT + 1] = { 0 };
|
||||
int i = 0;
|
||||
RenderPassKey config{};
|
||||
FramebufferKey frameKey{.layers = 1};
|
||||
VkClearValue clearValues[MAX_SUPPORTED_RENDER_TARGET_COUNT] = { 0 };
|
||||
RenderPassParams& params = node->params;
|
||||
int clearSurfaceIndex = -1;
|
||||
int i = 0, attachmentCount = 0;
|
||||
for (auto& it : node->outEdges) {
|
||||
if (it->IsAttachment()) {
|
||||
auto& desc = it->CastTo<api::AttachmentDesc>();
|
||||
TextureDesc& texture = desc.texture;
|
||||
config.colorFormat[i] = (VkFormat)TinyImageFormat_ToVkFormat(texture.format);
|
||||
config.samples = vkApiGetSmpleCountFlag(texture.sampleCount);
|
||||
|
||||
TargetBufferFlags flag = TargetBufferFlags(int(TargetBufferFlags::COLOR0) << i);
|
||||
config.clear |= flag;
|
||||
desc.imageView = graph.ResolveTextureView(texture);
|
||||
|
||||
frameKey.imageViews[i] = (VkImageView)desc.imageView;
|
||||
frameKey.height = texture.height;
|
||||
frameKey.width = texture.width;
|
||||
|
||||
//clearValues[i] =
|
||||
i++;
|
||||
uint32_t flag = 1 << i;
|
||||
TextureDesc& texture = it->CastTo<TextureDesc>();
|
||||
frameKey.imageViews[attachmentCount++] = (VkImageView)graph.ResolveTextureView(texture);
|
||||
frameKey.height = texture.height;
|
||||
frameKey.width = texture.width;
|
||||
config.colorFormat[i] = texture.format;
|
||||
if (params.sampleMask & flag) {
|
||||
TextureDesc resolve = texture.Resolve();
|
||||
graph.AcquireTexture(resolve);
|
||||
frameKey.imageViews[attachmentCount++] = (VkImageView)graph.ResolveTextureView(resolve);
|
||||
}
|
||||
if (texture.sampleCount > config.samples)
|
||||
config.samples = texture.sampleCount;
|
||||
VkClearValue& clearValue = clearValues[i];
|
||||
const bool bclear = params.clear & flag;
|
||||
if (texture.state == ResourceState::COLOR_ATTACHMENT) {
|
||||
if (!bclear && context.surface.id == texture.id && node->IsFirstInput()) {
|
||||
clearSurfaceIndex = i;//需要手动清除
|
||||
}
|
||||
if (bclear || clearSurfaceIndex == i) {
|
||||
clearValue.color.float32[0] = params.clearColor.r;
|
||||
clearValue.color.float32[1] = params.clearColor.g;
|
||||
clearValue.color.float32[2] = params.clearColor.b;
|
||||
clearValue.color.float32[3] = params.clearColor.a;
|
||||
}
|
||||
}
|
||||
else {
|
||||
config.depthMask |= flag;
|
||||
if (bclear) {
|
||||
clearValue.depthStencil = { (float)params.clearDepth, params.clearStencil };
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
frameKey.attachmentCount = i;
|
||||
frameKey.attachmentCount = attachmentCount;
|
||||
config.clear = params.clear;
|
||||
config.discardEnd = params.discardEnd;
|
||||
config.discardStart = params.discardStart;
|
||||
RenderPassInfo* passInfo = GetRenderPassInfo(node->name, node->hash);
|
||||
if (!passInfo) {
|
||||
passInfo = GetRenderPassInfo(node->hash, config);
|
||||
}
|
||||
frameKey.pass = passInfo->Pass();
|
||||
frameKey.pass = passInfo->pass;
|
||||
auto it = FramebufferCache.find(frameKey);
|
||||
VkFramebuffer framebuffer = it->second;
|
||||
if (it == FramebufferCache.end()) {
|
||||
@ -428,6 +449,7 @@ namespace vkn {
|
||||
cmd.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
|
||||
if(callback) callback(node);
|
||||
vkCmdBeginRenderPass(cmd.Ptr(), &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
if (clearSurfaceIndex != -1)ctx.ClearSurface(clearValues[clearSurfaceIndex].color);
|
||||
}
|
||||
void VulkanAPI::EndRenderPass(RenderPassNode* node)
|
||||
{
|
||||
@ -485,10 +507,10 @@ namespace vkn {
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
//单一renderpass,config.passMask 可以取 0
|
||||
RenderPassInfo* VulkanAPI::GetRenderPassInfo(size_t& hash, const RenderPassKey& config) {
|
||||
hash = config;
|
||||
auto it = RenderPassCache.find(hash);
|
||||
if (it != RenderPassCache.end()) {
|
||||
if (auto it = RenderPassCache.find(hash); it != RenderPassCache.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
// Set up some const aliases for terseness.
|
||||
@ -500,40 +522,34 @@ namespace vkn {
|
||||
|
||||
VkAttachmentReference inputAttachmentRef[MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
||||
VkAttachmentReference colorAttachmentRefs[2][MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
||||
VkAttachmentReference resolveAttachmentRef[MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
||||
VkAttachmentReference depthAttachmentRef = {};
|
||||
|
||||
const bool hasSubpasses = config.subpassMask != 0;
|
||||
const bool hasDepth = config.depthFormat != VK_FORMAT_UNDEFINED;
|
||||
VkAttachmentReference resolveAttachmentRef[2][MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
||||
VkAttachmentReference depthAttachmentRef[2] = {};
|
||||
|
||||
const bool hasSubpasses = config.subpassMask;
|
||||
const bool hasDepth1 = (!hasSubpasses && config.depthMask) || config.depthMask & config.passMask;
|
||||
const bool hasDepth2 = config.depthMask & config.subpassMask;
|
||||
const bool hasSample1 = (!hasSubpasses && config.sampleMask) || config.sampleMask & config.passMask;
|
||||
const bool hasSample2 = config.sampleMask & config.subpassMask;
|
||||
VkSubpassDescription subpasses[2] = { {
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
.pInputAttachments = nullptr,
|
||||
.pColorAttachments = colorAttachmentRefs[0],
|
||||
.pResolveAttachments = resolveAttachmentRef,
|
||||
.pDepthStencilAttachment = hasDepth ? &depthAttachmentRef : nullptr
|
||||
.pResolveAttachments = hasSample1 ? resolveAttachmentRef[0] : nullptr,
|
||||
.pDepthStencilAttachment = hasDepth1 ? &depthAttachmentRef[0] : nullptr
|
||||
},
|
||||
{
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
.pInputAttachments = inputAttachmentRef,
|
||||
.pColorAttachments = colorAttachmentRefs[1],
|
||||
.pResolveAttachments = resolveAttachmentRef,
|
||||
.pDepthStencilAttachment = hasDepth ? &depthAttachmentRef : nullptr
|
||||
.pResolveAttachments = hasSample2 ? resolveAttachmentRef[1] : nullptr,
|
||||
.pDepthStencilAttachment = hasDepth2 ? &depthAttachmentRef[1] : nullptr
|
||||
} };
|
||||
|
||||
// The attachment list contains: Color Attachments, Resolve Attachments, and Depth Attachment.
|
||||
// For simplicity, create an array that can hold the maximum possible number of attachments.
|
||||
// Note that this needs to have the same ordering as the corollary array in getFramebuffer.
|
||||
VkAttachmentDescription attachments[MAX_SUPPORTED_RENDER_TARGET_COUNT + MAX_SUPPORTED_RENDER_TARGET_COUNT + 1] = {};
|
||||
|
||||
VkAttachmentDescription attachments[MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
||||
// We support 2 subpasses, which means we need to supply 1 dependency struct.
|
||||
VkSubpassDependency dependencies[1] = { {
|
||||
.srcSubpass = 0,
|
||||
.dstSubpass = 1,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,
|
||||
} };
|
||||
// Finally, create the VkRenderPass.
|
||||
@ -544,127 +560,110 @@ namespace vkn {
|
||||
.subpassCount = hasSubpasses ? 2u : 1u,
|
||||
.pSubpasses = subpasses,
|
||||
.dependencyCount = hasSubpasses ? 1u : 0u,
|
||||
.pDependencies = dependencies
|
||||
};
|
||||
int attachmentIndex = 0;
|
||||
const VkSampleCountFlagBits samplecount = vkApiGetSmpleCountFlag(config.samples);
|
||||
uint32_t attachmentIndex = 0, samplePassIndex1 = 0, samplePassIndex2 = 0;
|
||||
// Populate the Color Attachments.
|
||||
for (int i = 0; i < MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
||||
if (config.colorFormat[i] == VK_FORMAT_UNDEFINED) {
|
||||
continue;
|
||||
for (uint32_t i = 0; i < MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
||||
if (config.colorFormat[i] == TinyImageFormat_UNDEFINED) {
|
||||
break;
|
||||
}
|
||||
const VkImageLayout subpassLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
uint32_t index;
|
||||
|
||||
if (!hasSubpasses) {
|
||||
index = subpasses[0].colorAttachmentCount++;
|
||||
colorAttachmentRefs[0][index].layout = subpassLayout;
|
||||
colorAttachmentRefs[0][index].attachment = attachmentIndex;
|
||||
}
|
||||
else {
|
||||
|
||||
// The Driver API consolidates all color attachments from the first and second subpasses
|
||||
// into a single list, and uses a bitmask to mark attachments that belong only to the
|
||||
// second subpass and should be available as inputs. All color attachments in the first
|
||||
// subpass are automatically made available to the second subpass.
|
||||
|
||||
// If there are subpasses, we require the input attachment to be the first attachment.
|
||||
// Breaking this assumption would likely require enhancements to the Driver API in order
|
||||
// to supply Vulkan with all the information needed.
|
||||
if (config.subpassMask & (1 << i)) {
|
||||
index = subpasses[0].colorAttachmentCount++;
|
||||
colorAttachmentRefs[0][index].layout = subpassLayout;
|
||||
colorAttachmentRefs[0][index].attachment = attachmentIndex;
|
||||
|
||||
index = subpasses[1].inputAttachmentCount++;
|
||||
inputAttachmentRef[index].layout = subpassLayout;
|
||||
inputAttachmentRef[index].attachment = attachmentIndex;
|
||||
}
|
||||
|
||||
index = subpasses[1].colorAttachmentCount++;
|
||||
colorAttachmentRefs[1][index].layout = subpassLayout;
|
||||
colorAttachmentRefs[1][index].attachment = attachmentIndex;
|
||||
}
|
||||
const TargetBufferFlags flag = TargetBufferFlags(int(TargetBufferFlags::COLOR0) << i);
|
||||
const bool clear = any(config.clear & flag);
|
||||
const bool discard = any(config.discardStart & flag);
|
||||
VkImageLayout layout = vkApiGetAttachmentLayout(config.colorFormat[i], true);
|
||||
attachments[attachmentIndex++] = {
|
||||
.format = config.colorFormat[i],
|
||||
.samples = config.samples,
|
||||
const uint8_t flag = 1 << i;
|
||||
const bool clear = config.clear & flag;
|
||||
const bool discard = config.discardStart & flag;
|
||||
const bool discardEnd = config.discardEnd & flag;
|
||||
const bool sample = config.sampleMask & flag;
|
||||
const VkFormat format = (VkFormat)TinyImageFormat_ToVkFormat(config.colorFormat[i]);
|
||||
VkImageLayout layout = vkApiGetAttachmentLayout(format, true);
|
||||
attachments[attachmentIndex] = {
|
||||
.format = format,
|
||||
.samples = sample ? samplecount : VK_SAMPLE_COUNT_1_BIT,
|
||||
.loadOp = clear ? kClear : (discard ? kDontCare : kKeep),
|
||||
.storeOp = kEnableStore,
|
||||
.storeOp = discardEnd ? kDisableStore : kEnableStore,
|
||||
.stencilLoadOp = kDontCare,
|
||||
.stencilStoreOp = kDisableStore,
|
||||
.initialLayout = layout,
|
||||
.finalLayout = layout,
|
||||
};
|
||||
}
|
||||
// Nulling out the zero-sized lists is necessary to avoid VK_ERROR_OUT_OF_HOST_MEMORY on Adreno.
|
||||
if (subpasses[0].colorAttachmentCount == 0) {
|
||||
subpasses[0].pColorAttachments = nullptr;
|
||||
subpasses[0].pResolveAttachments = nullptr;
|
||||
subpasses[1].pColorAttachments = nullptr;
|
||||
subpasses[1].pResolveAttachments = nullptr;
|
||||
}
|
||||
// Populate the Resolve Attachments.
|
||||
VkAttachmentReference* pResolveAttachment = resolveAttachmentRef;
|
||||
for (int i = 0; i < MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
||||
if (config.colorFormat[i] == VK_FORMAT_UNDEFINED) {
|
||||
continue;
|
||||
if (sample) {
|
||||
attachments[attachmentIndex + 1] = {
|
||||
.format = format,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.loadOp = clear ? kClear : (discard ? kDontCare : kKeep),
|
||||
.storeOp = discardEnd ? kDisableStore : kEnableStore,
|
||||
.stencilLoadOp = kDontCare,
|
||||
.stencilStoreOp = kDisableStore,
|
||||
.initialLayout = layout,
|
||||
.finalLayout = layout,
|
||||
};
|
||||
}
|
||||
|
||||
if (!(config.needsResolveMask & (1 << i))) {
|
||||
pResolveAttachment->attachment = VK_ATTACHMENT_UNUSED;
|
||||
++pResolveAttachment;
|
||||
continue;
|
||||
const bool isDepth = config.depthMask & flag;
|
||||
const bool isMask1 = !hasSubpasses || config.passMask & flag;
|
||||
const bool isMask2 = hasSubpasses && config.subpassMask & flag;
|
||||
uint32_t index = 0;
|
||||
if (isMask1) {
|
||||
index = subpasses[0].colorAttachmentCount++;
|
||||
colorAttachmentRefs[0][index].layout = layout;
|
||||
colorAttachmentRefs[0][index].attachment = attachmentIndex;
|
||||
if (sample) {
|
||||
index = subpasses[0].colorAttachmentCount++;
|
||||
colorAttachmentRefs[0][index].layout = layout;
|
||||
colorAttachmentRefs[0][index].attachment = attachmentIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
pResolveAttachment->attachment = attachmentIndex;
|
||||
pResolveAttachment->layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
++pResolveAttachment;
|
||||
|
||||
attachments[attachmentIndex++] = {
|
||||
.format = config.colorFormat[i],
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.loadOp = kDontCare,
|
||||
.storeOp = kEnableStore,
|
||||
.stencilLoadOp = kDontCare,
|
||||
.stencilStoreOp = kDisableStore,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
};
|
||||
}
|
||||
// Populate the Depth Attachment.
|
||||
if (hasDepth) {
|
||||
const bool clear = any(config.clear & TargetBufferFlags::DEPTH);
|
||||
const bool discardStart = any(config.discardStart & TargetBufferFlags::DEPTH);
|
||||
const bool discardEnd = any(config.discardEnd & TargetBufferFlags::DEPTH);
|
||||
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
depthAttachmentRef.attachment = attachmentIndex;
|
||||
attachments[attachmentIndex++] = {
|
||||
.format = config.depthFormat,
|
||||
.samples = (VkSampleCountFlagBits)config.samples,
|
||||
.loadOp = clear ? kClear : (discardStart ? kDontCare : kKeep),
|
||||
.storeOp = discardEnd ? kDisableStore : kEnableStore,
|
||||
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
if (isMask2) {
|
||||
if (isMask1) {
|
||||
index = subpasses[1].inputAttachmentCount++;
|
||||
inputAttachmentRef[index].layout = layout;
|
||||
inputAttachmentRef[index].attachment = sample ? attachmentIndex + 1 : attachmentIndex;
|
||||
if (isDepth) {
|
||||
dependencies->srcStageMask |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
dependencies->dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||
dependencies->srcAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
dependencies->dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
||||
}
|
||||
else {
|
||||
dependencies->srcStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependencies->dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
dependencies->srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dependencies->dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
index = subpasses[1].colorAttachmentCount++;
|
||||
colorAttachmentRefs[1][index].layout = layout;
|
||||
colorAttachmentRefs[1][index].attachment = attachmentIndex;
|
||||
if (sample) {
|
||||
index = subpasses[1].colorAttachmentCount++;
|
||||
colorAttachmentRefs[1][index].layout = layout;
|
||||
colorAttachmentRefs[1][index].attachment = attachmentIndex + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isDepth) {
|
||||
if (isMask1) {
|
||||
depthAttachmentRef[0].layout = layout;
|
||||
depthAttachmentRef[0].attachment = attachmentIndex;
|
||||
}
|
||||
if (isMask2) {
|
||||
depthAttachmentRef[1].layout = layout;
|
||||
depthAttachmentRef[1].attachment = attachmentIndex;
|
||||
}
|
||||
}
|
||||
attachmentIndex += sample ? 2 : 1;
|
||||
}
|
||||
renderPassInfo.pDependencies = dependencies->srcStageMask ? dependencies : nullptr;
|
||||
renderPassInfo.attachmentCount = attachmentIndex;
|
||||
VkRenderPass pass;
|
||||
VkResult error = vkCreateRenderPass(backend.GetDevice().Ptr(), &renderPassInfo, nullptr, &pass);
|
||||
RenderPassInfo info{ config};
|
||||
info.config.pass = pass;
|
||||
RenderPassInfo info{pass, config};
|
||||
backend.GetDevice().CreateSemaphores(info.semaphores, context.frameCount);
|
||||
Backend::RenderWorker->GetCommandPool().PopList(info.commands, context.frameCount);
|
||||
RenderPassCache.emplace(hash, info);
|
||||
return &RenderPassCache[hash];
|
||||
auto itr = RenderPassCache.emplace(hash, info);
|
||||
return &itr.first->second;
|
||||
}
|
||||
void VulkanAPI::SetRenderPassInfo(Name name, VkRenderPass pass) {
|
||||
RenderPassInfo info{};
|
||||
info.config.pass = pass;
|
||||
RenderPassInfo info{pass};
|
||||
backend.GetDevice().CreateSemaphores(info.semaphores, context.frameCount);
|
||||
Backend::RenderWorker->GetCommandPool().PopList(info.commands, context.frameCount);
|
||||
RenderPassNameCache.emplace(name, info);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#include <tuple>
|
||||
#include "meta/enum.h"
|
||||
#include "vkn/vulkan_api_help.h"
|
||||
namespace vkn {
|
||||
VkImageLayout vkApiGetAttachmentLayout(VkFormat format, bool includeStencilBit)
|
||||
|
||||
@ -56,6 +56,23 @@ namespace vkn {
|
||||
VulkanAPI::Ptr()->ExecuteResourceBarriers(desc);
|
||||
EndRecord(Backend::RenderWorker->GetQueue().Ptr());
|
||||
}
|
||||
void VulkanContext::ClearSurface(VkClearColorValue clearValue)
|
||||
{
|
||||
// 条件满足时,手动清除附件
|
||||
VkClearAttachment clearAttachment = {};
|
||||
clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // 仅清除颜色附件
|
||||
clearAttachment.colorAttachment = 0; // 附件索引
|
||||
clearAttachment.clearValue.color = clearValue; // 传递清除值
|
||||
|
||||
VkClearRect clearRect = {};
|
||||
clearRect.rect.offset = { 0, 0 }; // 清除区域
|
||||
clearRect.rect.extent = { surface.width, surface.height }; // 渲染区域的大小
|
||||
clearRect.baseArrayLayer = 0;
|
||||
clearRect.layerCount = 1; // 默认清除第一个层级
|
||||
|
||||
// 使用 vkCmdClearAttachments 清除颜色附件
|
||||
vkCmdClearAttachments(command, 1, &clearAttachment, 1, &clearRect);
|
||||
}
|
||||
void VulkanContext::BeginRecord(VkCommandBufferUsageFlags flag)
|
||||
{
|
||||
VkCommandBufferBeginInfo beginInfo{
|
||||
|
||||
@ -88,7 +88,8 @@ namespace vkn {
|
||||
Backend& backend = API->GetBackend();
|
||||
Queue* pQueue = backend.GetDevice().GetQueue(Queue::RenderQueue);
|
||||
VkDescriptorPool descriptorPool = CreateDescriptorPool(backend.GetDevice().Ptr());
|
||||
VkRenderPass renderPass = CreateRenderPass(API->context.surface.format, backend.GetDevice().Ptr());
|
||||
TextureDesc surface = API->context.surface;
|
||||
VkRenderPass renderPass = CreateRenderPass(surface.format, backend.GetDevice().Ptr());
|
||||
|
||||
ImGui_ImplVulkan_InitInfo init_info = {};
|
||||
init_info.Instance = backend.GetInstance().Ptr();
|
||||
@ -152,10 +153,9 @@ namespace vkn {
|
||||
}
|
||||
void VulkanImguiEditor::Setup(FrameGraph& graph, RenderPassBuilder& builder)
|
||||
{
|
||||
AttachmentDesc surface{ graph.GetRenderSurface() };
|
||||
builder.Name(ImguiPassName)
|
||||
.Type(RenderPassNodeType::Imgui, RenderPassNodeFlag::Output)
|
||||
.Write(surface, ResourceState::COLOR_ATTACHMENT);
|
||||
.Write(graph.GetRenderSurface(), ResourceState::COLOR_ATTACHMENT);
|
||||
if (gEngineConfig.IsRenderEditorSurface) {
|
||||
builder.Read(graph.GetSurface(), ResourceState::READ_ONLY);
|
||||
}
|
||||
|
||||
@ -2,7 +2,15 @@
|
||||
#include "data/global.h"
|
||||
#include <imgui.h>
|
||||
namespace api {
|
||||
TextureSampler sampler;
|
||||
TextureSampler sampler{
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
.filterMin = SamplerMinFilter::LINEAR,
|
||||
.wrapS = SamplerWrapMode::CLAMP_TO_EDGE,
|
||||
.wrapT = SamplerWrapMode::CLAMP_TO_EDGE,
|
||||
.wrapR = SamplerWrapMode::CLAMP_TO_EDGE,
|
||||
.compareMode = SamplerCompareMode::COMPARE_TO_TEXTURE,
|
||||
.compareFunc = SamplerCompareFunc::GE,
|
||||
};
|
||||
ImTextureID TextureIDList[10] = {};
|
||||
void AssetPreviewPanel::DrawPanel(FrameGraph& graph, RenderEditorContext& context) {
|
||||
static float my_float = 0.5f;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
[Window][Debug##Default]
|
||||
ViewportPos=480,240
|
||||
ViewportId=0x16723995
|
||||
Pos=60,60
|
||||
Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
@ -11,9 +10,8 @@ Size=191,71
|
||||
Collapsed=0
|
||||
|
||||
[Window][MainWindow]
|
||||
ViewportPos=480,240
|
||||
ViewportId=0x72FC8CA3
|
||||
Size=191,105
|
||||
Pos=163,77
|
||||
Size=695,351
|
||||
Collapsed=0
|
||||
|
||||
[Docking][Data]
|
||||
|
||||
@ -45,6 +45,9 @@ void ZWorldModule::MainLoop()
|
||||
while (running) {
|
||||
// 处理事件
|
||||
while (SDL_PollEvent(&event_)) {
|
||||
#ifdef WITH_EDITOR
|
||||
ImGui_ImplSDL2_ProcessEvent(&event_);
|
||||
#endif // WITH_EDITOR
|
||||
if (event_.type == SDL_QUIT) {
|
||||
running = false;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user