add dynamic buffer & add noesis

This commit is contained in:
ouczbs 2024-12-26 11:40:41 +08:00
parent fdfc42ed8c
commit 6c7dc30711
64 changed files with 1034 additions and 118 deletions

View File

@ -1,4 +1,4 @@
add_requires("spdlog", "vulkansdk","shaderc","spirv","spirv-cross")
add_requires("spdlog", "vulkansdk","shaderc","spirv","spirv-cross","stb")
add_requires("mimalloc", {configs = {shared = true, debug = true, copy = true}})
--add_requires("imgui",{configs = {shared = true, debug = true, copy = true}})
add_requires("noesis",{configs = {shared = true, copy = true}})

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl x:Class="api.UIWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:api"
Height="300" Width="400">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Name="HelloText" Text="Hello, Noesis GUI!" FontSize="24" Margin="10"/>
<Button Content="Click Me" Width="200" Height="50" Margin="10"/>
</StackPanel>
</UserControl>

View File

@ -1,4 +1,10 @@
#pragma once
#include "ui/ui_window.h"
namespace api {
class EditorMainWindow : public UIWindow {
public:
using UIWindow::UIWindow;
void InitializeComponent() override;
};
}

View File

@ -2,5 +2,4 @@
#include "data/global.h"
namespace api {
APP_API EngineConfig gEngineConfig{};
IMPLEMENT_STATIC_MODULE(APP_API, AppModule, app)
}

View File

@ -298,6 +298,5 @@ namespace api {
{
impl->SetFileFlag(name, flag);
}
IMPLEMENT_STATIC_MODULE(ASSET_API, AssetModule, asset)
}

View File

@ -246,5 +246,4 @@ namespace api {
{
return impl->spawnStaticModule(name);
}
IMPLEMENT_STATIC_MODULE(CORE_API, CoreModule, core)
}

View File

@ -66,5 +66,6 @@ namespace api
return "";
}
pmr::string RealPath()const;
static pmr::string RealPath(const char* str);
};
}

View File

@ -5,5 +5,9 @@ namespace api {
{
return FileManager::Ptr()->RealPath(*this);
}
pmr::string PackagePath::RealPath(const char* str)
{
return FileManager::Ptr()->RealPath(str);
}
}

View File

@ -2,7 +2,6 @@
#include "render/render_module.h"
namespace api {
SINGLETON_DEFINE(RenderAPI)
IMPLEMENT_STATIC_MODULE(RENDER_API, RenderModule, render);
void RenderAPI::RenderView(FRenderView& view)
{
view.context = &context;

View File

@ -7,7 +7,7 @@ namespace api {
{
public:
struct TextureID{
uint32_t id;
int32_t id;
uint32_t tick;
};
uint32_t mTickStamp{1};
@ -45,7 +45,7 @@ namespace api {
void TransitionState(TextureDesc& desc, ResourceState state);
bool ResolveState(TextureDesc& desc, ResourceState& srcstart, ResourceState& dststate);
bool ResolveState(BufferDesc& desc, ResourceState& srcstart, ResourceState& dststate);
TextureDesc& ResolveTexture(uint32_t id);
TextureDesc& ResolveTexture(int32_t id);
TextureDesc ResourceTexture(Name name, int num);
ImageViewPtr ResolveTextureView(TextureDesc& desc);
ImageViewPtr ResolveTextureView(TextureViewKey key);

View File

@ -0,0 +1,144 @@
#pragma once
#define PREALLOCATED_DYNAMIC_BUFFER_PAGES 2
#include "renderapi.h"
namespace api {
struct DynamicBufferDesc {
uint32_t size;
uint32_t pos;
uint32_t drawPos;
BufferUsage usage;
ResourceMemoryUsage memoryUsage;
};
struct DynamicBuffer : public DynamicBufferDesc
{
struct Page
{
uint32_t hash;
uint32_t frameNumber;
void* pBuffer;
void* pAllocation;
void* pMappingAddr;
Page* next;
};
struct PageAllocator
{
struct Block
{
Page pages[16];
Block* next;
};
uint32_t pageIndex;
uint32_t numPages;
Block* blocks = nullptr;
};
Page* currentPage;
Page* freePages;
Page* pendingPages;
PageAllocator allocator;
////////////////////////////////////////////////////////////////////////////////////////////////////
void InitBuffer(uint32_t _size, BufferUsage _usage, ResourceMemoryUsage _memoryUsage)
{
pos = 0;
drawPos = 0;
size = _size;
usage = _usage;
memoryUsage = _memoryUsage;
pendingPages = nullptr;
freePages = nullptr;
allocator.numPages = 0;
allocator.pageIndex = 0;
for (uint32_t i = 0; i < PREALLOCATED_DYNAMIC_BUFFER_PAGES; i++)
{
Page* page = AllocatePage();
page->next = freePages;
freePages = page;
}
currentPage = freePages;
freePages = freePages->next;
}
static Page* AllocatePageMemory(PageAllocator& allocator)
{
using Block = PageAllocator::Block;
if (!allocator.blocks || allocator.pageIndex == _countof(Block::pages))
{
Block* block = (Block*)xmalloc(sizeof(Block));
block->next = allocator.blocks;
allocator.blocks = block;
allocator.pageIndex = 0;
}
allocator.numPages++;
return allocator.blocks->pages + allocator.pageIndex++;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
Page* AllocatePage()
{
Page* page = AllocatePageMemory(allocator);
memset(page, 0, sizeof(Page));
BufferDesc desc{};
desc.size = size;
desc.usage = usage;
desc.memoryUsage = memoryUsage;
RenderAPI::Ptr()->CreateBuffer(desc);
page->pAllocation = desc.pAllocation;
page->pBuffer = desc.buffer;
page->pMappingAddr = desc.pMappingAddr;
return page;
}
void* MapBuffer(uint32_t _size, uint32_t frameNumber, uint32_t safeFrameNumber) {
if (pos + _size > size)
{
// We ran out of space in the current page, get a new one
// Move the current one to pending and insert a GPU fence
currentPage->frameNumber = frameNumber;
currentPage->next = pendingPages;
pendingPages = currentPage;
// If there is one free slot get it
if (freePages != nullptr)
{
currentPage = freePages;
freePages = freePages->next;
}
else
{
// Move pages already processed by GPU from pending to free
Page** it = &pendingPages->next;
while (*it != nullptr)
{
if ((*it)->frameNumber > safeFrameNumber)
{
it = &((*it)->next);
}
else
{
// Once we find a processed page, the rest of pages must be also processed
Page* page = *it;
*it = nullptr;
freePages = page;
break;
}
}
if (freePages != nullptr)
{
currentPage = freePages;
freePages = freePages->next;
}
else
{
currentPage = AllocatePage();
}
}
pos = 0;
}
drawPos = pos;
pos = pos + _size;
return (uint8_t*)currentPage->pMappingAddr + drawPos;
}
};
}

View File

@ -12,6 +12,7 @@ namespace api {
uint32_t frameCount{0};
uint32_t frame{ 0 };
uint32_t presentFrame{ 0 };
uint32_t frameNumber{ 0 };
virtual void SetViewport(float x, float y, float width, float height, float min_depth, float max_depth) = 0;
virtual void SetScissor(uint32_t x, uint32_t y, uint32_t width, uint32_t height) = 0;
virtual void BindIndexBuffer(BufferDesc desc, uint32_t index_stride) = 0;

View File

@ -38,21 +38,49 @@ namespace api {
DYNAMIC = 0x02, //!< content modified frequently, used many times
VERTEX = 0x04,
UNIFORM = 0x08,
SHADER_STORAGE = 0x10
SHADER_STORAGE = 0x10,
TRANSFER_SRC = 0x20,
};
enum class ResourceMemoryUsage : uint8_t
/*
GPU_RENDERING
GPU_STORAGE
GPU_COMPUTE GPU
HOST_VISIBLE访 CPU GPU
HOST_COHERENT CPU GPU
LAZY_ALLOCATED GPU
STATIC使
*/
enum class ResourceMemoryUsage : uint16_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,
GPU_ONLY = 0x01,
/// Memory will be mapped on host. Could be used for transfer to device.
CPU_ONLY = 2,
CPU_ONLY = 0x02,
/// Memory will be used for frequent (dynamic) updates from host and reads on device.
CPU_TO_GPU = 3,
CPU_TO_GPU = 0x04,
/// Memory will be used for writing on device and readback on host.
GPU_TO_CPU = 4,
COUNT,
GPU_TO_CPU = 0x08,
/// Memory is intended to be used for rendering or graphics purposes.
GPU_RENDERING = 0x10,
/// Memory will be used for storage or large buffers that don't require frequent updates.
GPU_STORAGE = 0x20,
/// Memory is visible to the host and the device, can be used for both read and write.
HOST_VISIBLE = 0x40,
/// Memory will be lazily allocated and can be used for GPU resources that are not immediately needed.
LAZY_ALLOCATED = 0x80,
/// Memory is coherent for both host and device, meaning no explicit synchronization is needed.
HOST_COHERENT = 0x100,
/// Static data, such as constant buffers or shader resources, that will not change after initialization.
STATIC = 0x200,
/// Memory intended for use by a compute shader, can be mapped or un-mapped depending on use case.
GPU_COMPUTE = 0x400,
};
enum SampleCount : uint8_t
{
@ -198,9 +226,10 @@ namespace api {
struct BufferBarrier;
struct TextureBarrier;
struct BufferDesc {
BufferPtr buffer;
void* mappingAddr;
uint32_t size;
BufferPtr buffer;
void* pAllocation;
void* pMappingAddr;
uint32_t size;
BufferUsage usage;
ResourceMemoryUsage memoryUsage;
static BufferDesc Make() {
@ -228,7 +257,7 @@ namespace api {
}
};
struct TextureKey {
uint32_t id;
int32_t id;
uint16_t width;
uint16_t height;
uint16_t depth;
@ -335,6 +364,13 @@ namespace api {
float clearDepth;
uint32_t clearStencil;
};
struct TextureUpdateArgs {
uint32_t x;
uint32_t y;
uint32_t width;
uint32_t height;
const void* data;
};
}
#include "meta/hash.h"
namespace std {

View File

@ -36,6 +36,7 @@ namespace api {
virtual void CreateTexture(TextureDesc& desc) = 0;
virtual ImageViewPtr CreateTextureView(TextureViewKey desc) = 0;
virtual SamplerPtr CreateTextureSampler(TextureSampler sampler) = 0;
virtual void UpdateTexture(TextureDesc& texture, const TextureUpdateArgs& update, ResourceState state) = 0;
virtual void BeginFrame() = 0;
virtual void EndFrame() = 0;
virtual void RenderView(FRenderView& view);

View File

@ -231,9 +231,9 @@ namespace api {
{
return true;
}
TextureDesc& FrameGraph::ResolveTexture(uint32_t id)
TextureDesc& FrameGraph::ResolveTexture(int32_t id)
{
if (!id || id > mTexturePool.size()) {
if (id <= 0 || id > mTexturePool.size()) {
return mTexturePool[0];//empty
}
TextureDesc& texture = mTexturePool[id - 1];
@ -292,6 +292,7 @@ namespace api {
if (it != mTextureKeyMap.end()) {
for (auto& id : it->second) {
if (id.tick != mTickStamp) {
id.tick = mTickStamp;
desc.id = id.id;
return;
}

View File

@ -0,0 +1,36 @@
#include <NoesisPCH.h>
namespace api{
////////////////////////////////////////////////////////////////////////////////////////////////////
static TinyImageFormat VKFormat(Noesis::TextureFormat::Enum format, bool sRGB)
{
switch (format)
{
case Noesis::TextureFormat::RGBA8: return sRGB ? TinyImageFormat_B8G8R8A8_SRGB : TinyImageFormat_B8G8R8A8_UNORM;
case Noesis::TextureFormat::RGBX8: return sRGB ? TinyImageFormat_B8G8R8A8_SRGB : TinyImageFormat_B8G8R8A8_UNORM;
case Noesis::TextureFormat::R8: return TinyImageFormat_R8_UNORM;
default: NS_ASSERT_UNREACHABLE;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
class UITexture final : public Noesis::Texture
{
public:
UITexture(TextureDesc desc) : desc(desc) {}
~UITexture()
{
}
uint32_t GetWidth() const override { return desc.width; }
uint32_t GetHeight() const override { return desc.height; }
bool HasMipMaps() const override { return desc.mipLevel > 1; }
bool IsInverted() const override { return isInverted; }
bool HasAlpha() const override { return hasAlpha; }
TextureDesc desc;
bool isInverted = false;
bool hasAlpha = false;
};
static Noesis::Ptr<Noesis::Texture> CreateUITexture(TextureDesc& desc) {
return Noesis::MakePtr<UITexture>(desc);
}
}

View File

@ -0,0 +1,141 @@
#include "ui/ui_render_device.h"
#include "ui/ui_module.h"
#include "ui_render_device_help.inl"
namespace api {
SINGLETON_DEFINE(UIRenderDevice)
UIRenderDevice::UIRenderDevice(RenderAPI* api) : mApi(api)
{
SINGLETON_PTR();
}
UIRenderDevice::~UIRenderDevice()
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
}
const Noesis::DeviceCaps& UIRenderDevice::GetCaps() const
{
return mCaps;
}
Noesis::Ptr<Noesis::RenderTarget> UIRenderDevice::CreateRenderTarget(const char* label, uint32_t width, uint32_t height, uint32_t sampleCount, bool needsStencil)
{
return Noesis::Ptr<Noesis::RenderTarget>();
}
Noesis::Ptr<Noesis::RenderTarget> UIRenderDevice::CloneRenderTarget(const char* label, Noesis::RenderTarget* surface)
{
return Noesis::Ptr<Noesis::RenderTarget>();
}
Noesis::Ptr<Noesis::Texture> UIRenderDevice::CreateTexture(const char* label, uint32_t width, uint32_t height, uint32_t numLevels, Noesis::TextureFormat::Enum format, const void** data)
{
TextureDesc desc{};
desc.id = -1;
desc.format = VKFormat(format, mCaps.linearRendering);
desc.width = width;
desc.height = height;
desc.mipLevel = numLevels;
desc.sampleCount = SAMPLE_COUNT_1;
desc.usage = TextureUsage::SAMPLEABLE | TextureUsage::BLIT_DST;
desc.state = ResourceState::UNDEFINED;
mApi->CreateTexture(desc);
return CreateUITexture(desc);
}
void UIRenderDevice::UpdateTexture(Noesis::Texture* texture, uint32_t level, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const void* data)
{
UITexture* uiTex = (UITexture*)texture;
}
void UIRenderDevice::BeginOffscreenRender()
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
}
void UIRenderDevice::EndOffscreenRender()
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
}
void UIRenderDevice::BeginOnscreenRender()
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
}
void UIRenderDevice::EndOnscreenRender()
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
}
void UIRenderDevice::SetRenderTarget(Noesis::RenderTarget* surface)
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
}
void UIRenderDevice::BeginTile(Noesis::RenderTarget* surface, const Noesis::Tile& tile)
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
}
void UIRenderDevice::EndTile(Noesis::RenderTarget* surface)
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
}
void UIRenderDevice::ResolveRenderTarget(Noesis::RenderTarget* surface, const Noesis::Tile* tiles, uint32_t numTiles)
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
}
void* UIRenderDevice::MapVertices(uint32_t bytes)
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
return nullptr;
}
void UIRenderDevice::UnmapVertices()
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
}
void* UIRenderDevice::MapIndices(uint32_t bytes)
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
return nullptr;
}
void UIRenderDevice::UnmapIndices()
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
}
void UIRenderDevice::DrawBatch(const Noesis::Batch& batch)
{
int b = 10000;
for (int a = 1; a < b; a++) {
b--;
}
}
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <NsGui/FontProvider.h>
namespace api {
class UI_API NoesisFontProvider : public Noesis::FontProvider
{
public:
NoesisFontProvider();
~NoesisFontProvider();
private:
/// From FontProvider
//@{
Noesis::FontSource MatchFont(const Noesis::Uri& baseUri, const char* familyName,
Noesis::FontWeight& weight, Noesis::FontStretch& stretch, Noesis::FontStyle& style) override;
bool FamilyExists(const Noesis::Uri& baseUri, const char* familyName) override;
//@}
};
}

View File

@ -0,0 +1,16 @@
#pragma once
#include <NsGui/TextureProvider.h>
namespace api {
class UI_API NoesisTextureProvider : public Noesis::TextureProvider
{
public:
NoesisTextureProvider();
~NoesisTextureProvider();
private:
/// From TextureProvider
//@{
Noesis::TextureInfo GetTextureInfo(const Noesis::Uri& uri) override;
Noesis::Ptr<Noesis::Texture> LoadTexture(const Noesis::Uri& uri, Noesis::RenderDevice* device) override;
};
}

View File

@ -0,0 +1,17 @@
#pragma once
#include <NsGui/XamlProvider.h>
namespace api {
class UI_API NoesisXamlProvider : public Noesis::XamlProvider
{
public:
NoesisXamlProvider();
~NoesisXamlProvider();
private:
/// From XamlProvider
//@{
Noesis::Ptr<Noesis::Stream> LoadXaml(const Noesis::Uri& uri) override;
//@}
};
}

View File

@ -7,5 +7,8 @@ namespace api {
void OnLoad(int argc, char** argv) override;
void OnUnload() override;
void InitMetaData(void) override {};
void Initialize()override;
void SetThemeProviders();
};
}

View File

@ -0,0 +1,41 @@
#pragma once
#include "render/renderapi.h"
#include <NsRender/RenderDevice.h>
namespace api {
class UI_API UIRenderDevice final : public Noesis::RenderDevice {
private:
RenderAPI* mApi;
Noesis::DeviceCaps mCaps;
SINGLETON_IMPL(UIRenderDevice)
public:
UIRenderDevice(RenderAPI* api);
~UIRenderDevice();
private:
/// From RenderDevice
//@{
const Noesis::DeviceCaps& GetCaps() const override;
Noesis::Ptr<Noesis::RenderTarget> CreateRenderTarget(const char* label, uint32_t width,
uint32_t height, uint32_t sampleCount, bool needsStencil) override;
Noesis::Ptr<Noesis::RenderTarget> CloneRenderTarget(const char* label,
Noesis::RenderTarget* surface) override;
Noesis::Ptr<Noesis::Texture> CreateTexture(const char* label, uint32_t width, uint32_t height,
uint32_t numLevels, Noesis::TextureFormat::Enum format, const void** data) override;
void UpdateTexture(Noesis::Texture* texture, uint32_t level, uint32_t x, uint32_t y,
uint32_t width, uint32_t height, const void* data) override;
void BeginOffscreenRender() override;
void EndOffscreenRender() override;
void BeginOnscreenRender() override;
void EndOnscreenRender() override;
void SetRenderTarget(Noesis::RenderTarget* surface) override;
void BeginTile(Noesis::RenderTarget* surface, const Noesis::Tile& tile) override;
void EndTile(Noesis::RenderTarget* surface) override;
void ResolveRenderTarget(Noesis::RenderTarget* surface, const Noesis::Tile* tiles,
uint32_t numTiles) override;
void* MapVertices(uint32_t bytes) override;
void UnmapVertices() override;
void* MapIndices(uint32_t bytes) override;
void UnmapIndices() override;
void DrawBatch(const Noesis::Batch& batch) override;
//@}
};
}

View File

@ -0,0 +1,19 @@
#pragma once
#include <NsCore/Noesis.h>
#include <NsGui/UserControl.h>
#include <NsCore/ReflectionDeclare.h>
namespace api {
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Provides the ability to create, configure, show, and manage the lifetime of windows.
///
/// http://msdn.microsoft.com/en-us/library/system.windows.window.aspx
////////////////////////////////////////////////////////////////////////////////////////////////////
class UIWindow : public Noesis::UserControl
{
public:
UIWindow();
~UIWindow();
virtual void InitializeComponent();
NS_DECLARE_REFLECTION(UIWindow, Noesis::UserControl)
};
}

View File

@ -0,0 +1,27 @@
#include "ui/noesis_font_provider.h"
#include <NsGui/Uri.h>
#include <NsGui/Stream.h>
namespace api {
using namespace Noesis;
NoesisFontProvider::NoesisFontProvider()
{
}
NoesisFontProvider::~NoesisFontProvider()
{
}
FontSource NoesisFontProvider::MatchFont(const Uri& baseUri, const char* familyName, FontWeight& weight, FontStretch& stretch, FontStyle& style)
{
auto uri = baseUri;
auto a1 = uri.Str();
auto a2 = uri.FullPath();
return FontSource();
}
bool NoesisFontProvider::FamilyExists(const Uri& baseUri, const char* familyName)
{
auto uri = baseUri;
auto a1 = uri.Str();
auto a2 = uri.FullPath();
return false;
}
}

View File

@ -0,0 +1,65 @@
#include "ui/noesis_texture_provider.h"
#include "os/package_path.h"
#include <NsGui/Uri.h>
#include <NsGui/Stream.h>
#include <NsCore/Log.h>
#include <NsRender/Texture.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
namespace api {
using namespace Noesis;
////////////////////////////////////////////////////////////////////////////////////////////////////
static int Read(void* user, char* data, int size)
{
Stream* stream = (Stream*)user;
return stream->Read(data, size);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
static void Skip(void* user, int n)
{
Stream* stream = (Stream*)user;
stream->SetPosition((int)stream->GetPosition() + n);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
static int Eof(void* user)
{
Stream* stream = (Stream*)user;
return stream->GetPosition() >= stream->GetLength();
}
NoesisTextureProvider::NoesisTextureProvider()
{
}
NoesisTextureProvider::~NoesisTextureProvider()
{
}
TextureInfo NoesisTextureProvider::GetTextureInfo(const Uri& uri)
{
TextureInfo info;
Ptr<Stream> file = OpenFileStream(PackagePath::RealPath(uri.FullPath()).c_str());
if (file != 0)
{
int x, y, n;
stbi_io_callbacks callbacks = { Read, Skip, Eof };
if (stbi_info_from_callbacks(&callbacks, file, &x, &y, &n))
{
info.width = x;
info.height = y;
}
else
{
NS_LOG_WARNING("%s: %s", uri.Str(), stbi_failure_reason());
}
file->Close();
}
return info;
}
Ptr<Texture> NoesisTextureProvider::LoadTexture(const Uri& uri, RenderDevice* device)
{
auto a1 = uri.Str();
auto a2 = uri.FullPath();
return Ptr<Texture>();
}
}

View File

@ -0,0 +1,18 @@
#include "ui/noesis_xaml_provider.h"
#include "os/package_path.h"
#include <NsGui/Uri.h>
#include <NsGui/Stream.h>
namespace api {
using namespace Noesis;
NoesisXamlProvider::NoesisXamlProvider()
{
}
NoesisXamlProvider::~NoesisXamlProvider()
{
}
Ptr<Stream> NoesisXamlProvider::LoadXaml(const Uri& uri)
{
return OpenFileStream(PackagePath::RealPath(uri.FullPath()).c_str());
}
}

View File

@ -1,10 +1,18 @@
#include "zlog.h"
#include "ui/ui_module.h"
#include "NoesisPCH.h"
#include "ui/ui_window.h"
#include "ui/ui_render_device.h"
#include "ui/noesis_xaml_provider.h"
#include "ui/noesis_font_provider.h"
#include "ui/noesis_texture_provider.h"
#include <NsGui/IntegrationAPI.h>
#include <NsGui/FontProperties.h>
#include <NsCore/RegisterComponent.inl>
namespace api {
using namespace Noesis;
void UIModule::OnLoad(int argc, char** argv)
{
Noesis::SetLogHandler([](const char*, uint32_t, uint32_t level, const char*, const char* msg)
SetLogHandler([](const char*, uint32_t, uint32_t level, const char*, const char* msg)
{
switch (level) {
case 0:
@ -23,12 +31,31 @@ namespace api {
}
});
// Sets the active license
Noesis::GUI::SetLicense(NS_LICENSE_NAME, NS_LICENSE_KEY);
GUI::SetLicense(NS_LICENSE_NAME, NS_LICENSE_KEY);
// Noesis initialization. This must be the first step before using any NoesisGUI functionality
Noesis::GUI::Init();
GUI::Init();
}
void UIModule::OnUnload()
{
// 清理资源提供者
GUI::SetFontProvider(nullptr);
GUI::SetTextureProvider(nullptr);
}
void UIModule::Initialize()
{
IStaticModule::Initialize();
GUI::SetXamlProvider(new NoesisXamlProvider());
GUI::SetFontProvider(new NoesisFontProvider());
GUI::SetTextureProvider(new NoesisTextureProvider());
RegisterComponent<api::UIWindow>();
SetThemeProviders();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UIModule::SetThemeProviders()
{
const char* fonts[] = {"Arial"};
GUI::SetFontFallbacks(fonts, NS_COUNTOF(fonts));
GUI::SetFontDefaultProperties(15.0f, FontWeight_Normal, FontStretch_Normal, FontStyle_Normal);
}
}

View File

@ -0,0 +1,21 @@
#include "ui/ui_window.h"
namespace api {
UIWindow::UIWindow()
{
}
UIWindow::~UIWindow()
{
}
void UIWindow::InitializeComponent()
{
}
NS_IMPLEMENT_REFLECTION(UIWindow,"api.UIWindow")
{
int A = 1;
if (NS_UNLIKELY(A == 0)) {
}
}
}

View File

@ -2,4 +2,4 @@ static_component("ui","engine")
add_headerfiles("include/**.h")
add_files("src/**.cpp")
add_deps("core", "asset", "zlib", "render")
add_packages("noesis", {public = true})
add_packages("noesis", "stb", {public = true})

View File

@ -1,6 +1,6 @@
#include "name.h"
constexpr inline size_t meta_align_size(size_t size, size_t alignment = 8) {
return (size + alignment - 1) / alignment * alignment;
return (size + (alignment - 1)) & ~(alignment - 1);
}
XMALLOC_API void* xmalloc(size_t size);
namespace pmr {

View File

@ -26,6 +26,5 @@ namespace vkn {
public:
static struct BufferWorker* TransferWorker;
static struct CommandWorker* RenderWorker;
static struct CommandWorker* PresentWorker;
};
};

View File

@ -1,17 +1,22 @@
#pragma once
#include "worker.h"
#include "vma/vk_mem_alloc.h"
#include "render/render_buffer.h"
#include <variant>
namespace api {
struct BufferDesc;
}
namespace vkn {
class Device;
class Queue;
class VulkanContext;
using api::DynamicBuffer;
extern pmr::FrameAllocatorPool vkCpuBufferPool;
inline pmr::FrameAllocatorPool* BufferPool(){
return &vkCpuBufferPool;
}
enum class TransferBufferType : uint8_t{
Transfer,
Graphics
};
struct Buffer {
VkBuffer buffer = VK_NULL_HANDLE;
VmaAllocation allocation = VK_NULL_HANDLE;
@ -29,26 +34,57 @@ namespace vkn {
void** ppCpuData;
uint32_t size;
VkBufferUsageFlags usage;
VkMemoryPropertyFlags momoryFlags;
VmaMemoryUsage memoryUsage;
};
struct BufferCommand {
using Command = std::variant<BufferUpload, BufferCreator>;
Command cmd;
BufferCommand(const BufferUpload& cmd) : cmd(cmd){}
BufferCommand(const BufferCreator& cmd) : cmd(cmd) {}
};
struct ImageCreator {
VkImageCreateInfo imageInfo;
VkImage* image;
};
struct ImageUpdator {
VkImage image;
uint32_t size;
uint32_t mipLevel;
TextureUpdateArgs args;
};
struct SyncTransferCommand {
uint32_t frameNumber;
};
struct BufferCommand {
using Command = std::variant<BufferUpload, BufferCreator, ImageUpdator, SyncTransferCommand>;
Command cmd;
BufferCommand(const BufferUpload& cmd) : cmd(cmd) {}
BufferCommand(const BufferCreator& cmd) : cmd(cmd) {}
BufferCommand(const ImageUpdator& cmd) : cmd(cmd) {}
BufferCommand(const SyncTransferCommand& cmd) : cmd(cmd) {}
};
struct DynamicBufferPool {
TransferBufferType type;
uint32_t commandIndex{0};
uint32_t safeFrameNumber{0};
VkCommandBuffer* pCommands;
DynamicBuffer uploadBuffer;
DynamicBufferPool(TransferBufferType type) : type(type) {}
void CreateDynamicBuffers();
DynamicBuffer* FindUploadBuffer(uint32_t size,uint32_t frameNumber,const void* data);
};
class BufferWorker : public ThreadWorker<BufferCommand, BufferWorker>{
public:
//pmr::vector<Buffer> mPool{BufferPool()};
uint32_t mFrameNumber{ 0 };
DynamicBufferPool mTransferBuffer{ TransferBufferType::Transfer };
DynamicBufferPool mGraphicsBuffer{ TransferBufferType::Graphics };
using ThreadWorker<BufferCommand, BufferWorker>::ThreadWorker;
void InitCommandBuffers(uint32_t frames);
void InitVmaAllocator(VkInstance instance);
void TrySyncTransfer(VulkanContext& ctx);
void Loop();
void UploadBuffer(const BufferUpload& elem);
void SyncTransfer(const SyncTransferCommand& elem);
void UploadBuffer(const BufferUpload& elem, TransferBufferType type = TransferBufferType::Graphics);
void CreateBuffer(BufferCreator& elem);
void CreateImage(ImageCreator& elem);
void UpdateImage(ImageUpdator& elem, TransferBufferType type = TransferBufferType::Graphics);
bool BeginDynamicCommand(DynamicBufferPool*& poolRef, CommandBuffer& cmd, bool isTransfer);
void EndDynamicCommand(DynamicBufferPool* poolRef, CommandBuffer& cmd, bool isTransfer);
};
};

View File

@ -12,9 +12,6 @@ namespace vkn {
void InvokeBuffer(const commandFn& fn, const Element& callback);
void Buffer(CommandBuffer& cmd, const commandFn& fn, const Element& callback);
void Flush();
void ImmediatelyExecute(const commandFn& fn, const Element& callback) {
Buffer(mImmediateExeCmd, fn , callback);
}
bool Present(VkPresentInfoKHR& presentInfo);
void Loop();
void SyncInvoke(const Element& fn);

View File

@ -12,8 +12,6 @@ namespace vkn {
Device& mDevice;
Queue& mQueue;
CommandPool mCommandPool;
CommandBuffer mImmediateExeCmd;
VkFence mImmediateFence;
public:
ThreadWorker(Name name, Device& device, Queue& queue, VkCommandPoolCreateFlags queueFlags)
: zstd::ThreadWorker<value_type, Worker>(64)
@ -21,8 +19,6 @@ namespace vkn {
, mDevice(device)
, mQueue(queue)
, mCommandPool(device, queueFlags, queue.QueueFamilyIndex())
, mImmediateExeCmd(mCommandPool.AllocateBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY))
, mImmediateFence(device.CreateFence(VK_FENCE_CREATE_SIGNALED_BIT))
{}
CommandPool& GetCommandPool() {
return mCommandPool;

View File

@ -30,6 +30,7 @@ namespace vkn {
using api::ShaderDescriptorType;
using api::BufferUsage;
using api::MaterialInfo;
using api::TextureUpdateArgs;
constexpr string_view VulkanEngineName = "vulkan";
constexpr uint8_t MAX_SUPPORTED_RENDER_TARGET_COUNT = 8u;

View File

@ -41,11 +41,14 @@ namespace vkn {
void CreateTexture(TextureDesc& desc)override;
ImageViewPtr CreateTextureView(TextureViewKey desc)override;
SamplerPtr CreateTextureSampler(TextureSampler sampler) override;
void UpdateTexture(TextureDesc& texture, const TextureUpdateArgs& update, ResourceState state) override;
void BeginFrame()override;
void EndFrame()override;
void BeginRenderPass(RenderPassNode* node, FnEnterRenderPass callback) override;
void EndRenderPass(RenderPassNode* node) override;
void ExecuteResourceBarriers(const ResourceBarrierDesc& desc) override;
VkPipeline GetPipeline() { return nullptr; };
RenderPassInfo* GetRenderPassInfo(Name name, size_t hash);
RenderPassInfo* GetRenderPassInfo(size_t& hash, const RenderPassKey& config);

View File

@ -5,6 +5,7 @@ namespace vkn {
using api::TextureBarrier;
using api::ShaderDescriptorType;
using api::ShaderStage;
using api::ResourceMemoryUsage;
struct VkTextureTransitionDesc {
VkAccessFlags srcAccessMask;
VkAccessFlags dstAccessMask;
@ -25,6 +26,9 @@ namespace vkn {
VkDescriptorType vkApiGetDescriptorType(ShaderDescriptorType type);
VkShaderStageFlags vkApiGetShaderStageFlags(ShaderStage stage);
VkBufferUsageFlagBits vkApiGetBufferUsage(BufferUsage usage);
VkSamplerCreateInfo vkApiGetSamplerCreateInfo(TextureSampler sampler);
VkBufferUsageFlagBits vkApiGetBufferUsage(BufferUsage usage);
VkMemoryPropertyFlags vkApiGetMemoryFlags(ResourceMemoryUsage usageFlags);
VmaMemoryUsage vkApiGetMemoryUsage(ResourceMemoryUsage usageFlags);
}

View File

@ -10,11 +10,11 @@ namespace vkn {
uint32_t frames;
uint32_t width;
uint32_t height;
uint32_t framesInFlight;
VkFormat imageFormat;
VkColorSpaceKHR imageColorSpace;
VkPresentModeKHR presentMode;
VkImageUsageFlags imageUsage;
uint32_t maxFrameInFlightCount;
VkExtent2D EnableImageExtent2D(VkSurfaceCapabilitiesKHR& capabilities);
static VulkanWindowArgs Default(uint32_t frames);
};

View File

@ -10,7 +10,6 @@
namespace vkn {
BufferWorker* Backend::TransferWorker;
CommandWorker* Backend::RenderWorker;
CommandWorker* Backend::PresentWorker;
template<typename Worker>
inline Worker* Backend::InitWorker(Name name, VkCommandPoolCreateFlags flag)
{
@ -28,8 +27,8 @@ namespace vkn {
deviceCreator.AddQueue(Queue::TransferQueue, VkQueueFlagBits::VK_QUEUE_TRANSFER_BIT, 1.0);
mDevice = new (GlobalPool()) Device(deviceCreator);
Backend::RenderWorker = InitWorker<CommandWorker>(Queue::RenderQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
Backend::TransferWorker = InitWorker<BufferWorker>(Queue::TransferQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
Backend::RenderWorker = InitWorker<CommandWorker>(Queue::RenderQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
Backend::TransferWorker->InitVmaAllocator(mInstance->Ptr());
auto poolSizes = DescriptorPool::DefaultDescriptorPoolSize();

View File

@ -1,11 +1,19 @@
#define VMA_IMPLEMENTATION
#include "vkn/backend.h"
#include "vkn/thread/command_worker.h"
#include "vkn/thread/buffer_worker.h"
#include "vkn/wrapper/queue.h"
#include "vkn/wrapper/device.h"
#include "vkn/vulkan_api_help.h"
#include "vkn/vulkan_context.h"
#include "meta/variant.h"
#include "zlog.h"
#define MAX_TRANSFER_SYNC_FENCES 11
#define SYNC_TRANSFER_INTERVAL_MS 100 // 每秒同步一次
#define DYNAMIC_TEX_SIZE 128 * 1024
namespace vkn {
static VkFence fenceList[MAX_TRANSFER_SYNC_FENCES - 1];
static VkCommandBuffer* commandList;
static pmr::FrameAllocatorPool vkCpuBufferPool;
static VmaAllocator vmaAllocator;
void BufferWorker::InitVmaAllocator(VkInstance instance)
@ -25,40 +33,84 @@ namespace vkn {
vmaInfo.pVulkanFunctions = &vmaVkFunctions;
vmaCreateAllocator(&vmaInfo, &vmaAllocator);
mTransferBuffer.CreateDynamicBuffers();
mGraphicsBuffer.CreateDynamicBuffers();
}
void BufferWorker::InitCommandBuffers(uint32_t frames)
{
commandList = (VkCommandBuffer*)xmalloc(MAX_TRANSFER_SYNC_FENCES * (frames + 1) * sizeof(VkCommandBuffer));
for (uint32_t i = 0; i <= frames; i++) {
for (uint32_t j = 0; j < MAX_TRANSFER_SYNC_FENCES - 1; j++) {
uint32_t k = j + (MAX_TRANSFER_SYNC_FENCES - 1) * i;
if (i == frames) {
fenceList[j] = mDevice.CreateFence(VK_FENCE_CREATE_SIGNALED_BIT);
commandList[k] = GetCommandPool().AllocateBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
}
else {
commandList[k] = Backend::RenderWorker->GetCommandPool().AllocateBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY);
}
}
}
vkResetFences(mDevice.Ptr(), MAX_TRANSFER_SYNC_FENCES - 1, fenceList);
mTransferBuffer.pCommands = commandList + (MAX_TRANSFER_SYNC_FENCES - 1) * frames;
mGraphicsBuffer.pCommands = commandList;
mFrameNumber = frames;
}
void BufferWorker::TrySyncTransfer(VulkanContext& ctx)
{
uint32_t frameNumber = ctx.frameNumber++;
if (frameNumber - mTransferBuffer.safeFrameNumber > SYNC_TRANSFER_INTERVAL_MS && mTransferBuffer.commandIndex < MAX_TRANSFER_SYNC_FENCES) {
mTransferBuffer.commandIndex += MAX_TRANSFER_SYNC_FENCES;
Invoke(SyncTransferCommand{ frameNumber });
}
mFrameNumber = frameNumber;//保守一点,慢一帧
mGraphicsBuffer.commandIndex = 0;
mGraphicsBuffer.pCommands = commandList + (MAX_TRANSFER_SYNC_FENCES - 1) * ctx.frame;
mGraphicsBuffer.safeFrameNumber = ctx.frameNumber - ctx.frameCount;
}
void BufferWorker::SyncTransfer(const SyncTransferCommand& elem)
{
DynamicBufferPool& bufferPoolRef = mTransferBuffer;
uint32_t index = bufferPoolRef.commandIndex % (MAX_TRANSFER_SYNC_FENCES);
if (index) { //没有提交任务时,不需要等待
vkWaitForFences(mDevice.Ptr(), index - 1, fenceList, VK_TRUE, UINT64_MAX);
vkResetFences(mDevice.Ptr(), index - 1, fenceList);
}
bufferPoolRef.safeFrameNumber = elem.frameNumber;
bufferPoolRef.commandIndex = 0;
}
void BufferWorker::Loop()
{
while (true) {
Element elem = mChannel.acquire();
std::visit(meta::overloaded{
[&](BufferUpload& cmd) { UploadBuffer(cmd); },
[&](BufferUpload& cmd) { UploadBuffer(cmd, TransferBufferType::Transfer); },
[&](BufferCreator& cmd) { CreateBuffer(cmd); },
[&](ImageUpdator& cmd) { UpdateImage(cmd); },
[&](SyncTransferCommand& cmd) { SyncTransfer(cmd); },
}, elem.cmd);
}
}
void BufferWorker::UploadBuffer(const BufferUpload& elem)
void BufferWorker::UploadBuffer(const BufferUpload& elem, TransferBufferType type)
{
mImmediateExeCmd.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
bool isTransfer = type == TransferBufferType::Transfer;
DynamicBufferPool* pPoolRef;
CommandBuffer command;
if (!BeginDynamicCommand(pPoolRef, command, isTransfer)) {
Invoke(elem);
return;
}
// 将数据复制到 Staging Buffer
DynamicBuffer* uploadBuffer = pPoolRef->FindUploadBuffer(elem.size, mFrameNumber + 1,elem.pCpuData);
VmaAllocationCreateInfo allocationInfo = {};
allocationInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
VkBufferCreateInfo bufferInfo = {};
bufferInfo.size = elem.size;
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocation stagingAllocation;
VmaAllocationCreateInfo allocationInfo = {};
allocationInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
VkBuffer stagingBuffer;
vmaCreateBuffer(vmaAllocator, &bufferInfo, &allocationInfo, &stagingBuffer, &stagingAllocation, nullptr);
// 将数据复制到 Staging Buffer
void* data;
vmaMapMemory(vmaAllocator, stagingAllocation, &data);
memcpy(data, elem.pCpuData, elem.size);
vmaUnmapMemory(vmaAllocator, stagingAllocation);
// 创建 GPU Buffer, GPU内部缓冲区访问速度非常快
VkBuffer& gpuBuffer = *elem.pBuffer;
bufferInfo.usage = elem.usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
@ -68,12 +120,10 @@ namespace vkn {
// 复制数据
VkBufferCopy copyRegion = {};
copyRegion.size = elem.size;
vkCmdCopyBuffer(mImmediateExeCmd.Ptr(), stagingBuffer, gpuBuffer, 1, &copyRegion);
mImmediateExeCmd.EndRecord();
vkResetFences(mDevice.Ptr(), 1, &mImmediateFence);
mImmediateExeCmd.Submit(mQueue.Ptr(), mImmediateFence);
vkWaitForFences(mDevice.Ptr(), 1, &mImmediateFence, VK_TRUE, UINT64_MAX);
vmaDestroyBuffer(vmaAllocator, stagingBuffer, stagingAllocation);
copyRegion.srcOffset = uploadBuffer->drawPos;
vkCmdCopyBuffer(command.Ptr(), (VkBuffer)uploadBuffer->currentPage->pBuffer, gpuBuffer, 1, &copyRegion);
EndDynamicCommand(pPoolRef, command, isTransfer);
}
void BufferWorker::CreateBuffer(BufferCreator& elem)
{
@ -84,6 +134,7 @@ namespace vkn {
VmaAllocationCreateInfo allocationInfo = {};
allocationInfo.usage = elem.memoryUsage;
allocationInfo.requiredFlags = elem.momoryFlags;
if (elem.ppCpuData)
allocationInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
vmaCreateBuffer(vmaAllocator, &bufferInfo, &allocationInfo, elem.pBuffer, elem.pAllocation, nullptr);
@ -99,4 +150,69 @@ namespace vkn {
VmaAllocation allocation;
VkResult result = vmaCreateImage(vmaAllocator, &elem.imageInfo, &allocCreateInfo, elem.image, &allocation, nullptr);
}
void BufferWorker::UpdateImage(ImageUpdator& elem, TransferBufferType type)
{
bool isTransfer = type == TransferBufferType::Transfer;
DynamicBufferPool* pPoolRef;
CommandBuffer command;
if (!BeginDynamicCommand(pPoolRef, command, isTransfer)) {
Invoke(elem);
return;
}
TextureUpdateArgs args = elem.args;
// 将数据复制到 Staging Buffer
DynamicBuffer* uploadBuffer = pPoolRef->FindUploadBuffer(elem.size, mFrameNumber + 1, args.data);
VkBufferImageCopy region{};
region.imageOffset.x = args.x;
region.imageOffset.y = args.y;
region.imageExtent.width = args.width;
region.imageExtent.height = args.height;
region.imageExtent.depth = 1;
region.imageSubresource.mipLevel = elem.mipLevel;
region.bufferOffset = uploadBuffer->drawPos;
region.imageSubresource.layerCount = 1;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
vkCmdCopyBufferToImage(command.Ptr(), (VkBuffer)uploadBuffer->currentPage->pBuffer, elem.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
EndDynamicCommand(pPoolRef, command, isTransfer);
}
bool BufferWorker::BeginDynamicCommand(DynamicBufferPool*& pPoolRef, CommandBuffer& command, bool isTransfer)
{
pPoolRef = isTransfer ? &mTransferBuffer : &mGraphicsBuffer;
if (pPoolRef->commandIndex >= MAX_TRANSFER_SYNC_FENCES) {
return false;
}
command = pPoolRef->pCommands[pPoolRef->commandIndex];
command.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
return true;
}
void BufferWorker::EndDynamicCommand(DynamicBufferPool* pPoolRef, CommandBuffer& command, bool isTransfer)
{
command.EndRecord();
pPoolRef->commandIndex++;
if (isTransfer) {
command.Submit(mQueue.Ptr(), fenceList[pPoolRef->commandIndex - 1]);
if (pPoolRef->commandIndex >= MAX_TRANSFER_SYNC_FENCES) {
SyncTransfer(SyncTransferCommand{ mFrameNumber });
}
return;
}
command.Submit(Backend::RenderWorker->GetQueue().Ptr(), nullptr);
}
void DynamicBufferPool::CreateDynamicBuffers()
{
uploadBuffer.InitBuffer(DYNAMIC_TEX_SIZE, BufferUsage::TRANSFER_SRC,
ResourceMemoryUsage::HOST_VISIBLE | ResourceMemoryUsage::HOST_COHERENT);
}
DynamicBuffer* DynamicBufferPool::FindUploadBuffer(uint32_t size, uint32_t frameNumber, const void* data)
{
// 将数据复制到 Staging Buffer
void* pMappingAddr = uploadBuffer.MapBuffer(meta_align_size(size, 4), frameNumber, safeFrameNumber);
if (data) {
memcpy(pMappingAddr, data, size);
}
return &uploadBuffer;
}
}

View File

@ -19,7 +19,7 @@ namespace vkn {
}
void VulkanAPI::Init()
{
Backend::TransferWorker->InitCommandBuffers(context.frameCount);
}
void VulkanAPI::Shutdown()
{
@ -267,7 +267,15 @@ namespace vkn {
}
void VulkanAPI::CreateBuffer(BufferDesc& desc)
{
BufferCreator creator{};
creator.size = desc.size;
creator.pBuffer = (VkBuffer*)&desc.buffer;
creator.pAllocation =(VmaAllocation*) &desc.pAllocation;
creator.ppCpuData = &desc.pMappingAddr;
creator.memoryUsage = vkApiGetMemoryUsage(desc.memoryUsage);
creator.momoryFlags = vkApiGetMemoryFlags(desc.memoryUsage);
creator.usage = vkApiGetBufferUsage(desc.usage);
Backend::TransferWorker->CreateBuffer(creator);
}
void VulkanAPI::CreateTexture(TextureDesc& desc)
{
@ -332,6 +340,31 @@ namespace vkn {
vkCreateSampler(backend.GetDevice().Ptr(), &samplerInfo, nullptr, &sampler);
return sampler;
}
void VulkanAPI::UpdateTexture(TextureDesc& texture, const TextureUpdateArgs& update, ResourceState state)
{
if (!texture.id) {
graph.AcquireTexture(texture);
}
if (texture.state != state) {
TextureBarrier barrier{};
barrier.mSrcState = texture.state;
barrier.mDstState = state;
barrier.mTexture = texture;
ResourceBarrierDesc desc{};
desc.pTextureBarriers = &barrier;
desc.textureBarriersCount = 1;
ExecuteResourceBarriers(desc);
}
VulkanContext& ctx = *(VulkanContext*)&context;
uint32_t texelBytes = texture.format == TinyImageFormat_R8_UNORM ? 1 : 4;
uint32_t size = update.width * update.height * texelBytes;
ImageUpdator updator{};
updator.args = update;
updator.size = size;
updator.mipLevel = texture.mipLevel;
updator.image = (VkImage)texture.image;
Backend::TransferWorker->UpdateImage(updator);
}
void VulkanAPI::BeginFrame()
{
VulkanContext& ctx = *(VulkanContext*)&context;
@ -343,6 +376,7 @@ namespace vkn {
{
VulkanContext& ctx = *(VulkanContext*)&context;
window.Present(ctx);
Backend::TransferWorker->TrySyncTransfer(ctx);
}
void VulkanAPI::ExecuteResourceBarriers(const ResourceBarrierDesc& desc) {
VulkanContext& ctx = *(VulkanContext*)&context;

View File

@ -256,19 +256,6 @@ namespace vkn {
}
return flags;
}
VkBufferUsageFlagBits vkApiGetBufferUsage(BufferUsage usage)
{
if (any(usage & BufferUsage::VERTEX)) {
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
}
if (any(usage & BufferUsage::UNIFORM)) {
return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
}
if (any(usage & BufferUsage::SHADER_STORAGE)) {
return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
}
return {};
}
using api::SamplerWrapMode;
using api::SamplerMinFilter;
using api::SamplerMagFilter;
@ -380,4 +367,52 @@ namespace vkn {
};
return samplerInfo;
}
VkBufferUsageFlagBits vkApiGetBufferUsage(BufferUsage usage)
{
if (any(usage & BufferUsage::VERTEX)) {
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
}
if (any(usage & BufferUsage::UNIFORM)) {
return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
}
if (any(usage & BufferUsage::SHADER_STORAGE)) {
return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
}
if (any(usage & BufferUsage::TRANSFER_SRC)) {
return VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
}
return {};
}
VkMemoryPropertyFlags vkApiGetMemoryFlags(ResourceMemoryUsage usageFlags) {
VkMemoryPropertyFlags flags = 0;
if (any(usageFlags & ResourceMemoryUsage::HOST_VISIBLE)) {
flags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
}
if (any(usageFlags & ResourceMemoryUsage::GPU_ONLY)) {
flags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
}
if (any(usageFlags & ResourceMemoryUsage::HOST_COHERENT)) {
flags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
}
if (any(usageFlags & ResourceMemoryUsage::LAZY_ALLOCATED)) {
flags |= VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT;
}
return flags;
}
VmaMemoryUsage vkApiGetMemoryUsage(ResourceMemoryUsage usageFlags) {
if (any(usageFlags & ResourceMemoryUsage::GPU_ONLY)) {
return VMA_MEMORY_USAGE_GPU_ONLY;
}
if (any(usageFlags & ResourceMemoryUsage::CPU_ONLY)) {
return VMA_MEMORY_USAGE_CPU_ONLY;
}
if (any(usageFlags & ResourceMemoryUsage::CPU_TO_GPU)) {
return VMA_MEMORY_USAGE_CPU_TO_GPU;
}
if (any(usageFlags & ResourceMemoryUsage::GPU_TO_CPU)) {
return VMA_MEMORY_USAGE_GPU_TO_CPU;
}
return VMA_MEMORY_USAGE_UNKNOWN; // 默认
}
}

View File

@ -22,7 +22,8 @@ namespace vkn {
args.width = mWidth;
args.height = mHeight;
mSwapchain = new (GlobalPool()) VulkanSwapchain(backend.GetDevice(), surface, args);
api->context.frameCount = args.frames;
api->context.frameCount = args.framesInFlight;
api->context.frameNumber = args.framesInFlight;
api->context.surface = mSwapchain->mSurfaces[0];
api->graph.InitSurface(mSwapchain->mSurfaces.data(), mSwapchain->mSurfaces.size());
return true;
@ -57,7 +58,7 @@ namespace vkn {
if (result != VK_SUCCESS) {
zlog::error("Failed to create swap chain.");
}
mFrames = args.frames;
mFrames = args.framesInFlight;
pmr::vector<VkImage> swapchain_images{ FramePool() };
uint32_t imageCount = 0;
vkGetSwapchainImagesKHR(device.Ptr(), mPtr, &imageCount, nullptr);
@ -138,11 +139,11 @@ namespace vkn {
{
return {
.frames = frames,
.framesInFlight = 2,
.imageFormat = VK_FORMAT_B8G8R8A8_SRGB,
.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
.presentMode = VK_PRESENT_MODE_MAILBOX_KHR,
.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.maxFrameInFlightCount = 2
};
}
}

View File

@ -1,8 +1,16 @@
#include "editor/editor.h"
#include "editor/window/editor_main_window.h"
#include "ui/ui_render_device.h"
#include "event/event_system.h"
#include "os/file_manager.h"
#include <NoesisPCH.h>
namespace api {
using namespace Noesis;
Ptr<IView> mView;
void EditorModule::OnLoad(int argc, char** argv)
{
PackagePath editor_noesis{"/engine/assets/noesis"};
FileManager::Ptr()->Mount("editor_noesis", editor_noesis.RealPath().c_str());
}
void EditorModule::OnUnload()
@ -10,6 +18,17 @@ namespace api {
}
void EditorModule::Initialize(void)
{
Ptr<FrameworkElement> xaml = GUI::LoadXaml<FrameworkElement>("/editor_noesis/Menu.xaml");
mView = GUI::CreateView(xaml);
mView->SetFlags(RenderFlags_PPAA | RenderFlags_LCD);
mView->SetSize(1024, 768);
//mView->GetRenderer()->Init(UIRenderDevice::Ptr());
EventSystem::Ptr()->BeginRenderFrame.Subscribe(mInfo.name, [](FrameGraph& graph, int32_t frame) {
//mView->Update(0.033);
//IRenderer* renderer = mView->GetRenderer();
//renderer->UpdateRenderTree();
//renderer->RenderOffscreen();
//renderer->Render();
});
}
}

View File

@ -0,0 +1,9 @@
#include "editor/window/editor_main_window.h"
namespace api {
void EditorMainWindow::InitializeComponent()
{
for (int i = 0; i < 1000; i++) {
int j = 1;
}
}
}

View File

@ -1,24 +1,28 @@
#include "engine/api.h"
#include "os/file_manager.h"
#include "ui/ui_render_device.h"
#include "xmalloc_new_delete.h"
class ENGINE_API EngineModule : public api::IDynamicModule
{
public:
void OnLoad(int argc, char** argv) override {
namespace api {
class ENGINE_API EngineModule : public api::IDynamicModule
{
public:
void OnLoad(int argc, char** argv) override {
#ifdef ENGINE_ROOT
api::FileManager::Ptr()->Mount("engine", TOSTRING(ENGINE_ROOT));
api::FileManager::Ptr()->Mount("engine", TOSTRING(ENGINE_ROOT));
#endif
};
void OnUnload() override {
};
void InitMetaData(void) override {
mInfo.dependencies = {
{"app","1.0.1", "static"},
{"core", "1.0.1", "static" },
{"asset", "1.0.1", "static" },
{"render", "1.0.1", "static" },
{"ui", "1.0.1", "static" },
new UIRenderDevice(RenderAPI::Ptr());
};
void OnUnload() override {
};
void InitMetaData(void) override {
mInfo.dependencies = {
{"app","1.0.1", "static"},
{"core", "1.0.1", "static" },
{"asset", "1.0.1", "static" },
{"render", "1.0.1", "static" },
{"ui", "1.0.1", "static" },
};
};
};
};
IMPLEMENT_DYNAMIC_MODULE(ENGINE_API, EngineModule, engine)
IMPLEMENT_DYNAMIC_MODULE(ENGINE_API, EngineModule, engine)
}

View File

@ -9,25 +9,33 @@
#include "zlog.h"
#include "module_manager_impl.inl"
#include "file_manager_impl.inl"
IMPLEMENT_STATIC_MODULE(CORE_API, api::CoreModule, core)
#endif // !CORE_API_VAL
#ifndef ASSET_API_VAL
#define ASSET_API_VAL 1
#include "resource_system_impl.inl"
#include "asset_visit_impl.inl"
IMPLEMENT_STATIC_MODULE(ASSET_API, api::AssetModule, asset)
#endif // !ASSET_API_VAL
#ifndef RENDER_API_VAL
#define RENDER_API_VAL 1
#include "renderapi_impl.inl"
#include "window_impl.inl"
#include "render/render_module.h"
IMPLEMENT_STATIC_MODULE(RENDER_API, api::RenderModule, render);
#endif // !RENDER_API_VAL
#ifndef APP_API_VAL
#define APP_API_VAL 1
#include "app_impl.inl"
#include "event_system_impl.inl"
IMPLEMENT_STATIC_MODULE(APP_API, api::AppModule, app)
#endif // !APP_API_VAL
#include "ui/ui_module.h"
IMPLEMENT_STATIC_MODULE(UI_API, api::UIModule, ui)
#ifndef UI_API_VAL
#define UI_API_VAL 1
#include "ui_render_device_impl.inl"
IMPLEMENT_STATIC_MODULE(UI_API, api::UIModule, ui)
#endif // !UI_API_VAL

View File

@ -12,7 +12,7 @@ target("editor")
set_kind("shared")
set_group("Engine")
add_rules("engine.api")
add_headerfiles("include/editor/**.h")
add_headerfiles("include/editor/**.h","assets/noesis/*.xaml")
add_includedirs("include")
add_files("src/editor/**.cpp")
add_deps("engine",{public = true})

View File

@ -20,9 +20,6 @@ void ZWorldModule::OnLoad(int argc, char** argv)
window->CreateRender(args);
API->Init();
API->context.views.push_back({});
EventSystem::Ptr()->BeginRenderFrame.Subscribe(mInfo.name, [](FrameGraph& graph, uint32_t frame) {
graph.AddRenderPass<DemoPass>();
});
}
void ZWorldModule::InitMetaData()
{
@ -35,6 +32,9 @@ void ZWorldModule::InitMetaData()
}
void ZWorldModule::Initialize()
{
EventSystem::Ptr()->BeginRenderFrame.Subscribe(mInfo.name, [](FrameGraph& graph, uint32_t frame) {
graph.AddRenderPass<DemoPass>();
});
}
void ZWorldModule::OnUnload()
{

View File

@ -6,7 +6,7 @@ set_languages("cxx20")
set_project("zengine")
set_toolchains("clang")
set_runtimes("MD","c++_shared")
add_cxflags("-stdlib=libc++")
add_cxxflags("-stdlib=libc++", "-Wno-parentheses-equality")
add_ldflags("-stdlib=libc++")
includes("engine")
includes("game/*/xmake.lua")