renderpass rebuild

This commit is contained in:
ouczbs 2024-12-21 15:32:22 +08:00
parent 44bf81dcfe
commit fcf226ff3f
24 changed files with 711 additions and 724 deletions

View File

@ -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 {};
}
};*/
}

View File

@ -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 {
};
}

View File

@ -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);
};

View File

@ -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);
@ -57,5 +62,4 @@ namespace api {
static void ExecuteResourceBarriers(RenderPassNode* node, RenderPassType type);
};
}
#include "frame_graph_builder.inl"
}

View File

@ -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;}
};
}

View File

@ -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);
};
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "type.h"
#include "render_type.h"
namespace api {
struct RenderContext;
struct FRenderView {

View 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);
}
};
}

View File

@ -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);
}
};
}

View File

@ -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);

View File

@ -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;
}
}

View 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;
}
}

View File

@ -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;
}
}

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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);
};

View File

@ -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;
}
//单一renderpassconfig.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);

View File

@ -1,4 +1,4 @@
#include <tuple>
#include "meta/enum.h"
#include "vkn/vulkan_api_help.h"
namespace vkn {
VkImageLayout vkApiGetAttachmentLayout(VkFormat format, bool includeStencilBit)

View File

@ -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{

View File

@ -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);
}

View File

@ -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;

View File

@ -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]

View File

@ -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;
}