vulkan api bugfix
This commit is contained in:
parent
c39296d050
commit
9b1704246d
@ -10,7 +10,7 @@ public:
|
||||
~Singleton() {
|
||||
ms_Singleton = nullptr;
|
||||
}
|
||||
static constexpr T* Ptr(void) {
|
||||
static T* Ptr(void) {
|
||||
return ms_Singleton;
|
||||
}
|
||||
};
|
||||
@ -1,6 +1,7 @@
|
||||
#include "render/renderapi.h"
|
||||
#include "render/module.h"
|
||||
namespace api {
|
||||
RenderAPI* API;
|
||||
IMPLEMENT_STATIC_MODULE(RENDER_API, RenderModule, render);
|
||||
void RenderAPI::RenderView(FRenderView& view)
|
||||
{
|
||||
@ -15,4 +16,15 @@ namespace api {
|
||||
RenderView(view);
|
||||
}
|
||||
}
|
||||
RenderAPI::RenderAPI(RenderContext* ctx) : context(*ctx)
|
||||
{
|
||||
API = this;
|
||||
}
|
||||
RenderAPI::~RenderAPI()
|
||||
{
|
||||
delete& context;
|
||||
}
|
||||
RenderAPI* RenderAPI::Ptr() {
|
||||
return API;
|
||||
}
|
||||
}
|
||||
@ -10,15 +10,16 @@ namespace api {
|
||||
public:
|
||||
TextureDesc mSurface;
|
||||
table<Name, TextureDesc> mResourceTable;
|
||||
table<TextureDesc::Key, TextureDesc> mResourcePool;
|
||||
table<TextureDesc::Key, TextureDesc> mResourceViewPool;
|
||||
table<TextureDesc, ImagePtr> mResourcePool;
|
||||
table<TextureViewDesc, ImageViewPtr> mResourceViewPool;
|
||||
lemon::ListGraph mGraph;
|
||||
pmr::vector<FrameGraphNodePtr> mNodes{FramePool()};
|
||||
public:
|
||||
template<typename T>
|
||||
FrameGraphNodePtr AddRenderPass() { return AddRenderPass(&T::Setup, &T::Execute); }
|
||||
using RenderPassSetupFunction = std::function<void(FrameGraph&, RenderPassBuilder&)>;
|
||||
using RenderPassSetupFunction = std::function<bool(FrameGraph&, RenderPassBuilder&)>;
|
||||
FrameGraphNodePtr AddRenderPass(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor);
|
||||
FrameGraphNodePtr AddPresent(const FrameGraphEdgePtr& edge);
|
||||
using TextureSetupFunction = std::function<void(FrameGraph&, class TextureBuilder&)>;
|
||||
FrameGraphEdgePtr CreateTexture(const TextureSetupFunction& setup);
|
||||
|
||||
@ -26,12 +27,18 @@ namespace api {
|
||||
void Execute(FRenderView& view);
|
||||
void Clear();
|
||||
TextureDesc Resource(Name name) {
|
||||
constexpr size_t surface = pmr::string_hash("surface");
|
||||
if (name.Hash() == surface) {
|
||||
return mSurface;
|
||||
}
|
||||
auto it = mResourceTable.find(name);
|
||||
if (it == mResourceTable.end()) {
|
||||
return {};
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
ImagePtr ResolveTexture(TextureDesc desc);
|
||||
ImageViewPtr ResolveTextureView(TextureViewDesc desc);
|
||||
public:
|
||||
void ExecuteRenderPass(RenderPassNode* node, FRenderView& view);
|
||||
void ExecutePresentPass(RenderPassNode* node, FRenderView& view);
|
||||
@ -40,4 +47,5 @@ namespace api {
|
||||
|
||||
void ExecuteResourceBarriers(RenderPassNode* node);
|
||||
};
|
||||
}
|
||||
}
|
||||
#include "frame_graph_builder.inl"
|
||||
@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
#include "frame_graph.h"
|
||||
namespace api {
|
||||
struct FrameGraph::RenderPassBuilder {
|
||||
FrameGraph& graph;
|
||||
@ -9,19 +8,18 @@ namespace api {
|
||||
RenderPassBuilder(FrameGraph* graph, FrameGraphNodePtr& node) noexcept
|
||||
: graph(*graph) , node(node) {};
|
||||
FrameGraph::RenderPassBuilder& Name(pmr::Name name);
|
||||
FrameGraph::RenderPassBuilder& Pass(RenderPass* pass);
|
||||
FrameGraph::RenderPassBuilder& Read(TextureDesc desc, ResourceState state);
|
||||
FrameGraph::RenderPassBuilder& Write(BufferDesc desc, ResourceState state);
|
||||
FrameGraph::RenderPassBuilder& Attach(AttachmentDesc desc, ResourceState state);
|
||||
FrameGraph::RenderPassBuilder& Read(const FrameGraphEdgePtr& edge);
|
||||
FrameGraph::RenderPassBuilder& Write(const FrameGraphEdgePtr& edge);
|
||||
FrameGraph::RenderPassBuilder& Read(const FrameGraphEdgePtr& refEdge, ResourceState state);
|
||||
FrameGraph::RenderPassBuilder& Write(const FrameGraphEdgePtr& refEdge, ResourceState state);
|
||||
FrameGraph::RenderPassBuilder& Present(const FrameGraphEdgePtr& refEdge, ResourceState state);
|
||||
};
|
||||
struct FrameGraph::TextureBuilder {
|
||||
FrameGraph& graph;
|
||||
FrameGraphEdgePtr& edge;
|
||||
public:
|
||||
TextureBuilder(FrameGraph* graph, FrameGraphEdgePtr& edge)noexcept : graph(*graph), edge(edge) {};
|
||||
FrameGraph::TextureBuilder& Name(pmr::Name name);
|
||||
FrameGraph::TextureBuilder& Import(ImagePtr& ptr, AttachmentDesc desc, ResourceState state);
|
||||
FrameGraph::TextureBuilder& Import(pmr::Name name, AttachmentDesc desc, ResourceState state);
|
||||
};
|
||||
}
|
||||
@ -27,6 +27,7 @@ namespace api {
|
||||
NodeType type{ NodeType::Render };
|
||||
RenderPassNode* node;
|
||||
FrameGraphNodePtr() : node(nullptr){};
|
||||
FrameGraphNodePtr(GraphNodeRef ref, NodeType type = NodeType::Present);
|
||||
FrameGraphNodePtr(GraphNodeRef ref, const RenderPassNodeExecuteFn& executor, NodeType type = NodeType::Render);
|
||||
operator bool() const {
|
||||
return node;
|
||||
@ -34,6 +35,7 @@ namespace api {
|
||||
RenderPassNode* operator ->()const {
|
||||
return node;
|
||||
}
|
||||
void Presnet(FrameGraph&, RenderPassContext&);
|
||||
};
|
||||
struct FrameResource {
|
||||
using Resource = std::variant<TextureDesc, BufferDesc, AttachmentDesc>;
|
||||
@ -59,8 +61,11 @@ namespace api {
|
||||
struct FrameGraphEdgePtr {
|
||||
ResourceState targetState;
|
||||
FrameResource* resource;
|
||||
ImagePtr* ppImage;
|
||||
FrameGraphEdgePtr() = default;
|
||||
FrameGraphEdgePtr(const FrameGraphEdgePtr& edge, ResourceState state) {
|
||||
targetState = state;
|
||||
resource = edge.resource;
|
||||
}
|
||||
FrameResource* Make() {
|
||||
resource = new (FramePool()) FrameResource();
|
||||
return resource;
|
||||
@ -72,11 +77,11 @@ namespace api {
|
||||
return resource;
|
||||
}
|
||||
void Resolve(FrameGraph* graph);
|
||||
void ResolveView(FrameGraph* graph);
|
||||
};
|
||||
using RenderPassEdgeIterFn = std::function<void(FrameResource*, FrameGraphEdgePtr)>;
|
||||
struct RenderPassNode {
|
||||
Name name;
|
||||
const void* pass;
|
||||
RenderPassNodeExecuteFn executor;
|
||||
pmr::vector<FrameGraphEdgePtr> inEdges{ FramePool() };
|
||||
pmr::vector<FrameGraphEdgePtr> outEdges{ FramePool() };
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
#include "render_pass.h"
|
||||
#include "render/graph/frame_graph_builder.h"
|
||||
#include "render/graph/frame_graph.h"
|
||||
namespace api {
|
||||
class DemoPass : public RenderPass {
|
||||
public:
|
||||
static void Setup(FrameGraph& graph, FrameGraph::RenderPassBuilder& builder);
|
||||
static bool Setup(FrameGraph& graph, FrameGraph::RenderPassBuilder& builder);
|
||||
static void Execute(FrameGraph&, RenderPassContext&);
|
||||
};
|
||||
|
||||
|
||||
@ -7,19 +7,21 @@ namespace api {
|
||||
class Mesh;
|
||||
class Shader;
|
||||
class RenderPassNode;
|
||||
class RENDER_API RenderAPI : public Singleton<RenderAPI>
|
||||
class RENDER_API RenderAPI
|
||||
{
|
||||
public:
|
||||
RenderContext& context;
|
||||
FrameGraph graph;
|
||||
RenderAPI(RenderContext* ctx) : context(*ctx){};
|
||||
virtual ~RenderAPI() { delete &context; };
|
||||
RenderAPI(RenderContext* ctx);
|
||||
virtual ~RenderAPI();
|
||||
public:
|
||||
void* operator new(size_t size) {
|
||||
return ::operator new(size, GlobalPool());
|
||||
}
|
||||
void operator delete(void* p) {}
|
||||
static RenderAPI* Ptr();
|
||||
public:
|
||||
|
||||
virtual void Init() = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
@ -27,6 +29,8 @@ namespace api {
|
||||
virtual void DrawStaticMesh(Mesh& mesh) = 0;
|
||||
|
||||
virtual void LoadShader(Shader& shader) = 0;
|
||||
virtual ImagePtr CreateTexture(TextureDesc desc) = 0;
|
||||
virtual ImageViewPtr CreateTextureView(TextureViewDesc desc) = 0;
|
||||
|
||||
virtual void BeginFrame() = 0;
|
||||
virtual void EndFrame() = 0;
|
||||
|
||||
@ -17,48 +17,24 @@ namespace api {
|
||||
SAMPLE_COUNT_16 = 16,
|
||||
SAMPLE_COUNT_COUNT = 5,
|
||||
};
|
||||
struct BufferDesc {
|
||||
static BufferDesc Make() {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
using ImagePtr = void*;
|
||||
struct TextureDesc {
|
||||
using Key = uint32_t;
|
||||
ImagePtr image;
|
||||
static TextureDesc Make() {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
struct AttachmentDesc {
|
||||
ImagePtr image;
|
||||
TinyImageFormat colorFormat;
|
||||
SampleCount sampleCount;
|
||||
static AttachmentDesc Make() {
|
||||
return {};
|
||||
}
|
||||
TextureDesc ToTexture() {
|
||||
return TextureDesc{image};
|
||||
}
|
||||
};
|
||||
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.
|
||||
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.
|
||||
};
|
||||
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
|
||||
{
|
||||
// The initial layout after the creation of the VkImage. We use this to denote the state before
|
||||
@ -81,9 +57,65 @@ namespace api {
|
||||
// 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,
|
||||
// For color attachment MSAA resolves.
|
||||
COLOR_ATTACHMENT_RESOLVE,
|
||||
};
|
||||
enum class TextureDimension
|
||||
{
|
||||
TEX_1D = 0x01,
|
||||
TEX_2D = 0x02,
|
||||
TEX_3D = 0x04,
|
||||
TEX_CUBE = 0x08,
|
||||
};
|
||||
using ImagePtr = void*;
|
||||
using ImageViewPtr = void*;
|
||||
struct BufferDesc {
|
||||
static BufferDesc Make() {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
struct TextureDesc {
|
||||
ImagePtr image;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t depth : 16;
|
||||
TinyImageFormat format : 16;
|
||||
ResourceState state : 8;
|
||||
SampleCount sampleCount : 8;
|
||||
uint32_t arraySize : 8;
|
||||
TextureDimension dimension : 4;
|
||||
uint32_t mipLevel : 4;
|
||||
};
|
||||
struct TextureViewDesc {
|
||||
ImagePtr image;
|
||||
TinyImageFormat format : 16;
|
||||
ResourceState state : 8;
|
||||
TextureDimension dimension: 8;
|
||||
uint32_t baseArrayLayer : 8;
|
||||
uint32_t layerCount : 8;
|
||||
uint32_t baseMipLevel : 8;
|
||||
uint32_t levelCount : 8;
|
||||
};
|
||||
struct AttachmentDesc {
|
||||
ImagePtr image;
|
||||
ImageViewPtr imageView;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
TextureDimension dimension : 16;
|
||||
TinyImageFormat colorFormat : 16;
|
||||
SampleCount sampleCount : 16;
|
||||
AttachmentDesc& FromTexture(const TextureDesc& desc) {
|
||||
width = desc.width;
|
||||
height = desc.height;
|
||||
image = desc.image;
|
||||
return *this;
|
||||
}
|
||||
TextureDesc ToTexture() {
|
||||
return TextureDesc{
|
||||
.image = image,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
}
|
||||
};
|
||||
struct TextureBarrier
|
||||
{
|
||||
TextureDesc mTexture;
|
||||
@ -114,4 +146,23 @@ namespace api {
|
||||
const TextureBarrier* pTextureBarriers;
|
||||
uint32_t textureBarriersCount;
|
||||
};
|
||||
}
|
||||
#include "meta/hash.h"
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<api::TextureViewDesc>
|
||||
{
|
||||
size_t operator()(const api::TextureViewDesc& key) const noexcept
|
||||
{
|
||||
return meta::MurmurHashFn(key);
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct hash<api::TextureDesc>
|
||||
{
|
||||
size_t operator()(const api::TextureDesc& key) const noexcept
|
||||
{
|
||||
return meta::MurmurHashFn(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1,13 +1,44 @@
|
||||
#include "render/graph/frame_graph.h"
|
||||
#include "render/graph/frame_graph_builder.h"
|
||||
#include "render/renderapi.h"
|
||||
namespace api {
|
||||
inline bool operator==(const TextureViewDesc& k1, const TextureViewDesc& k2) {
|
||||
if (k1.image != k2.image) return false;
|
||||
if (k1.format != k2.format) return false;
|
||||
if (k1.dimension != k2.dimension) return false;
|
||||
if (k1.state != k2.state) 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;
|
||||
}
|
||||
inline bool operator==(const TextureDesc& k1, const TextureDesc& k2) {
|
||||
if (k1.image != k2.image) return false;
|
||||
if (k1.format != k2.format) return false;
|
||||
if (k1.dimension != k2.dimension) return false;
|
||||
if (k1.state != k2.state) 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;
|
||||
}
|
||||
FrameGraphNodePtr FrameGraph::AddPresent(const FrameGraphEdgePtr& edge)
|
||||
{
|
||||
FrameGraphNodePtr node_ptr{ mGraph.addNode()};
|
||||
RenderPassBuilder builder{ this, node_ptr };
|
||||
builder.Read(edge, ResourceState::PRESENT);
|
||||
mNodes.push_back(node_ptr);
|
||||
return node_ptr;
|
||||
}
|
||||
FrameGraphNodePtr FrameGraph::AddRenderPass(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor)
|
||||
{
|
||||
FrameGraphNodePtr node_ptr{ mGraph.addNode(), executor };
|
||||
RenderPassBuilder builder{ this, node_ptr };
|
||||
setup(*this, builder);
|
||||
mNodes.push_back(node_ptr);
|
||||
if(setup(*this, builder))
|
||||
mNodes.push_back(node_ptr);
|
||||
return node_ptr;
|
||||
}
|
||||
FrameGraphEdgePtr FrameGraph::CreateTexture(const TextureSetupFunction& setup)
|
||||
@ -63,8 +94,7 @@ namespace api {
|
||||
}
|
||||
void FrameGraph::ExecutePresentPass(RenderPassNode* node, FRenderView& view)
|
||||
{
|
||||
RenderPassContext context{};
|
||||
std::get<RenderPassExecuteFunction>(node->executor)(*this, context);
|
||||
ExecuteResourceBarriers(node);
|
||||
}
|
||||
void FrameGraph::ExecuteComputePass(RenderPassNode* node, FRenderView& view)
|
||||
{
|
||||
@ -104,6 +134,7 @@ namespace api {
|
||||
}
|
||||
textureBarrier.push_back(barrier);
|
||||
}
|
||||
resource->sourceState = edge.targetState;
|
||||
});
|
||||
if (bufferBarrier.empty() && textureBarrier.empty()) {
|
||||
return;
|
||||
@ -123,4 +154,24 @@ namespace api {
|
||||
fn(edge.resource, edge);
|
||||
}
|
||||
}
|
||||
ImagePtr FrameGraph::ResolveTexture(TextureDesc desc)
|
||||
{
|
||||
auto it = mResourcePool.find(desc);
|
||||
if (it != mResourcePool.end()) {
|
||||
return it->second;
|
||||
}
|
||||
ImagePtr image = RenderAPI::Ptr()->CreateTexture(desc);
|
||||
mResourcePool.emplace(desc, image);
|
||||
return image;
|
||||
}
|
||||
ImageViewPtr FrameGraph::ResolveTextureView(TextureViewDesc desc)
|
||||
{
|
||||
auto it = mResourceViewPool.find(desc);
|
||||
if (it != mResourceViewPool.end()) {
|
||||
return it->second;
|
||||
}
|
||||
ImageViewPtr view = RenderAPI::Ptr()->CreateTextureView(desc);
|
||||
mResourceViewPool.emplace(desc, view);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,16 +1,12 @@
|
||||
#include "render/graph/frame_graph_builder.h"
|
||||
#include "render/graph/frame_graph.h"
|
||||
#include "render/pass/render_pass.h"
|
||||
#include "meta/enum.h"
|
||||
namespace api {
|
||||
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Name(pmr::Name name)
|
||||
{
|
||||
node->name = name;
|
||||
return *this;
|
||||
}
|
||||
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Pass(RenderPass* pass)
|
||||
{
|
||||
node->pass = pass;
|
||||
return *this;
|
||||
}
|
||||
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Read(TextureDesc desc, ResourceState state)
|
||||
{
|
||||
FrameGraphEdgePtr edge{};
|
||||
@ -44,34 +40,39 @@ namespace api {
|
||||
return *this;
|
||||
}
|
||||
|
||||
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Read(const FrameGraphEdgePtr& edge)
|
||||
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Read(const FrameGraphEdgePtr& refEdge, ResourceState state)
|
||||
{
|
||||
if (!edge) { return *this; }
|
||||
if (!refEdge) { return *this; }
|
||||
FrameGraphEdgePtr edge{ refEdge , state};
|
||||
node->inEdges.emplace_back(edge);
|
||||
edge->targets.emplace_back(node);
|
||||
if(edge->source)
|
||||
graph.mGraph.addEdge(edge->source.ref, node.ref);
|
||||
refEdge->targets.emplace_back(node);
|
||||
if(refEdge->source)
|
||||
graph.mGraph.addEdge(refEdge->source.ref, node.ref);
|
||||
return *this;
|
||||
}
|
||||
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Write(const FrameGraphEdgePtr& edge)
|
||||
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Write(const FrameGraphEdgePtr& refEdge, ResourceState state)
|
||||
{
|
||||
if (!edge) { return *this; }
|
||||
if (!refEdge) { return *this; }
|
||||
FrameGraphEdgePtr edge{ refEdge , state };
|
||||
node->outEdges.emplace_back(edge);
|
||||
edge->targets.emplace_back(node);
|
||||
if (edge->source)
|
||||
graph.mGraph.addEdge(node.ref, edge->source.ref);
|
||||
refEdge->targets.emplace_back(node);
|
||||
if (refEdge->source)
|
||||
graph.mGraph.addEdge(node.ref, refEdge->source.ref);
|
||||
return *this;
|
||||
}
|
||||
FrameGraph::TextureBuilder& FrameGraph::TextureBuilder::Name(pmr::Name name)
|
||||
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Present(const FrameGraphEdgePtr& refEdge, ResourceState state)
|
||||
{
|
||||
Write(refEdge, state);
|
||||
graph.mNodes.push_back(node);
|
||||
graph.AddPresent(refEdge);
|
||||
return *this;
|
||||
}
|
||||
FrameGraph::TextureBuilder& FrameGraph::TextureBuilder::Import(pmr::Name name, AttachmentDesc desc, ResourceState state)
|
||||
{
|
||||
desc.image = nullptr;
|
||||
edge->name = name;
|
||||
return *this;
|
||||
}
|
||||
FrameGraph::TextureBuilder& FrameGraph::TextureBuilder::Import(ImagePtr& ptr, AttachmentDesc desc, ResourceState state)
|
||||
{
|
||||
edge.ppImage = &ptr;
|
||||
edge.targetState = state;
|
||||
edge->resource = desc;
|
||||
edge.targetState = state;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
#include "render/graph/type.h"
|
||||
#include "render/renderapi.h"
|
||||
namespace api {
|
||||
void FrameGraphEdgePtr::Resolve(FrameGraph* graph)
|
||||
{
|
||||
@ -17,8 +18,42 @@ namespace api {
|
||||
if (*imageptr) {
|
||||
return;
|
||||
}
|
||||
if (ppImage) {
|
||||
*imageptr = *ppImage;
|
||||
TextureDesc desc = graph->Resource(resource->name);
|
||||
if (!desc.image) {
|
||||
graph->ResolveTexture(desc);
|
||||
}
|
||||
else {
|
||||
*imageptr = desc.image;
|
||||
}
|
||||
}
|
||||
void FrameGraphEdgePtr::ResolveView(FrameGraph* graph)
|
||||
{
|
||||
if (!resource) {
|
||||
Make();
|
||||
}
|
||||
if (resource->IsAttachment()) {
|
||||
AttachmentDesc& attach = resource->CastTo<AttachmentDesc>();
|
||||
TextureViewDesc view{};
|
||||
view.image = attach.image;
|
||||
view.format = attach.colorFormat;
|
||||
view.state = targetState;
|
||||
view.baseArrayLayer = 0;
|
||||
view.baseMipLevel = 0;
|
||||
view.layerCount = 1;
|
||||
view.levelCount = 1;
|
||||
view.dimension = attach.dimension;
|
||||
attach.imageView = graph->ResolveTextureView(view);
|
||||
}
|
||||
}
|
||||
FrameGraphNodePtr::FrameGraphNodePtr(GraphNodeRef ref, NodeType type)
|
||||
: ref(ref), type(type)
|
||||
{
|
||||
node = new (FramePool()) RenderPassNode();
|
||||
node->executor = [&](FrameGraph& graph, RenderPassContext& ctx) {
|
||||
this->Presnet(graph, ctx);
|
||||
};
|
||||
}
|
||||
void FrameGraphNodePtr::Presnet(FrameGraph&, RenderPassContext&) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,18 +1,20 @@
|
||||
#include "render/pass/demo_pass.h"
|
||||
|
||||
namespace api {
|
||||
void DemoPass::Setup(FrameGraph& graph, FrameGraph::RenderPassBuilder& builder)
|
||||
bool DemoPass::Setup(FrameGraph& graph, FrameGraph::RenderPassBuilder& builder)
|
||||
{
|
||||
AttachmentDesc surface{};
|
||||
surface.colorFormat = TinyImageFormat_B8G8R8A8_UNORM;
|
||||
surface.FromTexture(graph.mSurface);
|
||||
surface.colorFormat = TinyImageFormat_B8G8R8A8_SRGB;
|
||||
surface.sampleCount = SAMPLE_COUNT_1;
|
||||
surface.dimension = TextureDimension::TEX_2D;
|
||||
auto edge = graph.CreateTexture(
|
||||
[=](FrameGraph& graph, FrameGraph::TextureBuilder& builder) {
|
||||
builder.Name("import")
|
||||
.Import(graph.mSurface.image, surface, ResourceState::PRESENT);
|
||||
builder.Import("surface", surface, ResourceState::COLOR_ATTACHMENT);
|
||||
});
|
||||
builder.Name("MiniPass")
|
||||
.Write(edge);
|
||||
.Present(edge, edge.targetState);
|
||||
return false;
|
||||
}
|
||||
void DemoPass::Execute(FrameGraph&, RenderPassContext&)
|
||||
{
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
static_component("render","engine")
|
||||
add_includedirs("3rdparty", {public = true})
|
||||
add_headerfiles("include/**.h", "impl/*.inl")
|
||||
add_headerfiles("include/**.h", "include/**.inl", "impl/*.inl")
|
||||
add_files("src/**.cpp")
|
||||
add_deps("asset", "zlib", "core")
|
||||
add_syslinks("user32", {public = true})
|
||||
|
||||
@ -15,6 +15,14 @@ namespace vkn {
|
||||
using voidFn = std::function<void()>;
|
||||
using commandFn = std::function<void(CommandBuffer& cmd)>;
|
||||
using api::TargetBufferFlags;
|
||||
using api::ResourceBarrierDesc;
|
||||
using api::TextureViewDesc;
|
||||
using api::ImageViewPtr;
|
||||
using api::ImagePtr;
|
||||
using api::TextureDimension;
|
||||
using api::SampleCount;
|
||||
using api::ResourceState;
|
||||
using api::TextureDesc;
|
||||
|
||||
constexpr string_view VulkanEngineName = "vulkan";
|
||||
constexpr uint8_t MAX_SUPPORTED_RENDER_TARGET_COUNT = 8u;
|
||||
@ -37,8 +45,15 @@ namespace vkn {
|
||||
uint8_t initialColorLayoutMask;// 1 byte
|
||||
uint8_t needsResolveMask; // 1 byte
|
||||
};
|
||||
struct FramebufferKey {
|
||||
VkRenderPass pass;
|
||||
VkImageView imageViews[MAX_SUPPORTED_RENDER_TARGET_COUNT * 2 + 1];
|
||||
uint32_t attachmentCount;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t layers;
|
||||
};
|
||||
}
|
||||
#include "meta/hash.h"
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<vkn::RenderPassKey>
|
||||
@ -48,4 +63,12 @@ namespace std {
|
||||
return meta::MurmurHashFn(key);
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct hash<vkn::FramebufferKey>
|
||||
{
|
||||
size_t operator()(const vkn::FramebufferKey& key) const noexcept
|
||||
{
|
||||
return meta::MurmurHashFn(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -13,7 +13,6 @@ namespace vkn {
|
||||
using api::Mesh;
|
||||
using api::Shader;
|
||||
using api::RenderPassNode;
|
||||
using api::ResourceBarrierDesc;
|
||||
struct VulkanContext : public api::RenderContext {
|
||||
VkFence surfaceFence;;
|
||||
VkSemaphore surfaceSemaphore;
|
||||
@ -26,6 +25,7 @@ namespace vkn {
|
||||
Backend backend;
|
||||
table<Guid, MeshVAO> MeshTable;
|
||||
table<RenderPassKey, VkRenderPass> RenderPassCache;
|
||||
table<FramebufferKey, VkFramebuffer> FramebufferCache;
|
||||
public:
|
||||
VulkanAPI();
|
||||
|
||||
@ -36,6 +36,8 @@ namespace vkn {
|
||||
void DrawStaticMesh(Mesh& mesh)override;
|
||||
|
||||
void LoadShader(Shader& shader)override;
|
||||
ImagePtr CreateTexture(TextureDesc desc)override;
|
||||
ImageViewPtr CreateTextureView(TextureViewDesc desc)override;
|
||||
|
||||
void BeginFrame()override;
|
||||
void EndFrame()override;
|
||||
@ -43,7 +45,7 @@ namespace vkn {
|
||||
void EndRenderPass(RenderPassNode* node) override;
|
||||
void ExecuteResourceBarriers(const ResourceBarrierDesc& desc) override;
|
||||
|
||||
VkPipeline GetPipeline();
|
||||
VkPipeline GetPipeline() { return nullptr; };
|
||||
VkRenderPass GetRenderPass(RenderPassKey& config);
|
||||
|
||||
Backend& GetBackend() {
|
||||
|
||||
@ -10,6 +10,13 @@ namespace vkn {
|
||||
VkImageLayout mSrcState;
|
||||
VkImageLayout mDstState;
|
||||
};
|
||||
VkImageLayout GetVkLayout(ResourceState layout);
|
||||
VkImageMemoryBarrier GetVkTextureTransition(VkPipelineStageFlags& mSrcStage, VkPipelineStageFlags mDstStage, const TextureBarrier& barrier);
|
||||
VkImageLayout vkApiGetAttachmentLayout(VkFormat format, bool includeStencilBit);
|
||||
VkImageLayout vkApiGetImageLayout(ResourceState layout);
|
||||
VkImageMemoryBarrier vkApiGetTextureTransition(VkPipelineStageFlags& mSrcStage, VkPipelineStageFlags& mDstStage, const TextureBarrier& barrier);
|
||||
VkImageAspectFlags vkApiGetImageAspectMask(VkFormat format, bool includeStencilBit);
|
||||
VkImageUsageFlags vkApiGetImageUsageFlags(ResourceState startState);
|
||||
VkImageViewType vkApiGetImageViewType(TextureDimension dimension, uint32_t arraySize);
|
||||
VkImageType vkApiGetImageType(TextureDimension dimension);
|
||||
VkImageCreateFlags vkApiGetImageCreateFlag(TextureDimension dimension, uint32_t arraySize);
|
||||
VkSampleCountFlagBits vkApiGetSmpleCountFlag(SampleCount sample);
|
||||
}
|
||||
@ -20,13 +20,14 @@ namespace vkn {
|
||||
};
|
||||
class VulkanSwapchain {
|
||||
private:
|
||||
friend class VulkanWindow;
|
||||
Device& mDevice;
|
||||
VkSwapchainKHR mPtr;
|
||||
int mFrames;
|
||||
pmr::vector<TextureDesc> mSurfaces{GlobalPool()};
|
||||
pmr::vector<TextureDesc> mSurfaces{ GlobalPool() };
|
||||
pmr::vector<VkCommandBuffer> mCommands{ GlobalPool() };
|
||||
pmr::vector<VkFence> mFences{ GlobalPool() };
|
||||
pmr::vector<VkSemaphore> mSemaphores{ GlobalPool() };
|
||||
pmr::vector<VkFence> mFences{ GlobalPool() };
|
||||
pmr::vector<VkSemaphore> mSemaphores{ GlobalPool() };
|
||||
public:
|
||||
VulkanSwapchain(Device& device, VkSurfaceKHR surface, VulkanWindowArgs& args);
|
||||
void Aquire(VulkanContext& ctx);
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include "render/asset/mesh.h"
|
||||
#include "meta/enum.h"
|
||||
#include "tinyimageformat/tinyimageformat_apis.h"
|
||||
|
||||
#include "zlog.h"
|
||||
namespace vkn {
|
||||
inline bool operator==(const RenderPassKey& k1, const RenderPassKey& k2) {
|
||||
if (k1.initialColorLayoutMask != k2.initialColorLayoutMask) return false;
|
||||
@ -24,6 +24,17 @@ namespace vkn {
|
||||
if (k1.subpassMask != k2.subpassMask) return false;
|
||||
return true;
|
||||
}
|
||||
inline bool operator==(const FramebufferKey& k1, const FramebufferKey& k2) {
|
||||
if (k1.pass != k2.pass) return false;
|
||||
if (k1.attachmentCount != k2.attachmentCount) return false;
|
||||
for (int i = 0; i < k1.attachmentCount; i++) {
|
||||
if (k1.imageViews[i] != k2.imageViews[i]) return false;
|
||||
}
|
||||
if (k1.height != k2.height) return false;
|
||||
if (k1.width != k2.width) return false;
|
||||
if (k1.layers != k2.layers) return false;
|
||||
return true;
|
||||
}
|
||||
VulkanAPI::VulkanAPI() : RenderAPI(new VulkanContext())
|
||||
, window(*VulkanWindow::Ptr())
|
||||
, backend(VulkanEngineName)
|
||||
@ -67,6 +78,65 @@ namespace vkn {
|
||||
void VulkanAPI::LoadShader(Shader& shader)
|
||||
{
|
||||
}
|
||||
ImagePtr VulkanAPI::CreateTexture(TextureDesc desc)
|
||||
{
|
||||
if (desc.image) {
|
||||
return desc.image;
|
||||
}
|
||||
uint32_t depth = any(desc.dimension & TextureDimension::TEX_3D) ? 3 : 1;
|
||||
VkImageCreateInfo imageCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = vkApiGetImageCreateFlag(desc.dimension, desc.arraySize),
|
||||
.imageType = vkApiGetImageType(desc.dimension),
|
||||
.format = (VkFormat)TinyImageFormat_ToVkFormat(desc.format),
|
||||
.extent = {
|
||||
.width = (uint32_t)desc.width,
|
||||
.height = (uint32_t)desc.height,
|
||||
.depth = (uint32_t)desc.depth,
|
||||
},
|
||||
.mipLevels = desc.mipLevel,
|
||||
.arrayLayers = desc.arraySize,
|
||||
.samples = vkApiGetSmpleCountFlag(desc.sampleCount),
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = vkApiGetImageUsageFlags(desc.state),
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = NULL,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED
|
||||
};
|
||||
return ImagePtr();
|
||||
}
|
||||
ImageViewPtr VulkanAPI::CreateTextureView(TextureViewDesc desc)
|
||||
{
|
||||
VkImageViewCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
createInfo.image = (VkImage)desc.image;
|
||||
createInfo.viewType = vkApiGetImageViewType(desc.dimension, desc.layerCount);
|
||||
createInfo.format = (VkFormat)TinyImageFormat_ToVkFormat(desc.format);
|
||||
|
||||
// components字段允许调整颜色通道的最终的映射逻辑
|
||||
// 比如,我们可以将所有颜色通道映射为红色通道,以实现单色纹理,我们也可以将通道映射具体的常量数值0和1
|
||||
// 这里用默认的
|
||||
createInfo.components.r = VK_COMPONENT_SWIZZLE_R;
|
||||
createInfo.components.g = VK_COMPONENT_SWIZZLE_G;
|
||||
createInfo.components.b = VK_COMPONENT_SWIZZLE_B;
|
||||
createInfo.components.a = VK_COMPONENT_SWIZZLE_A;
|
||||
|
||||
// subresourceRangle字段用于描述图像的使用目标是什么,以及可以被访问的有效区域
|
||||
// 这个图像用作填充color还是depth stencil等
|
||||
createInfo.subresourceRange.aspectMask = vkApiGetImageAspectMask(createInfo.format, false);
|
||||
// 默认处理所有Mipmap
|
||||
createInfo.subresourceRange.baseMipLevel = desc.baseMipLevel;
|
||||
createInfo.subresourceRange.levelCount = desc.levelCount;
|
||||
// 默认处理所有Layers
|
||||
createInfo.subresourceRange.baseArrayLayer = desc.baseArrayLayer;
|
||||
createInfo.subresourceRange.layerCount = desc.layerCount;
|
||||
|
||||
VkImageView imageView;
|
||||
vkCreateImageView(backend.GetDevice().Ptr(), &createInfo, nullptr, &imageView);
|
||||
return (ImageViewPtr)imageView;
|
||||
}
|
||||
void VulkanAPI::BeginFrame()
|
||||
{
|
||||
VulkanContext& ctx = *(VulkanContext*)&context;
|
||||
@ -77,7 +147,21 @@ namespace vkn {
|
||||
{
|
||||
VulkanContext& ctx = *(VulkanContext*)&context;
|
||||
ctx.command.EndRecord();
|
||||
ctx.command.Submit(Backend::RenderWorker->GetQueue().Ptr(), ctx.surfaceFence);
|
||||
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; // 等待渲染阶段
|
||||
VkSemaphore waitSemaphores[] = { ctx.surfaceSemaphore };
|
||||
VkSemaphore signalSemaphores[] = { ctx.presentSemaphore };// 渲染完成信号量
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &ctx.command.Ptr();
|
||||
|
||||
submitInfo.waitSemaphoreCount = 1;
|
||||
submitInfo.pWaitSemaphores = waitSemaphores;
|
||||
submitInfo.pWaitDstStageMask = waitStages;
|
||||
|
||||
submitInfo.signalSemaphoreCount = 1;
|
||||
submitInfo.pSignalSemaphores = signalSemaphores;
|
||||
vkQueueSubmit(Backend::RenderWorker->GetQueue().Ptr(), 1, &submitInfo, ctx.surfaceFence);
|
||||
window.Present(ctx);
|
||||
}
|
||||
void VulkanAPI::ExecuteResourceBarriers(const ResourceBarrierDesc& desc) {
|
||||
@ -86,12 +170,11 @@ namespace vkn {
|
||||
bufferBarriers.reserve(desc.bufferBarriersCount);
|
||||
pmr::vector<VkImageMemoryBarrier> imageBarriers{ FramePool() };
|
||||
imageBarriers.reserve(desc.textureBarriersCount);
|
||||
using api::ResourceState;
|
||||
VkPipelineStageFlags srcStageMask = 0, dstStageMask = 0;
|
||||
for (uint32_t i = 0; i < desc.textureBarriersCount; i++)
|
||||
{
|
||||
auto& barrier = desc.pTextureBarriers[i];
|
||||
auto desc = GetVkTextureTransition(srcStageMask, dstStageMask, barrier);
|
||||
auto desc = vkApiGetTextureTransition(srcStageMask, dstStageMask, barrier);
|
||||
imageBarriers.push_back(desc);
|
||||
}
|
||||
if (dstStageMask == 0) {
|
||||
@ -101,24 +184,66 @@ namespace vkn {
|
||||
}
|
||||
void VulkanAPI::BeginRenderPass(RenderPassNode* node)
|
||||
{
|
||||
RenderPassKey config{};
|
||||
RenderPassKey config{};
|
||||
FramebufferKey frameKey{.layers = 1};
|
||||
VkClearValue clearValues[2 * MAX_SUPPORTED_RENDER_TARGET_COUNT + 1] = { 0 };
|
||||
int i = 0;
|
||||
for (auto& it : node->outEdges) {
|
||||
if (it->IsAttachment()) {
|
||||
auto& desc = it->CastTo<api::AttachmentDesc>();
|
||||
|
||||
config.colorFormat[i] = (VkFormat)TinyImageFormat_ToVkFormat(desc.colorFormat);
|
||||
config.samples = (VkSampleCountFlagBits)desc.sampleCount;
|
||||
config.samples = vkApiGetSmpleCountFlag(desc.sampleCount);
|
||||
|
||||
TargetBufferFlags flag = TargetBufferFlags(int(TargetBufferFlags::COLOR0) << i);
|
||||
config.clear |= flag;
|
||||
it.ResolveView(&graph);
|
||||
frameKey.imageViews[i] = (VkImageView)desc.imageView;
|
||||
frameKey.height = desc.height;
|
||||
frameKey.width = desc.width;
|
||||
|
||||
//clearValues[i] =
|
||||
i++;
|
||||
}
|
||||
}
|
||||
node->pass = GetRenderPass(config);
|
||||
frameKey.attachmentCount = i;
|
||||
VkRenderPass pass = GetRenderPass(config);
|
||||
frameKey.pass = pass;
|
||||
auto it = FramebufferCache.find(frameKey);
|
||||
VkFramebuffer framebuffer = it->second;
|
||||
if (it == FramebufferCache.end()) {
|
||||
VkFramebufferCreateInfo framebufferInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.renderPass = pass,
|
||||
.attachmentCount = frameKey.attachmentCount,
|
||||
.pAttachments = frameKey.imageViews,
|
||||
.width = frameKey.width,
|
||||
.height = frameKey.height,
|
||||
.layers = frameKey.layers
|
||||
};
|
||||
vkCreateFramebuffer(backend.GetDevice().Ptr(), &framebufferInfo, nullptr, &framebuffer);
|
||||
FramebufferCache.emplace(frameKey, framebuffer);
|
||||
}
|
||||
VkRect2D renderAarea = {
|
||||
.offset = {0,0},
|
||||
.extent = {frameKey.width,frameKey.height}
|
||||
};
|
||||
VkRenderPassBeginInfo beginInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
.pNext = VK_NULL_HANDLE,
|
||||
.renderPass = pass,
|
||||
.framebuffer = framebuffer,
|
||||
.renderArea = renderAarea,
|
||||
.clearValueCount = frameKey.attachmentCount,
|
||||
.pClearValues = clearValues
|
||||
};
|
||||
VulkanContext& ctx = *(VulkanContext*)&context;
|
||||
vkCmdBeginRenderPass(ctx.command.Ptr(), &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
void VulkanAPI::EndRenderPass(RenderPassNode* node)
|
||||
{
|
||||
|
||||
VulkanContext& ctx = *(VulkanContext*)&context;
|
||||
vkCmdEndRenderPass(ctx.command.Ptr());
|
||||
}
|
||||
VkRenderPass VulkanAPI::GetRenderPass(RenderPassKey& config) {
|
||||
auto it = RenderPassCache.find(config);
|
||||
@ -221,6 +346,7 @@ namespace vkn {
|
||||
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,
|
||||
@ -228,9 +354,8 @@ namespace vkn {
|
||||
.storeOp = kEnableStore,
|
||||
.stencilLoadOp = kDontCare,
|
||||
.stencilStoreOp = kDisableStore,
|
||||
.initialLayout = ((!discard && config.initialColorLayoutMask & (1 << i)) || clear)
|
||||
? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.initialLayout = layout,
|
||||
.finalLayout = layout,
|
||||
};
|
||||
}
|
||||
// Nulling out the zero-sized lists is necessary to avoid VK_ERROR_OUT_OF_HOST_MEMORY on Adreno.
|
||||
|
||||
@ -1,7 +1,32 @@
|
||||
#include <tuple>
|
||||
#include "vkn/vulkan_api_help.h"
|
||||
#include "meta/enum.h"
|
||||
namespace vkn {
|
||||
VkImageLayout GetVkLayout(ResourceState layout) {
|
||||
VkImageLayout vkApiGetAttachmentLayout(VkFormat format, bool includeStencilBit)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
// Depth
|
||||
case VK_FORMAT_D16_UNORM:
|
||||
case VK_FORMAT_X8_D24_UNORM_PACK32:
|
||||
case VK_FORMAT_D32_SFLOAT:
|
||||
return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
|
||||
// Stencil
|
||||
case VK_FORMAT_S8_UINT:
|
||||
return VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
// Depth/stencil
|
||||
case VK_FORMAT_D16_UNORM_S8_UINT:
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||
if (includeStencilBit)
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
|
||||
// Assume everything else is Color
|
||||
default:
|
||||
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
}
|
||||
VkImageLayout vkApiGetImageLayout(ResourceState layout) {
|
||||
switch (layout) {
|
||||
case ResourceState::UNDEFINED:
|
||||
return VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
@ -19,31 +44,22 @@ namespace vkn {
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
case ResourceState::PRESENT:
|
||||
return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
// Filament sometimes samples from one miplevel while writing to another level in the
|
||||
// same texture (e.g. bloom does this). Moreover we'd like to avoid lots of expensive
|
||||
// layout transitions. So, keep it simple and use GENERAL for all color-attachable
|
||||
// textures.
|
||||
case ResourceState::COLOR_ATTACHMENT:
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
case ResourceState::COLOR_ATTACHMENT_RESOLVE:
|
||||
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
}
|
||||
VkImageMemoryBarrier GetVkTextureTransition(VkPipelineStageFlags& mSrcStage, VkPipelineStageFlags mDstStage, const TextureBarrier& barrier) {
|
||||
VkImageMemoryBarrier vkApiGetTextureTransition(VkPipelineStageFlags& mSrcStage, VkPipelineStageFlags& mDstStage, const TextureBarrier& barrier) {
|
||||
VkAccessFlags srcAccessMask, dstAccessMask;
|
||||
VkPipelineStageFlags srcStage, dstStage;
|
||||
|
||||
switch (barrier.mSrcState) {
|
||||
case ResourceState::UNDEFINED:
|
||||
srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
||||
srcAccessMask = 0;
|
||||
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
break;
|
||||
case ResourceState::COLOR_ATTACHMENT:
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
break;
|
||||
case ResourceState::READ_WRITE:
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
@ -69,23 +85,16 @@ namespace vkn {
|
||||
srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case ResourceState::COLOR_ATTACHMENT_RESOLVE:
|
||||
srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
case ResourceState::PRESENT:
|
||||
srcAccessMask = VK_ACCESS_NONE;
|
||||
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (barrier.mDstState) {
|
||||
case ResourceState::COLOR_ATTACHMENT:
|
||||
dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dstStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
|
||||
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
break;
|
||||
case ResourceState::READ_WRITE:
|
||||
dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
@ -115,10 +124,9 @@ namespace vkn {
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||
break;
|
||||
case ResourceState::PRESENT:
|
||||
case ResourceState::COLOR_ATTACHMENT_RESOLVE:
|
||||
case ResourceState::UNDEFINED:
|
||||
dstAccessMask = 0;
|
||||
dstStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
dstStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
break;
|
||||
}
|
||||
mSrcStage |= srcStage;
|
||||
@ -134,12 +142,95 @@ namespace vkn {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = srcAccessMask,
|
||||
.dstAccessMask = dstAccessMask,
|
||||
.oldLayout = GetVkLayout(barrier.mSrcState),
|
||||
.newLayout = GetVkLayout(barrier.mDstState),
|
||||
.oldLayout = vkApiGetImageLayout(barrier.mSrcState),
|
||||
.newLayout = vkApiGetImageLayout(barrier.mDstState),
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = (VkImage)barrier.mTexture.image,
|
||||
.subresourceRange = subresources
|
||||
};
|
||||
}
|
||||
VkImageAspectFlags vkApiGetImageAspectMask(VkFormat format, bool includeStencilBit)
|
||||
{
|
||||
VkImageAspectFlags result = 0;
|
||||
switch (format)
|
||||
{
|
||||
// Depth
|
||||
case VK_FORMAT_D16_UNORM:
|
||||
case VK_FORMAT_X8_D24_UNORM_PACK32:
|
||||
case VK_FORMAT_D32_SFLOAT:
|
||||
result = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
break;
|
||||
// Stencil
|
||||
case VK_FORMAT_S8_UINT:
|
||||
result = VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
break;
|
||||
// Depth/stencil
|
||||
case VK_FORMAT_D16_UNORM_S8_UINT:
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||
result = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (includeStencilBit)
|
||||
result |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
break;
|
||||
// Assume everything else is Color
|
||||
default:
|
||||
result = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
VkImageUsageFlags vkApiGetImageUsageFlags(ResourceState startState)
|
||||
{
|
||||
VkImageUsageFlags usageFlags = 0;
|
||||
if (any(startState & ResourceState::COLOR_ATTACHMENT))
|
||||
usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
else if (any(startState & ResourceState::DEPTH_ATTACHMENT))
|
||||
usageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
return usageFlags;
|
||||
}
|
||||
VkImageViewType vkApiGetImageViewType(TextureDimension dimension, uint32_t arraySize)
|
||||
{
|
||||
if (any(dimension & TextureDimension::TEX_1D)) {
|
||||
return arraySize > 1 ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D;
|
||||
}
|
||||
if (any(dimension & TextureDimension::TEX_CUBE)) {
|
||||
return arraySize > 1 ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
}
|
||||
if (any(dimension & TextureDimension::TEX_2D)) {
|
||||
return arraySize > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
|
||||
}
|
||||
if (any(dimension & TextureDimension::TEX_3D)) {
|
||||
return VK_IMAGE_VIEW_TYPE_3D;
|
||||
}
|
||||
return VK_IMAGE_VIEW_TYPE_MAX_ENUM;
|
||||
}
|
||||
VkImageType vkApiGetImageType(TextureDimension dimension)
|
||||
{
|
||||
if (any(dimension & TextureDimension::TEX_1D)) {
|
||||
return VK_IMAGE_TYPE_1D;
|
||||
}
|
||||
if (any(dimension & TextureDimension::TEX_2D)) {
|
||||
return VK_IMAGE_TYPE_2D;
|
||||
}
|
||||
if (any(dimension & TextureDimension::TEX_3D)) {
|
||||
return VK_IMAGE_TYPE_3D;
|
||||
}
|
||||
return VK_IMAGE_TYPE_MAX_ENUM;
|
||||
}
|
||||
VkImageCreateFlags vkApiGetImageCreateFlag(TextureDimension dimension, uint32_t arraySize)
|
||||
{
|
||||
VkImageCreateFlags flag{};
|
||||
if (any(dimension & TextureDimension::TEX_CUBE)) {
|
||||
flag |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
||||
}
|
||||
if (arraySize > 0) {
|
||||
flag |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
VkSampleCountFlagBits vkApiGetSmpleCountFlag(SampleCount sample)
|
||||
{
|
||||
return (VkSampleCountFlagBits)sample;
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,7 @@
|
||||
#include "asset/resource_system.h"
|
||||
#include "zlog.h"
|
||||
#include <algorithm>
|
||||
#include <tinyimageformat/tinyimageformat_apis.h>
|
||||
namespace vkn {
|
||||
bool VulkanWindow::CreateRender(CreatePFN createPFN, VulkanWindowArgs& args)
|
||||
{
|
||||
@ -21,6 +22,7 @@ namespace vkn {
|
||||
args.width = mWidth;
|
||||
args.height = mHeight;
|
||||
mSwapchain = new (GlobalPool()) VulkanSwapchain(backend.GetDevice(), surface, args);
|
||||
api->graph.mSurface = mSwapchain->mSurfaces[0];
|
||||
return true;
|
||||
}
|
||||
VulkanSwapchain::VulkanSwapchain(Device& device, VkSurfaceKHR surface, VulkanWindowArgs& args)
|
||||
@ -63,8 +65,16 @@ namespace vkn {
|
||||
mSurfaces.reserve(mFrames);
|
||||
mCommands.reserve(mFrames);
|
||||
mSemaphores.reserve(mFrames + mFrames);
|
||||
TextureDesc desc{};
|
||||
desc.width = args.width;
|
||||
desc.height = args.height;
|
||||
desc.format = TinyImageFormat_FromVkFormat((TinyImageFormat_VkFormat)args.imageFormat);
|
||||
desc.state = ResourceState::PRESENT;
|
||||
desc.sampleCount = SampleCount::SAMPLE_COUNT_1;
|
||||
desc.arraySize = 1;
|
||||
desc.mipLevel = 1;
|
||||
desc.depth = 1;
|
||||
for (int i = 0; i < mFrames; i++) {
|
||||
api::TextureDesc desc;
|
||||
desc.image = swapchain_images[i];
|
||||
mSurfaces.push_back(desc);
|
||||
mSemaphores.push_back(mDevice.CreateSemaphore());
|
||||
@ -91,7 +101,7 @@ namespace vkn {
|
||||
{
|
||||
VkPresentInfoKHR presentInfo = {};
|
||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
presentInfo.pWaitSemaphores = &ctx.surfaceSemaphore;
|
||||
presentInfo.pWaitSemaphores = &ctx.presentSemaphore;
|
||||
presentInfo.waitSemaphoreCount = 1;
|
||||
presentInfo.pSwapchains = &mPtr;
|
||||
presentInfo.swapchainCount = 1;
|
||||
|
||||
@ -5,14 +5,6 @@
|
||||
#include "render/pass/demo_pass.h"
|
||||
#include <iostream>
|
||||
using namespace api;
|
||||
FrameGraphNodePtr FrameGraph::AddRenderPass(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor)
|
||||
{
|
||||
FrameGraphNodePtr node_ptr{ mGraph.addNode(), executor };
|
||||
RenderPassBuilder builder{ this, node_ptr };
|
||||
setup(*this, builder);
|
||||
mNodes.push_back(node_ptr);
|
||||
return node_ptr;
|
||||
}
|
||||
RenderAPI* API;
|
||||
void ZWorldModule::OnLoad(int argc, char** argv)
|
||||
{
|
||||
@ -24,6 +16,7 @@ void ZWorldModule::OnLoad(int argc, char** argv)
|
||||
if (!window->CreateRender(&SDL_Vulkan_CreateSurface, args)) {
|
||||
zlog::errorf("SDL_Vulkan_CreateSurface failed {}", SDL_GetError());
|
||||
}
|
||||
API->Init();
|
||||
API->context.views.push_back({});
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user