diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 3cefb53..2aa4868 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,7 +3,8 @@ { "name": "Win32", "includePath": [ - "${workspaceFolder}/**" + "${workspaceFolder}/**", + "${VULKAN_SDK}\\Include" ], "defines": [ "_DEBUG", @@ -13,7 +14,13 @@ "windowsSdkVersion": "10.0.18362.0", "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.25.28610/bin/Hostx64/x64/cl.exe", "intelliSenseMode": "msvc-x64", - "configurationProvider": "ms-vscode.cmake-tools" + "configurationProvider": "ms-vscode.cmake-tools", + "cppStandard": "c++17", + "browse": { + "path": [ + "${VULKAN_SDK}/**" + ] + } } ], "version": 4 diff --git a/.vscode/settings.json b/.vscode/settings.json index d21560e..954fc30 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -111,5 +111,7 @@ "cmake.skipConfigureIfCachePresent": false, "cmake.configureArgs": [ "-Wno-dev" - ] + ], + "C_Cpp.default.cppStandard": "c++17", + "C_Cpp.default.intelliSenseMode": "msvc-x64" } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 55c90b7..6b0b2fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD 17) # Handle superbuild first option (USE_SUPERBUILD "Whether or not a superbuild should be invoked" ON) + set(ENGINE_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/src/Engine) set(EXTERNAL_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/external) set(ASSIMP_ROOT ${EXTERNAL_ROOT}/assimp) @@ -14,12 +15,18 @@ set(GLM_ROOT ${EXTERNAL_ROOT}/glm) set(GLFW_ROOT ${EXTERNAL_ROOT}/glfw) set(JSON_ROOT ${EXTERNAL_ROOT}/json) set(STB_ROOT ${EXTERNAL_ROOT}/stb) +set(SPIRV_ROOT ${EXTERNAL_ROOT}/SPIRV-Cross) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/) set(Boost_USE_STATIC_LIBS ON) 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 +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/bin/Debug) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/bin/Release) + if (USE_SUPERBUILD) project (SUPERBUILD NONE) # execute the superbuild (this script will be invoked again without the @@ -30,26 +37,25 @@ else() project (Seele) endif() -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}) -#Workaround for vs, because it places artifacts into an additional subfolder -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/bin/Debug) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/bin/Release) find_package(Vulkan REQUIRED) find_package(Boost REQUIRED COMPONENTS serialization) find_package(Threads REQUIRED) -find_package(assimp REQUIRED ${ASSIMP_ROOT}) +find_package(assimp REQUIRED) find_package(JSON REQUIRED) find_package(GLFW REQUIRED) +find_package(SPIRV REQUIRED) include_directories(${GLM_INCLUDE_DIRS}) include_directories(${STB_INCLUDE_DIRS}) include_directories(${Vulkan_INCLUDE_DIR}) +include_directories(${SPIRV_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS}) include_directories(${GLFW_INCLUDE_DIRS}) include_directories(${SLANG_INCLUDE_DIRS}) include_directories(${ASSIMP_INCLUDE_DIRS}) include_directories(${JSON_INCLUDE_DIRS}) +include_directories(${SPIRV_INCLUDE_DIRS}) include_directories(${ENGINE_ROOT}) include_directories(src/Engine) add_definitions(${GLM_DEFINITIONS}) @@ -66,6 +72,7 @@ target_link_libraries(SeeleEngine ${GLFW_LIBRARIES}) target_link_libraries(SeeleEngine ${SLANG_LIBRARY}) target_link_libraries(SeeleEngine ${ASSIMP_LIBRARIES}) target_link_libraries(SeeleEngine ${JSON_LIBRARY}) +target_link_libraries(SeeleEngine ${SPIRV_LIBRARIES}) #target_precompile_headers(SeeleEngine # PRIVATE diff --git a/cmake-variants.json b/cmake-variants.json index 0b3c911..31d9d3a 100644 --- a/cmake-variants.json +++ b/cmake-variants.json @@ -6,7 +6,10 @@ "debug": { "short": "Debug", "long": "Enable debugging and validation", - "buildType": "Debug" + "buildType": "Debug", + "settings": { + "CMAKE_DEBUG_POSTFIX": "d" + } }, "release": { "short": "Release", diff --git a/cmake/FindAssimp.cmake b/cmake/FindAssimp.cmake index d825b15..320418c 100644 --- a/cmake/FindAssimp.cmake +++ b/cmake/FindAssimp.cmake @@ -26,19 +26,17 @@ if (WIN32) # Find library files find_library( ASSIMP_LIBRARY - NAMES assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.lib + NAMES assimp-vc${MSVC_TOOLSET_VERSION}-mt${CMAKE_DEBUG_POSTFIX} PATHS $ENV{PROGRAMFILES}/lib - ${ASSIMP_ROOT}/lib/ - PATH_SUFFIXES Debug Release) + ${ASSIMP_ROOT}/lib/) find_file( ASSIMP_BINARY - NAMES assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.dll + NAMES assimp-vc${MSVC_TOOLSET_VERSION}-mt${CMAKE_DEBUG_POSTFIX}.dll PATHS $ENV{PROGRAMFILES}/bin - ${ASSIMP_ROOT}/bin/ - PATH_SUFFIXES Debug Release) + ${ASSIMP_ROOT}/bin/) else() # Find include files find_path( diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index 5caa755..26e4601 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -8,7 +8,7 @@ set(ASSIMP_BUILD_TESTS OFF CACHE INTERNAL "") set(ASSIMP_BUILD_ASSIMP_TOOLS OFF CACHE INTERNAL "") set(ASSIMP_INSTALL OFF CACHE INTERNAL "") -add_subdirectory(${ASSIMP_ROOT} ${ASSIMP_ROOT}) +add_subdirectory(${ASSIMP_ROOT} ${}) target_compile_definitions(assimp PRIVATE _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING) #-------------BOOST---------------- @@ -97,6 +97,18 @@ list(APPEND EXTRA_CMAKE_ARGS -DSLANG_BINARY=${SLANG_BINARY} -DSLANG_GLSLANG=${SLANG_GLSLANG}) + +#----------------SPIR-V-CROSS-------------------- +list(APPEND DEPENDENCIES spirv-cross-reflect) +set(SPIRV_CROSS_ENABLE_HLSL OFF CACHE BOOL "") +set(SPIRV_CROSS_ENABLE_TESTS OFF CACHE BOOL "") +set(SPIRV_CROSS_CLI OFF CACHE BOOL "") +set(SPIRV_CROSS_ENABLE_C_API OFF CACHE BOOL "") +set(SPIRV_CROSS_ENABLE_UTIL OFF CACHE BOOL "") +set(SPIRV_CROSS_SKIP_INSTALL ON CACHE BOOL "") +add_subdirectory(${SPIRV_ROOT}) + + #-----------------SeeleEngine-------------------- ExternalProject_Add(SeeleEngine DEPENDS ${DEPENDENCIES} diff --git a/external/slang b/external/slang index bc0d0f9..83514bd 160000 --- a/external/slang +++ b/external/slang @@ -1 +1 @@ -Subproject commit bc0d0f9e2a5a7297d8559a2ee1e3bd59454813cf +Subproject commit 83514bd25160a9af91abc1b9acd7e44657447526 diff --git a/res/shaders/DepthPrepass.slang b/res/shaders/DepthPrepass.slang index ec3260e..39f5603 100644 --- a/res/shaders/DepthPrepass.slang +++ b/res/shaders/DepthPrepass.slang @@ -1,30 +1,14 @@ +import Common; import Material; import VERTEX_INPUT_IMPORT; import MATERIAL_IMPORT; - -struct ViewParams -{ - float4x4 viewMatrix; - float4x4 projectionMatrix; - float4 cameraPos_WS; -}; - -layout(set = 0, binding = 0) -ParameterBlock gViewParams; - - -layout(set = 1) -type_param TMaterial : IMaterial; -ParameterBlock gMaterial; +import PrimitiveSceneData; struct ModelParameter { float4x4 modelMatrix; } -[[vk::push_constant]] -ConstantBuffer gModelParams; - struct VertexStageOutput { float4 position : SV_Position; diff --git a/res/shaders/ForwardPlus.slang b/res/shaders/ForwardPlus.slang index 732b9c5..14fc7c2 100644 --- a/res/shaders/ForwardPlus.slang +++ b/res/shaders/ForwardPlus.slang @@ -1,7 +1,7 @@ +import Common; import LightEnv; import BRDF; import Material; -import Common; import VERTEX_INPUT_IMPORT; import MATERIAL_IMPORT; @@ -13,9 +13,6 @@ import MaterialParameter; //layout(set = 0, binding = 3) //RWTexture2D lightGrid; -type_param TMaterial : IMaterial; -layout(set = 1) -ParameterBlock gMaterial; struct VertexStageOutput { @@ -31,9 +28,10 @@ VertexStageOutput vertexMain( VertexStageOutput output; VertexValueCache cache = input.getVertexCache(); float3 worldPosition = input.getWorldPosition(); + worldPosition += gMaterial.getWorldOffset(); float4 clipSpacePosition; - float3x3 tangentToLocal = cache.tangentToLocal; + float3x3 tangentToLocal = cache.getTangentToLocal(); MaterialVertexParameter vertexParams = input.getMaterialVertexParameters(cache, worldPosition, tangentToLocal); float4 viewSpacePosition = mul(gViewParams.viewMatrix, float4(worldPosition, 1)); @@ -75,5 +73,5 @@ float4 fragmentMain( } - return float4(0, 1, 0, 1); + return float4(result, 1); } diff --git a/res/shaders/lib/Common.slang b/res/shaders/lib/Common.slang index 086f79b..fd8fc74 100644 --- a/res/shaders/lib/Common.slang +++ b/res/shaders/lib/Common.slang @@ -2,17 +2,28 @@ const static float PI = 3.1415926535897932f; const static uint MAX_PARTICLES = 65536; const static uint BLOCK_SIZE = 8; -cbuffer ScreenToViewParams +struct ViewParameter +{ + float4x4 viewMatrix; + float4x4 projectionMatrix; + float4 cameraPos_WS; +} +layout(set = 1, binding = 0, std430) +ConstantBuffer gViewParams; + +struct ScreenToViewParams { float4x4 inverseProjection; float2 screenDimensions; } +layout(set = 1, binding = 1, std430) +ConstantBuffer gScreenToViewParams; // Convert clip space coordinates to view space float4 clipToView( float4 clip ) { // View space position. - float4 view = mul( inverseProjection, clip ); + float4 view = mul( gScreenToViewParams.inverseProjection, clip ); // Perspective projection. view = view / view.w; @@ -23,7 +34,7 @@ float4 clipToView( float4 clip ) float4 screenToView( float4 screen ) { // Convert to normalized texture coordinates - float2 texCoord = screen.xy / screenDimensions; + float2 texCoord = screen.xy / gScreenToViewParams.screenDimensions; // Convert to clip space float4 clip = float4( float2( texCoord.x, -texCoord.y ) * 2.0f - 1.0f, screen.z, screen.w ); diff --git a/res/shaders/lib/LightEnv.slang b/res/shaders/lib/LightEnv.slang index 66f4251..a70b4ba 100644 --- a/res/shaders/lib/LightEnv.slang +++ b/res/shaders/lib/LightEnv.slang @@ -23,28 +23,27 @@ struct PointLight : ILightEnv { float4 positionWS; float4 positionVS; - float3 color; - float range; - + float4 colorRange; + float3 illuminate(MaterialFragmentParameter input, B brdf, float3 viewDir) { float3 lightVec = positionWS.xyz - input.worldPosition; float d = length(lightVec); float3 direction = normalize(lightVec); - float illuminance = max(1 - d / range, 0); - return illuminance * brdf.evaluate(viewDir, direction, input.worldNormal, input.worldTangent, input.worldBiTangent, color); + float illuminance = max(1 - d / colorRange.w, 0); + return illuminance * brdf.evaluate(viewDir, direction, input.worldNormal, input.worldTangent, input.worldBiTangent, colorRange.xyz); } bool insidePlane(Plane plane) { - return dot(plane.n, positionVS.xyz) - plane.d < -range; + return dot(plane.n, positionVS.xyz) - plane.d < -colorRange.w; } bool insideFrustum(Frustum frustum, float zNear, float zFar) { bool result = true; - //if(positionVS.z - range > zNear || positionVS.z + range < zFar) + //if(positionVS.z - range > zNear || positionVS.z + colorRange.w < zFar) { // result = false; } @@ -69,5 +68,5 @@ struct Lights uint numPointLights; }; -layout(set = 0, binding = 1) +layout(set = 0, binding = 0, std430) ConstantBuffer gLightEnv; diff --git a/res/shaders/lib/Material.slang b/res/shaders/lib/Material.slang index 4ce6639..9a343c1 100644 --- a/res/shaders/lib/Material.slang +++ b/res/shaders/lib/Material.slang @@ -16,3 +16,7 @@ interface IMaterial float getRoughness(MaterialFragmentParameter input); float getSheen(MaterialFragmentParameter input); }; + +type_param TMaterial : IMaterial; +layout(set = 2, binding = 0, std430) +ParameterBlock gMaterial; diff --git a/res/shaders/lib/MaterialParameter.slang b/res/shaders/lib/MaterialParameter.slang index 1dba517..6ec555a 100644 --- a/res/shaders/lib/MaterialParameter.slang +++ b/res/shaders/lib/MaterialParameter.slang @@ -44,4 +44,3 @@ struct MaterialFragmentParameter } }; - diff --git a/res/shaders/lib/PrimitiveSceneData.slang b/res/shaders/lib/PrimitiveSceneData.slang index cfadc45..cd6e162 100644 --- a/res/shaders/lib/PrimitiveSceneData.slang +++ b/res/shaders/lib/PrimitiveSceneData.slang @@ -4,16 +4,5 @@ struct PrimitiveSceneData float4x4 worldToLocal; }; - -struct ViewParameter -{ - float4x4 viewMatrix; - float4x4 projectionMatrix; - float4 cameraPos_WS; -}; -layout(set = 0) -ConstantBuffer gViewParams; - -layout(set = 2) +layout(set = 3, binding = 0, std430) ConstantBuffer gSceneData; - diff --git a/res/shaders/lib/StaticMeshVertexInput.slang b/res/shaders/lib/StaticMeshVertexInput.slang index 89ca563..bc1d7c0 100644 --- a/res/shaders/lib/StaticMeshVertexInput.slang +++ b/res/shaders/lib/StaticMeshVertexInput.slang @@ -1,13 +1,30 @@ +import Common; import MaterialParameter; import PrimitiveSceneData; struct VertexValueCache { - float3x3 tangentToLocal; - float3x3 tangentToWorld; + //This struct is passed between vertex and fragment stage + //which means, that it is passed as out mat3x3 in glsl + //but Slang for some reason puts a layout(row_major) above + //every attribute, including this matrix, but matrix layout + //qualifiers are illegal for non-uniform and buffer fields, + //leading to a compiler error + float3 tangentToLocal[3]; + float3 tangentToWorld[3]; float tangentToWorldSign; float4 color; + float3x3 getTangentToLocal() + { + return float3x3(tangentToLocal[0], tangentToLocal[1], tangentToLocal[2]); + } + + float3x3 getTangentToWorld() + { + return float3x3(tangentToWorld[0], tangentToWorld[1], tangentToWorld[2]); + } + #if USE_INSTANCING float4 instanceOrigin; float3 instanceTransform1; @@ -133,9 +150,15 @@ struct VertexShaderInput #endif float tangentSign; - cache.tangentToLocal = calcTangentToLocal(tangentSign); + float3x3 tangentToLocal = calcTangentToLocal(tangentSign); + cache.tangentToLocal[0] = tangentToLocal[0]; + cache.tangentToLocal[1] = tangentToLocal[1]; + cache.tangentToLocal[2] = tangentToLocal[2]; float3x3 localToWorld = float3x3(gSceneData.localToWorld[0].xyz, gSceneData.localToWorld[1].xyz, gSceneData.localToWorld[2].xyz); - cache.tangentToWorld = mul(cache.tangentToLocal, localToWorld); + float3x3 tangentToWorld = mul(tangentToLocal, localToWorld); + cache.tangentToWorld[0] = tangentToWorld[0]; + cache.tangentToWorld[1] = tangentToWorld[1]; + cache.tangentToWorld[2] = tangentToWorld[2]; cache.tangentToWorldSign = tangentSign; return cache; @@ -146,7 +169,7 @@ struct VertexShaderInput MaterialVertexParameter result; result.worldPosition = worldPosition; result.vertexColor = cache.color; - result.tangentToWorld = cache.tangentToWorld; + result.tangentToWorld = cache.getTangentToWorld(); // TODO instancing /*for(int i = 0; i < NUM_MATERIAL_TEXCOORDS-1; i+=2) { diff --git a/src/Engine/Asset/AssetRegistry.cpp b/src/Engine/Asset/AssetRegistry.cpp index b6ca24c..43e4ce6 100644 --- a/src/Engine/Asset/AssetRegistry.cpp +++ b/src/Engine/Asset/AssetRegistry.cpp @@ -24,7 +24,6 @@ void AssetRegistry::importFile(const std::string &filePath) { std::filesystem::path fsPath = std::filesystem::path(filePath); std::string extension = fsPath.extension().string(); - std::cout << extension << std::endl; if (extension.compare(".fbx") == 0 || extension.compare(".obj") == 0) { @@ -46,6 +45,16 @@ PMeshAsset AssetRegistry::findMesh(const std::string &filePath) return get().meshes[filePath]; } +PTextureAsset AssetRegistry::findTexture(const std::string &filePath) +{ + PTextureAsset result = get().textures[filePath]; + if(result == nullptr) + { + return get().textureLoader->getPlaceholderTexture(); + } + return result; +} + PMaterialAsset AssetRegistry::findMaterial(const std::string &filePath) { return get().materials[filePath]; @@ -61,11 +70,6 @@ std::ifstream AssetRegistry::createReadStream(const std::string& relativePath, s return get().internalCreateReadStream(relativePath, openmode); } -PTextureAsset AssetRegistry::findTexture(const std::string &filePath) -{ - return get().textures[filePath]; -} - AssetRegistry &AssetRegistry::get() { static AssetRegistry instance; @@ -122,6 +126,11 @@ void AssetRegistry::registerMesh(PMeshAsset mesh) } } +void AssetRegistry::registerMaterial(PMaterialAsset material) +{ + materials[material->getFileName()] = material; +} + std::ofstream AssetRegistry::internalCreateWriteStream(const std::string& relativePath, std::ios_base::openmode openmode) { return std::ofstream(rootFolder.generic_string().append(relativePath), openmode); diff --git a/src/Engine/Asset/MaterialLoader.cpp b/src/Engine/Asset/MaterialLoader.cpp index 29164dd..e7c9406 100644 --- a/src/Engine/Asset/MaterialLoader.cpp +++ b/src/Engine/Asset/MaterialLoader.cpp @@ -1,6 +1,7 @@ #include "MaterialLoader.h" #include "Material/Material.h" #include "Graphics/Graphics.h" +#include "AssetRegistry.h" using namespace Seele; @@ -21,7 +22,13 @@ PMaterial MaterialLoader::queueAsset(const std::filesystem::path& filePath) PMaterial result = new Material(filePath); result->compile(); graphics->getShaderCompiler()->registerMaterial(result); + AssetRegistry::get().registerMaterial(result); // TODO: There is actually no real reason to import a standalone material, // maybe in the future there could be a substance loader or something return result; } + +PMaterial MaterialLoader::getPlaceHolderMaterial() +{ + return placeholderMaterial; +} diff --git a/src/Engine/Asset/MaterialLoader.h b/src/Engine/Asset/MaterialLoader.h index c4b954c..771b846 100644 --- a/src/Engine/Asset/MaterialLoader.h +++ b/src/Engine/Asset/MaterialLoader.h @@ -15,6 +15,7 @@ public: MaterialLoader(Gfx::PGraphics graphic); ~MaterialLoader(); PMaterial queueAsset(const std::filesystem::path& filePath); + PMaterial getPlaceHolderMaterial(); private: Gfx::PGraphics graphics; List> futures; diff --git a/src/Engine/Asset/MeshLoader.cpp b/src/Engine/Asset/MeshLoader.cpp index 80d98ca..d48d42f 100644 --- a/src/Engine/Asset/MeshLoader.cpp +++ b/src/Engine/Asset/MeshLoader.cpp @@ -33,7 +33,7 @@ void MeshLoader::importAsset(const std::filesystem::path &path) import(path); } -void loadMaterials(const aiScene* scene, Array& globalMaterials, Gfx::PGraphics graphics) +void MeshLoader::loadMaterials(const aiScene* scene, Array& globalMaterials, Gfx::PGraphics graphics) { using json = nlohmann::json; for(uint32 i = 0; i < scene->mNumMaterials; ++i) @@ -42,7 +42,6 @@ void loadMaterials(const aiScene* scene, Array& globalMaterials, json matCode; matCode["name"] = material->GetName().C_Str(); matCode["profile"] = "BlinnPhong"; //TODO: other shading models - std::vector code; aiString texPath; //TODO make samplers based on used textures matCode["params"]["texSampler"] = @@ -57,7 +56,7 @@ void loadMaterials(const aiScene* scene, Array& globalMaterials, {"type", "Texture2D"}, {"default", texPath.C_Str()} }; - code.push_back("result.baseColor = diffuseTexture.Sample(textureSampler, geometry.texCoord).xyz;\n"); + matCode["code"]["baseColor"] = "return diffuseTexture.Sample(textureSampler, geometry.texCoord).xyz;"; } if(material->GetTexture(aiTextureType_SPECULAR, 0, &texPath) == AI_SUCCESS) { @@ -67,7 +66,7 @@ void loadMaterials(const aiScene* scene, Array& globalMaterials, {"type", "Texture2D"}, {"default", texPath.C_Str()} }; - code.push_back("result.specular = specularTexture.Sample(textureSampler, geometry.texCoord).xyz;\n"); + matCode["code"]["specular"] = "return specularTexture.Sample(textureSampler, geometry.texCoord).xyz;"; } if(material->GetTexture(aiTextureType_NORMALS, 0, &texPath) == AI_SUCCESS) { @@ -77,21 +76,20 @@ void loadMaterials(const aiScene* scene, Array& globalMaterials, {"type", "Texture2D"}, {"default", texPath.C_Str()} }; - code.push_back("float3 bumpMapNormal = normalTexture.Sample(textureSampler, geometry.texCoord).xyz;\n"); - code.push_back("bumpMapNormal = 2.0 * bumpMapNormal - float3(1.0f, 1.0f, 1.0f);\n"); - code.push_back("result.normal = geometry.transformLocalToWorld(bumpMapNormal);\n"); + matCode["code"]["normal"] = "return normalTexture.Sample(textureSampler, geometry.texCoord).xyz;"; } - code.push_back("return result;\n"); - matCode["code"] = code; std::string outMatFilename = matCode["name"].get().append(".asset"); std::ofstream outMatFile = AssetRegistry::createWriteStream(outMatFilename); outMatFile << std::setw(4) << matCode; outMatFile.flush(); outMatFile.close(); //TODO: let the material loader handle this instead - std::cout << matCode["name"] << std::endl; - AssetRegistry::importFile(outMatFilename); - PMaterialAsset asset = AssetRegistry::findMaterial(outMatFilename); + //std::cout << matCode << std::endl; + PMaterial result = new Material(outMatFilename); + result->compile(); + graphics->getShaderCompiler()->registerMaterial(result); + AssetRegistry::get().registerMaterial(result); + PMaterialAsset asset = AssetRegistry::findMaterial(result->getFileName()); globalMaterials[i] = asset; } } @@ -148,35 +146,38 @@ VertexStreamComponent createVertexStream(uint32 size, aiVector2D* sourceData, Gf Gfx::PVertexBuffer vertexBuffer = graphics->createVertexBuffer(vbInfo); return VertexStreamComponent(vertexBuffer, 0, vbInfo.vertexSize, Gfx::SE_FORMAT_R32G32_SFLOAT); } -void loadGlobalMeshes(const aiScene* scene, Array& globalMeshes, Array materials, Gfx::PGraphics graphics) +void MeshLoader::loadGlobalMeshes(const aiScene* scene, Array& globalMeshes, Array materials, Gfx::PGraphics graphics) { for (uint32 meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) { aiMesh *mesh = scene->mMeshes[meshIndex]; PStaticMeshVertexInput vertexShaderInput = new StaticMeshVertexInput(std::string(mesh->mName.C_Str())); - VertexStreamComponent positionStream = createVertexStream(mesh->mNumVertices, mesh->mVertices, graphics); - vertexShaderInput->setPositionStream(positionStream); + StaticMeshDataType data; + data.positionStream = createVertexStream(mesh->mNumVertices, mesh->mVertices, graphics); for(uint32 i = 0; i < MAX_TEXCOORDS; ++i) { if(mesh->HasTextureCoords(i)) { - VertexStreamComponent texCoordStream = createVertexStream(mesh->mNumVertices, mesh->mTextureCoords[i], graphics); - vertexShaderInput->setTexCoordStream(i, texCoordStream); + data.textureCoordinates.add(createVertexStream(mesh->mNumVertices, mesh->mTextureCoords[i], graphics)); } } if(mesh->HasNormals()) { - VertexStreamComponent normalStream = createVertexStream(mesh->mNumVertices, mesh->mNormals, graphics); - vertexShaderInput->setTangentXStream(normalStream); + data.tangentBasisComponents[0] = createVertexStream(mesh->mNumVertices, mesh->mNormals, graphics); } if(mesh->HasTangentsAndBitangents()) { //TODO: use bitangent to calculate sign for 4th coordinate of tangentstream - VertexStreamComponent tangentStream = createVertexStream(mesh->mNumVertices, mesh->mTangents, graphics); - vertexShaderInput->setTangentZStream(tangentStream); + data.tangentBasisComponents[1] = createVertexStream(mesh->mNumVertices, mesh->mTangents, graphics); } + if(mesh->HasVertexColors(0)) + { + //data.colorComponent = createVertexStream(mesh->mNumVertices, mesh->mColors[0], graphics); + } + vertexShaderInput->setData(data); + vertexShaderInput->init(graphics); Array indices(mesh->mNumFaces * 3); for (uint32 faceIndex = 0; faceIndex < mesh->mNumFaces; ++faceIndex) @@ -197,7 +198,7 @@ void loadGlobalMeshes(const aiScene* scene, Array& globalMeshes, ArrayreferencedMaterial = materials[mesh->mMaterialIndex]; } } -void convertAssimpARGB(unsigned char* dst, aiTexel* src, uint32 numPixels) +void MeshLoader::convertAssimpARGB(unsigned char* dst, aiTexel* src, uint32 numPixels) { for(uint32 i = 0; i < numPixels; ++i) { @@ -207,7 +208,7 @@ void convertAssimpARGB(unsigned char* dst, aiTexel* src, uint32 numPixels) dst[i * 4 + 3] = src[i].a; } } -void loadTextures(const aiScene* scene, Gfx::PGraphics graphics, const std::filesystem::path& meshPath) +void MeshLoader::loadTextures(const aiScene* scene, Gfx::PGraphics graphics, const std::filesystem::path& meshPath) { for (uint32 i = 0; i < scene->mNumTextures; ++i) { diff --git a/src/Engine/Asset/MeshLoader.h b/src/Engine/Asset/MeshLoader.h index 485d996..cf30454 100644 --- a/src/Engine/Asset/MeshLoader.h +++ b/src/Engine/Asset/MeshLoader.h @@ -5,9 +5,13 @@ #include #include +struct aiScene; +struct aiTexel; namespace Seele { -DECLARE_REF(MeshAsset) +DECLARE_REF(Mesh); +DECLARE_REF(MeshAsset); +DECLARE_REF(MaterialAsset); DECLARE_NAME_REF(Gfx, Graphics); class MeshLoader { @@ -16,6 +20,11 @@ public: ~MeshLoader(); void importAsset(const std::filesystem::path& filePath); private: + void loadMaterials(const aiScene* scene, Array& globalMaterials, Gfx::PGraphics graphics); + void loadTextures(const aiScene* scene, Gfx::PGraphics graphics, const std::filesystem::path& meshPath); + void loadGlobalMeshes(const aiScene* scene, Array& globalMeshes, Array materials, Gfx::PGraphics graphics); + void convertAssimpARGB(unsigned char* dst, aiTexel* src, uint32 numPixels); + void import(const std::filesystem::path& path); List> futures; Gfx::PGraphics graphics; diff --git a/src/Engine/Asset/TextureLoader.cpp b/src/Engine/Asset/TextureLoader.cpp index b9d3393..7b41239 100644 --- a/src/Engine/Asset/TextureLoader.cpp +++ b/src/Engine/Asset/TextureLoader.cpp @@ -12,7 +12,10 @@ using namespace Seele; TextureLoader::TextureLoader(Gfx::PGraphics graphics) : graphics(graphics) { + placeholderAsset = new TextureAsset(); placeholderTexture = import("./textures/placeholder.png"); + placeholderAsset->setTexture(placeholderTexture); + placeholderAsset->setStatus(Asset::Status::Ready); } TextureLoader::~TextureLoader() @@ -26,11 +29,16 @@ void TextureLoader::importAsset(const std::filesystem::path& filePath) asset->setStatus(Asset::Status::Loading); asset->setTexture(placeholderTexture); AssetRegistry::get().textures[filePath.string()] = asset; - futures.add(std::async(std::launch::async, [this, filePath, asset] () mutable { + //futures.add(std::async(std::launch::async, [this, filePath, asset] () mutable { Gfx::PTexture2D texture = import(filePath); asset->setTexture(texture); asset->setStatus(Asset::Status::Ready); - })); + //})); +} + +PTextureAsset TextureLoader::getPlaceholderTexture() +{ + return placeholderAsset; } Gfx::PTexture2D TextureLoader::import(const std::filesystem::path& path) diff --git a/src/Engine/Asset/TextureLoader.h b/src/Engine/Asset/TextureLoader.h index ea2baa5..04cd5df 100644 --- a/src/Engine/Asset/TextureLoader.h +++ b/src/Engine/Asset/TextureLoader.h @@ -16,11 +16,13 @@ public: TextureLoader(Gfx::PGraphics graphic); ~TextureLoader(); void importAsset(const std::filesystem::path& filePath); + PTextureAsset getPlaceholderTexture(); private: Gfx::PTexture2D import(const std::filesystem::path& path); Gfx::PGraphics graphics; List> futures; Gfx::PTexture2D placeholderTexture; + PTextureAsset placeholderAsset; }; DEFINE_REF(TextureLoader); } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Containers/Array.h b/src/Engine/Containers/Array.h index 442644e..135e28f 100644 --- a/src/Engine/Containers/Array.h +++ b/src/Engine/Containers/Array.h @@ -229,6 +229,15 @@ namespace Seele refreshIterators(); return _data[arraySize - 1]; } + T &addUnique(const T &item = T()) + { + Iterator it; + if((it = find(item)) != endIt) + { + return *it; + } + return add(item); + } template T &emplace(args...) { @@ -291,6 +300,22 @@ namespace Seele } refreshIterators(); } + inline uint32 indexOf(Iterator iterator) + { + return iterator - beginIt; + } + inline uint32 indexOf(ConstIterator iterator) const + { + return iterator.p - beginIt.p; + } + inline uint32 indexOf(T& t) + { + return indexOf(find(t)); + } + inline uint32 indexOf(const T& t) const + { + return indexOf(find(t)); + } inline uint32 size() const { return arraySize; diff --git a/src/Engine/Graphics/Graphics.cpp b/src/Engine/Graphics/Graphics.cpp index d4a1d15..9b55e72 100644 --- a/src/Engine/Graphics/Graphics.cpp +++ b/src/Engine/Graphics/Graphics.cpp @@ -10,4 +10,19 @@ Graphics::Graphics() Graphics::~Graphics() { +} + +PVertexBuffer Graphics::getNullVertexBuffer() +{ + if(nullVertexBuffer == nullptr) + { + VertexBufferCreateInfo createInfo; + createInfo.numVertices = 1; + createInfo.vertexSize = sizeof(Vector4); + Vector4 data = Vector4(1, 1, 1, 1); + createInfo.resourceData.data = reinterpret_cast(&data); + createInfo.resourceData.size = sizeof(Vector4); + nullVertexBuffer = createVertexBuffer(createInfo); + } + return nullVertexBuffer; } \ No newline at end of file diff --git a/src/Engine/Graphics/Graphics.h b/src/Engine/Graphics/Graphics.h index f469ad5..af5c3f7 100644 --- a/src/Engine/Graphics/Graphics.h +++ b/src/Engine/Graphics/Graphics.h @@ -41,17 +41,22 @@ public: virtual PVertexBuffer createVertexBuffer(const VertexBufferCreateInfo &bulkData) = 0; virtual PIndexBuffer createIndexBuffer(const IndexBufferCreateInfo &bulkData) = 0; virtual PRenderCommand createRenderCommand() = 0; + virtual PVertexDeclaration createVertexDeclaration(const Array& element) = 0; virtual PVertexShader createVertexShader(const ShaderCreateInfo& createInfo) = 0; virtual PControlShader createControlShader(const ShaderCreateInfo& createInfo) = 0; virtual PEvaluationShader createEvaluationShader(const ShaderCreateInfo& createInfo) = 0; virtual PGeometryShader createGeometryShader(const ShaderCreateInfo& createInfo) = 0; virtual PFragmentShader createFragmentShader(const ShaderCreateInfo& createInfo) = 0; virtual PGraphicsPipeline createGraphicsPipeline(const GraphicsPipelineCreateInfo& createInfo) = 0; - - virtual Gfx::PDescriptorLayout createDescriptorLayout() = 0; - virtual Gfx::PPipelineLayout createPipelineLayout() = 0; + virtual PSamplerState createSamplerState(const SamplerCreateInfo& createInfo) = 0; + + virtual PDescriptorLayout createDescriptorLayout() = 0; + virtual PPipelineLayout createPipelineLayout() = 0; + + PVertexBuffer getNullVertexBuffer(); protected: + PVertexBuffer nullVertexBuffer; QueueFamilyMapping queueMapping; PShaderCompiler shaderCompiler; friend class Window; diff --git a/src/Engine/Graphics/GraphicsEnums.h b/src/Engine/Graphics/GraphicsEnums.h index 43391ed..dbbe085 100644 --- a/src/Engine/Graphics/GraphicsEnums.h +++ b/src/Engine/Graphics/GraphicsEnums.h @@ -7,6 +7,7 @@ namespace Gfx static constexpr bool useAsyncCompute = true; static constexpr bool waitIdleOnSubmit = true; static constexpr uint32 numFramesBuffered = 3; +static uint32 currentFrameIndex = 0; enum class MaterialShadingModel { diff --git a/src/Engine/Graphics/GraphicsInitializer.h b/src/Engine/Graphics/GraphicsInitializer.h index 930c6b1..bccefa9 100644 --- a/src/Engine/Graphics/GraphicsInitializer.h +++ b/src/Engine/Graphics/GraphicsInitializer.h @@ -19,7 +19,7 @@ struct GraphicsInitializer Array instanceExtensions; Array deviceExtensions; GraphicsInitializer() - : applicationName("SeeleEngine"), engineName("SeeleEngine"), layers{"VK_LAYER_LUNARG_standard_validation"}, instanceExtensions{}, deviceExtensions{"VK_KHR_swapchain"}, windowHandle(nullptr) + : applicationName("SeeleEngine"), engineName("SeeleEngine"), layers{"VK_LAYER_KHRONOS_validation"}, instanceExtensions{}, deviceExtensions{"VK_KHR_swapchain"}, windowHandle(nullptr) { } GraphicsInitializer(const GraphicsInitializer &other) @@ -74,6 +74,9 @@ struct TextureCreateInfo { } }; +struct SamplerCreateInfo +{ +}; struct VertexBufferCreateInfo { BulkResourceData resourceData; @@ -114,12 +117,18 @@ struct SePushConstantRange struct VertexElement { VertexElement(){} - VertexElement(uint32 location, SeFormat vertexFormat, uint32 offset) - : location(location), vertexFormat(vertexFormat), offset(offset) + //VertexElement(uint8 attributeIndex, SeFormat vertexFormat, uint8 offset) + // : attributeIndex(attributeIndex), vertexFormat(vertexFormat), offset(offset) + //{} + VertexElement(uint8 streamIndex, uint8 offset, SeFormat vertexFormat, uint8 attributeIndex, uint8 stride) + : streamIndex(streamIndex), offset(offset), vertexFormat(vertexFormat), attributeIndex(attributeIndex), stride(stride) {} - uint32 location; + uint8 streamIndex; + uint8 offset; SeFormat vertexFormat; - uint32 offset; + uint8 attributeIndex; + uint8 stride; + uint8 bInstanced = 0; }; struct RasterizationState { @@ -190,6 +199,7 @@ struct GraphicsPipelineCreateInfo Gfx::PGeometryShader geometryShader; Gfx::PFragmentShader fragmentShader; Gfx::PRenderPass renderPass; + Gfx::PPipelineLayout pipelineLayout; Gfx::SePrimitiveTopology topology; Gfx::RasterizationState rasterizationState; Gfx::DepthStencilState depthStencilState; diff --git a/src/Engine/Graphics/GraphicsResources.cpp b/src/Engine/Graphics/GraphicsResources.cpp index 266d6ec..d95f79e 100644 --- a/src/Engine/Graphics/GraphicsResources.cpp +++ b/src/Engine/Graphics/GraphicsResources.cpp @@ -72,6 +72,13 @@ ShaderCollection& ShaderMap::createShaders( collection.fragmentShader = graphics->createFragmentShader(createInfo); } + ShaderPermutation permutation; + std::string materialName = material->getFileName(); //Filename is fine, because it just has to be unique + std::string vertexInputName = vertexInput->getName(); + permutation.passType = renderPass; + std::memcpy(permutation.materialName, materialName.c_str(), sizeof(permutation.materialName)); + std::memcpy(permutation.vertexInputName, vertexInputName.c_str(), sizeof(permutation.vertexInputName)); + collection.id = PermutationId(permutation); return collection; } @@ -95,6 +102,11 @@ PDescriptorSet DescriptorLayout::allocatedDescriptorSet() return result; } +void DescriptorLayout::reset() +{ + allocator->reset(); +} + void PipelineLayout::addDescriptorLayout(uint32 setIndex, PDescriptorLayout layout) { if (descriptorSetLayouts.size() <= setIndex) @@ -110,7 +122,6 @@ void PipelineLayout::addDescriptorLayout(uint32 setIndex, PDescriptorLayout layo { if (otherBindings[i].descriptorType != SE_DESCRIPTOR_TYPE_MAX_ENUM) { - assert(thisBindings[i].descriptorType != SE_DESCRIPTOR_TYPE_MAX_ENUM ? thisBindings[i].descriptorType == otherBindings[i].descriptorType : true); thisBindings[i] = otherBindings[i]; } } @@ -118,8 +129,8 @@ void PipelineLayout::addDescriptorLayout(uint32 setIndex, PDescriptorLayout layo else { descriptorSetLayouts[setIndex] = layout; - layout->setIndex = setIndex; } + layout->setIndex = setIndex; } void PipelineLayout::addPushConstants(const SePushConstantRange &pushConstant) @@ -155,14 +166,27 @@ Buffer::~Buffer() { } -UniformBuffer::UniformBuffer(QueueFamilyMapping mapping, QueueType startQueueType) - : Buffer(mapping, startQueueType) +UniformBuffer::UniformBuffer(QueueFamilyMapping mapping, const BulkResourceData& resourceData) + : Buffer(mapping, resourceData.owner) + , size(resourceData.size) { + if(resourceData.data != nullptr) + { + contents = new uint8[size]; + std::memcpy(contents, resourceData.data, size); + } } UniformBuffer::~UniformBuffer() { } + +void UniformBuffer::updateContents(const BulkResourceData& resourceData) +{ + assert(size == resourceData.size); + std::memcpy(contents, resourceData.data, size); +} + StructuredBuffer::StructuredBuffer(QueueFamilyMapping mapping, QueueType startQueueType) : Buffer(mapping, startQueueType) { @@ -220,15 +244,27 @@ VertexDeclaration::VertexDeclaration() VertexDeclaration::~VertexDeclaration() { } -uint32 VertexDeclaration::addVertexStream(const VertexStreamComponent &element) + +static std::mutex vertexDeclarationLock; +static Map vertexDeclarationCache; + +PVertexDeclaration VertexDeclaration::createDeclaration(PGraphics graphics, const Array& elementList) { - VertexStream& stream = vertexStreams.add(); - stream.addVertexElement(VertexElement(element.streamOffset, element.type, element.offset)); - return stream.vertexDescription.size() - 1; -} -const Array &VertexDeclaration::getVertexStreams() const -{ - return vertexStreams; + std::scoped_lock lock(vertexDeclarationLock); + boost::crc_32_type result; + result.process_bytes(&elementList, sizeof(VertexElement) * elementList.size()); + uint32 key = result.checksum(); + + auto found = vertexDeclarationCache[key]; + if(found == nullptr) + { + return found; + } + + PVertexDeclaration newDeclaration = graphics->createVertexDeclaration(elementList); + + vertexDeclarationCache[key] = newDeclaration; + return newDeclaration; } Texture::Texture(QueueFamilyMapping mapping, Gfx::QueueType startQueueType) @@ -263,21 +299,21 @@ RenderTargetLayout::RenderTargetLayout() } RenderTargetLayout::RenderTargetLayout(PRenderTargetAttachment depthAttachment) - : inputAttachments(), colorAttachments(), depthAttachment(depthAttachment) + : inputAttachments(), colorAttachments(), depthAttachment(depthAttachment), width(depthAttachment->getTexture()->getSizeX()), height(depthAttachment->getTexture()->getSizeY()) { } RenderTargetLayout::RenderTargetLayout(PRenderTargetAttachment colorAttachment, PRenderTargetAttachment depthAttachment) - : inputAttachments(), depthAttachment(depthAttachment) + : inputAttachments(), depthAttachment(depthAttachment), width(depthAttachment->getTexture()->getSizeX()), height(depthAttachment->getTexture()->getSizeY()) { colorAttachments.add(colorAttachment); } RenderTargetLayout::RenderTargetLayout(Array colorAttachments, PRenderTargetAttachment depthAttachmet) - : inputAttachments(), colorAttachments(colorAttachments), depthAttachment(depthAttachment) + : inputAttachments(), colorAttachments(colorAttachments), depthAttachment(depthAttachment), width(depthAttachment->getTexture()->getSizeX()), height(depthAttachment->getTexture()->getSizeY()) { } RenderTargetLayout::RenderTargetLayout(Array inputAttachments, Array colorAttachments, PRenderTargetAttachment depthAttachment) - : inputAttachments(inputAttachments), colorAttachments(colorAttachments), depthAttachment(depthAttachment) + : inputAttachments(inputAttachments), colorAttachments(colorAttachments), depthAttachment(depthAttachment), width(depthAttachment->getTexture()->getSizeX()), height(depthAttachment->getTexture()->getSizeY()) { } @@ -297,4 +333,5 @@ Viewport::Viewport(PWindow owner, const ViewportCreateInfo &viewportInfo) Viewport::~Viewport() { -} \ No newline at end of file +} + diff --git a/src/Engine/Graphics/GraphicsResources.h b/src/Engine/Graphics/GraphicsResources.h index ee25e52..f0d3b52 100644 --- a/src/Engine/Graphics/GraphicsResources.h +++ b/src/Engine/Graphics/GraphicsResources.h @@ -16,6 +16,7 @@ namespace Seele struct VertexInputStream; struct VertexStreamComponent; class VertexInputType; +DECLARE_REF(Material) namespace Gfx { DECLARE_REF(Graphics); @@ -178,6 +179,7 @@ public: DescriptorAllocator() {} virtual ~DescriptorAllocator() {} virtual void allocateDescriptorSet(PDescriptorSet &descriptorSet) = 0; + virtual void reset() = 0; }; DEFINE_REF(DescriptorAllocator); DECLARE_REF(UniformBuffer); @@ -187,6 +189,8 @@ class DescriptorSet { public: virtual ~DescriptorSet() {} + virtual void beginFrame() = 0; + virtual void endFrame() = 0; virtual void writeChanges() = 0; virtual void updateBuffer(uint32 binding, PUniformBuffer uniformBuffer) = 0; virtual void updateBuffer(uint32 binding, PStructuredBuffer structuredBuffer) = 0; @@ -213,6 +217,7 @@ public: } virtual void create() = 0; virtual void addDescriptorBinding(uint32 binding, SeDescriptorType type, uint32 arrayCount = 1); + virtual void reset(); virtual PDescriptorSet allocatedDescriptorSet(); const Array &getBindings() const { return descriptorBindings; } inline uint32 getSetIndex() const { return setIndex; } @@ -308,9 +313,28 @@ protected: class UniformBuffer : public Buffer { public: - UniformBuffer(QueueFamilyMapping mapping, QueueType startQueueType); + UniformBuffer(QueueFamilyMapping mapping, const BulkResourceData& resourceData); virtual ~UniformBuffer(); + virtual void updateContents(const BulkResourceData& resourceData); + bool isDataEquals(UniformBuffer* other) + { + if(other == nullptr) + { + return false; + } + if(size != other->size) + { + return false; + } + if(std::memcmp(contents, other->contents, size) != 0) + { + return false; + } + return true; + } protected: + void* contents; + uint32 size; // Inherited via QueueOwnedResource virtual void executeOwnershipBarrier(QueueType newOwner) = 0; }; @@ -393,11 +417,9 @@ class VertexDeclaration public: VertexDeclaration(); ~VertexDeclaration(); - uint32 addVertexStream(const VertexStreamComponent &vertexStream); - const Array &getVertexStreams() const; + static PVertexDeclaration createDeclaration(PGraphics graphics, const Array& elementList); private: - Array vertexStreams; }; DEFINE_REF(VertexDeclaration); class GraphicsPipeline @@ -429,6 +451,7 @@ public: virtual uint32 getSizeX() const = 0; virtual uint32 getSizeY() const = 0; virtual SeSampleCountFlags getNumSamples() const = 0; + virtual class Texture2D* getTexture2D() { return nullptr; } protected: // Inherited via QueueOwnedResource virtual void executeOwnershipBarrier(QueueType newOwner) = 0; @@ -444,19 +467,23 @@ public: virtual uint32 getSizeX() const = 0; virtual uint32 getSizeY() const = 0; virtual SeSampleCountFlags getNumSamples() const = 0; + virtual class Texture2D* getTexture2D() { return this; } protected: //Inherited via QueueOwnedResource virtual void executeOwnershipBarrier(QueueType newOwner) = 0; }; DEFINE_REF(Texture2D); +DECLARE_REF(Viewport); class RenderCommand { public: RenderCommand(); virtual ~RenderCommand(); + virtual void setViewport(Gfx::PViewport viewport) = 0; virtual void bindPipeline(Gfx::PGraphicsPipeline pipeline) = 0; virtual void bindDescriptor(Gfx::PDescriptorSet set) = 0; + virtual void bindDescriptor(Array sets) = 0; virtual void bindVertexBuffer(const Array& streams) = 0; virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) = 0; virtual void draw(const MeshBatchElement& data) = 0; @@ -592,6 +619,8 @@ public: Array inputAttachments; Array colorAttachments; PRenderTargetAttachment depthAttachment; + uint32 width; + uint32 height; }; DEFINE_REF(RenderTargetLayout); diff --git a/src/Engine/Graphics/MeshBatch.h b/src/Engine/Graphics/MeshBatch.h index 04cf688..26cb8cc 100644 --- a/src/Engine/Graphics/MeshBatch.h +++ b/src/Engine/Graphics/MeshBatch.h @@ -2,7 +2,7 @@ namespace Seele { -DECLARE_REF(Material); +DECLARE_REF(MaterialAsset); DECLARE_REF(VertexShaderInput); DECLARE_NAME_REF(Gfx, VertexBuffer); DECLARE_NAME_REF(Gfx, IndexBuffer); @@ -54,7 +54,7 @@ struct MeshBatch PVertexShaderInput vertexInput; - PMaterial material; + PMaterialAsset material; inline int32 getNumPrimitives() const { diff --git a/src/Engine/Graphics/RenderPass/BasePass.cpp b/src/Engine/Graphics/RenderPass/BasePass.cpp index 5832edd..22a5a7f 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.cpp +++ b/src/Engine/Graphics/RenderPass/BasePass.cpp @@ -1,11 +1,14 @@ #include "BasePass.h" #include "Graphics/Graphics.h" #include "Graphics/Window.h" +#include "Scene/Components/CameraComponent.h" +#include "Scene/Actor/CameraActor.h" using namespace Seele; -BasePassMeshProcessor::BasePassMeshProcessor(const PScene scene, Gfx::PGraphics graphics, uint8 translucentBasePass) +BasePassMeshProcessor::BasePassMeshProcessor(const PScene scene, Gfx::PViewport viewport, Gfx::PGraphics graphics, uint8 translucentBasePass) : MeshProcessor(scene, graphics) + , target(viewport) , translucentBasePass(translucentBasePass) { } @@ -16,31 +19,49 @@ BasePassMeshProcessor::~BasePassMeshProcessor() void BasePassMeshProcessor::addMeshBatch( const MeshBatch& batch, - const PPrimitiveComponent primitiveComponent, +// const PPrimitiveComponent primitiveComponent, const Gfx::PRenderPass renderPass, + Gfx::PPipelineLayout pipelineLayout, + Gfx::PDescriptorLayout primitiveLayout, + Array descriptorSets, int32 staticMeshId) { - const PMaterial material = batch.material; + const PMaterialAsset material = batch.material; const Gfx::MaterialShadingModel shadingModel = material->getShadingModel(); const PVertexShaderInput vertexInput = batch.vertexInput; - //TODO query tesselation - - const Gfx::ShaderCollection* collection = material->getShaders(Gfx::RenderPassType::BasePass, vertexInput->getType()); + const Gfx::ShaderCollection* collection = material->getRenderMaterial()->getShaders(Gfx::RenderPassType::BasePass, vertexInput->getType()); assert(collection != nullptr); + for(uint32 i = 0; i < batch.elements.size(); ++i) + { + Gfx::PDescriptorSet descriptorSet = primitiveLayout->allocatedDescriptorSet(); + descriptorSet->updateBuffer(0, batch.elements[i].uniformBuffer); + descriptorSet->writeChanges(); + cachedPrimitiveSets.add(descriptorSet); + } Gfx::PRenderCommand renderCommand = graphics->createRenderCommand(); - buildMeshDrawCommand(batch, - primitiveComponent, - renderPass, - renderCommand, - material, - collection->vertexShader, - collection->controlShader, - collection->evalutionShader, - collection->geometryShader, - collection->fragmentShader, - false); + renderCommand->setViewport(target); + uint32 primitiveDescriptorIndex = 0; + for(uint32 i = 0; i < batch.elements.size(); ++i) + { + pipelineLayout->addDescriptorLayout(2, material->getRenderMaterial()->getDescriptorLayout()); + pipelineLayout->create(); + descriptorSets[2] = material->getDescriptor(); + descriptorSets[3] = cachedPrimitiveSets[primitiveDescriptorIndex++]; + buildMeshDrawCommand(batch, +// primitiveComponent, + renderPass, + pipelineLayout, + renderCommand, + descriptorSets, + collection->vertexShader, + collection->controlShader, + collection->evalutionShader, + collection->geometryShader, + collection->fragmentShader, + false); + } renderCommands.add(renderCommand); } @@ -52,12 +73,16 @@ Array BasePassMeshProcessor::getRenderCommands() void BasePassMeshProcessor::clearCommands() { renderCommands.clear(); + cachedPrimitiveSets.clear(); } -BasePass::BasePass(const PScene scene, Gfx::PGraphics graphics, Gfx::PViewport viewport) - : processor(new BasePassMeshProcessor(scene, graphics, false)) +BasePass::BasePass(const PScene scene, Gfx::PGraphics graphics, Gfx::PViewport viewport, PCameraActor source) + : processor(new BasePassMeshProcessor(scene, viewport, graphics, false)) , scene(scene) , graphics(graphics) + , viewport(viewport) + , descriptorSets(4) + , source(source->getCameraComponent()) { Gfx::PRenderTargetAttachment colorAttachment = new Gfx::SwapchainAttachment(viewport->getOwner()); TextureCreateInfo depthBufferInfo; @@ -70,20 +95,83 @@ BasePass::BasePass(const PScene scene, Gfx::PGraphics graphics, Gfx::PViewport v new Gfx::RenderTargetAttachment(depthBuffer, Gfx::SE_ATTACHMENT_LOAD_OP_DONT_CARE, Gfx::SE_ATTACHMENT_STORE_OP_STORE); Gfx::PRenderTargetLayout layout = new Gfx::RenderTargetLayout(colorAttachment, depthAttachment); renderPass = graphics->createRenderPass(layout); + + BulkResourceData uniformInitializer; + + basePassLayout = graphics->createPipelineLayout(); + + lightLayout = graphics->createDescriptorLayout(); + lightLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + uniformInitializer.size = sizeof(LightEnv); + uniformInitializer.data = (uint8*)&scene->getLightEnvironment(); + lightUniform = graphics->createUniformBuffer(uniformInitializer); + lightLayout->create(); + basePassLayout->addDescriptorLayout(0, lightLayout); + descriptorSets[0] = lightLayout->allocatedDescriptorSet(); + + viewLayout = graphics->createDescriptorLayout(); + viewLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + uniformInitializer.size = sizeof(ViewParameter); + uniformInitializer.data = (uint8*)&viewParams; + viewParamBuffer = graphics->createUniformBuffer(uniformInitializer); + viewLayout->addDescriptorBinding(1, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + uniformInitializer.size = sizeof(ScreenToViewParameter); + uniformInitializer.data = (uint8*)&screenToViewParams; + screenToViewParamBuffer = graphics->createUniformBuffer(uniformInitializer); + viewLayout->create(); + basePassLayout->addDescriptorLayout(1, viewLayout); + descriptorSets[1] = viewLayout->allocatedDescriptorSet(); + + primitiveLayout = graphics->createDescriptorLayout(); + primitiveLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + primitiveLayout->create(); + basePassLayout->addDescriptorLayout(3, primitiveLayout); } -BasePass::~BasePass() +BasePass::~BasePass() { } +void BasePass::beginFrame() +{ + processor->clearCommands(); + primitiveLayout->reset(); + BulkResourceData uniformUpdate; + uniformUpdate.size = sizeof(LightEnv); + uniformUpdate.data = (uint8*)&scene->getLightEnvironment(); + lightUniform->updateContents(uniformUpdate); + descriptorSets[0]->beginFrame(); + descriptorSets[0]->updateBuffer(0, lightUniform); + descriptorSets[0]->writeChanges(); + + viewParams.viewMatrix = source->getViewMatrix(); + viewParams.projectionMatrix = source->getProjectionMatrix(); + viewParams.cameraPosition = Vector4(source->getTransform().getPosition(), 0); + screenToViewParams.inverseProjectionMatrix = glm::inverse(viewParams.projectionMatrix); + screenToViewParams.screenDimensions = Vector2(static_cast(viewport->getSizeX()), static_cast(viewport->getSizeY())); + uniformUpdate.size = sizeof(ViewParameter); + uniformUpdate.data = (uint8*)&viewParams; + viewParamBuffer->updateContents(uniformUpdate); + uniformUpdate.size = sizeof(ScreenToViewParameter); + uniformUpdate.data = (uint8*)&screenToViewParams; + screenToViewParamBuffer->updateContents(uniformUpdate); + descriptorSets[1]->beginFrame(); + descriptorSets[1]->updateBuffer(0, viewParamBuffer); + descriptorSets[1]->updateBuffer(1, screenToViewParamBuffer); + descriptorSets[1]->writeChanges(); +} + void BasePass::render() { - processor->clearCommands(); graphics->beginRenderPass(renderPass); for (auto &&primitive : scene->getStaticMeshes()) { - processor->addMeshBatch(primitive, nullptr, renderPass); + processor->addMeshBatch(primitive, renderPass, basePassLayout, primitiveLayout, descriptorSets); } graphics->executeCommands(processor->getRenderCommands()); graphics->endRenderPass(); } + +void BasePass::endFrame() +{ +} diff --git a/src/Engine/Graphics/RenderPass/BasePass.h b/src/Engine/Graphics/RenderPass/BasePass.h index 18bbb76..622d52a 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.h +++ b/src/Engine/Graphics/RenderPass/BasePass.h @@ -7,33 +7,69 @@ namespace Seele class BasePassMeshProcessor : public MeshProcessor { public: - BasePassMeshProcessor(const PScene scene, Gfx::PGraphics graphics, uint8 translucentBasePass); + BasePassMeshProcessor(const PScene scene, Gfx::PViewport viewport, Gfx::PGraphics graphics, uint8 translucentBasePass); virtual ~BasePassMeshProcessor(); virtual void addMeshBatch( const MeshBatch& batch, - const PPrimitiveComponent primitiveComponent, +// const PPrimitiveComponent primitiveComponent, const Gfx::PRenderPass renderPass, + Gfx::PPipelineLayout pipelineLayout, + Gfx::PDescriptorLayout primitiveLayout, + Array descriptorSets, int32 staticMeshId = -1) override; Array getRenderCommands(); void clearCommands(); private: Array renderCommands; + Array cachedPrimitiveSets; + Gfx::PViewport target; uint8 translucentBasePass; }; DEFINE_REF(BasePassMeshProcessor); +DECLARE_REF(CameraActor); +DECLARE_REF(CameraComponent); class BasePass { public: - BasePass(const PScene scene, Gfx::PGraphics graphics, Gfx::PViewport viewport); + BasePass(const PScene scene, Gfx::PGraphics graphics, Gfx::PViewport viewport, PCameraActor source); ~BasePass(); + void beginFrame(); void render(); + void endFrame(); private: + struct ViewParameter + { + Matrix4 viewMatrix; + Matrix4 projectionMatrix; + Vector4 cameraPosition; + } viewParams; + struct ScreenToViewParameter + { + Matrix4 inverseProjectionMatrix; + Vector2 screenDimensions; + } screenToViewParams; + Gfx::PRenderPass renderPass; Gfx::PTexture2D depthBuffer; const PScene scene; UPBasePassMeshProcessor processor; + Gfx::PPipelineLayout basePassLayout; + // Set 0: Light environment + Gfx::PDescriptorLayout lightLayout; + Gfx::PUniformBuffer lightUniform; + // Set 1: viewParameter + Gfx::PDescriptorLayout viewLayout; + Gfx::PUniformBuffer viewParamBuffer; + Gfx::PUniformBuffer screenToViewParamBuffer; + // Set 2: materials, generated + // Set 3: primitive scene data + Gfx::PDescriptorLayout primitiveLayout; + Gfx::PUniformBuffer primitiveUniformBuffer; + Array descriptorSets; Gfx::PGraphics graphics; + PCameraComponent source; + Gfx::PViewport viewport; }; DEFINE_REF(BasePass); } // namespace Seele diff --git a/src/Engine/Graphics/RenderPass/MeshProcessor.cpp b/src/Engine/Graphics/RenderPass/MeshProcessor.cpp index 65a7995..9ff9bbd 100644 --- a/src/Engine/Graphics/RenderPass/MeshProcessor.cpp +++ b/src/Engine/Graphics/RenderPass/MeshProcessor.cpp @@ -17,10 +17,11 @@ MeshProcessor::~MeshProcessor() void MeshProcessor::buildMeshDrawCommand( const MeshBatch& meshBatch, - const PPrimitiveComponent primitiveComponent, +// const PPrimitiveComponent primitiveComponent, const Gfx::PRenderPass renderPass, + Gfx::PPipelineLayout pipelineLayout, Gfx::PRenderCommand drawCommand, - PMaterial material, + Array descriptors, Gfx::PVertexShader vertexShader, Gfx::PControlShader controlShader, Gfx::PEvaluationShader evaluationShader, @@ -40,6 +41,7 @@ void MeshProcessor::buildMeshDrawCommand( pipelineInitializer.geometryShader = geometryShader; pipelineInitializer.fragmentShader = fragmentShader; pipelineInitializer.renderPass = renderPass; + pipelineInitializer.pipelineLayout = pipelineLayout; VertexInputStreamArray vertexStreams; if(positionOnly) @@ -50,9 +52,10 @@ void MeshProcessor::buildMeshDrawCommand( { vertexInput->getStreams(vertexStreams); } - drawCommand->bindVertexBuffer(vertexStreams); Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(pipelineInitializer); drawCommand->bindPipeline(pipeline); + drawCommand->bindVertexBuffer(vertexStreams); + drawCommand->bindDescriptor(descriptors); for(auto element : meshBatch.elements) { drawCommand->bindIndexBuffer(element.indexBuffer); diff --git a/src/Engine/Graphics/RenderPass/MeshProcessor.h b/src/Engine/Graphics/RenderPass/MeshProcessor.h index 8347b77..243e3fe 100644 --- a/src/Engine/Graphics/RenderPass/MeshProcessor.h +++ b/src/Engine/Graphics/RenderPass/MeshProcessor.h @@ -16,15 +16,19 @@ protected: Gfx::PGraphics graphics; virtual void addMeshBatch( const MeshBatch& meshBatch, - const PPrimitiveComponent primitiveComponent, +// const PPrimitiveComponent primitiveComponent, const Gfx::PRenderPass renderPass, + Gfx::PPipelineLayout pipelineLayout, + Gfx::PDescriptorLayout primitiveLayout, + Array descriptorSets, int32 staticMeshId = -1) = 0; void buildMeshDrawCommand( const MeshBatch& meshBatch, - const PPrimitiveComponent primitiveComponent, +// const PPrimitiveComponent primitiveComponent, const Gfx::PRenderPass renderPass, + Gfx::PPipelineLayout pipelineLayout, Gfx::PRenderCommand drawCommand, - PMaterial material, + Array descriptors, Gfx::PVertexShader vertexShader, Gfx::PControlShader controlShader, Gfx::PEvaluationShader evaluationShader, diff --git a/src/Engine/Graphics/SceneRenderPath.cpp b/src/Engine/Graphics/SceneRenderPath.cpp index 1703590..d37d5c8 100644 --- a/src/Engine/Graphics/SceneRenderPath.cpp +++ b/src/Engine/Graphics/SceneRenderPath.cpp @@ -5,11 +5,11 @@ using namespace Seele; -SceneRenderPath::SceneRenderPath(PScene scene, Gfx::PGraphics graphics, Gfx::PViewport target) +SceneRenderPath::SceneRenderPath(PScene scene, Gfx::PGraphics graphics, Gfx::PViewport target, PCameraActor source) : RenderPath(graphics, target) , scene(scene) { - basePass = new BasePass(scene, graphics, target); + basePass = new BasePass(scene, graphics, target, source); } SceneRenderPath::~SceneRenderPath() @@ -28,7 +28,7 @@ void SceneRenderPath::init() void SceneRenderPath::beginFrame() { - + basePass->beginFrame(); } void SceneRenderPath::render() @@ -38,5 +38,5 @@ void SceneRenderPath::render() void SceneRenderPath::endFrame() { - + basePass->endFrame(); } diff --git a/src/Engine/Graphics/SceneRenderPath.h b/src/Engine/Graphics/SceneRenderPath.h index f1a11ba..6cc880f 100644 --- a/src/Engine/Graphics/SceneRenderPath.h +++ b/src/Engine/Graphics/SceneRenderPath.h @@ -5,10 +5,11 @@ namespace Seele { DECLARE_REF(Scene); +DECLARE_REF(CameraActor); class SceneRenderPath : public RenderPath { public: - SceneRenderPath(PScene scene, Gfx::PGraphics graphics, Gfx::PViewport target); + SceneRenderPath(PScene scene, Gfx::PGraphics graphics, Gfx::PViewport target, PCameraActor source); virtual ~SceneRenderPath(); void setTargetScene(PScene scene); virtual void init(); diff --git a/src/Engine/Graphics/SceneView.cpp b/src/Engine/Graphics/SceneView.cpp index bc4c6d2..b3d9494 100644 --- a/src/Engine/Graphics/SceneView.cpp +++ b/src/Engine/Graphics/SceneView.cpp @@ -2,6 +2,7 @@ #include "SceneRenderPath.h" #include "Scene/Scene.h" #include "Window.h" +#include "Scene/Actor/CameraActor.h" using namespace Seele; @@ -9,7 +10,9 @@ Seele::SceneView::SceneView(Gfx::PGraphics graphics, PWindow owner, const Viewpo : View(graphics, owner, createInfo) { scene = new Scene(graphics); - renderer = new SceneRenderPath(scene, graphics, viewport); + PCameraActor camera = new CameraActor(); + scene->addActor(camera); + renderer = new SceneRenderPath(scene, graphics, viewport, camera); } Seele::SceneView::~SceneView() diff --git a/src/Engine/Graphics/ShaderCompiler.cpp b/src/Engine/Graphics/ShaderCompiler.cpp index 7e2154c..b368b24 100644 --- a/src/Engine/Graphics/ShaderCompiler.cpp +++ b/src/Engine/Graphics/ShaderCompiler.cpp @@ -18,7 +18,7 @@ ShaderCompiler::~ShaderCompiler() void ShaderCompiler::registerMaterial(PMaterial material) { - for(auto type : VertexInputType::getTypeList()) + for(auto& type : VertexInputType::getTypeList()) { material->createShaders(graphics, Gfx::RenderPassType::DepthPrepass, type); material->createShaders(graphics, Gfx::RenderPassType::BasePass, type); diff --git a/src/Engine/Graphics/StaticMeshVertexInput.cpp b/src/Engine/Graphics/StaticMeshVertexInput.cpp index c191606..649e9bf 100644 --- a/src/Engine/Graphics/StaticMeshVertexInput.cpp +++ b/src/Engine/Graphics/StaticMeshVertexInput.cpp @@ -1,4 +1,5 @@ #include "StaticMeshVertexInput.h" +#include "Graphics/Graphics.h" using namespace Seele; @@ -13,36 +14,56 @@ StaticMeshVertexInput::~StaticMeshVertexInput() } -void StaticMeshVertexInput::setPositionStream(const VertexStreamComponent& positionStream) +void StaticMeshVertexInput::init(Gfx::PGraphics graphics) { - declaration->addVertexStream(positionStream); - positionDeclaration->addVertexStream(positionStream); - data.positionStream = positionStream; + if(data.positionStream.vertexBuffer != data.tangentBasisComponents[0].vertexBuffer) + { + Array positionOnlyStreamElements; + positionOnlyStreamElements.add(accessPositionStreamComponent(data.positionStream, 0)); + + initPositionDeclaration(graphics, positionOnlyStreamElements); + } + + Array elements; + if(data.positionStream.vertexBuffer != nullptr) + { + elements.add(accessStreamComponent(data.positionStream, 0)); + } + + uint8 tangentBasisAttributes[2] = {1, 2}; + for(int32 axisIndex = 0; axisIndex < 2; axisIndex++) + { + if(data.tangentBasisComponents[axisIndex].vertexBuffer != nullptr) + { + elements.add(accessStreamComponent(data.tangentBasisComponents[axisIndex], tangentBasisAttributes[axisIndex])); + } + } + + if(data.colorComponent.vertexBuffer != nullptr) + { + elements.add(accessStreamComponent(data.colorComponent, 3)); + } + else + { + elements.add(accessStreamComponent(VertexStreamComponent(graphics->getNullVertexBuffer(), 0, 0, Gfx::SE_FORMAT_R32G32B32A32_SFLOAT), 3)); + } + if(data.textureCoordinates.size()) + { + const int32 baseTexCoordAttribute = 4; + for(uint32 coordinateIndex = 0; coordinateIndex < data.textureCoordinates.size(); ++coordinateIndex) + { + elements.add(accessStreamComponent( + data.textureCoordinates[coordinateIndex], + baseTexCoordAttribute + coordinateIndex + )); + } + } + initDeclaration(graphics, elements); } -void StaticMeshVertexInput::setTangentXStream(const VertexStreamComponent& tangentXStream) +void StaticMeshVertexInput::setData(StaticMeshDataType data) { - declaration->addVertexStream(tangentXStream); - data.tangentBasisComponents[0] = tangentXStream; -} - -void StaticMeshVertexInput::setTangentZStream(const VertexStreamComponent& tangentZStream) -{ - declaration->addVertexStream(tangentZStream); - data.tangentBasisComponents[1] = tangentZStream; -} - -void StaticMeshVertexInput::setTexCoordStream(uint32 index, const VertexStreamComponent& textureStream) -{ - //TODO: replace add with proper indexing - declaration->addVertexStream(textureStream); - data.textureCoordinates.add(textureStream); -} - -void StaticMeshVertexInput::setColorStream(const VertexStreamComponent& colorStream) -{ - declaration->addVertexStream(colorStream); - data.colorComponent = colorStream; + this->data = data; } IMPLEMENT_VERTEX_INPUT_TYPE(StaticMeshVertexInput, "StaticMeshVertexInput"); \ No newline at end of file diff --git a/src/Engine/Graphics/StaticMeshVertexInput.h b/src/Engine/Graphics/StaticMeshVertexInput.h index 7ea8c9d..47dee25 100644 --- a/src/Engine/Graphics/StaticMeshVertexInput.h +++ b/src/Engine/Graphics/StaticMeshVertexInput.h @@ -20,11 +20,8 @@ class StaticMeshVertexInput : public VertexShaderInput public: StaticMeshVertexInput(std::string name); virtual ~StaticMeshVertexInput(); - void setPositionStream(const VertexStreamComponent& positionStream); - void setTangentXStream(const VertexStreamComponent& tangentXStream); - void setTangentZStream(const VertexStreamComponent& tangentZStream); - void setTexCoordStream(uint32 index, const VertexStreamComponent& textureStream); - void setColorStream(const VertexStreamComponent& colorStream); + virtual void init(Gfx::PGraphics graphics) override; + void setData(StaticMeshDataType data); private: StaticMeshDataType data; }; diff --git a/src/Engine/Graphics/VertexShaderInput.cpp b/src/Engine/Graphics/VertexShaderInput.cpp index 299eb6c..8fc7d28 100644 --- a/src/Engine/Graphics/VertexShaderInput.cpp +++ b/src/Engine/Graphics/VertexShaderInput.cpp @@ -1,5 +1,6 @@ #include "VertexShaderInput.h" #include "Graphics/Mesh.h" +#include "Graphics/Graphics.h" #include #include @@ -7,7 +8,7 @@ using namespace Seele; List VertexInputType::globalTypeList; -List VertexInputType::getTypeList() +List& VertexInputType::getTypeList() { return globalTypeList; } @@ -62,7 +63,7 @@ void VertexShaderInput::getStreams(VertexInputStreamArray& outVertexStreams) con { for(uint32 i = 0; i < streams.size(); ++i) { - const VertexInputStream& stream = streams[i]; + const VertexStream& stream = streams[i]; if(stream.vertexBuffer == nullptr) { outVertexStreams.add(VertexInputStream(i, 0, nullptr)); @@ -78,7 +79,37 @@ void VertexShaderInput::getPositionOnlyStream(VertexInputStreamArray& outVertexS { for (uint32 i = 0; i < positionStreams.size(); ++i) { - const VertexInputStream& stream = positionStreams[i]; + const VertexStream& stream = positionStreams[i]; outVertexStreams.add(VertexInputStream(i, stream.offset, stream.vertexBuffer)); } +} + +Gfx::VertexElement VertexShaderInput::accessStreamComponent(const VertexStreamComponent& component, uint8 attributeIndex) +{ + VertexStream vertexStream; + vertexStream.vertexBuffer = component.vertexBuffer; + vertexStream.stride = component.stride; + vertexStream.offset = component.offset; + + return Gfx::VertexElement(streams.indexOf(streams.addUnique(vertexStream)), component.offset, component.type, attributeIndex, vertexStream.stride); +} + +Gfx::VertexElement VertexShaderInput::accessPositionStreamComponent(const VertexStreamComponent& component, uint8 attributeIndex) +{ + VertexStream vertexStream; + vertexStream.vertexBuffer = component.vertexBuffer; + vertexStream.stride = component.stride; + vertexStream.offset = component.offset; + + return Gfx::VertexElement(streams.indexOf(streams.addUnique(vertexStream)), component.offset, component.type, attributeIndex, vertexStream.stride); +} + +void VertexShaderInput::initDeclaration(Gfx::PGraphics graphics, Array& elements) +{ + declaration = graphics->createVertexDeclaration(elements); +} + +void VertexShaderInput::initPositionDeclaration(Gfx::PGraphics graphics, const Array& elements) +{ + positionDeclaration = graphics->createVertexDeclaration(elements); } \ No newline at end of file diff --git a/src/Engine/Graphics/VertexShaderInput.h b/src/Engine/Graphics/VertexShaderInput.h index 3b6b45a..6445eb4 100644 --- a/src/Engine/Graphics/VertexShaderInput.h +++ b/src/Engine/Graphics/VertexShaderInput.h @@ -81,7 +81,7 @@ struct VertexStreamComponent class VertexInputType { public: - static List getTypeList(); + static List& getTypeList(); static VertexInputType* getVertexInputByName(const std::string& name); VertexInputType( @@ -117,6 +117,7 @@ class VertexShaderInput public: VertexShaderInput(std::string name); virtual ~VertexShaderInput(); + virtual void init(Gfx::PGraphics graphics) {}; void getStreams(VertexInputStreamArray& outVertexStreams) const; void getPositionOnlyStream(VertexInputStreamArray& outVertexStreams) const; virtual bool supportsTesselation() { return false; } @@ -125,11 +126,34 @@ public: Gfx::PVertexDeclaration getPositionDeclaration() const {return positionDeclaration;} std::string getName() const { return name; } protected: + Gfx::VertexElement accessStreamComponent(const VertexStreamComponent& component, uint8 attributeIndex); + Gfx::VertexElement accessPositionStreamComponent(const VertexStreamComponent& component, uint8 attributeIndex); + + void initDeclaration(Gfx::PGraphics graphics, Array& elements); + void initPositionDeclaration(Gfx::PGraphics graphics, const Array& elements); + static List registeredInputs; static std::mutex registeredInputsLock; Array layout; - StaticArray streams; - StaticArray positionStreams; + + // internal helper class, basically a VertexInputStream plus stride + struct VertexStream + { + Gfx::PVertexBuffer vertexBuffer = nullptr; + uint8 stride = 0; + uint8 offset = 0; + friend bool operator==(const VertexStream& a, const VertexStream& b) + { + return a.vertexBuffer == b.vertexBuffer && + a.stride == b.stride && + a.offset == b.offset; + } + VertexStream() + { + } + }; + Array streams; + Array positionStreams; Gfx::PVertexDeclaration declaration; Gfx::PVertexDeclaration positionDeclaration; std::string name; diff --git a/src/Engine/Graphics/Vulkan/VulkanBuffer.cpp b/src/Engine/Graphics/Vulkan/VulkanBuffer.cpp index 7d5d266..0401014 100644 --- a/src/Engine/Graphics/Vulkan/VulkanBuffer.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanBuffer.cpp @@ -71,6 +71,11 @@ ShaderBuffer::~ShaderBuffer() graphics = nullptr; } +VkDeviceSize ShaderBuffer::getOffset() const +{ + return buffers[currentBuffer].allocation->getOffset(); +} + void ShaderBuffer::executeOwnershipBarrier(Gfx::QueueType newOwner) { VkBufferMemoryBarrier barrier = @@ -235,7 +240,7 @@ void ShaderBuffer::unlock() UniformBuffer::UniformBuffer(PGraphics graphics, const BulkResourceData &resourceData) : Vulkan::ShaderBuffer(graphics, resourceData.size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, resourceData.owner) - , Gfx::UniformBuffer(graphics->getFamilyMapping(), resourceData.owner) + , Gfx::UniformBuffer(graphics->getFamilyMapping(), resourceData) { if (resourceData.data != nullptr) { diff --git a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp index 490dee2..2dee623 100644 --- a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.cpp @@ -150,6 +150,7 @@ void SecondaryCmdBuffer::begin(PCmdBuffer parent) inheritanceInfo.renderPass = parent->renderPass->getHandle(); inheritanceInfo.subpass = parent->subpassIndex; beginInfo.pInheritanceInfo = &inheritanceInfo; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; VK_CHECK(vkBeginCommandBuffer(handle, &beginInfo)); } @@ -158,6 +159,14 @@ void SecondaryCmdBuffer::end() VK_CHECK(vkEndCommandBuffer(handle)); } +void SecondaryCmdBuffer::setViewport(Gfx::PViewport viewport) +{ + VkViewport vp = viewport.cast()->getHandle(); + VkRect2D scissors = init::Rect2D(viewport->getSizeX(), viewport->getSizeY(), viewport->getOffsetX(), viewport->getOffsetY()); + vkCmdSetViewport(handle, 0, 1, &vp); + vkCmdSetScissor(handle, 0, 1, &scissors); +} + void SecondaryCmdBuffer::bindPipeline(Gfx::PGraphicsPipeline gfxPipeline) { pipeline = gfxPipeline.cast(); @@ -168,6 +177,17 @@ void SecondaryCmdBuffer::bindDescriptor(Gfx::PDescriptorSet descriptorSet) VkDescriptorSet setHandle = descriptorSet.cast()->getHandle(); vkCmdBindDescriptorSets(handle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getLayout(), descriptorSet->getSetIndex(), 1, &setHandle, 0, nullptr); } +void SecondaryCmdBuffer::bindDescriptor(Array descriptorSets) +{ + VkDescriptorSet* sets = new VkDescriptorSet[descriptorSets.size()]; + for(uint32 i = 0; i < descriptorSets.size(); ++i) + { + auto descriptorSet = descriptorSets[i].cast(); + sets[descriptorSet->getSetIndex()] = descriptorSet->getHandle(); + } + vkCmdBindDescriptorSets(handle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getLayout(), 0, descriptorSets.size(), sets, 0, nullptr); + delete[] sets; +} void SecondaryCmdBuffer::bindVertexBuffer(const Array& streams) { Array buffers(streams.size()); diff --git a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.h b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.h index faee272..ca59b39 100644 --- a/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.h +++ b/src/Engine/Graphics/Vulkan/VulkanCommandBuffer.h @@ -70,15 +70,17 @@ private: DEFINE_REF(CmdBuffer); DECLARE_REF(GraphicsPipeline); -class SecondaryCmdBuffer : public CmdBufferBase, public Gfx::RenderCommand +class SecondaryCmdBuffer : public Gfx::RenderCommand, public CmdBufferBase { public: SecondaryCmdBuffer(PGraphics graphics, VkCommandPool cmdPool); virtual ~SecondaryCmdBuffer(); void begin(PCmdBuffer parent); void end(); + virtual void setViewport(Gfx::PViewport viewport) override; virtual void bindPipeline(Gfx::PGraphicsPipeline pipeline) override; virtual void bindDescriptor(Gfx::PDescriptorSet descriptorSet) override; + virtual void bindDescriptor(Array descriptorSets) override; virtual void bindVertexBuffer(const Array& streams) override; virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) override; virtual void draw(const MeshBatchElement& data) override; diff --git a/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp b/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp index 87c9f6b..e7ccf72 100644 --- a/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.cpp @@ -7,6 +7,11 @@ using namespace Seele; using namespace Seele::Vulkan; +DescriptorLayout::DescriptorLayout(PGraphics graphics) + : graphics(graphics) + , layoutHandle(VK_NULL_HANDLE) +{ +} DescriptorLayout::~DescriptorLayout() { if (layoutHandle != VK_NULL_HANDLE) @@ -36,7 +41,13 @@ void DescriptorLayout::create() init::DescriptorSetLayoutCreateInfo(bindings.data(), bindings.size()); VK_CHECK(vkCreateDescriptorSetLayout(graphics->getDevice(), &createInfo, nullptr, &layoutHandle)); + std::cout << "creating descriptorlayout " << layoutHandle << std::endl; + allocator = new DescriptorAllocator(graphics, *this); + + boost::crc_32_type result; + result.process_bytes(bindings.data(), sizeof(VkDescriptorSetLayoutBinding) * bindings.size()); + hash = result.checksum(); } PipelineLayout::~PipelineLayout() @@ -47,15 +58,23 @@ PipelineLayout::~PipelineLayout() } } +static Map layoutCache; + void PipelineLayout::create() { vulkanDescriptorLayouts.resize(descriptorSetLayouts.size()); for (size_t i = 0; i < descriptorSetLayouts.size(); ++i) { + // There could be unused descriptor set indices + if(descriptorSetLayouts[i] == nullptr) + { + continue; + } PDescriptorLayout layout = descriptorSetLayouts[i].cast(); layout->create(); vulkanDescriptorLayouts[i] = layout->getHandle(); } + VkPipelineLayoutCreateInfo createInfo = init::PipelineLayoutCreateInfo(vulkanDescriptorLayouts.data(), vulkanDescriptorLayouts.size()); Array vkPushConstants(pushConstants.size()); @@ -67,11 +86,20 @@ void PipelineLayout::create() } createInfo.pushConstantRangeCount = vkPushConstants.size(); createInfo.pPushConstantRanges = vkPushConstants.data(); - VK_CHECK(vkCreatePipelineLayout(graphics->getDevice(), &createInfo, nullptr, &layoutHandle)); boost::crc_32_type result; - result.process_bytes(&createInfo, sizeof(VkPipelineLayoutCreateInfo)); + result.process_bytes(createInfo.pPushConstantRanges, sizeof(VkPushConstantRange) * createInfo.pushConstantRangeCount); + result.process_bytes(createInfo.pSetLayouts, sizeof(VkDescriptorSetLayout) * createInfo.setLayoutCount); layoutHash = result.checksum(); + + if(layoutCache[layoutHash] != VK_NULL_HANDLE) + { + layoutHandle = layoutCache[layoutHash]; + return; + } + + VK_CHECK(vkCreatePipelineLayout(graphics->getDevice(), &createInfo, nullptr, &layoutHandle)); + layoutCache[layoutHash] = layoutHandle; } void PipelineLayout::reset() @@ -85,29 +113,57 @@ DescriptorSet::~DescriptorSet() { } +void DescriptorSet::beginFrame() +{ + currentFrameSet = (currentFrameSet + 1) % Gfx::numFramesBuffered; +} + +void DescriptorSet::endFrame() +{ +} + void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PUniformBuffer uniformBuffer) { PUniformBuffer vulkanBuffer = uniformBuffer.cast(); - // VkDescriptorBufferInfo bufferInfo = init::DescriptorBufferInfo(vulkanBuffer->getHandle(), vulkanBuffer->getOffset(), vulkanBuffer->getSize()); - // bufferInfos.add(bufferInfo); + UniformBuffer* cachedBuffer = reinterpret_cast(cachedData[currentFrameSet][binding]); + if(vulkanBuffer->isDataEquals(cachedBuffer)) + { + return; + } + VkDescriptorBufferInfo bufferInfo = init::DescriptorBufferInfo(vulkanBuffer->getHandle(), 0, vulkanBuffer->getSize()); + bufferInfos.add(bufferInfo); - VkWriteDescriptorSet writeDescriptor = init::WriteDescriptorSet(setHandle, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, binding, &bufferInfos.back()); + VkWriteDescriptorSet writeDescriptor = init::WriteDescriptorSet(setHandle[currentFrameSet], VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, binding, &bufferInfos.back()); writeDescriptors.add(writeDescriptor); + + cachedData[currentFrameSet][binding] = vulkanBuffer.getHandle(); } void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PStructuredBuffer uniformBuffer) { PStructuredBuffer vulkanBuffer = uniformBuffer.cast(); - // VkDescriptorBufferInfo bufferInfo = init::DescriptorBufferInfo(vulkanBuffer->getHandle(), vulkanBuffer->getOffset(), vulkanBuffer->getSize()); - // bufferInfos.add(bufferInfo); + StructuredBuffer* cachedBuffer = reinterpret_cast(cachedData[currentFrameSet][binding]); + if(vulkanBuffer.getHandle() == cachedBuffer) + { + return; + } + VkDescriptorBufferInfo bufferInfo = init::DescriptorBufferInfo(vulkanBuffer->getHandle(), 0, vulkanBuffer->getSize()); + bufferInfos.add(bufferInfo); - VkWriteDescriptorSet writeDescriptor = init::WriteDescriptorSet(setHandle, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, binding, &bufferInfos.back()); + VkWriteDescriptorSet writeDescriptor = init::WriteDescriptorSet(setHandle[currentFrameSet], VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, binding, &bufferInfos.back()); writeDescriptors.add(writeDescriptor); + + cachedData[currentFrameSet][binding] = vulkanBuffer.getHandle(); } void DescriptorSet::updateSampler(uint32_t binding, Gfx::PSamplerState samplerState) { PSamplerState vulkanSampler = samplerState.cast(); + SamplerState* cachedSampler = reinterpret_cast(cachedData[currentFrameSet][binding]); + if(vulkanSampler.getHandle() == cachedSampler) + { + return; + } VkDescriptorImageInfo imageInfo = init::DescriptorImageInfo( vulkanSampler->sampler, @@ -115,13 +171,20 @@ void DescriptorSet::updateSampler(uint32_t binding, Gfx::PSamplerState samplerSt VK_IMAGE_LAYOUT_UNDEFINED); imageInfos.add(imageInfo); - VkWriteDescriptorSet writeDescriptor = init::WriteDescriptorSet(setHandle, VK_DESCRIPTOR_TYPE_SAMPLER, binding, &imageInfos.back()); + VkWriteDescriptorSet writeDescriptor = init::WriteDescriptorSet(setHandle[currentFrameSet], VK_DESCRIPTOR_TYPE_SAMPLER, binding, &imageInfos.back()); writeDescriptors.add(writeDescriptor); + + cachedData[currentFrameSet][binding] = vulkanSampler.getHandle(); } void DescriptorSet::updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx::PSamplerState samplerState) { - PTextureHandle vulkanTexture = TextureBase::cast(texture); + TextureHandle* vulkanTexture = TextureBase::cast(texture); + TextureHandle* cachedTexture = reinterpret_cast(cachedData[currentFrameSet][binding]); + if(vulkanTexture == cachedTexture) + { + return; + } //It is assumed that the image is in the correct layout VkDescriptorImageInfo imageInfo = init::DescriptorImageInfo( @@ -134,12 +197,14 @@ void DescriptorSet::updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx:: imageInfo.sampler = vulkanSampler->sampler; } imageInfos.add(imageInfo); - VkWriteDescriptorSet writeDescriptor = init::WriteDescriptorSet(setHandle, samplerState != nullptr ? VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, binding, &imageInfos.back()); + VkWriteDescriptorSet writeDescriptor = init::WriteDescriptorSet(setHandle[currentFrameSet], samplerState != nullptr ? VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, binding, &imageInfos.back()); if (vulkanTexture->getUsage() & VK_IMAGE_USAGE_STORAGE_BIT) { writeDescriptor.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; } writeDescriptors.add(writeDescriptor); + + cachedData[currentFrameSet][binding] = vulkanTexture; } bool DescriptorSet::operator<(Gfx::PDescriptorSet other) @@ -160,8 +225,10 @@ void DescriptorSet::writeChanges() } DescriptorAllocator::DescriptorAllocator(PGraphics graphics, DescriptorLayout &layout) - : layout(layout), graphics(graphics) + : layout(layout), graphics(graphics), currentCachedIndex(0) { + std::memset(&cachedHandles, 0, sizeof(cachedHandles)); + uint32 perTypeSizes[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT]; // TODO: FIX ENUM std::memset(perTypeSizes, 0, sizeof(perTypeSizes)); for (uint32 i = 0; i < layout.getBindings().size(); ++i) @@ -198,5 +265,25 @@ void DescriptorAllocator::allocateDescriptorSet(Gfx::PDescriptorSet &descriptorS VkDescriptorSetLayout layoutHandle = layout.getHandle(); VkDescriptorSetAllocateInfo allocInfo = init::DescriptorSetAllocateInfo(poolHandle, &layoutHandle, 1); - VK_CHECK(vkAllocateDescriptorSets(graphics->getDevice(), &allocInfo, &vulkanSet->setHandle)); + for(uint32 i = 0; i < Gfx::numFramesBuffered; ++i) + { + if(cachedHandles[currentCachedIndex] != VK_NULL_HANDLE) + { + vulkanSet->setHandle[i] = cachedHandles[currentCachedIndex++]; + } + else + { + VK_CHECK(vkAllocateDescriptorSets(graphics->getDevice(), &allocInfo, &vulkanSet->setHandle[i])); + cachedHandles[currentCachedIndex++] = vulkanSet->setHandle[i]; + } + + vulkanSet->cachedData[i].resize(layout.bindings.size()); + // Not really pretty, but this way the set knows which ones are valid + std::memset(vulkanSet->cachedData[i].data(), 0, sizeof(void*) * vulkanSet->cachedData[i].size()); + } } + +void DescriptorAllocator::reset() +{ + currentCachedIndex = 0; +} \ No newline at end of file diff --git a/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.h b/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.h index 0ec3a03..4e88a1b 100644 --- a/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.h +++ b/src/Engine/Graphics/Vulkan/VulkanDescriptorSets.h @@ -9,10 +9,7 @@ DECLARE_REF(Graphics); class DescriptorLayout : public Gfx::DescriptorLayout { public: - DescriptorLayout(PGraphics graphics) - : graphics(graphics), layoutHandle(VK_NULL_HANDLE) - { - } + DescriptorLayout(PGraphics graphics); virtual ~DescriptorLayout(); virtual void create(); inline VkDescriptorSetLayout getHandle() const @@ -21,9 +18,11 @@ public: } private: + uint32 hash; PGraphics graphics; Array bindings; VkDescriptorSetLayout layoutHandle; + friend class DescriptorAllocator; }; DEFINE_REF(DescriptorLayout); class PipelineLayout : public Gfx::PipelineLayout @@ -59,6 +58,7 @@ public: DescriptorAllocator(PGraphics graphics, DescriptorLayout &layout); virtual ~DescriptorAllocator(); virtual void allocateDescriptorSet(Gfx::PDescriptorSet &descriptorSet); + virtual void reset(); inline VkDescriptorPool getHandle() const { @@ -71,7 +71,9 @@ public: private: PGraphics graphics; - int maxSets = 512; + const static int maxSets = 512; + VkDescriptorSet cachedHandles[maxSets]; + uint32 currentCachedIndex; VkDescriptorPool poolHandle; DescriptorLayout &layout; }; @@ -81,10 +83,13 @@ class DescriptorSet : public Gfx::DescriptorSet { public: DescriptorSet(PGraphics graphics, PDescriptorAllocator owner) - : graphics(graphics), owner(owner), setHandle(VK_NULL_HANDLE) + : graphics(graphics), owner(owner), currentFrameSet(0) { } virtual ~DescriptorSet(); + virtual void beginFrame(); + virtual void endFrame(); + virtual void writeChanges(); virtual void updateBuffer(uint32_t binding, Gfx::PUniformBuffer uniformBuffer); virtual void updateBuffer(uint32_t binding, Gfx::PStructuredBuffer uniformBuffer); virtual void updateSampler(uint32_t binding, Gfx::PSamplerState samplerState); @@ -92,7 +97,7 @@ public: virtual bool operator<(Gfx::PDescriptorSet other); inline VkDescriptorSet getHandle() const { - return setHandle; + return setHandle[currentFrameSet]; } virtual uint32 getSetIndex() const { @@ -100,11 +105,15 @@ public: } private: - virtual void writeChanges(); Array imageInfos; Array bufferInfos; Array writeDescriptors; - VkDescriptorSet setHandle; + // contains the previously bound resources at every binding + // since the layout is fixed, trying to bind a texture to a buffer + // would not work anyways, so casts should be safe + Array cachedData[Gfx::numFramesBuffered]; + VkDescriptorSet setHandle[Gfx::numFramesBuffered]; + uint32 currentFrameSet; PDescriptorAllocator owner; PGraphics graphics; friend class DescriptorAllocator; diff --git a/src/Engine/Graphics/Vulkan/VulkanFramebuffer.cpp b/src/Engine/Graphics/Vulkan/VulkanFramebuffer.cpp index 4c3ef2b..a255e51 100644 --- a/src/Engine/Graphics/Vulkan/VulkanFramebuffer.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanFramebuffer.cpp @@ -39,6 +39,7 @@ Framebuffer::Framebuffer(PGraphics graphics, PRenderPass renderPass, Gfx::PRende renderPass->getRenderArea().extent.width, renderPass->getRenderArea().extent.height, 1); + VK_CHECK(vkCreateFramebuffer(graphics->getDevice(), &createInfo, nullptr, &handle)); boost::crc_32_type result; diff --git a/src/Engine/Graphics/Vulkan/VulkanGraphics.cpp b/src/Engine/Graphics/Vulkan/VulkanGraphics.cpp index 9d70e37..89417fe 100644 --- a/src/Engine/Graphics/Vulkan/VulkanGraphics.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanGraphics.cpp @@ -124,6 +124,13 @@ Gfx::PRenderCommand Graphics::createRenderCommand() cmdBuffer->begin(getGraphicsCommands()->getCommands()); return cmdBuffer; } + +Gfx::PVertexDeclaration Graphics::createVertexDeclaration(const Array& element) +{ + PVertexDeclaration declaration = new VertexDeclaration(element); + return declaration; +} + Gfx::PVertexShader Graphics::createVertexShader(const ShaderCreateInfo& createInfo) { PVertexShader shader = new VertexShader(this); @@ -159,6 +166,15 @@ Gfx::PGraphicsPipeline Graphics::createGraphicsPipeline(const GraphicsPipelineCr PGraphicsPipeline pipeline = pipelineCache->createPipeline(createInfo); return pipeline; } + +Gfx::PSamplerState Graphics::createSamplerState(const SamplerCreateInfo& createInfo) +{ + PSamplerState sampler = new SamplerState(); // TODO: proper sampler creation + VkSamplerCreateInfo vkInfo = + init::SamplerCreateInfo(); + VK_CHECK(vkCreateSampler(handle, &vkInfo, nullptr, &sampler->sampler)); + return sampler; +} Gfx::PDescriptorLayout Graphics::createDescriptorLayout() { PDescriptorLayout layout = new DescriptorLayout(this); @@ -280,7 +296,7 @@ void Graphics::initInstance(GraphicsInitializer initInfo) appInfo.applicationVersion = VK_MAKE_VERSION(0, 0, 1); appInfo.pEngineName = initInfo.engineName; appInfo.engineVersion = VK_MAKE_VERSION(0, 0, 1); - appInfo.apiVersion = VK_API_VERSION_1_1; + appInfo.apiVersion = VK_API_VERSION_1_2; VkInstanceCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; diff --git a/src/Engine/Graphics/Vulkan/VulkanGraphics.h b/src/Engine/Graphics/Vulkan/VulkanGraphics.h index ed5536a..76fa04c 100644 --- a/src/Engine/Graphics/Vulkan/VulkanGraphics.h +++ b/src/Engine/Graphics/Vulkan/VulkanGraphics.h @@ -53,12 +53,14 @@ public: virtual Gfx::PVertexBuffer createVertexBuffer(const VertexBufferCreateInfo &bulkData) override; virtual Gfx::PIndexBuffer createIndexBuffer(const IndexBufferCreateInfo &bulkData) override; virtual Gfx::PRenderCommand createRenderCommand() override; + virtual Gfx::PVertexDeclaration createVertexDeclaration(const Array& element) override; virtual Gfx::PVertexShader createVertexShader(const ShaderCreateInfo& createInfo) override; virtual Gfx::PControlShader createControlShader(const ShaderCreateInfo& createInfo) override; virtual Gfx::PEvaluationShader createEvaluationShader(const ShaderCreateInfo& createInfo) override; virtual Gfx::PGeometryShader createGeometryShader(const ShaderCreateInfo& createInfo) override; virtual Gfx::PFragmentShader createFragmentShader(const ShaderCreateInfo& createInfo) override; virtual Gfx::PGraphicsPipeline createGraphicsPipeline(const GraphicsPipelineCreateInfo& createInfo) override; + virtual Gfx::PSamplerState createSamplerState(const SamplerCreateInfo& createInfo) override; virtual Gfx::PDescriptorLayout createDescriptorLayout() override; virtual Gfx::PPipelineLayout createPipelineLayout() override; diff --git a/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.cpp b/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.cpp index d250869..57e69d8 100644 --- a/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.cpp @@ -49,6 +49,14 @@ void QueueOwnedResourceDeletion::run() } } +void UniformBuffer::updateContents(const BulkResourceData &resourceData) +{ + Gfx::UniformBuffer::updateContents(resourceData); + void* data = lock(); + std::memcpy(data, resourceData.data, resourceData.size); + unlock(); +} + Semaphore::Semaphore(PGraphics graphics) : graphics(graphics) { @@ -121,3 +129,12 @@ void Fence::wait(uint32 timeout) break; } } + +VertexDeclaration::VertexDeclaration(const Array& elementList) + : elementList(elementList) +{ +} + +VertexDeclaration::~VertexDeclaration() +{ +} diff --git a/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.h b/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.h index 7c3c7c9..05ba3c6 100644 --- a/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.h +++ b/src/Engine/Graphics/Vulkan/VulkanGraphicsResources.h @@ -53,6 +53,17 @@ private: }; DEFINE_REF(Fence); +class VertexDeclaration : public Gfx::VertexDeclaration +{ +public: + Array elementList; + + VertexDeclaration(const Array& elementList); + virtual ~VertexDeclaration(); +private: +}; +DEFINE_REF(VertexDeclaration); + class QueueOwnedResourceDeletion { public: @@ -83,6 +94,11 @@ public: { return buffers[currentBuffer].buffer; } + uint32 getSize() const + { + return size; + } + VkDeviceSize getOffset() const; void advanceBuffer() { currentBuffer = (currentBuffer + 1) % numBuffers; @@ -116,7 +132,7 @@ class UniformBuffer : public Gfx::UniformBuffer, public ShaderBuffer public: UniformBuffer(PGraphics graphics, const BulkResourceData &resourceData); virtual ~UniformBuffer(); - + virtual void updateContents(const BulkResourceData &resourceData); protected: // Inherited via Vulkan::Buffer virtual void requestOwnershipTransfer(Gfx::QueueType newOwner); @@ -232,23 +248,16 @@ private: friend class TextureBase; friend class Texture2D; }; -DEFINE_REF(TextureHandle); -DECLARE_REF(TextureBase); class TextureBase { public: - static PTextureHandle cast(Gfx::PTexture texture) - { - PTextureBase base = texture.cast(); - return base->textureHandle; - } + static TextureHandle* cast(Gfx::PTexture texture); void changeLayout(VkImageLayout newLayout); protected: - PTextureHandle textureHandle; + TextureHandle* textureHandle; }; -DEFINE_REF(TextureBase); class Texture2D : public Gfx::Texture2D, public TextureBase { @@ -290,7 +299,7 @@ protected: }; DEFINE_REF(Texture2D); -class SamplerState +class SamplerState : public Gfx::SamplerState { public: VkSampler sampler; @@ -343,9 +352,9 @@ public: virtual ~Viewport(); virtual void resize(uint32 newX, uint32 newY); virtual void move(uint32 newOffsetX, uint32 newOffsetY); - -protected: + VkViewport getHandle() const { return handle; } private: + VkViewport handle; PGraphics graphics; friend class Graphics; }; diff --git a/src/Engine/Graphics/Vulkan/VulkanInitializer.cpp b/src/Engine/Graphics/Vulkan/VulkanInitializer.cpp index 5e2898b..2f4bb5d 100644 --- a/src/Engine/Graphics/Vulkan/VulkanInitializer.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanInitializer.cpp @@ -768,7 +768,14 @@ VkPipelineShaderStageCreateInfo init::PipelineShaderStageCreateInfo(VkShaderStag #pragma warning(disable : 4100) VkBool32 Seele::Vulkan::debugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char *layerPrefix, const char *msg, void *userDataManager) { - std::cerr << layerPrefix << ": " << msg << std::endl; + if(flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) + { + std::cerr << layerPrefix << ": " << msg << std::endl; + } + else + { + std::cerr << layerPrefix << ": " << msg << std::endl; + } return VK_FALSE; } #pragma warning(default : 4100) diff --git a/src/Engine/Graphics/Vulkan/VulkanPipelineCache.cpp b/src/Engine/Graphics/Vulkan/VulkanPipelineCache.cpp index 34332b3..4c8e7d8 100644 --- a/src/Engine/Graphics/Vulkan/VulkanPipelineCache.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanPipelineCache.cpp @@ -54,24 +54,17 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo createInfo.flags = 0; createInfo.stageCount = 0; - PPipelineLayout layout = graphics->createPipelineLayout(); - VkPipelineTessellationStateCreateInfo tessInfo; VkPipelineShaderStageCreateInfo stageInfos[5]; std::memset(stageInfos, 0, sizeof(stageInfos)); - if(gfxInfo.vertexShader != nullptr) - { - PVertexShader shader = gfxInfo.vertexShader.cast(); - VkPipelineShaderStageCreateInfo& vertInfo = stageInfos[createInfo.stageCount++]; - vertInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vertInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; - vertInfo.module = shader->getModuleHandle(); - vertInfo.pName = shader->getEntryPointName(); - for(auto descriptor : shader->getDescriptorLayouts()) - { - layout->addDescriptorLayout(descriptor.key, descriptor.value); - } - } + + PVertexShader vertexShader = gfxInfo.vertexShader.cast(); + VkPipelineShaderStageCreateInfo& vertInfo = stageInfos[createInfo.stageCount++]; + vertInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertInfo.module = vertexShader->getModuleHandle(); + vertInfo.pName = vertexShader->getEntryPointName(); + if(gfxInfo.controlShader != nullptr) { assert(gfxInfo.evalShader != nullptr); @@ -94,15 +87,6 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo tessInfo.pNext = 0; tessInfo.flags = 0; tessInfo.patchControlPoints = control->getNumPatches(); - - for(auto descriptor : eval->getDescriptorLayouts()) - { - layout->addDescriptorLayout(descriptor.key, descriptor.value); - } - for(auto descriptor : control->getDescriptorLayouts()) - { - layout->addDescriptorLayout(descriptor.key, descriptor.value); - } } if(gfxInfo.geometryShader != nullptr) { @@ -113,11 +97,6 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo geometryInfo.stage = VK_SHADER_STAGE_GEOMETRY_BIT; geometryInfo.module = geometry->getModuleHandle(); geometryInfo.pName = geometry->getEntryPointName(); - - for(auto descriptor : geometry->getDescriptorLayouts()) - { - layout->addDescriptorLayout(descriptor.key, descriptor.value); - } } if(gfxInfo.fragmentShader != nullptr) { @@ -128,40 +107,81 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo fragmentInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fragmentInfo.module = fragment->getModuleHandle(); fragmentInfo.pName = fragment->getEntryPointName(); - - for(auto descriptor : fragment->getDescriptorLayouts()) - { - layout->addDescriptorLayout(descriptor.key, descriptor.value); - } } - layout->create(); VkPipelineVertexInputStateCreateInfo vertexInput = init::PipelineVertexInputStateCreateInfo(); - Gfx::PVertexDeclaration vertexDecl = gfxInfo.vertexDeclaration; - auto vertexStreams = vertexDecl->getVertexStreams(); - Array bindingDesc(vertexStreams.size()); - Array attribDesc; + PVertexDeclaration vertexDecl = gfxInfo.vertexDeclaration; + auto vertexStreams = vertexDecl->elementList; uint32 bindingNum = 0; - for(auto vertexBinding : vertexStreams) + uint32 bindingsMask = 0; + uint32 attributesNum = 0; + Array bindings; + Array attributes; + Map bindingToStream; + Map streamToBinding; + std::memset(bindings.data(), 0, sizeof(VkVertexInputBindingDescription) * 16); // if default allocation size ever changes, this breaks + std::memset(attributes.data(), 0, sizeof(VkVertexInputAttributeDescription) * 16); + for(auto& element : vertexStreams) { - uint32 stride = 0; - for(auto vertexAttrib : vertexBinding.getVertexDescriptions()) + //if((1 << element.attributeIndex) & vertexAttributeMask) // TODO: attribute mask { - auto attrib = attribDesc.add(); - attrib.binding = bindingNum; - attrib.format = cast(vertexAttrib.vertexFormat); - attrib.location = vertexAttrib.location; - attrib.offset = vertexAttrib.offset; + if(element.streamIndex >= bindings.size()) + { + bindings.resize(element.streamIndex + 1); // This should not cause any actual allocations + } + VkVertexInputBindingDescription currBinding = bindings[element.streamIndex]; + if((bindingsMask & (1 << element.streamIndex)) != 0) + { + assert(currBinding.binding == element.streamIndex); + assert(currBinding.inputRate == element.bInstanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX); + assert(currBinding.stride == element.stride); + } + else + { + assert(currBinding.binding == 0 && currBinding.inputRate == 0 && currBinding.stride == 0); + currBinding.binding = element.streamIndex; + currBinding.inputRate = element.bInstanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; + currBinding.stride = element.stride; + + bindingsMask |= 1 << element.streamIndex; + } } - bindingDesc[bindingNum].binding = bindingNum; - bindingDesc[bindingNum].stride = stride; - bindingDesc[bindingNum].inputRate = vertexBinding.isInstanced() ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; + } + + for(uint32 i = 0; i < bindings.size(); ++i) + { + if(!((1 << i) & bindingsMask)) + { + continue; + } + + bindingToStream[bindingNum] = i; + streamToBinding[i] = bindingNum; + VkVertexInputBindingDescription& currBinding = bindings[bindingNum]; + currBinding = bindings[i]; + currBinding.binding = bindingNum; bindingNum++; } - vertexInput.pVertexBindingDescriptions = bindingDesc.data(); - vertexInput.vertexBindingDescriptionCount = bindingDesc.size(); - vertexInput.pVertexAttributeDescriptions = attribDesc.data(); - vertexInput.vertexAttributeDescriptionCount = attribDesc.size(); + + for(auto& element : vertexStreams) + { + //TODO: vertex attribute mask + if(attributesNum >= attributes.size()) + { + attributes.resize(attributesNum + 1); // This should not cause any actual allocations + } + + VkVertexInputAttributeDescription& currAttribute = attributes[attributesNum++]; + currAttribute.location = element.attributeIndex; + currAttribute.binding = streamToBinding[element.streamIndex]; + currAttribute.format = cast(element.vertexFormat); + currAttribute.offset = element.offset; + } + + vertexInput.pVertexBindingDescriptions = bindings.data(); + vertexInput.vertexBindingDescriptionCount = bindings.size(); + vertexInput.pVertexAttributeDescriptions = attributes.data(); + vertexInput.vertexAttributeDescriptionCount = attributes.size(); VkPipelineInputAssemblyStateCreateInfo assemblyInfo = init::PipelineInputAssemblyStateCreateInfo( @@ -242,6 +262,8 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo 0 ); + PPipelineLayout layout = gfxInfo.pipelineLayout.cast(); + createInfo.pStages = stageInfos; createInfo.pVertexInputState = &vertexInput; createInfo.pInputAssemblyState = &assemblyInfo; @@ -260,7 +282,7 @@ PGraphicsPipeline PipelineCache::createPipeline(const GraphicsPipelineCreateInfo auto beginTime = std::chrono::high_resolution_clock::now(); VK_CHECK(vkCreateGraphicsPipelines(graphics->getDevice(), cache, 1, &createInfo, nullptr, &pipelineHandle)); auto endTime = std::chrono::high_resolution_clock::now(); - int64 delta = std::chrono::duration_cast(endTime - beginTime).count(); + int64 delta = std::chrono::duration_cast(endTime - beginTime).count(); std::cout << "Gfx creation time: " << delta << std::endl; PGraphicsPipeline result = new GraphicsPipeline(graphics, pipelineHandle, layout, gfxInfo); diff --git a/src/Engine/Graphics/Vulkan/VulkanRenderPass.cpp b/src/Engine/Graphics/Vulkan/VulkanRenderPass.cpp index f1a834a..c90ec51 100644 --- a/src/Engine/Graphics/Vulkan/VulkanRenderPass.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanRenderPass.cpp @@ -11,6 +11,11 @@ RenderPass::RenderPass(PGraphics graphics, Gfx::PRenderTargetLayout layout) : Gfx::RenderPass(layout) , graphics(graphics) { + renderArea.extent.width = layout->width; + renderArea.extent.height = layout->height; + renderArea.offset.x = 0; + renderArea.offset.y = 0; + subpassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS; Array attachments; Array inputRefs; Array colorRefs; diff --git a/src/Engine/Graphics/Vulkan/VulkanShader.cpp b/src/Engine/Graphics/Vulkan/VulkanShader.cpp index 82cdb02..cdf8af4 100644 --- a/src/Engine/Graphics/Vulkan/VulkanShader.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanShader.cpp @@ -2,6 +2,8 @@ #include "VulkanGraphics.h" #include "VulkanDescriptorSets.h" #include "slang.h" +#include "spirv_cross/spirv_reflect.hpp" +#include using namespace slang; using namespace Seele; @@ -46,8 +48,42 @@ static SlangStage getStageFromShaderType(ShaderType type) } } +/*static void createMixedDescriptorLayout(PDescriptorLayout layout, VariableLayoutReflection* parameter) +{ + //std::cout << "category: " << (uint32)parameter->ge << std::endl; + uint32 categoryCount = parameter->getCategoryCount(); + std::cout << "Mixed parameter " << parameter->getName() << " with categories: " << std::endl; + for(uint32 i = 0; i < categoryCount; ++i) + { + ParameterCategory category = parameter->getCategoryByIndex(i); + uint32 offset = parameter->getOffset(category); + uint32 space = parameter->getBindingSpace(category); + std::cout << "category: " << category << std::endl << " offset: " << offset << std::endl << " space: " << space << std::endl; + } +} + +static Gfx::SeDescriptorType getTypeFromKind(slang::TypeReflection::Kind kind) +{ + switch (kind) + { + case slang::TypeReflection::Kind::ConstantBuffer: + case slang::TypeReflection::Kind::GenericTypeParameter: + case slang::TypeReflection::Kind::ParameterBlock: + return Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + case slang::TypeReflection::Kind::ShaderStorageBuffer: + return Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER; + case slang::TypeReflection::Kind::TextureBuffer: + return Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + case slang::TypeReflection::Kind::SamplerState: + return Gfx::SE_DESCRIPTOR_TYPE_SAMPLER; + default: + return Gfx::SE_DESCRIPTOR_TYPE_MAX_ENUM; + } +}*/ + void Shader::create(const ShaderCreateInfo& createInfo) { + std::cout << "--------------------------------" << std::endl; entryPointName = createInfo.entryPoint; static SlangSession* session = spCreateSession(NULL); @@ -82,28 +118,14 @@ void Shader::create(const ShaderCreateInfo& createInfo) std::cout << diagnostics << std::endl; } - ShaderReflection* reflection = slang::ShaderReflection::get(request); - - uint32 parameterCount = reflection->getParameterCount(); - for(uint32 i = 0; i < parameterCount; ++i) - { - VariableLayoutReflection* parameter = - reflection->getParameterByIndex(i); - uint32 descriptorIndex = parameter->getBindingSpace(); - uint32 descriptorBinding = parameter->getBindingIndex(); - PDescriptorLayout& layout = descriptorSets[descriptorIndex]; - std::cout << parameter->getTypeLayout()->getName() << std::endl; - //layout->addDescriptorBinding(descriptorBinding, parame) - } - size_t dataSize = 0; - const void* data = spGetEntryPointCode(request, entryPointIndex, &dataSize); + const uint32* data = reinterpret_cast(spGetEntryPointCode(request, entryPointIndex, &dataSize)); VkShaderModuleCreateInfo moduleInfo; moduleInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; moduleInfo.pNext = nullptr; moduleInfo.flags = 0; moduleInfo.codeSize = dataSize; - moduleInfo.pCode = static_cast(data); + moduleInfo.pCode = data; VK_CHECK(vkCreateShaderModule(graphics->getDevice(), &moduleInfo, nullptr, &module)); } \ No newline at end of file diff --git a/src/Engine/Graphics/Vulkan/VulkanShader.h b/src/Engine/Graphics/Vulkan/VulkanShader.h index 18113ca..2b3762f 100644 --- a/src/Engine/Graphics/Vulkan/VulkanShader.h +++ b/src/Engine/Graphics/Vulkan/VulkanShader.h @@ -22,7 +22,8 @@ public: } const char* getEntryPointName() const { - return entryPointName.c_str(); + //SLang renames all entry points to main, so we dont need that + return "main";//entryPointName.c_str(); } Map getDescriptorLayouts(); private: diff --git a/src/Engine/Graphics/Vulkan/VulkanTexture.cpp b/src/Engine/Graphics/Vulkan/VulkanTexture.cpp index 3b20a69..d150155 100644 --- a/src/Engine/Graphics/Vulkan/VulkanTexture.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanTexture.cpp @@ -162,6 +162,16 @@ TextureHandle::~TextureHandle() deletionQueue.addPendingDelete(cmdBuffer, [device, img]() { vkDestroyImage(device, img, nullptr); }); } +TextureHandle* TextureBase::cast(Gfx::PTexture texture) +{ + if(texture->getTexture2D() != nullptr) + { + PTexture2D texture2D = texture.cast(); + return texture2D->textureHandle; + } + return nullptr; +} + void TextureHandle::changeLayout(VkImageLayout newLayout) { VkImageMemoryBarrier barrier = diff --git a/src/Engine/Graphics/Vulkan/VulkanViewport.cpp b/src/Engine/Graphics/Vulkan/VulkanViewport.cpp index 82122a0..c817a41 100644 --- a/src/Engine/Graphics/Vulkan/VulkanViewport.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanViewport.cpp @@ -258,6 +258,9 @@ void Window::choosePresentMode(const Array &modes) Viewport::Viewport(PGraphics graphics, PWindow owner, const ViewportCreateInfo &viewportInfo) : Gfx::Viewport(owner, viewportInfo), graphics(graphics) { + handle = init::Viewport(static_cast(viewportInfo.sizeX), static_cast(viewportInfo.sizeY), 0.f, 1.f); + handle.x = static_cast(viewportInfo.offsetX); + handle.y = static_cast(viewportInfo.offsetY); } Viewport::~Viewport() diff --git a/src/Engine/Material/CMakeLists.txt b/src/Engine/Material/CMakeLists.txt index 4ebfe39..8e7de34 100644 --- a/src/Engine/Material/CMakeLists.txt +++ b/src/Engine/Material/CMakeLists.txt @@ -8,4 +8,5 @@ target_sources(SeeleEngine MaterialAsset.cpp MaterialInstance.h MaterialInstance.cpp - ShaderExpression.h) \ No newline at end of file + ShaderExpression.h + ShaderExpression.cpp) \ No newline at end of file diff --git a/src/Engine/Material/Material.cpp b/src/Engine/Material/Material.cpp index 87812b4..ab17f26 100644 --- a/src/Engine/Material/Material.cpp +++ b/src/Engine/Material/Material.cpp @@ -2,6 +2,7 @@ #include "Asset/AssetRegistry.h" #include "Graphics/VertexShaderInput.h" #include "BRDF.h" +#include "Graphics/WindowManager.h" #include #include #include @@ -32,21 +33,23 @@ Material::~Material() void Material::save() { - } void Material::load() { - } void Material::compile() { + layout = WindowManager::getGraphics()->createDescriptorLayout(); auto& stream = getReadStream(); json j; stream >> j; materialName = j["name"].get(); + std::cout << "Compiling material " << materialName << std::endl; + //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(); @@ -57,45 +60,55 @@ void Material::compile() codeStream << "import MaterialParameter;" << std::endl; codeStream << "struct " << materialName << ": IMaterial {" << std::endl; + uint32 uniformBufferOffset = 0; + uint32 bindingCounter = 1; // Uniform buffers are always binding 0 + layout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); for(auto param : j["params"].items()) { std::string type = param.value()["type"].get(); - auto default = param.value().find("default"); if(type.compare("float") == 0) { - PFloatParameter p = new FloatParameter(); - p->name = param.key(); + PFloatParameter p = new FloatParameter(param.key(), uniformBufferOffset, 0); + codeStream << "layout(offset = " << uniformBufferOffset << ")"; + uniformBufferOffset += 4; if(default != param.value().end()) { - p->defaultValue = std::stof(default.value().get()); + p->data = std::stof(default.value().get()); } parameters.add(p); } else if(type.compare("float3") == 0) { - PVectorParameter p = new VectorParameter(); - p->name = param.key(); + PVectorParameter p = new VectorParameter(param.key(), uniformBufferOffset, 0); + codeStream << "layout(offset = " << uniformBufferOffset << ")"; + uniformBufferOffset += 12; if(default != param.value().end()) { - p->defaultValue = parseVector(default.value().get().c_str()); + p->data = parseVector(default.value().get().c_str()); } parameters.add(p); } else if(type.compare("Texture2D") == 0) { - PTextureParameter p = new TextureParameter(); - p->name = param.key(); + PTextureParameter p = new TextureParameter(param.key(), 0, bindingCounter); + layout->addDescriptorBinding(bindingCounter++, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE); if(default != param.value().end()) { - + p->data = AssetRegistry::findTexture(default.value().get()); + } + else + { + p->data = AssetRegistry::findTexture(""); // this will return placeholder texture } parameters.add(p); } else if(type.compare("SamplerState") == 0) { - PSamplerParameter p = new SamplerParameter(); - p->name = param.key(); + 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 @@ -104,6 +117,18 @@ void Material::compile() } codeStream << type << " " << param.key() << ";\n"; } + uniformDataSize = uniformBufferOffset; + if(uniformDataSize != 0) + { + uniformData = new uint8[uniformDataSize]; + BulkResourceData resourceData; + resourceData.data = uniformData; + resourceData.size = uniformDataSize; + uniformBuffer = WindowManager::getGraphics()->createUniformBuffer(resourceData); + } + layout->create(); + descriptorSet = layout->allocatedDescriptorSet(); + updateDescriptorData(); BRDF* brdf = BRDF::getBRDFByName(profile); brdf->generateMaterialCode(codeStream, j["code"]); codeStream << "};"; @@ -113,10 +138,11 @@ void Material::compile() const Gfx::ShaderCollection* Material::getShaders(Gfx::RenderPassType renderPass, VertexInputType* vertexInput) const { Gfx::ShaderPermutation permutation; + permutation.passType = renderPass; std::string materialName = getFileName(); std::string vertexInputName = vertexInput->getName(); std::memcpy(permutation.materialName, materialName.c_str(), sizeof(permutation.materialName)); - std::memcpy(permutation.materialName, vertexInputName.c_str(), sizeof(permutation.materialName)); + std::memcpy(permutation.vertexInputName, vertexInputName.c_str(), sizeof(permutation.vertexInputName)); return shaderMap.findShaders(Gfx::PermutationId(permutation)); } diff --git a/src/Engine/Material/Material.h b/src/Engine/Material/Material.h index 4f498f9..4bc164d 100644 --- a/src/Engine/Material/Material.h +++ b/src/Engine/Material/Material.h @@ -14,7 +14,9 @@ public: ~Material(); virtual void save() override; virtual void load() override; - virtual PMaterial getRenderMaterial() { return this; } + 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; @@ -25,7 +27,9 @@ private: static std::mutex shaderMapLock; std::string materialName; + Gfx::PDescriptorLayout layout; friend class MaterialLoader; + friend class MaterialInstance; }; DEFINE_REF(Material); } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Material/MaterialAsset.cpp b/src/Engine/Material/MaterialAsset.cpp index 24979b6..a272b98 100644 --- a/src/Engine/Material/MaterialAsset.cpp +++ b/src/Engine/Material/MaterialAsset.cpp @@ -1,4 +1,5 @@ #include "MaterialAsset.h" +#include "Graphics/WindowManager.h" using namespace Seele; @@ -19,3 +20,35 @@ MaterialAsset::MaterialAsset(const std::filesystem::path& fullPath) MaterialAsset::~MaterialAsset() { } + +void MaterialAsset::beginFrame() +{ + descriptorSet->beginFrame(); +} + +void MaterialAsset::endFrame() +{ + descriptorSet->endFrame(); +} + +void MaterialAsset::updateDescriptorData() +{ + BulkResourceData uniformUpdate; + uniformUpdate.size = uniformDataSize; + uniformUpdate.data = uniformData; + for(auto param : parameters) + { + param->updateDescriptorSet(descriptorSet, uniformData); + } + if(uniformUpdate.size != 0) + { + uniformBuffer->updateContents(uniformUpdate); + descriptorSet->updateBuffer(0, uniformBuffer); + } + descriptorSet->writeChanges(); +} + +Gfx::PDescriptorSet MaterialAsset::getDescriptor() const +{ + return descriptorSet; +} \ No newline at end of file diff --git a/src/Engine/Material/MaterialAsset.h b/src/Engine/Material/MaterialAsset.h index e6c4efa..c408019 100644 --- a/src/Engine/Material/MaterialAsset.h +++ b/src/Engine/Material/MaterialAsset.h @@ -14,15 +14,24 @@ public: MaterialAsset(const std::string &directory, const std::string &name); MaterialAsset(const std::filesystem::path &fullPath); ~MaterialAsset(); + virtual void beginFrame(); + virtual void endFrame(); virtual void save() = 0; virtual void load() = 0; - virtual PMaterial getRenderMaterial() = 0; + virtual const Material* getRenderMaterial() const = 0; 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(); + Gfx::PDescriptorSet getDescriptor() const; protected: //For now its simply the collection of parameters, since there is no point for expressions Array parameters; + Gfx::PDescriptorSet descriptorSet; + Gfx::PUniformBuffer uniformBuffer; + uint32 uniformDataSize; + uint8* uniformData; }; DEFINE_REF(MaterialAsset); } // namespace Seele diff --git a/src/Engine/Material/MaterialInstance.cpp b/src/Engine/Material/MaterialInstance.cpp index ae5e47a..074f048 100644 --- a/src/Engine/Material/MaterialInstance.cpp +++ b/src/Engine/Material/MaterialInstance.cpp @@ -1,5 +1,6 @@ #include "MaterialInstance.h" #include "Material.h" +#include "Graphics/WindowManager.h" using namespace Seele; @@ -28,20 +29,15 @@ void MaterialInstance::save() void MaterialInstance::load() { - + baseMaterial = nullptr; // TODO: actually load the file + BulkResourceData resourceData; + resourceData.size = baseMaterial->uniformDataSize; + resourceData.data = nullptr; + uniformBuffer = WindowManager::getGraphics()->createUniformBuffer(resourceData); + descriptorSet = baseMaterial->layout->allocatedDescriptorSet(); } -PMaterial MaterialInstance::getRenderMaterial() +const Material* MaterialInstance::getRenderMaterial() const { return baseMaterial; } - -PMaterial MaterialInstance::getBaseMaterial() const -{ - return baseMaterial; -} - -Gfx::PDescriptorSet MaterialInstance::getDescriptor() -{ - return nullptr; -} \ No newline at end of file diff --git a/src/Engine/Material/MaterialInstance.h b/src/Engine/Material/MaterialInstance.h index d407ecb..4aa983f 100644 --- a/src/Engine/Material/MaterialInstance.h +++ b/src/Engine/Material/MaterialInstance.h @@ -14,11 +14,9 @@ public: ~MaterialInstance(); virtual void save() override; virtual void load() override; - virtual PMaterial getRenderMaterial(); - PMaterial getBaseMaterial() const; - Gfx::PDescriptorSet getDescriptor(); + virtual const Material* getRenderMaterial() const; private: - PMaterial baseMaterial; + Material* baseMaterial; }; DEFINE_REF(MaterialInstance); } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Material/ShaderExpression.h b/src/Engine/Material/ShaderExpression.h index def0fd4..b292eb7 100644 --- a/src/Engine/Material/ShaderExpression.h +++ b/src/Engine/Material/ShaderExpression.h @@ -14,65 +14,50 @@ struct ExpressionOutput struct ShaderExpression { }; +DECLARE_NAME_REF(Gfx, DescriptorSet); struct ShaderParameter : public ShaderExpression { std::string name; + uint32 byteOffset; + uint32 binding; + ShaderParameter(std::string name, uint32 byteOffset, uint32 binding); + virtual ~ShaderParameter(); + // update a descriptorset, in case of a uniform buffer, copy the data to the dst + byteOffset + virtual void updateDescriptorSet(Gfx::PDescriptorSet descriptorSet, uint8* dst) = 0; }; DEFINE_REF(ShaderParameter); struct FloatParameter : public ShaderParameter { - float defaultValue; - bool setParameter(const std::string& paramName, float newDefault) - { - if(name.compare(paramName) == 0) - { - defaultValue = newDefault; - return true; - } - return false; - } + float data; + FloatParameter(std::string name, uint32 byteOffset, uint32 binding); + virtual ~FloatParameter(); + virtual void updateDescriptorSet(Gfx::PDescriptorSet descriptorSet, uint8* dst) override; }; DEFINE_REF(FloatParameter); struct VectorParameter : public ShaderParameter { - Vector defaultValue; - bool setParameter(const std::string& paramName, Vector newDefault) - { - if(name.compare(paramName) == 0) - { - defaultValue = newDefault; - return true; - } - return false; - } + Vector data; + VectorParameter(std::string name, uint32 byteOffset, uint32 binding); + virtual ~VectorParameter(); + virtual void updateDescriptorSet(Gfx::PDescriptorSet descriptorSet, uint8* dst) override; }; DEFINE_REF(VectorParameter); -DECLARE_NAME_REF(Gfx, Texture2D); +DECLARE_REF(TextureAsset); struct TextureParameter : public ShaderParameter { - Gfx::PTexture2D defaultValue; - bool setParameter(const std::string& paramName, Gfx::PTexture2D newDefault) - { - if(name.compare(paramName) == 0) - { - return true; - } - return false; - } + PTextureAsset data; + TextureParameter(std::string name, uint32 byteOffset, uint32 binding); + virtual ~TextureParameter(); + virtual void updateDescriptorSet(Gfx::PDescriptorSet descriptorSet, uint8* dst) override; }; DEFINE_REF(TextureParameter); DECLARE_NAME_REF(Gfx, SamplerState); struct SamplerParameter : public ShaderParameter { - Gfx::PSamplerState defaultValue; - bool setParameter(const std::string& paramName, Gfx::PSamplerState newDefault) - { - if(name.compare(paramName) == 0) - { - return true; - } - return false; - } + Gfx::PSamplerState data; + SamplerParameter(std::string name, uint32 byteOffset, uint32 binding); + virtual ~SamplerParameter(); + virtual void updateDescriptorSet(Gfx::PDescriptorSet descriptorSet, uint8* dst) override; }; DEFINE_REF(SamplerParameter); diff --git a/src/Engine/MinimalEngine.h b/src/Engine/MinimalEngine.h index 40a5b7c..635b2e8 100644 --- a/src/Engine/MinimalEngine.h +++ b/src/Engine/MinimalEngine.h @@ -136,6 +136,7 @@ public: { object = (RefObject *)registeredObj->value; } + object->addRef(); } explicit RefPtr(RefObject *other) : object(other) diff --git a/src/Engine/main.cpp b/src/Engine/main.cpp index 6671a32..be15ca8 100644 --- a/src/Engine/main.cpp +++ b/src/Engine/main.cpp @@ -12,7 +12,7 @@ int main() mainWindowInfo.height = 720; mainWindowInfo.bFullscreen = false; mainWindowInfo.numSamples = 1; - mainWindowInfo.pixelFormat = Gfx::SE_FORMAT_R8G8B8_UNORM; + mainWindowInfo.pixelFormat = Gfx::SE_FORMAT_B8G8R8A8_UNORM; auto window = core.getWindowManager()->addWindow(mainWindowInfo); ViewportCreateInfo sceneViewInfo; sceneViewInfo.sizeX = 1280;