Pipeline factory and materials
- AssetManager uses static assets ID from path hash - PipelineFactory creates Vulkan pipelines using PipelineConfig structure depending on AssetMaterial and creation flags - AssetMaterial describes pipelines (e.g. used shaders) - Materials are described with JSON in sources with path references to other assets - AssetMaterial is parsed from binary file with asset IDs in references - compile_config tool compiles material JSON file to binary file with path references replaced with asset IDs - Allocator supports type's constructors with arguments - NativeFileSystem: fixed empty bufferSize and buffer trash
This commit is contained in:
parent
b0be28ff2c
commit
389ed599c8
@ -10,6 +10,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
project (EtrediaEmpires)
|
||||
|
||||
add_subdirectory(materials)
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory (p7lib)
|
||||
add_subdirectory (ECSAPI)
|
||||
|
||||
1
assets/materials/helloworld.mat
Normal file
1
assets/materials/helloworld.mat
Normal file
@ -0,0 +1 @@
|
||||
âąx/$W
|
||||
Binary file not shown.
Binary file not shown.
@ -13,8 +13,8 @@ project (EEfrontend)
|
||||
|
||||
# List sources
|
||||
|
||||
set(HEADERS "Renderer.hpp" "FileSystem.hpp" "compile_config.hpp" "AssetManager.hpp" "AssetData.hpp")
|
||||
set(SOURCES "main.cpp" "Renderer.cpp" "FileSystem.cpp" "AssetManager.cpp" "AssetData.cpp")
|
||||
set(HEADERS "Engine.hpp" "Renderer.hpp" "FileSystem.hpp" "compile_config.hpp" "AssetManager.hpp" "AssetData.hpp" "PipelineFactory.hpp")
|
||||
set(SOURCES "main.cpp" "Engine.cpp" "Renderer.cpp" "FileSystem.cpp" "AssetManager.cpp" "AssetData.cpp" "PipelineFactory.cpp")
|
||||
|
||||
list(TRANSFORM HEADERS PREPEND "include/")
|
||||
list(TRANSFORM SOURCES PREPEND "src/")
|
||||
@ -22,6 +22,7 @@ list(TRANSFORM SOURCES PREPEND "src/")
|
||||
# Find dependencies
|
||||
|
||||
find_package(Boost REQUIRED COMPONENTS lockfree)
|
||||
find_package(xxHash CONFIG REQUIRED)
|
||||
find_package(SDL2 CONFIG REQUIRED)
|
||||
find_package(Vulkan REQUIRED)
|
||||
find_package(RmlUi CONFIG REQUIRED)
|
||||
@ -33,6 +34,7 @@ add_executable(${PROJECT_NAME} ${HEADERS} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC utils)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Boost::lockfree)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE xxHash::xxhash)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE p7)
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
|
||||
@ -8,9 +8,23 @@ template<typename T> concept Asset = std::derived_from<T, AssetData>;
|
||||
struct AssetBinary : AssetData
|
||||
{
|
||||
uint8_t* content = nullptr;
|
||||
size_t size= 0;
|
||||
size_t size = 0;
|
||||
|
||||
AssetBinary(uint8_t* &source, size_t sourceSize);
|
||||
AssetBinary(uint8_t* &source, const size_t &sourceSize);
|
||||
~AssetBinary();
|
||||
};
|
||||
typedef AssetBinary AssetShader;
|
||||
|
||||
struct AssetShader : AssetData
|
||||
{
|
||||
uint32_t* content = nullptr;
|
||||
size_t size = 0;
|
||||
|
||||
AssetShader(uint8_t* &source, const size_t &sourceSize);
|
||||
~AssetShader();
|
||||
};
|
||||
|
||||
struct AssetMaterial : AssetData
|
||||
{
|
||||
uint32_t vertexShader;
|
||||
uint32_t fragmentShader;
|
||||
};
|
||||
@ -7,8 +7,11 @@
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <Boost/lockfree/spsc_queue.hpp>
|
||||
|
||||
#define INVALID_ASSET_ID UINT32_MAX
|
||||
|
||||
struct AssetAddress
|
||||
{
|
||||
std::atomic<void*> resource;
|
||||
@ -16,7 +19,8 @@ struct AssetAddress
|
||||
|
||||
struct AssetHandle
|
||||
{
|
||||
size_t id = 0;
|
||||
size_t slot = 0;
|
||||
uint32_t id = 0;
|
||||
};
|
||||
|
||||
class AssetInfo
|
||||
@ -64,6 +68,7 @@ struct AssetStreamCommand
|
||||
} type = NONE;
|
||||
|
||||
AssetHandle target;
|
||||
uint32_t targetId = INVALID_ASSET_ID;
|
||||
std::filesystem::path targetPath;
|
||||
AssetInfo::Type targetType = AssetInfo::BINARY;
|
||||
std::atomic<void*>* out;
|
||||
@ -87,6 +92,7 @@ public:
|
||||
|
||||
void LoadAsync(AssetInfo::Type type, const std::filesystem::path &path);
|
||||
AssetHandle& Find(const std::filesystem::path &path);
|
||||
AssetHandle& Find(const uint32_t &id);
|
||||
void Redirect(AssetHandle &handle, void *resource);
|
||||
template <Asset T> T& Get(const AssetHandle &handle);
|
||||
void Free(AssetHandle &handle);
|
||||
@ -99,11 +105,14 @@ private:
|
||||
IFileSystem *diskSystem;
|
||||
|
||||
std::vector<AssetInfo> activeAssets;
|
||||
std::unordered_map<std::filesystem::path, AssetHandle*> assetsMapping;
|
||||
std::unordered_map<std::filesystem::path, uint32_t> assetsIdMapping;
|
||||
std::unordered_map<uint32_t, AssetHandle*> assetsMapping;
|
||||
std::vector<size_t> freeAssetSlots;
|
||||
std::vector<AssetLoadingEntry> loadingEntries;
|
||||
|
||||
std::vector<AssetBinary*> binaryStorage;
|
||||
std::vector<AssetShader*> shadersStorage;
|
||||
std::vector<AssetMaterial*> materialsStorage;
|
||||
|
||||
void Threading();
|
||||
void Loop();
|
||||
|
||||
13
frontend/include/Engine.hpp
Normal file
13
frontend/include/Engine.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "AssetManager.hpp"
|
||||
#include "Renderer.hpp"
|
||||
|
||||
class Engine
|
||||
{
|
||||
public:
|
||||
static AssetManager *assetManager;
|
||||
static Renderer *renderer;
|
||||
|
||||
private:
|
||||
Engine();
|
||||
};
|
||||
64
frontend/include/PipelineFactory.hpp
Normal file
64
frontend/include/PipelineFactory.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include "AssetData.hpp"
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vector>
|
||||
|
||||
#define PIPELINE_CREATE_NEW 0
|
||||
#define PIPELINE_CREATE_DERIVED (1 << 0)
|
||||
|
||||
struct PipelineConfig
|
||||
{
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputConfig;
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyConfig;
|
||||
VkPipelineViewportStateCreateInfo viewportStateConfig;
|
||||
VkPipelineRasterizationStateCreateInfo rasterizerConfig;
|
||||
VkPipelineMultisampleStateCreateInfo multisamplingConfig;
|
||||
VkPipelineDepthStencilStateCreateInfo depthStencilConfig;
|
||||
|
||||
// SRC - new color, DST - old color
|
||||
std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachmentConfigs;
|
||||
VkPipelineColorBlendStateCreateInfo colorBlendConfig;
|
||||
VkPipelineDynamicStateCreateInfo dynamicStateConfig;
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutConfig;
|
||||
|
||||
VkViewport defaultViewport;
|
||||
VkRect2D defaultScissors;
|
||||
std::vector<VkDynamicState> dynamicStates;
|
||||
|
||||
std::vector<VkAttachmentDescription> colorAttachmentConfigs;
|
||||
std::vector<VkAttachmentReference> colorAttachmentRefs;
|
||||
std::vector<VkSubpassDescription> subpassConfigs;
|
||||
VkRenderPassCreateInfo renderPassConfig;
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineConfig;
|
||||
|
||||
PipelineConfig Copy() const;
|
||||
};
|
||||
|
||||
struct Pipeline
|
||||
{
|
||||
VkPipeline instance;
|
||||
VkPipelineLayout layout;
|
||||
VkRenderPass renderPass;
|
||||
};
|
||||
|
||||
class PipelineFactory
|
||||
{
|
||||
public:
|
||||
PipelineFactory(const AssetMaterial &baseMaterial, VkDevice &device, VkExtent2D &surfaceExtent, VkFormat &surfaceFormat);
|
||||
~PipelineFactory();
|
||||
|
||||
PipelineConfig &Request(const AssetMaterial &material, uint32_t flags);
|
||||
|
||||
private:
|
||||
PipelineConfig basePipelineConfig;
|
||||
|
||||
Pipeline basePipeline;
|
||||
std::vector<Pipeline> pipelines;
|
||||
|
||||
VkDevice &device;
|
||||
VkExtent2D &surfaceExtent;
|
||||
VkFormat &surfaceFormat;
|
||||
|
||||
void Create(const AssetMaterial &material, uint32_t flags);
|
||||
};
|
||||
@ -9,6 +9,8 @@
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <RmlUi/Core.h>
|
||||
|
||||
#include "PipelineFactory.hpp"
|
||||
|
||||
#ifdef VALIDATION_LAYER_ON
|
||||
#define VALIDATION_LAYER "VK_LAYER_KHRONOS_validation"
|
||||
#else
|
||||
@ -63,7 +65,7 @@ public:
|
||||
std::atomic<bool> isRunning;
|
||||
std::atomic<int> screenWidth, screenHeight;
|
||||
|
||||
Renderer(SDL_Window *window);
|
||||
Renderer(SDL_Window *window, const AssetMaterial& baseMaterial);
|
||||
~Renderer();
|
||||
|
||||
void Start();
|
||||
@ -91,6 +93,8 @@ private:
|
||||
QueueFamiliesBundle queueFamilies;
|
||||
QueuesBundle queues;
|
||||
const float defaultQueuePriority = 1.0f;
|
||||
const AssetMaterial &baseMaterial;
|
||||
PipelineFactory *pipelineFactory;
|
||||
|
||||
Rml::Context *uiContext;
|
||||
|
||||
|
||||
@ -10,4 +10,6 @@
|
||||
#define MAJOR_VERSION 0
|
||||
#define MINOR_VERSION 0
|
||||
#define PATCH_VERSION 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define ASSETS_HASH_SPACE 0
|
||||
@ -1,7 +1,7 @@
|
||||
#include "AssetData.hpp"
|
||||
#include "allocator.hpp"
|
||||
|
||||
AssetBinary::AssetBinary(uint8_t* &source, size_t sourceSize)
|
||||
AssetBinary::AssetBinary(uint8_t* &source, const size_t &sourceSize)
|
||||
{
|
||||
content = source;
|
||||
size = sourceSize;
|
||||
@ -12,4 +12,17 @@ AssetBinary::~AssetBinary()
|
||||
{
|
||||
if (content != nullptr)
|
||||
DeallocateArray(content);
|
||||
}
|
||||
}
|
||||
|
||||
AssetShader::AssetShader(uint8_t* &source, const size_t &sourceSize)
|
||||
{
|
||||
content = reinterpret_cast<uint32_t*>(source);
|
||||
size = sourceSize;
|
||||
source = nullptr;
|
||||
}
|
||||
|
||||
AssetShader::~AssetShader()
|
||||
{
|
||||
if (content != nullptr)
|
||||
DeallocateArray(content);
|
||||
}
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
#include "compile_config.hpp"
|
||||
#include "AssetManager.hpp"
|
||||
#include "allocator.hpp"
|
||||
#include "Logger.h"
|
||||
#include <stdexcept>
|
||||
#include <xxhash.h>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
AssetInfo::AssetInfo(void *resource)
|
||||
{
|
||||
@ -10,6 +14,7 @@ AssetInfo::AssetInfo(void *resource)
|
||||
}
|
||||
|
||||
AssetInfo::AssetInfo(AssetInfo&& other) noexcept :
|
||||
type(other.type),
|
||||
resourceAddress(other.resourceAddress)
|
||||
{
|
||||
isReady.store(other.isReady.load(std::memory_order_relaxed), std::memory_order_relaxed);
|
||||
@ -22,6 +27,7 @@ AssetInfo& AssetInfo::operator=(AssetInfo&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
type = other.type;
|
||||
resourceAddress = other.resourceAddress;
|
||||
isReady.store(other.isReady.load(std::memory_order_relaxed), std::memory_order_relaxed);
|
||||
|
||||
@ -33,7 +39,7 @@ AssetInfo& AssetInfo::operator=(AssetInfo&& other) noexcept
|
||||
|
||||
void AssetManager::Redirect(AssetHandle &handle, void* resource)
|
||||
{
|
||||
AssetInfo &asset = activeAssets[handle.id];
|
||||
AssetInfo &asset = activeAssets[handle.slot];
|
||||
if (asset.resourceAddress == nullptr)
|
||||
{
|
||||
LOG(WARNING, "Attempt to redirect empty handle");
|
||||
@ -52,12 +58,12 @@ void AssetManager::Redirect(AssetHandle &handle, void* resource)
|
||||
|
||||
void AssetManager::Free(AssetHandle &handle)
|
||||
{
|
||||
AssetInfo &asset = activeAssets[handle.id];
|
||||
AssetInfo &asset = activeAssets[handle.slot];
|
||||
Redirect(handle, nullptr);
|
||||
Deallocate(asset.resourceAddress);
|
||||
asset.resourceAddress = nullptr;
|
||||
|
||||
freeAssetSlots.push_back(handle.id);
|
||||
freeAssetSlots.push_back(handle.slot);
|
||||
}
|
||||
|
||||
AssetManager::AssetManager()
|
||||
@ -102,6 +108,18 @@ AssetHandle& AssetManager::Find(const std::filesystem::path &path)
|
||||
while (command.out->load() == nullptr);
|
||||
return *reinterpret_cast<AssetHandle*>(command.out->load());
|
||||
}
|
||||
AssetHandle& AssetManager::Find(const uint32_t &id)
|
||||
{
|
||||
std::atomic<void*> result;
|
||||
AssetStreamCommand command {
|
||||
.type = AssetStreamCommand::FIND,
|
||||
.targetId = id,
|
||||
.out = &result
|
||||
};
|
||||
Request(command);
|
||||
while (command.out->load() == nullptr);
|
||||
return *reinterpret_cast<AssetHandle*>(command.out->load());
|
||||
}
|
||||
|
||||
void AssetManager::Start()
|
||||
{
|
||||
@ -152,13 +170,26 @@ void AssetManager::Loop()
|
||||
bool isReady = entry.fileOwner->PollReady(*entry.file);
|
||||
if (isReady)
|
||||
{
|
||||
AssetInfo& asset = activeAssets[entry.handle.id];
|
||||
AssetInfo& asset = activeAssets[entry.handle.slot];
|
||||
|
||||
//TODO: functions for each type
|
||||
switch (asset.type)
|
||||
{
|
||||
case AssetInfo::SHADER:
|
||||
{
|
||||
AssetShader* shader = Allocate<AssetShader>(entry.file->data, entry.file->size);
|
||||
shadersStorage.push_back(shader);
|
||||
Redirect(entry.handle, shadersStorage.back());
|
||||
break;
|
||||
}
|
||||
|
||||
case AssetInfo::MATERIAL:
|
||||
{
|
||||
AssetMaterial* material = Allocate<AssetMaterial>();
|
||||
if (entry.file->size < sizeof(AssetMaterial))
|
||||
LOG(CRITICAL, "File size is less than needed for material");
|
||||
std::memcpy(material, entry.file->data, sizeof(AssetMaterial));
|
||||
materialsStorage.push_back(material);
|
||||
Redirect(entry.handle, materialsStorage.back());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -167,11 +198,10 @@ void AssetManager::Loop()
|
||||
break;
|
||||
}
|
||||
|
||||
case AssetInfo::SHADER:
|
||||
case AssetInfo::BINARY:
|
||||
default:
|
||||
{
|
||||
AssetBinary* data = new AssetBinary(entry.file->data, entry.file->size);
|
||||
AssetBinary* data = Allocate<AssetBinary>(entry.file->data, entry.file->size);
|
||||
binaryStorage.push_back(data);
|
||||
Redirect(entry.handle, binaryStorage.back());
|
||||
break;
|
||||
@ -180,8 +210,7 @@ void AssetManager::Loop()
|
||||
|
||||
entry.fileOwner->Close(*entry.file);
|
||||
#ifndef NDEBUG
|
||||
auto path = entry.file->debugPath.c_str();
|
||||
LOG(INFO, "Asset loaded: [%s]", path);
|
||||
LOG(INFO, "Asset loaded: [%hs]", entry.file->debugPath.generic_u8string().c_str());
|
||||
#endif
|
||||
entry.file = nullptr;
|
||||
asset.isReady.store(true);
|
||||
@ -199,7 +228,7 @@ void AssetManager::ProcessCommand(AssetStreamCommand &command)
|
||||
{
|
||||
case AssetStreamCommand::LOAD:
|
||||
{
|
||||
LOG(INFO, "LOAD command: [%s]", command.targetPath.c_str());
|
||||
LOG(INFO, "LOAD command: [%hs]", command.targetPath.generic_u8string().c_str());
|
||||
|
||||
/* TODO: process path to select FS */
|
||||
/* TODO: select between async load and sync job task */
|
||||
@ -225,8 +254,12 @@ void AssetManager::ProcessCommand(AssetStreamCommand &command)
|
||||
activeAssets.push_back(std::move(asset));
|
||||
assetPos = activeAssets.size() - 1;
|
||||
}
|
||||
handle->id = assetPos;
|
||||
assetsMapping[command.targetPath] = handle;
|
||||
handle->slot = assetPos;
|
||||
auto assetPath = command.targetPath.generic_u8string();
|
||||
uint32_t assetId = assetsIdMapping[command.targetPath] =
|
||||
XXH32(assetPath.data(), assetPath.size(), ASSETS_HASH_SPACE);
|
||||
handle->id = assetId;
|
||||
assetsMapping[assetId] = handle;
|
||||
|
||||
AssetLoadingEntry loadingEntry {
|
||||
.handle = *handle,
|
||||
@ -241,12 +274,21 @@ void AssetManager::ProcessCommand(AssetStreamCommand &command)
|
||||
|
||||
case AssetStreamCommand::FIND:
|
||||
{
|
||||
std::unordered_map<std::filesystem::path, AssetHandle*>::iterator mapping = assetsMapping.find(command.targetPath);
|
||||
uint32_t id = command.targetId;
|
||||
if (id == INVALID_ASSET_ID)
|
||||
{
|
||||
std::unordered_map<std::filesystem::path, uint32_t>::iterator idMapping = assetsIdMapping.find(command.targetPath);
|
||||
if (idMapping == assetsIdMapping.end())
|
||||
break;
|
||||
id = idMapping->second;
|
||||
}
|
||||
|
||||
std::unordered_map<uint32_t, AssetHandle*>::iterator assetMapping = assetsMapping.find(id);
|
||||
|
||||
if (mapping == assetsMapping.end())
|
||||
if (assetMapping == assetsMapping.end())
|
||||
break;
|
||||
|
||||
command.out->store(mapping->second);
|
||||
command.out->store(assetMapping->second);
|
||||
|
||||
command.type = AssetStreamCommand::COMPLETED;
|
||||
break;
|
||||
@ -254,12 +296,12 @@ void AssetManager::ProcessCommand(AssetStreamCommand &command)
|
||||
|
||||
case AssetStreamCommand::GET:
|
||||
{
|
||||
if (activeAssets.size() <= command.target.id)
|
||||
if (activeAssets.size() <= command.target.slot)
|
||||
break;
|
||||
if (!activeAssets[command.target.id].isReady)
|
||||
if (!activeAssets[command.target.slot].isReady)
|
||||
break;
|
||||
|
||||
command.out->store(activeAssets[command.target.id].resourceAddress->resource);
|
||||
command.out->store(activeAssets[command.target.slot].resourceAddress->resource);
|
||||
|
||||
command.type = AssetStreamCommand::COMPLETED;
|
||||
break;
|
||||
@ -291,6 +333,20 @@ void AssetManager::Release()
|
||||
Deallocate(mapping.second);
|
||||
assetsMapping.clear();
|
||||
|
||||
//TODO: ClrearStorage(&storage);
|
||||
for (AssetBinary* &resource : binaryStorage)
|
||||
{
|
||||
if (resource != nullptr)
|
||||
Deallocate(resource);
|
||||
}
|
||||
binaryStorage.clear();
|
||||
for (AssetShader* &resource : shadersStorage)
|
||||
{
|
||||
if (resource != nullptr)
|
||||
Deallocate(resource);
|
||||
}
|
||||
shadersStorage.clear();
|
||||
|
||||
LOG(INFO, "Asset Streaming is released");
|
||||
isRunning.store(false);
|
||||
}
|
||||
|
||||
4
frontend/src/Engine.cpp
Normal file
4
frontend/src/Engine.cpp
Normal file
@ -0,0 +1,4 @@
|
||||
#include "Engine.hpp"
|
||||
|
||||
AssetManager* Engine::assetManager;
|
||||
Renderer* Engine::renderer;
|
||||
@ -1,7 +1,6 @@
|
||||
#include "FileSystem.hpp"
|
||||
#include "Logger.h"
|
||||
#include "allocator.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
IFileSystem::~IFileSystem()
|
||||
{
|
||||
@ -72,6 +71,7 @@ void NativeFileSystem::ReadAsync(FileHandle &file, const uint32_t bufferSize, co
|
||||
.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)
|
||||
};
|
||||
file.buffer = AllocateArray<uint8_t>(bufferSize);
|
||||
file.bufferSize = bufferSize;
|
||||
|
||||
BOOL isSync = ReadFile(
|
||||
file.win32Handle,
|
||||
@ -87,31 +87,6 @@ void NativeFileSystem::ReadAsync(FileHandle &file, const uint32_t bufferSize, co
|
||||
|
||||
bool NativeFileSystem::PollReady(FileHandle &file)
|
||||
{
|
||||
// DWORD transferredSize = 0L;
|
||||
// BOOL status = GetOverlappedResult(
|
||||
// file.win32Handle,
|
||||
// &file.overlapped,
|
||||
// &transferredSize,
|
||||
// FALSE
|
||||
// );
|
||||
|
||||
// DWORD error = GetLastError();
|
||||
// if (!status && error != ERROR_IO_INCOMPLETE)
|
||||
// {
|
||||
// LOG(CRITICAL, "Error in reading file status. Code: %d", error);
|
||||
// throw std::runtime_error("Error in reading file status");
|
||||
// }
|
||||
|
||||
// if (file.size == transferredSize)
|
||||
// {
|
||||
// file.data = file.buffer;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// /* TODO: reserve size for data, shift and move */
|
||||
// }
|
||||
// file.buffer = nullptr;
|
||||
|
||||
DWORD status = WaitForSingleObject(file.overlapped.hEvent, 0);
|
||||
|
||||
switch (status)
|
||||
@ -121,6 +96,7 @@ bool NativeFileSystem::PollReady(FileHandle &file)
|
||||
if (file.size == file.bufferSize)
|
||||
{
|
||||
file.data = file.buffer;
|
||||
file.buffer = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -137,7 +113,7 @@ bool NativeFileSystem::PollReady(FileHandle &file)
|
||||
default:
|
||||
{
|
||||
LOG(CRITICAL, "Failed to get file status. Error: %d", GetLastError());
|
||||
throw std::runtime_error("Failed to get file status");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
301
frontend/src/PipelineFactory.cpp
Normal file
301
frontend/src/PipelineFactory.cpp
Normal file
@ -0,0 +1,301 @@
|
||||
#include "PipelineFactory.hpp"
|
||||
#include "Engine.hpp"
|
||||
#include "Logger.h"
|
||||
|
||||
PipelineConfig PipelineConfig::Copy() const
|
||||
{
|
||||
PipelineConfig copy = *this;
|
||||
|
||||
copy.viewportStateConfig.pViewports = ©.defaultViewport;
|
||||
copy.viewportStateConfig.pScissors = ©.defaultScissors;
|
||||
copy.dynamicStateConfig.pDynamicStates = copy.dynamicStates.data();
|
||||
copy.colorBlendConfig.pAttachments = copy.colorBlendAttachmentConfigs.data();
|
||||
copy.renderPassConfig.pAttachments = copy.colorAttachmentConfigs.data();
|
||||
copy.renderPassConfig.pSubpasses = copy.subpassConfigs.data();
|
||||
for (VkSubpassDescription &config : copy.subpassConfigs)
|
||||
{
|
||||
config.pColorAttachments = copy.colorAttachmentRefs.data();
|
||||
}
|
||||
|
||||
copy.pipelineConfig.pVertexInputState = ©.vertexInputConfig;
|
||||
copy.pipelineConfig.pInputAssemblyState = ©.inputAssemblyConfig;
|
||||
copy.pipelineConfig.pViewportState = ©.viewportStateConfig;
|
||||
copy.pipelineConfig.pRasterizationState = ©.rasterizerConfig;
|
||||
copy.pipelineConfig.pMultisampleState = ©.multisamplingConfig;
|
||||
copy.pipelineConfig.pDepthStencilState = nullptr;
|
||||
copy.pipelineConfig.pColorBlendState = ©.colorBlendConfig;
|
||||
copy.pipelineConfig.pDynamicState = ©.dynamicStateConfig;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
PipelineFactory::PipelineFactory(const AssetMaterial &baseMaterial, VkDevice &device, VkExtent2D &surfaceExtent, VkFormat &surfaceFormat) :
|
||||
device(device), surfaceExtent(surfaceExtent), surfaceFormat(surfaceFormat)
|
||||
{
|
||||
basePipelineConfig.dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT);
|
||||
|
||||
basePipelineConfig.colorBlendAttachmentConfigs.push_back({
|
||||
.blendEnable = VK_TRUE,
|
||||
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
|
||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
|
||||
});
|
||||
|
||||
basePipelineConfig.colorAttachmentConfigs.push_back({
|
||||
.format = surfaceFormat,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT, // TODO: Multisampling
|
||||
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
|
||||
});
|
||||
basePipelineConfig.colorAttachmentRefs.push_back({
|
||||
.attachment = 0,
|
||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||
});
|
||||
|
||||
basePipelineConfig.subpassConfigs.push_back({
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
.colorAttachmentCount = static_cast<uint32_t>(basePipelineConfig.colorAttachmentRefs.size()),
|
||||
.pColorAttachments = basePipelineConfig.colorAttachmentRefs.data()
|
||||
});
|
||||
|
||||
basePipelineConfig.vertexInputConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.vertexBindingDescriptionCount = 0,
|
||||
.pVertexBindingDescriptions = nullptr,
|
||||
.vertexAttributeDescriptionCount = 0,
|
||||
.pVertexAttributeDescriptions = nullptr
|
||||
};
|
||||
|
||||
basePipelineConfig.inputAssemblyConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||
.primitiveRestartEnable = VK_FALSE
|
||||
};
|
||||
|
||||
basePipelineConfig.rasterizerConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.depthClampEnable = VK_FALSE,
|
||||
.rasterizerDiscardEnable = VK_FALSE,
|
||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
||||
.cullMode = VK_CULL_MODE_NONE,
|
||||
.depthBiasEnable = VK_FALSE,
|
||||
.lineWidth = 1.0f,
|
||||
};
|
||||
|
||||
basePipelineConfig.multisamplingConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.sampleShadingEnable = VK_FALSE,
|
||||
};
|
||||
|
||||
basePipelineConfig.depthStencilConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
};
|
||||
|
||||
basePipelineConfig.dynamicStateConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.dynamicStateCount = static_cast<uint32_t>(basePipelineConfig.dynamicStates.size()),
|
||||
.pDynamicStates = basePipelineConfig.dynamicStates.data()
|
||||
};
|
||||
|
||||
basePipelineConfig.pipelineLayoutConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.setLayoutCount = 0, //TODO: vector
|
||||
.pSetLayouts = nullptr,
|
||||
.pushConstantRangeCount = 0,
|
||||
.pPushConstantRanges = nullptr
|
||||
};
|
||||
|
||||
basePipelineConfig.defaultViewport = {
|
||||
.x = 0.0f,
|
||||
.y = 0.0f,
|
||||
.width = static_cast<float>(surfaceExtent.width),
|
||||
.height = static_cast<float>(surfaceExtent.height),
|
||||
.minDepth = 0.0f,
|
||||
.maxDepth = 1.0f
|
||||
};
|
||||
|
||||
basePipelineConfig.defaultScissors = {
|
||||
.offset = {.x = 0, .y = 0},
|
||||
.extent = surfaceExtent
|
||||
};
|
||||
|
||||
basePipelineConfig.viewportStateConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.viewportCount = 1,
|
||||
.pViewports = &basePipelineConfig.defaultViewport,
|
||||
.scissorCount = 1,
|
||||
.pScissors = &basePipelineConfig.defaultScissors
|
||||
};
|
||||
|
||||
basePipelineConfig.colorBlendConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.logicOpEnable = VK_FALSE,
|
||||
.attachmentCount = static_cast<uint32_t>(basePipelineConfig.colorBlendAttachmentConfigs.size()),
|
||||
.pAttachments = basePipelineConfig.colorBlendAttachmentConfigs.data(),
|
||||
};
|
||||
|
||||
basePipelineConfig.renderPassConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.attachmentCount = static_cast<uint32_t>(basePipelineConfig.colorAttachmentConfigs.size()),
|
||||
.pAttachments = basePipelineConfig.colorAttachmentConfigs.data(),
|
||||
.subpassCount = static_cast<uint32_t>(basePipelineConfig.subpassConfigs.size()),
|
||||
.pSubpasses = basePipelineConfig.subpassConfigs.data()
|
||||
};
|
||||
|
||||
basePipelineConfig.pipelineConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.pVertexInputState = &basePipelineConfig.vertexInputConfig,
|
||||
.pInputAssemblyState = &basePipelineConfig.inputAssemblyConfig,
|
||||
.pViewportState = &basePipelineConfig.viewportStateConfig,
|
||||
.pRasterizationState = &basePipelineConfig.rasterizerConfig,
|
||||
.pMultisampleState = &basePipelineConfig.multisamplingConfig,
|
||||
.pDepthStencilState = nullptr,
|
||||
.pColorBlendState = &basePipelineConfig.colorBlendConfig,
|
||||
.pDynamicState = &basePipelineConfig.dynamicStateConfig,
|
||||
.subpass = 0,
|
||||
.basePipelineHandle = VK_NULL_HANDLE,
|
||||
.basePipelineIndex = -1
|
||||
};
|
||||
|
||||
LOG(INFO, "Creating base material pipeline...");
|
||||
Create(baseMaterial, PIPELINE_CREATE_NEW);
|
||||
LOG(INFO, "Base material pipeline created");
|
||||
}
|
||||
|
||||
void PipelineFactory::Create(const AssetMaterial &material, uint32_t flags)
|
||||
{
|
||||
Pipeline newPipeline {};
|
||||
Pipeline *result = &basePipeline;
|
||||
|
||||
PipelineConfig newConfig;
|
||||
PipelineConfig *config = &basePipelineConfig;
|
||||
|
||||
if (flags & PIPELINE_CREATE_DERIVED)
|
||||
{
|
||||
newConfig = basePipelineConfig.Copy();
|
||||
config = &newConfig;
|
||||
|
||||
result = &newPipeline;
|
||||
config->pipelineConfig.basePipelineHandle = basePipeline.instance;
|
||||
}
|
||||
|
||||
VkResult vkResult = vkCreatePipelineLayout(
|
||||
device,
|
||||
&config->pipelineLayoutConfig,
|
||||
nullptr,
|
||||
&result->layout
|
||||
);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to create pipeline layout");
|
||||
config->pipelineConfig.layout = result->layout;
|
||||
|
||||
vkResult = vkCreateRenderPass(device, &config->renderPassConfig, nullptr, &result->renderPass);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to create render pass");
|
||||
config->pipelineConfig.renderPass = result->renderPass;
|
||||
|
||||
// Configure shaders
|
||||
AssetHandle shaderHandle;
|
||||
AssetShader *shader;
|
||||
VkShaderModuleCreateInfo shaderModuleCreateConfig;
|
||||
std::vector<VkPipelineShaderStageCreateInfo> stagesConfigs;
|
||||
|
||||
stagesConfigs.reserve(3);
|
||||
|
||||
// Vertex
|
||||
VkShaderModule vertexModule;
|
||||
shaderHandle = Engine::assetManager->Find(material.vertexShader);
|
||||
shader = &Engine::assetManager->Get<AssetShader>(shaderHandle);
|
||||
shaderModuleCreateConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.codeSize = shader->size,
|
||||
.pCode = shader->content
|
||||
};
|
||||
vkResult = vkCreateShaderModule(device, &shaderModuleCreateConfig, nullptr, &vertexModule);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(ERROR, "Failed to create vertex shader module [Asset ID: %d]. Code: %d", shaderHandle.id, vkResult);
|
||||
stagesConfigs.push_back({
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.module = vertexModule,
|
||||
.pName = "main",
|
||||
.pSpecializationInfo = nullptr
|
||||
});
|
||||
|
||||
// Fragment
|
||||
VkShaderModule fragmentModule;
|
||||
shaderHandle = Engine::assetManager->Find(material.fragmentShader);
|
||||
shader = &Engine::assetManager->Get<AssetShader>(shaderHandle);
|
||||
shaderModuleCreateConfig = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.codeSize = shader->size,
|
||||
.pCode = shader->content
|
||||
};
|
||||
vkResult = vkCreateShaderModule(device, &shaderModuleCreateConfig, nullptr, &fragmentModule);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(ERROR, "Failed to create fragment shader module [Asset ID: %d]. Code: %d", shaderHandle.id, vkResult);
|
||||
stagesConfigs.push_back({
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.module = fragmentModule,
|
||||
.pName = "main",
|
||||
.pSpecializationInfo = nullptr
|
||||
});
|
||||
|
||||
config->pipelineConfig.stageCount = static_cast<uint32_t>(stagesConfigs.size());
|
||||
config->pipelineConfig.pStages = stagesConfigs.data();
|
||||
|
||||
vkResult = vkCreateGraphicsPipelines(
|
||||
device,
|
||||
VK_NULL_HANDLE,
|
||||
1,
|
||||
&config->pipelineConfig,
|
||||
nullptr,
|
||||
&result->instance
|
||||
);
|
||||
if (vkResult != VK_SUCCESS)
|
||||
LOG(CRITICAL, "Failed to create pipeline");
|
||||
|
||||
if (flags & PIPELINE_CREATE_DERIVED)
|
||||
pipelines.push_back(newPipeline);
|
||||
|
||||
vkDestroyShaderModule(device, vertexModule, nullptr);
|
||||
vkDestroyShaderModule(device, fragmentModule, nullptr);
|
||||
}
|
||||
|
||||
PipelineFactory::~PipelineFactory()
|
||||
{
|
||||
vkDestroyPipeline(device, basePipeline.instance, nullptr);
|
||||
vkDestroyPipelineLayout(device, basePipeline.layout, nullptr);
|
||||
vkDestroyRenderPass(device, basePipeline.renderPass, nullptr);
|
||||
for (Pipeline &pipeline : pipelines)
|
||||
{
|
||||
vkDestroyPipeline(device, pipeline.instance, nullptr);
|
||||
vkDestroyPipelineLayout(device, pipeline.layout, nullptr);
|
||||
vkDestroyRenderPass(device, pipeline.renderPass, nullptr);
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,9 @@
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
|
||||
Renderer::Renderer(SDL_Window *window) : isRunning(false)
|
||||
Renderer::Renderer(SDL_Window *window, const AssetMaterial &baseMaterial) :
|
||||
isRunning(false),
|
||||
baseMaterial(baseMaterial)
|
||||
{
|
||||
this->window = window;
|
||||
}
|
||||
@ -431,6 +433,7 @@ void Renderer::Threading()
|
||||
InitVulkan();
|
||||
SetupDevice();
|
||||
SetupSwapchain();
|
||||
pipelineFactory = Allocate<PipelineFactory>(baseMaterial, device, surfaceInfo.extent, surfaceInfo.format.format);
|
||||
|
||||
Loop();
|
||||
|
||||
@ -493,6 +496,8 @@ void Renderer::Request(const RenderCommand::Type &type)
|
||||
|
||||
void Renderer::Release()
|
||||
{
|
||||
Deallocate(pipelineFactory);
|
||||
|
||||
for (VkImageView &frameView : frameViews)
|
||||
{
|
||||
vkDestroyImageView(device, frameView, nullptr);
|
||||
|
||||
@ -2,8 +2,7 @@
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include "compile_config.hpp"
|
||||
#include "AssetManager.hpp"
|
||||
#include "Renderer.hpp"
|
||||
#include "Engine.hpp"
|
||||
|
||||
IP7_Trace* Logger::trace;
|
||||
|
||||
@ -46,9 +45,15 @@ int SDL_main(int argc, char **argv)
|
||||
assetManager.LoadShaders();
|
||||
|
||||
// Setup Renderer
|
||||
Renderer renderer(window);
|
||||
assetManager.LoadAsync(AssetInfo::MATERIAL, "assets/materials/helloworld.mat");
|
||||
AssetHandle baseMaterialHandle = assetManager.Find("assets/materials/helloworld.mat");
|
||||
Renderer renderer(window, assetManager.Get<AssetMaterial>(baseMaterialHandle));
|
||||
renderer.Start();
|
||||
|
||||
//Setup Engine
|
||||
Engine::assetManager = &assetManager;
|
||||
Engine::renderer = &renderer;
|
||||
|
||||
// Process SDL events
|
||||
while(!quit)
|
||||
{
|
||||
|
||||
46
materials/CMakeLists.txt
Normal file
46
materials/CMakeLists.txt
Normal file
@ -0,0 +1,46 @@
|
||||
cmake_minimum_required (VERSION 3.8)
|
||||
|
||||
if (POLICY CMP0141)
|
||||
cmake_policy(SET CMP0141 NEW)
|
||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
|
||||
endif()
|
||||
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
project (compile_materials)
|
||||
|
||||
find_package(nlohmann_json CONFIG REQUIRED)
|
||||
find_package(xxHash CONFIG REQUIRED)
|
||||
|
||||
add_executable(${PROJECT_NAME} compile_materials.cpp)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE nlohmann_json::nlohmann_json)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE xxHash::xxhash)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/frontend/include/)
|
||||
|
||||
if (CMAKE_VERSION VERSION_GREATER 3.12)
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
|
||||
endif()
|
||||
|
||||
file(GLOB MATERIAL_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.mat.json")
|
||||
|
||||
set(COMPILED_DIR "${CMAKE_SOURCE_DIR}/assets/materials")
|
||||
|
||||
foreach(MAT ${MATERIAL_FILES})
|
||||
get_filename_component(MAT_NAME ${MAT} NAME_WE)
|
||||
set(OUT_FILE "${COMPILED_DIR}/${MAT_NAME}.mat")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${OUT_FILE}
|
||||
COMMAND ${PROJECT_NAME} ${MAT} ${OUT_FILE}
|
||||
DEPENDS ${MAT}
|
||||
COMMENT "Compiling material ${MAT_NAME}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
list(APPEND COMPILED_BINARIES ${OUT_FILE})
|
||||
endforeach()
|
||||
|
||||
add_custom_target(compile_assets ALL
|
||||
DEPENDS ${COMPILED_BINARIES}
|
||||
)
|
||||
0
materials/_schema.json
Normal file
0
materials/_schema.json
Normal file
59
materials/compile_materials.cpp
Normal file
59
materials/compile_materials.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <xxhash.h>
|
||||
#include <string>
|
||||
#include "AssetData.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(AssetMaterial, vertexShader, fragmentShader)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::filesystem::path in = argv[1];
|
||||
std::filesystem::path out = argv[2];
|
||||
|
||||
|
||||
std::ifstream fin(in);
|
||||
std::ofstream fout(out);
|
||||
|
||||
if (!fin.is_open()) {
|
||||
std::cout << "Error: Could not open input file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (!fout.is_open()) {
|
||||
std::cout << "Error: Could not open output file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
json data = json::parse(fin);
|
||||
|
||||
for (const char *link : {
|
||||
"vertexShader",
|
||||
"fragmentShader"
|
||||
})
|
||||
{
|
||||
std::filesystem::path linkPath = data[link];
|
||||
auto linkPath8 = linkPath.generic_u8string();
|
||||
uint32_t assetId = XXH32(linkPath8.data(), linkPath8.size(), 0);
|
||||
data[link] = assetId;
|
||||
}
|
||||
|
||||
AssetMaterial material = data.get<AssetMaterial>();
|
||||
fout.write(reinterpret_cast<const char*>(&material), sizeof(material));
|
||||
|
||||
fin.close();
|
||||
fout.close();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
4
materials/helloworld.mat.json
Normal file
4
materials/helloworld.mat.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"vertexShader": "assets/shaders/helloworld.vert.spv",
|
||||
"fragmentShader": "assets/shaders/helloworld.frag.spv"
|
||||
}
|
||||
@ -1,8 +1,10 @@
|
||||
#version 330
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
|
||||
layout(location = 0) in vec3 fragColor;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
outColor = vec4(fragColor, 1.0);
|
||||
}
|
||||
@ -1,12 +1,21 @@
|
||||
#version 330
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
|
||||
vec2 positions[3] = vec2[](
|
||||
vec2(-1.0, 1.0),
|
||||
vec2(0.0, -1.0),
|
||||
vec2(1.0, 1.0)
|
||||
vec2(0.0, -0.5),
|
||||
vec2(0.5, 0.5),
|
||||
vec2(-0.5, 0.5)
|
||||
);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 colors[3] = vec3[](
|
||||
vec3(1.0, 0.0, 0.0),
|
||||
vec3(0.0, 1.0, 0.0),
|
||||
vec3(0.0, 0.0, 1.0)
|
||||
);
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
|
||||
fragColor = colors[gl_VertexIndex];
|
||||
}
|
||||
@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
#include <utility>
|
||||
|
||||
template<typename T> T* Allocate()
|
||||
template<typename T, typename... Args> T* Allocate(Args&&... args)
|
||||
{
|
||||
return new T();
|
||||
return new T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T> void Deallocate(T* obj)
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"boost-lockfree",
|
||||
"xxhash",
|
||||
"nlohmann-json",
|
||||
"entt",
|
||||
"vulkan",
|
||||
{"name": "sdl2", "features": ["vulkan"]},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user