Finished writeup and fixed crashes

This commit is contained in:
Dynamitos
2021-10-19 23:04:38 +02:00
parent a0693daa67
commit 451572f254
36 changed files with 295 additions and 375 deletions
+4 -4
View File
@@ -3,22 +3,22 @@
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**",
"external/**"
"${workspaceFolder}/src/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"intelliSenseMode": "msvc-x64",
"intelliSenseMode": "windows-msvc-x64",
"configurationProvider": "ms-vscode.cmake-tools",
"cppStandard": "c++20",
"browse": {
"path": [
"external/**"
]
}
},
"compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.29.30037/bin/Hostx64/x64/cl.exe"
}
],
"version": 4
+2 -1
View File
@@ -133,5 +133,6 @@
"**/target": true
},
"C_Cpp.errorSquiggles": "Disabled",
"git.ignoreSubmodules": true
"git.ignoreSubmodules": true,
"cmake.configureOnOpen": true
}
+4 -2
View File
@@ -21,6 +21,7 @@ set(NSAM_ROOT ${EXTERNAL_ROOT}/aftermath)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/)
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_LIB_PREFIX lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE})
#Workaround for vs, because it places artifacts into an additional subfolder
@@ -37,7 +38,6 @@ else()
project (Seele)
endif()
find_package(Vulkan REQUIRED)
find_package(Boost REQUIRED COMPONENTS serialization)
find_package(Threads REQUIRED)
@@ -117,7 +117,7 @@ if(WIN32)
add_custom_target(copy-binaries ALL
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SLANG_BINARIES} $<TARGET_FILE_DIR:SeeleEngine>
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SLANG_GLSLANG} $<TARGET_FILE_DIR:SeeleEngine>
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${GLFW_BINARY} $<TARGET_FILE_DIR:SeeleEngine>
#COMMAND ${CMAKE_COMMAND} -E copy_if_different ${GLFW_BINARY} $<TARGET_FILE_DIR:SeeleEngine>
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ASSIMP_BINARY} $<TARGET_FILE_DIR:SeeleEngine>
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${NSAM_BINARIES} $<TARGET_FILE_DIR:SeeleEngine>)
else()
@@ -127,3 +127,5 @@ endif()
add_custom_target(copy-runtime-files ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/res $<TARGET_FILE_DIR:SeeleEngine>
DEPENDS SeeleEngine copy-binaries)
+66 -4
View File
@@ -9,7 +9,7 @@ API that doesn't support it, like OpenGL. These APIs would suffer a significant
## Custom containers and other utilities
Some of the basic containers are reimplemented, mostly not for any particular feature, but because that makes them more customizable and extendable for future uses and
performance optimizations, like serialization for example. Due to them occuring in the code samples later, they will be quickly mentioned here.
performance optimizations, like serialization for example. Due to some of them occuring in the code samples later, they will be quickly mentioned here.
- `Array`: A heap-array backed dynamically resizable container, like `std::vector`
- `StaticArray`: A static-array backed non-resizable container, like `std::array`
@@ -139,8 +139,70 @@ The document starts with the asset `name`, followed by the `profile`, which tell
### MaterialAsset
The `MaterialAsset` class represents such a JSON document on disk, and is the base class for `Material` and `MaterialInstance`. It stores the layout of the parameters as well as their values, but does not store, parse or generate any shader code.
A `MaterialAsset` represents such a JSON document on disk, as well as the GPU resources needed to render a mesh with the material. When loading the file, the a descriptor layout is generated to fit the `slang` code that will be generated later by consolidating the plain variables (`float`, `double`, etc.) into a single uniform buffer. The parameters are stored in an array of `ShaderParameter`s, which contain the current parameter value, like texture references or plain data, as well as information on how to update the GPU resources.
### Material
At the same time a slang-compilable shader is generated, which matches the parameters provided by the descriptor layout. The generated shader is a `Material`, which is an interface that "prepares" a BRDF by initializing its input values, similar to official slang example. How each input value is calculated is read from the `code` section of the JSON document, and wrapped in an accessor to allow for multi line calculations.
The `Material` class inherits from `MaterialAsset` and represents a base material,
Here is the material generated from the above JSON example:
```cpp
import VERTEX_INPUT_IMPORT;
import Material;
import BRDF;
import MaterialParameter;
struct Placeholder: IMaterial {
layout(offset = 0)float anisotropic;
layout(offset = 4)float clearCoat;
layout(offset = 8)float clearCoatGloss;
Texture2D diffuseTexture;
layout(offset = 12)float metallic;
Texture2D normalTexture;
layout(offset = 16)float roughness;
layout(offset = 20)float sheen;
layout(offset = 24)float sheenTint;
Texture2D specularTexture;
layout(offset = 28)float specularTint;
layout(offset = 32)float subsurface;
SamplerState textureSampler;
layout(offset = 36)float uvScale;
layout(offset = 40)float3 worldOffset;
float3 getBaseColor(MaterialFragmentParameter input) {
return diffuseTexture.Sample(textureSampler, input.texCoords[0] * uvScale).xyz;;
}
float getMetallic(MaterialFragmentParameter input) {
return 0;;
}
float3 getNormal(MaterialFragmentParameter input) {
return normalTexture.Sample(textureSampler, input.texCoords[0] * uvScale).xyz;;
}
float getSpecular(MaterialFragmentParameter input) {
return specularTexture.Sample(textureSampler, input.texCoords[0] * uvScale).x;;
}
float getRoughness(MaterialFragmentParameter input) {
return roughness;;
}
float getSheen(MaterialFragmentParameter input) {
return sheen;;
}
float3 getWorldOffset() {
return worldOffset;;
}
typedef BlinnPhong BRDF;
BlinnPhong prepare(MaterialFragmentParameter geometry){
BlinnPhong result;
result.baseColor = getBaseColor(geometry);
result.metallic = getMetallic(geometry);
result.normal = getNormal(geometry);
result.specular = getSpecular(geometry);
result.roughness = getRoughness(geometry);
result.sheen = getSheen(geometry);
return result;
}
};
```
### Renderpass interaction
Each render pass has a "base file" containing the vertex and fragment stages. From that base file a variant is generated for each material that will be used with that render pass using `#define` macros to change the material import, and a `type_param` to update the `ParameterBlock` containing the material itself. Other renderpass dependent data like camera parameter or lights are stored in separate descriptor sets, and to avoid code duplication, they parts that are used by more than one render pass are implemented in separate slang files. But since in Vulkan pipeline layouts cannot have empty indices, the descriptor set indices sometimes need to change. This is done using the static `modifyRenderPassMacros` function in each renderpass to `#define` the correct set indices for each shared descriptor layout.
+9 -8
View File
@@ -48,14 +48,15 @@ if (WIN32)
unset(GLFW_LIBRARY_NAME)
find_file(
GLFW_BINARY
NAMES glfw3${CMAKE_DEBUG_POSTFIX}.dll
PATHS
$ENV{PROGRAMFILES}/bin
${GLFW_ROOT}/src
${GLFW_ROOT}/bin
PATH_SUFFIXES Debug Release)
#find_file(
# GLFW_BINARY
# NAMES glfw3${CMAKE_DEBUG_POSTFIX}.dll
# PATHS
# $ENV{PROGRAMFILES}/bin
# ${CMAKE_BINARY_DIR}
# ${GLFW_ROOT}/src
# ${GLFW_ROOT}/bin
# PATH_SUFFIXES Debug Release)
else()
# Find include files
find_path(
+1 -2
View File
@@ -28,14 +28,13 @@ else()
endif()
ExternalProject_Add(boost
SOURCE_DIR ${BOOST_ROOT}
UPDATE_COMMAND ""
CONFIGURE_COMMAND ./bootstrap.${BOOTSTRAP_EXTENSION} --with-libraries=serialization,test
BUILD_COMMAND ./b2 -d0
BUILD_IN_SOURCE 1
INSTALL_COMMAND "")
list (APPEND EXTRA_CMAKE_ARGS
-DBoost_NO_SYSTEM_PATHS=OFF)
-DBoost_NO_SYSTEM_PATHS=ON)
#-----------------KTX----------------------------
list(APPEND DEPENDENCIES ktx)
+2 -1
View File
@@ -105,7 +105,8 @@ void cullLights(ComputeShaderInput in)
for ( uint i = in.groupIndex; i < numPointLights; i += BLOCK_SIZE * BLOCK_SIZE )
{
PointLight light = pointLights[i];
if(light.insideFrustum(groupFrustum, nearClipVS, maxDepthVS))
//TODO: why doesn't this check go through?
//if(light.insideFrustum(groupFrustum, nearClipVS, maxDepthVS))
{
tAppendLight(i);
if(!light.insidePlane(minPlane))
+1 -1
View File
@@ -4,7 +4,7 @@
#include "TextureLoader.h"
#include "MaterialLoader.h"
#include "MeshLoader.h"
#include "Material/Material.h"
#include "Material/MaterialAsset.h"
#include "Graphics/Graphics.h"
#include "Window/WindowManager.h"
#include "MeshAsset.h"
+7 -7
View File
@@ -1,6 +1,6 @@
#include "MaterialLoader.h"
#include "Material/Material.h"
#include "Graphics/Graphics.h"
#include "Material/MaterialAsset.h"
#include "AssetRegistry.h"
using namespace Seele;
@@ -8,8 +8,8 @@ using namespace Seele;
MaterialLoader::MaterialLoader(Gfx::PGraphics graphics)
: graphics(graphics)
{
placeholderMaterial = new Material(std::filesystem::absolute("./shaders/Placeholder.asset"));
placeholderMaterial->compile();
placeholderMaterial = new MaterialAsset(std::filesystem::absolute("./shaders/Placeholder.asset"));
placeholderMaterial->load();
graphics->getShaderCompiler()->registerMaterial(placeholderMaterial);
}
@@ -17,10 +17,10 @@ MaterialLoader::~MaterialLoader()
{
}
PMaterial MaterialLoader::queueAsset(const std::filesystem::path& filePath)
PMaterialAsset MaterialLoader::queueAsset(const std::filesystem::path& filePath)
{
PMaterial result = new Material(filePath);
result->compile();
PMaterialAsset result = new MaterialAsset(filePath);
result->load();
graphics->getShaderCompiler()->registerMaterial(result);
AssetRegistry::get().registerMaterial(result);
// TODO: There is actually no real reason to import a standalone material,
@@ -28,7 +28,7 @@ PMaterial MaterialLoader::queueAsset(const std::filesystem::path& filePath)
return result;
}
PMaterial MaterialLoader::getPlaceHolderMaterial()
PMaterialAsset MaterialLoader::getPlaceHolderMaterial()
{
return placeholderMaterial;
}
+4 -4
View File
@@ -7,19 +7,19 @@
namespace Seele
{
DECLARE_REF(Material)
DECLARE_REF(MaterialAsset)
DECLARE_NAME_REF(Gfx, Graphics)
class MaterialLoader
{
public:
MaterialLoader(Gfx::PGraphics graphic);
~MaterialLoader();
PMaterial queueAsset(const std::filesystem::path& filePath);
PMaterial getPlaceHolderMaterial();
PMaterialAsset queueAsset(const std::filesystem::path& filePath);
PMaterialAsset getPlaceHolderMaterial();
private:
Gfx::PGraphics graphics;
List<std::future<void>> futures;
PMaterial placeholderMaterial;
PMaterialAsset placeholderMaterial;
};
DEFINE_REF(MaterialLoader)
} // namespace Seele
+2 -3
View File
@@ -5,7 +5,6 @@
#include "Graphics/Mesh.h"
#include "Graphics/StaticMeshVertexInput.h"
#include "AssetRegistry.h"
#include "Material/Material.h"
#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>
@@ -88,8 +87,8 @@ void MeshLoader::loadMaterials(const aiScene* scene, Array<PMaterialAsset>& glob
outMatFile.close();
std::cout << "writing json to " << outMatFilename << std::endl;
PMaterial result = new Material(outMatFilename);
result->compile();
PMaterialAsset result = new MaterialAsset(outMatFilename);
result->load();
graphics->getShaderCompiler()->registerMaterial(result);
AssetRegistry::get().registerMaterial(result);
PMaterialAsset asset = AssetRegistry::findMaterial(result->getFileName());
+1 -3
View File
@@ -1,6 +1,4 @@
#include "GraphicsResources.h"
#include "Material/MaterialInstance.h"
#include "Material/Material.h"
#include "Graphics.h"
#include "RenderPass/DepthPrepass.h"
#include "RenderPass/BasePass.h"
@@ -55,7 +53,7 @@ const ShaderCollection* ShaderMap::findShaders(PermutationId&& id) const
ShaderCollection& ShaderMap::createShaders(
PGraphics graphics,
RenderPassType renderPass,
PMaterial material,
PMaterialAsset material,
VertexInputType* vertexInput,
bool /*bPositionOnly*/)
{
+1 -2
View File
@@ -17,7 +17,6 @@ namespace Seele
struct VertexInputStream;
struct VertexStreamComponent;
class VertexInputType;
DECLARE_REF(Material)
namespace Gfx
{
DECLARE_REF(Graphics)
@@ -140,7 +139,7 @@ public:
ShaderCollection& createShaders(
PGraphics graphics,
RenderPassType passName,
PMaterial material,
PMaterialAsset material,
VertexInputType* vertexInput,
bool bPositionOnly);
private:
+2 -2
View File
@@ -34,7 +34,7 @@ void BasePassMeshProcessor::addMeshBatch(
const PVertexShaderInput vertexInput = batch.vertexInput;
const Gfx::ShaderCollection* collection = material->getRenderMaterial()->getShaders(Gfx::RenderPassType::BasePass, vertexInput->getType());
const Gfx::ShaderCollection* collection = material->getShaders(Gfx::RenderPassType::BasePass, vertexInput->getType());
assert(collection != nullptr);
for(uint32 i = 0; i < batch.elements.size(); ++i)
{
@@ -47,7 +47,7 @@ void BasePassMeshProcessor::addMeshBatch(
renderCommand->setViewport(target);
for(uint32 i = 0; i < batch.elements.size(); ++i)
{
pipelineLayout->addDescriptorLayout(BasePass::INDEX_MATERIAL, material->getRenderMaterial()->getDescriptorLayout());
pipelineLayout->addDescriptorLayout(BasePass::INDEX_MATERIAL, material->getDescriptorLayout());
pipelineLayout->create();
descriptorSets[BasePass::INDEX_MATERIAL] = material->getDescriptor();
descriptorSets[BasePass::INDEX_SCENE_DATA] = cachedPrimitiveSets[cachedPrimitiveIndex++];
@@ -33,7 +33,7 @@ void DepthPrepassMeshProcessor::addMeshBatch(
const PVertexShaderInput vertexInput = batch.vertexInput;
const Gfx::ShaderCollection* collection = material->getRenderMaterial()->getShaders(Gfx::RenderPassType::DepthPrepass, vertexInput->getType());
const Gfx::ShaderCollection* collection = material->getShaders(Gfx::RenderPassType::DepthPrepass, vertexInput->getType());
assert(collection != nullptr);
for(uint32 i = 0; i < batch.elements.size(); ++i)
{
@@ -46,7 +46,7 @@ void DepthPrepassMeshProcessor::addMeshBatch(
renderCommand->setViewport(target);
for(uint32 i = 0; i < batch.elements.size(); ++i)
{
pipelineLayout->addDescriptorLayout(DepthPrepass::INDEX_MATERIAL, material->getRenderMaterial()->getDescriptorLayout());
pipelineLayout->addDescriptorLayout(DepthPrepass::INDEX_MATERIAL, material->getDescriptorLayout());
pipelineLayout->create();
descriptorSets[DepthPrepass::INDEX_MATERIAL] = material->getDescriptor();
descriptorSets[DepthPrepass::INDEX_SCENE_DATA] = cachedPrimitiveSets[cachedPrimitiveIndex++];
@@ -33,14 +33,19 @@ void LightCullingPass::beginFrame()
uniformUpdate.data = (uint8*)&viewParams;
viewParamsBuffer->updateContents(uniformUpdate);
LightEnv lightEnv = passData.lightEnv;
for(uint32 i = 0; i < lightEnv.numPointLights; ++i)
{
lightEnv.pointLights[i].positionVS = lightEnv.pointLights[i].positionWS;
}
const LightEnv& lightEnv = passData.lightEnv;
uniformUpdate.size = sizeof(DirectionalLight) * MAX_DIRECTIONAL_LIGHTS;
uniformUpdate.data = (uint8*)&lightEnv.directionalLights;
directLightBuffer->updateContents(uniformUpdate);
uniformUpdate.size = sizeof(PointLight) * MAX_POINT_LIGHTS;
uniformUpdate.data = (uint8*)&lightEnv.pointLights;
pointLightBuffer->updateContents(uniformUpdate);
uniformUpdate.size = sizeof(uint32);
uniformUpdate.data = (uint8*)&lightEnv.numDirectionalLights;
numDirLightBuffer->updateContents(uniformUpdate);
uniformUpdate.data = (uint8*)&lightEnv.numPointLights;
numPointLightBuffer->updateContents(uniformUpdate);
BulkResourceData counterReset;
uint32 reset = 0;
@@ -64,6 +69,7 @@ void LightCullingPass::beginFrame()
cullingDescriptorSet->updateTexture(8, oLightGrid);
cullingDescriptorSet->updateTexture(9, tLightGrid);
lightEnvDescriptorSet->updateBuffer(0, directLightBuffer);
lightEnvDescriptorSet->updateBuffer(1, numDirLightBuffer);
lightEnvDescriptorSet->updateBuffer(2, pointLightBuffer);
@@ -133,30 +139,28 @@ void LightCullingPass::publishOutputs()
resources->registerBufferOutput("LIGHTCULLING_OLIGHTLIST", oLightIndexList);
resources->registerBufferOutput("LIGHTCULLING_TLIGHTLIST", tLightIndexList);
const LightEnv& lightEnv = passData.lightEnv;
resourceData.size = sizeof(DirectionalLight) * MAX_DIRECTIONAL_LIGHTS;
resourceData.data = (uint8*)&lightEnv.directionalLights;
structInfo.resourceData = resourceData;
structInfo.bDynamic = true;
directLightBuffer = graphics->createStructuredBuffer(structInfo);
resourceData.size = sizeof(PointLight) * MAX_POINT_LIGHTS;
resourceData.data = (uint8*)&lightEnv.pointLights;
structInfo.resourceData = resourceData;
pointLightBuffer = graphics->createStructuredBuffer(structInfo);
UniformBufferCreateInfo uniformInfo;
resourceData.size = sizeof(uint32);
resourceData.data = (uint8*)&lightEnv.numDirectionalLights;
uniformInfo.resourceData = resourceData;
uniformInfo.bDynamic = true;
numDirLightBuffer = graphics->createUniformBuffer(uniformInfo);
resourceData.data = (uint8*)&lightEnv.numPointLights;
uniformInfo.resourceData = resourceData;
uniformInfo.bDynamic = true;
numPointLightBuffer = graphics->createUniformBuffer(uniformInfo);
resources->registerBufferOutput("DIRECTIONAL_LIGHTS", directLightBuffer);
resources->registerUniformOutput("NUM_DIRECTIONAL_LIGHTS", numDirLightBuffer);
resources->registerBufferOutput("POINT_LIGHTS", pointLightBuffer);
resources->registerUniformOutput("NUM_POINT_LIGHTS", numPointLightBuffer);
TextureCreateInfo textureInfo;
textureInfo.width = dispatchParams.numThreadGroups.x;
textureInfo.height = dispatchParams.numThreadGroups.y;
@@ -164,6 +168,7 @@ void LightCullingPass::publishOutputs()
textureInfo.usage = Gfx::SE_IMAGE_USAGE_STORAGE_BIT;
oLightGrid = graphics->createTexture2D(textureInfo);
tLightGrid = graphics->createTexture2D(textureInfo);
resources->registerTextureOutput("LIGHTCULLING_OLIGHTGRID", oLightGrid);
resources->registerTextureOutput("LIGHTCULLING_TLIGHTGRID", tLightGrid);
}
+2 -2
View File
@@ -1,5 +1,5 @@
#include "ShaderCompiler.h"
#include "Material/Material.h"
#include "Material/MaterialAsset.h"
#include "VertexShaderInput.h"
using namespace Seele;
@@ -16,7 +16,7 @@ ShaderCompiler::~ShaderCompiler()
}
void ShaderCompiler::registerMaterial(PMaterial material)
void ShaderCompiler::registerMaterial(PMaterialAsset material)
{
for(auto& type : VertexInputType::getTypeList())
{
+2 -3
View File
@@ -3,7 +3,6 @@
namespace Seele
{
DECLARE_REF(Material)
DECLARE_NAME_REF(Gfx, Graphics)
namespace Gfx
{
@@ -12,9 +11,9 @@ class ShaderCompiler
public:
ShaderCompiler(PGraphics graphics);
~ShaderCompiler();
void registerMaterial(PMaterial material);
void registerMaterial(PMaterialAsset material);
private:
Array<PMaterial> pendingCompiles;
Array<PMaterialAsset> pendingCompiles;
PGraphics graphics;
};
DEFINE_REF(ShaderCompiler)
@@ -77,7 +77,7 @@ void GpuCrashTracker::Initialize()
void GpuCrashTracker::OnCrashDump(const void* pGpuCrashDump, const uint32_t gpuCrashDumpSize)
{
// Make sure only one thread at a time...
std::lock_guard<std::mutex> lock(m_mutex);
std::unique_lock<std::mutex> lock(m_mutex);
// Write to file for later in-depth analysis with Nsight Graphics.
WriteGpuCrashDumpToFile(pGpuCrashDump, gpuCrashDumpSize);
@@ -87,7 +87,7 @@ void GpuCrashTracker::OnCrashDump(const void* pGpuCrashDump, const uint32_t gpuC
void GpuCrashTracker::OnShaderDebugInfo(const void* pShaderDebugInfo, const uint32_t shaderDebugInfoSize)
{
// Make sure only one thread at a time...
std::lock_guard<std::mutex> lock(m_mutex);
std::unique_lock<std::mutex> lock(m_mutex);
// Get shader debug information identifier
GFSDK_Aftermath_ShaderDebugInfoIdentifier identifier = {};
@@ -336,7 +336,7 @@ void ComputeCommand::bindDescriptor(Gfx::PDescriptorSet descriptorSet)
auto descriptor = descriptorSet.cast<DescriptorSet>();
boundDescriptors.add(descriptor.getHandle());
descriptor->bind();
//std::cout << "Binding descriptor " << descriptor->getHandle() << " to cmd " << handle << std::endl;
VkDescriptorSet setHandle = descriptor->getHandle();
vkCmdBindDescriptorSets(handle, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->getLayout(), descriptorSet->getSetIndex(), 1, &setHandle, 0, nullptr);
}
@@ -373,7 +373,7 @@ CommandBufferManager::CommandBufferManager(PGraphics graphics, PQueue queue)
activeCmdBuffer = new CmdBuffer(graphics, commandPool, this);
activeCmdBuffer->begin();
std::lock_guard lock(allocatedBufferLock);
std::unique_lock lock(allocatedBufferLock);
allocatedBuffers.add(activeCmdBuffer);
}
@@ -397,6 +397,7 @@ PRenderCommand CommandBufferManager::createRenderCommand(const std::string& name
PRenderCommand cmdBuffer = allocatedRenderCommands[i];
if (cmdBuffer->isReady())
{
cmdBuffer->name = name;
cmdBuffer->begin(activeCmdBuffer);
return cmdBuffer;
}
@@ -416,6 +417,7 @@ PComputeCommand CommandBufferManager::createComputeCommand(const std::string& na
PComputeCommand cmdBuffer = allocatedComputeCommands[i];
if (cmdBuffer->isReady())
{
cmdBuffer->name = name;
cmdBuffer->begin(activeCmdBuffer);
return cmdBuffer;
}
-4
View File
@@ -2,11 +2,7 @@ target_sources(SeeleEngine
PRIVATE
BRDF.h
BRDF.cpp
Material.h
Material.cpp
MaterialAsset.h
MaterialAsset.cpp
MaterialInstance.h
MaterialInstance.cpp
ShaderExpression.h
ShaderExpression.cpp)
-162
View File
@@ -1,162 +0,0 @@
#include "Material.h"
#include "Asset/AssetRegistry.h"
#include "Graphics/VertexShaderInput.h"
#include "BRDF.h"
#include "Window/WindowManager.h"
#include <nlohmann/json.hpp>
#include <sstream>
#include <iostream>
Gfx::ShaderMap Material::shaderMap;
std::mutex Material::shaderMapLock;
using namespace Seele;
using json = nlohmann::json;
Material::Material()
{
}
Material::Material(const std::string& directory, const std::string& name)
: MaterialAsset(directory, name)
{
}
Material::Material(const std::filesystem::path& fullPath)
: MaterialAsset(fullPath)
{
}
Material::~Material()
{
}
void Material::save()
{
}
void Material::load()
{
}
void Material::compile()
{
setStatus(Status::Loading);
auto& stream = getReadStream();
json j;
stream >> j;
materialName = j["name"].get<std::string>();
layout = WindowManager::getGraphics()->createDescriptorLayout(materialName + "Layout");
//Shader file needs to conform to the slang standard, which prohibits _
materialName.erase(std::remove(materialName.begin(), materialName.end(), '_'), materialName.end());
std::ofstream codeStream("./shaders/generated/"+materialName+".slang");
std::string profile = j["profile"].get<std::string>();
codeStream << "import VERTEX_INPUT_IMPORT;" << std::endl;
codeStream << "import Material;" << std::endl;
codeStream << "import BRDF;" << std::endl;
codeStream << "import MaterialParameter;" << std::endl << std::endl;
codeStream << "struct " << materialName << " : IMaterial {" << std::endl;
uint32 uniformBufferOffset = 0;
uint32 bindingCounter = 0; // Uniform buffers are always binding 0
uniformBinding = -1;
for(auto param : j["params"].items())
{
std::string type = param.value()["type"].get<std::string>();
auto defaultValue = param.value().find("default");
if(type.compare("float") == 0)
{
PFloatParameter p = new FloatParameter(param.key(), uniformBufferOffset, 0);
codeStream << "\tlayout(offset = " << uniformBufferOffset << ")";
if(uniformBinding == -1)
{
layout->addDescriptorBinding(bindingCounter, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
uniformBinding = bindingCounter++;
}
uniformBufferOffset += 4;
if(defaultValue != param.value().end())
{
p->data = std::stof(defaultValue.value().get<std::string>());
}
parameters.add(p);
}
else if(type.compare("float3") == 0)
{
PVectorParameter p = new VectorParameter(param.key(), uniformBufferOffset, 0);
codeStream << "\tlayout(offset = " << uniformBufferOffset << ")";
if(uniformBinding == -1)
{
layout->addDescriptorBinding(bindingCounter, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
uniformBinding = bindingCounter++;
}
uniformBufferOffset += 12;
if(defaultValue != param.value().end())
{
p->data = parseVector(defaultValue.value().get<std::string>().c_str());
}
parameters.add(p);
}
else if(type.compare("Texture2D") == 0)
{
PTextureParameter p = new TextureParameter(param.key(), 0, bindingCounter);
layout->addDescriptorBinding(bindingCounter++, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
if(defaultValue != param.value().end())
{
std::string defaultString = defaultValue.value().get<std::string>();
p->data = AssetRegistry::findTexture(defaultString);
}
else
{
p->data = AssetRegistry::findTexture(""); // this will return placeholder texture
}
assert(p->data != nullptr);
parameters.add(p);
}
else if(type.compare("SamplerState") == 0)
{
PSamplerParameter p = new SamplerParameter(param.key(), 0, bindingCounter);
layout->addDescriptorBinding(bindingCounter++, Gfx::SE_DESCRIPTOR_TYPE_SAMPLER);
SamplerCreateInfo createInfo;
p->data = WindowManager::getGraphics()->createSamplerState(createInfo);
parameters.add(p);
}
else
{
std::cout << "Error unsupported parameter type" << std::endl;
}
codeStream << "\t" << type << " " << param.key() << ";\n";
}
uniformDataSize = uniformBufferOffset;
if(uniformDataSize != 0)
{
uniformData = new uint8[uniformDataSize];
UniformBufferCreateInfo uniformInitializer;
uniformInitializer.resourceData.data = uniformData;
uniformInitializer.resourceData.size = uniformDataSize;
uniformBuffer = WindowManager::getGraphics()->createUniformBuffer(uniformInitializer);
}
BRDF* brdf = BRDF::getBRDFByName(profile);
brdf->generateMaterialCode(codeStream, j["code"]);
codeStream << "};";
codeStream.close();
layout->create();
setStatus(Status::Ready);
}
const Gfx::ShaderCollection* Material::getShaders(Gfx::RenderPassType renderPass, VertexInputType* vertexInput) const
{
Gfx::ShaderPermutation permutation;
permutation.passType = renderPass;
std::string vertexInputName = vertexInput->getName();
std::memcpy(permutation.materialName, materialName.c_str(), sizeof(permutation.materialName));
std::memcpy(permutation.vertexInputName, vertexInputName.c_str(), sizeof(permutation.vertexInputName));
return shaderMap.findShaders(Gfx::PermutationId(permutation));
}
Gfx::ShaderCollection& Material::createShaders(Gfx::PGraphics graphics, Gfx::RenderPassType renderPass, VertexInputType* vertexInput)
{
std::lock_guard lock(shaderMapLock);
return shaderMap.createShaders(graphics, renderPass, this, vertexInput, false);
}
-34
View File
@@ -1,34 +0,0 @@
#pragma once
#include "MinimalEngine.h"
#include "MaterialAsset.h"
namespace Seele
{
class VertexInputType;
class Material : public MaterialAsset
{
public:
Material();
Material(const std::string &directory, const std::string &name);
Material(const std::filesystem::path& fullPath);
~Material();
virtual void save() override;
virtual void load() override;
virtual const Material* getRenderMaterial() const { return this; }
Gfx::PDescriptorLayout getDescriptorLayout() const { return layout; }
// The name of the generated material shader, opposed to the name of the .asset file
const std::string& getName() {return materialName;}
const Gfx::ShaderCollection* getShaders(Gfx::RenderPassType renderPass, VertexInputType* vertexInput) const;
Gfx::ShaderCollection& createShaders(Gfx::PGraphics graphics, Gfx::RenderPassType renderPass, VertexInputType* vertexInput);
void compile();
private:
static Gfx::ShaderMap shaderMap;
static std::mutex shaderMapLock;
std::string materialName;
friend class MaterialLoader;
friend class MaterialInstance;
};
DEFINE_REF(Material)
} // namespace Seele
+137 -3
View File
@@ -1,5 +1,16 @@
#include "MaterialAsset.h"
#include "Window/WindowManager.h"
#include "Asset/AssetRegistry.h"
#include "BRDF.h"
#include <nlohmann/json.hpp>
#include <sstream>
#include <iostream>
Gfx::ShaderMap MaterialAsset::shaderMap;
std::mutex MaterialAsset::shaderMapLock;
using namespace Seele;
using json = nlohmann::json;
using namespace Seele;
@@ -21,6 +32,118 @@ MaterialAsset::~MaterialAsset()
{
}
void MaterialAsset::save()
{
assert(false && "TODO");
}
void MaterialAsset::load()
{
setStatus(Status::Loading);
auto& stream = getReadStream();
json j;
stream >> j;
materialName = j["name"].get<std::string>();
layout = WindowManager::getGraphics()->createDescriptorLayout(materialName + "Layout");
//Shader file needs to conform to the slang standard, which prohibits _
materialName.erase(std::remove(materialName.begin(), materialName.end(), '_'), materialName.end());
std::ofstream codeStream("./shaders/generated/"+materialName+".slang");
std::string profile = j["profile"].get<std::string>();
codeStream << "import VERTEX_INPUT_IMPORT;" << std::endl;
codeStream << "import Material;" << std::endl;
codeStream << "import BRDF;" << std::endl;
codeStream << "import MaterialParameter;" << std::endl << std::endl;
codeStream << "struct " << materialName << " : IMaterial {" << std::endl;
uint32 uniformBufferOffset = 0;
uint32 bindingCounter = 0; // Uniform buffers are always binding 0
uniformBinding = -1;
for(auto param : j["params"].items())
{
std::string type = param.value()["type"].get<std::string>();
auto defaultValue = param.value().find("default");
if(type.compare("float") == 0)
{
PFloatParameter p = new FloatParameter(param.key(), uniformBufferOffset, 0);
codeStream << "\tlayout(offset = " << uniformBufferOffset << ")";
if(uniformBinding == -1)
{
layout->addDescriptorBinding(bindingCounter, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
uniformBinding = bindingCounter++;
}
uniformBufferOffset += 4;
if(defaultValue != param.value().end())
{
p->data = std::stof(defaultValue.value().get<std::string>());
}
parameters.add(p);
}
else if(type.compare("float3") == 0)
{
PVectorParameter p = new VectorParameter(param.key(), uniformBufferOffset, 0);
codeStream << "\tlayout(offset = " << uniformBufferOffset << ")";
if(uniformBinding == -1)
{
layout->addDescriptorBinding(bindingCounter, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
uniformBinding = bindingCounter++;
}
uniformBufferOffset += 12;
if(defaultValue != param.value().end())
{
p->data = parseVector(defaultValue.value().get<std::string>().c_str());
}
parameters.add(p);
}
else if(type.compare("Texture2D") == 0)
{
PTextureParameter p = new TextureParameter(param.key(), 0, bindingCounter);
layout->addDescriptorBinding(bindingCounter++, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
if(defaultValue != param.value().end())
{
std::string defaultString = defaultValue.value().get<std::string>();
p->data = AssetRegistry::findTexture(defaultString);
}
else
{
p->data = AssetRegistry::findTexture(""); // this will return placeholder texture
}
assert(p->data != nullptr);
parameters.add(p);
}
else if(type.compare("SamplerState") == 0)
{
PSamplerParameter p = new SamplerParameter(param.key(), 0, bindingCounter);
layout->addDescriptorBinding(bindingCounter++, Gfx::SE_DESCRIPTOR_TYPE_SAMPLER);
SamplerCreateInfo createInfo;
p->data = WindowManager::getGraphics()->createSamplerState(createInfo);
parameters.add(p);
}
else
{
std::cout << "Error unsupported parameter type" << std::endl;
}
codeStream << "\t" << type << " " << param.key() << ";\n";
}
uniformDataSize = uniformBufferOffset;
if(uniformDataSize != 0)
{
uniformData = new uint8[uniformDataSize];
UniformBufferCreateInfo uniformInitializer;
uniformInitializer.resourceData.data = uniformData;
uniformInitializer.resourceData.size = uniformDataSize;
uniformBuffer = WindowManager::getGraphics()->createUniformBuffer(uniformInitializer);
}
BRDF* brdf = BRDF::getBRDFByName(profile);
brdf->generateMaterialCode(codeStream, j["code"]);
codeStream << "};";
codeStream.close();
layout->create();
setStatus(Status::Ready);
}
void MaterialAsset::beginFrame()
{
}
@@ -48,7 +171,18 @@ void MaterialAsset::updateDescriptorData()
descriptorSet->writeChanges();
}
const Gfx::PDescriptorSet MaterialAsset::getDescriptor() const
const Gfx::ShaderCollection* MaterialAsset::getShaders(Gfx::RenderPassType renderPass, VertexInputType* vertexInput) const
{
return descriptorSet;
}
Gfx::ShaderPermutation permutation;
permutation.passType = renderPass;
std::string vertexInputName = vertexInput->getName();
std::memcpy(permutation.materialName, materialName.c_str(), sizeof(permutation.materialName));
std::memcpy(permutation.vertexInputName, vertexInputName.c_str(), sizeof(permutation.vertexInputName));
return shaderMap.findShaders(Gfx::PermutationId(permutation));
}
Gfx::ShaderCollection& MaterialAsset::createShaders(Gfx::PGraphics graphics, Gfx::RenderPassType renderPass, VertexInputType* vertexInput)
{
std::unique_lock lock(shaderMapLock);
return shaderMap.createShaders(graphics, renderPass, this, vertexInput, false);
}
+14 -6
View File
@@ -6,7 +6,6 @@
namespace Seele
{
DECLARE_REF(VertexShaderInput)
DECLARE_REF(Material)
class MaterialAsset : public Asset
{
public:
@@ -16,18 +15,26 @@ public:
~MaterialAsset();
virtual void beginFrame();
virtual void endFrame();
virtual void save() = 0;
virtual void load() = 0;
virtual const Material* getRenderMaterial() const = 0;
virtual void save() override;
virtual void load() override;
Gfx::SeBlendOp getBlendMode() const {return Gfx::SE_BLEND_OP_END_RANGE;}
Gfx::MaterialShadingModel getShadingModel() const {return Gfx::MaterialShadingModel::DefaultLit;}
// This needs to be called while the descriptorset is unused
void updateDescriptorData();
void resetDescriptorSet();
const Gfx::PDescriptorSet getDescriptor() const;
const Gfx::PDescriptorSet getDescriptor() const { return descriptorSet; };
Gfx::PDescriptorLayout getDescriptorLayout() const { return layout; }
// The name of the generated material shader, opposed to the name of the .asset file
const std::string& getName() {return materialName;}
const Gfx::ShaderCollection* getShaders(Gfx::RenderPassType renderPass, VertexInputType* vertexInput) const;
Gfx::ShaderCollection& createShaders(Gfx::PGraphics graphics, Gfx::RenderPassType renderPass, VertexInputType* vertexInput);
private:
static Gfx::ShaderMap shaderMap;
static std::mutex shaderMapLock;
protected:
//For now its simply the collection of parameters, since there is no point for expressions
Array<PShaderParameter> parameters;
Gfx::PDescriptorSet descriptorSet;
@@ -36,6 +43,7 @@ protected:
uint32 uniformDataSize;
uint8* uniformData;
int32 uniformBinding;
std::string materialName;
};
DEFINE_REF(MaterialAsset)
} // namespace Seele
-42
View File
@@ -1,42 +0,0 @@
#include "MaterialInstance.h"
#include "Material.h"
#include "Window/WindowManager.h"
using namespace Seele;
MaterialInstance::MaterialInstance()
{
}
MaterialInstance::MaterialInstance(const std::string& directory, const std::string& name)
: MaterialAsset(directory, name)
{
}
MaterialInstance::MaterialInstance(const std::filesystem::path& fullPath)
: MaterialAsset(fullPath)
{
}
MaterialInstance::~MaterialInstance()
{
}
void MaterialInstance::save()
{
}
void MaterialInstance::load()
{
baseMaterial = nullptr; // TODO: actually load the file
UniformBufferCreateInfo uniformInitializer;
uniformInitializer.resourceData.size = baseMaterial->uniformDataSize;
uniformInitializer.resourceData.data = nullptr;
uniformBuffer = WindowManager::getGraphics()->createUniformBuffer(uniformInitializer);
}
const Material* MaterialInstance::getRenderMaterial() const
{
return baseMaterial;
}
-22
View File
@@ -1,22 +0,0 @@
#pragma once
#include "MaterialAsset.h"
namespace Seele
{
DECLARE_NAME_REF(Gfx, DescriptorSet)
DECLARE_REF(Material)
class MaterialInstance : public MaterialAsset
{
public:
MaterialInstance();
MaterialInstance(const std::string& directory, const std::string& name);
MaterialInstance(const std::filesystem::path& fullPath);
~MaterialInstance();
virtual void save() override;
virtual void load() override;
virtual const Material* getRenderMaterial() const;
private:
Material* baseMaterial;
};
DEFINE_REF(MaterialInstance)
} // namespace Seele
@@ -9,7 +9,7 @@ CameraComponent::CameraComponent()
: bNeedsViewBuild(true)
, bNeedsProjectionBuild(true)
, originPoint(0, 0, 0)
, cameraPosition(0, 0, 0)
, cameraPosition(0, 0, 50)
{
distance = 50;
rotationX = 0;
@@ -1,6 +1,6 @@
#include "PrimitiveComponent.h"
#include "Scene/Scene.h"
#include "Material/MaterialInstance.h"
#include "Material/MaterialAsset.h"
#include "Asset/MeshAsset.h"
#include "Graphics/VertexShaderInput.h"
#include <iostream>
+1 -2
View File
@@ -1,8 +1,7 @@
#include "Scene.h"
#include "Components/PrimitiveComponent.h"
#include "Components/PrimitiveUniformBufferLayout.h"
#include "Material/MaterialInstance.h"
#include "Material/Material.h"
#include "Material/MaterialAsset.h"
#include "Graphics/Graphics.h"
using namespace Seele;
-1
View File
@@ -4,7 +4,6 @@
#include "Graphics/GraphicsResources.h"
#include "Components/PrimitiveComponent.h"
#include "Graphics/MeshBatch.h"
#include "Material/Material.h"
#include "SceneUpdater.h"
namespace Seele
+4 -4
View File
@@ -31,7 +31,7 @@ RenderHierarchy::~RenderHierarchy()
void RenderHierarchy::addElement(PElement addedElement)
{
std::lock_guard lock(updateLock);
std::unique_lock lock(updateLock);
updates.add(new AddElementRenderHierarchyUpdate{
addedElement.getHandle(),
addedElement->getParent().getHandle()
@@ -40,7 +40,7 @@ void RenderHierarchy::addElement(PElement addedElement)
void RenderHierarchy::removeElement(PElement elementToRemove)
{
std::lock_guard lock(updateLock);
std::unique_lock lock(updateLock);
updates.add(new RemoveElementRenderHierarchyUpdate{
elementToRemove.getHandle(),
});
@@ -48,7 +48,7 @@ void RenderHierarchy::removeElement(PElement elementToRemove)
void RenderHierarchy::moveElement(PElement elementToMove, PElement newParent)
{
std::lock_guard lock(updateLock);
std::unique_lock lock(updateLock);
updates.add(new AddElementRenderHierarchyUpdate{
elementToMove.getHandle(),
newParent.getHandle()
@@ -62,7 +62,7 @@ void RenderHierarchy::updateHierarchy()
{
List<RenderHierarchyUpdate*> localUpdates;
{ // make a local copy of the updates so we dont hold the lock for too long
std::lock_guard lock(updateLock);
std::unique_lock lock(updateLock);
localUpdates = updates;
updates.clear();
}
-2
View File
@@ -1,7 +1,5 @@
target_sources(SeeleEngine
PRIVATE
Frame.h
Frame.cpp
InspectorView.h
InspectorView.cpp
SceneView.h
View File
-18
View File
@@ -1,18 +0,0 @@
#pragma once
#include "View.h"
namespace Seele
{
// A frame is the mutable data needed to
// process a time step for the game updates
// It contains all the game update relevant data
// and is handed over to the renderer for read only processing
// If the game loop runs faster than the renderer, the renderer
// simply discards old Frames and starts working on the more recent ones
// if the game loop runs slower than the renderer (bad), the renderer has to wait
struct Frame
{
uint64 frameNumber;
Array<PViewFrame> viewFrame;
};
} // namespace Seele
+4 -8
View File
@@ -25,10 +25,10 @@ void Window::render()
gfxHandle->beginFrame();
for(auto& windowView : views)
{
{
std::lock_guard lock(windowView->workerMutex);
windowView->view->prepareRender();
}
windowView->view->beginUpdate();
windowView->view->update();
windowView->view->commitUpdate();
windowView->view->prepareRender();
windowView->view->render();
}
gfxHandle->endFrame();
@@ -58,9 +58,5 @@ void Window::viewWorker(WindowView* windowView)
{
while(true)
{
windowView->view->beginUpdate();
windowView->view->update();
std::lock_guard lock(windowView->workerMutex);
windowView->view->commitUpdate();
}
}