diff --git a/.gitmodules b/.gitmodules index c2c720e..4c388b1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "external/Vulkan-Utility-Libraries"] path = external/Vulkan-Utility-Libraries url = https://github.com/KhronosGroup/Vulkan-Utility-Libraries +[submodule "external/slang"] + path = external/slang + url = https://github.com/shader-slang/slang.git diff --git a/build.cpp b/build.cpp index 2443b5b..09df40a 100755 --- a/build.cpp +++ b/build.cpp @@ -83,7 +83,7 @@ CUtlString client_lib; #include "rapier/__build.cpp" #include "engine/__build.cpp" +#include "shadercompiler/__build.cpp" #include "launcher/__build.cpp" - #include "funnyassets/__build.cpp" diff --git a/engine/engine.cpp b/engine/engine.cpp index 4fe3773..813552a 100644 --- a/engine/engine.cpp +++ b/engine/engine.cpp @@ -18,7 +18,63 @@ extern "C" void FunnyMain( int argc, char **argv ) ServerGameDLL()->Init(); + IShader *pShader = NULL; + IBuffer *pCameraInfoBuffer = NULL; + IMaterial *pMaterial = NULL; + + IImage *pOutputImage = NULL; + IVertexBuffer *pVertices = NULL; + + float vertices[9] = { + 0,-0.5, 0, + 0.5,0.5, 0, + -0.5,0.5, 0, + }; + + pVertices = g_pRenderContext->CreateVertexBuffer(36); + + void *pMapped = pVertices->Map(); + V_memcpy(pMapped, vertices, 36); + pVertices->Unmap(); + + pCameraInfoBuffer = g_pRenderContext->CreateConstantBuffer(64); + + pShader = g_pRenderContext->CreateShader("funnygame/core/shaders/flat.shader_c"); + pMaterial = g_pRenderContext->CreateMaterial(pShader); + pMaterial->PSSetConstantsBuffer(0, pCameraInfoBuffer); + + pOutputImage = g_pRenderContext->CreateRenderTarget( + g_pRenderContext->GetNewOutputImageWidth(), + g_pRenderContext->GetNewOutputImageHeight(), + IMAGE_FORMAT_RGBA8_UNORM, + MULTISAMPLE_TYPE_NONE); + + IRenderCommandList *pCommandList = g_pRenderContext->CreateCommandList(); + pCommandList->StartRecording(); + pCommandList->SetRenderTarget(0, pOutputImage); + pCommandList->SetMaterial(pMaterial); + pCommandList->SetVertexBuffer(0, pVertices); + pCommandList->DrawPrimitives(3, 0, 1, 0); + pCommandList->EndRecording(); + for (;;) { + /* + if (g_pRenderContext->BIsOutputImageOutdated()) + { + uint32_t nWidth; + uint32_t nHeight; + pOutputImage = g_pRenderContext->CreateRenderTarget( + g_pRenderContext->GetNewOutputImageWidth(), + g_pRenderContext->GetNewOutputImageHeight(), + IMAGE_FORMAT_RGBA8_UNORM, + MULTISAMPLE_TYPE_NONE); + } + */ + + g_pRenderContext->SubmitCommandList(pCommandList); + + g_pRenderContext->SetOutputImage(pOutputImage); + gamewindow->UpdateWindow(); Materials()->Frame(0); }; diff --git a/engine/filesystem_pak.cpp b/engine/filesystem_pak.cpp index ca175e8..423d9e9 100644 --- a/engine/filesystem_pak.cpp +++ b/engine/filesystem_pak.cpp @@ -83,6 +83,7 @@ public: delete pHandle; } virtual CUtlBuffer Read( IFileHandle *pFile ) override { return NULL; }; + virtual const char *ReadString( IFileHandle *pFile ) override { return NULL; }; }; EXPOSE_FILESYSTEM(CPAKFileSystem, "pakfs"); diff --git a/external/linux/libgfx.so b/external/linux/libgfx.so new file mode 100755 index 0000000..692c920 Binary files /dev/null and b/external/linux/libgfx.so differ diff --git a/external/linux/libgfx.so.0.2025.24.2 b/external/linux/libgfx.so.0.2025.24.2 new file mode 100644 index 0000000..692c920 Binary files /dev/null and b/external/linux/libgfx.so.0.2025.24.2 differ diff --git a/external/linux/libslang-compiler.so b/external/linux/libslang-compiler.so new file mode 100755 index 0000000..3df3d5c Binary files /dev/null and b/external/linux/libslang-compiler.so differ diff --git a/external/linux/libslang-compiler.so.0.2025.24.2 b/external/linux/libslang-compiler.so.0.2025.24.2 new file mode 100644 index 0000000..3df3d5c Binary files /dev/null and b/external/linux/libslang-compiler.so.0.2025.24.2 differ diff --git a/external/linux/libslang-glsl-module-2025.24.2.so b/external/linux/libslang-glsl-module-2025.24.2.so new file mode 100644 index 0000000..1da6b5f Binary files /dev/null and b/external/linux/libslang-glsl-module-2025.24.2.so differ diff --git a/external/linux/libslang-glslang-2025.24.2.so b/external/linux/libslang-glslang-2025.24.2.so new file mode 100644 index 0000000..9e03bc5 Binary files /dev/null and b/external/linux/libslang-glslang-2025.24.2.so differ diff --git a/external/linux/libslang-llvm.so b/external/linux/libslang-llvm.so new file mode 100644 index 0000000..5a01092 Binary files /dev/null and b/external/linux/libslang-llvm.so differ diff --git a/external/linux/libslang-rt.so b/external/linux/libslang-rt.so new file mode 100755 index 0000000..6f4b26c Binary files /dev/null and b/external/linux/libslang-rt.so differ diff --git a/external/linux/libslang-rt.so.0.2025.24.2 b/external/linux/libslang-rt.so.0.2025.24.2 new file mode 100644 index 0000000..6f4b26c Binary files /dev/null and b/external/linux/libslang-rt.so.0.2025.24.2 differ diff --git a/external/linux/libslang.so b/external/linux/libslang.so new file mode 100755 index 0000000..3df3d5c Binary files /dev/null and b/external/linux/libslang.so differ diff --git a/external/slang b/external/slang new file mode 160000 index 0000000..5d775e2 --- /dev/null +++ b/external/slang @@ -0,0 +1 @@ +Subproject commit 5d775e2829ceef5bd34ec89aa3eafa4968a74c8e diff --git a/fpc/fpc_temp b/fpc/fpc_temp deleted file mode 100755 index ccd52b1..0000000 Binary files a/fpc/fpc_temp and /dev/null differ diff --git a/fpc/library/clang/ld.cpp b/fpc/library/clang/ld.cpp index 4ababf3..d43e59d 100644 --- a/fpc/library/clang/ld.cpp +++ b/fpc/library/clang/ld.cpp @@ -157,6 +157,7 @@ CUtlString CClangLinker::Link( LinkProject_t *pProject ) if (pProject->m_target.kernel == TARGET_KERNEL_LINUX || pProject->m_target.kernel == TARGET_KERNEL_ANDROID) { args.AppendTail("-rdynamic"); + args.AppendTail("-Wl,-rpath,$ORIGIN"); } // Dynamic libraries @@ -180,6 +181,11 @@ CUtlString CClangLinker::Link( LinkProject_t *pProject ) args.AppendTail("-l"); args.AppendTail(lib); } + for (auto lib: pProject->libraryDirectories) + { + args.AppendTail("-L"); + args.AppendTail(lib); + } // Apple frameworks for (auto &directory: pProject->frameworkDirectories) diff --git a/fpc/main.cpp b/fpc/main.cpp index dd63e7e..159714e 100644 --- a/fpc/main.cpp +++ b/fpc/main.cpp @@ -63,6 +63,9 @@ void IEngine_Signal(int sig) Plat_Backtrace(); Plat_FatalErrorFunc("Fault"); break; + case SIGINT: + Plat_Exit(0); + break; default: break; }; diff --git a/funnyassets/__build.cpp b/funnyassets/__build.cpp index bce7449..1e5de76 100644 --- a/funnyassets/__build.cpp +++ b/funnyassets/__build.cpp @@ -37,7 +37,6 @@ DECLARE_BUILD_STAGE(assets) filesystem2->CopyDirectory("build", "tools"); filesystem2->CopyDirectory(CUtlString("build/funnygame/assets"), "funnyassets/maps"); - filesystem2->CopyDirectory(CUtlString("build/funnygame/assets"), "funnyassets/shaders"); filesystem2->CopyDirectory(CUtlString("build/funnygame/assets"), "funnyassets/fonts"); filesystem2->CopyDirectory(CUtlString("build/funnygame/assets"), "funnyassets/textures"); filesystem2->CopyDirectory(CUtlString("build/funnygame/assets"), "funnyassets/materials"); @@ -49,13 +48,14 @@ DECLARE_BUILD_STAGE(assets) build_shader("fgui_text_frag"); build_shader("fgui_text_vert"); */ - build_shader("flat"); CUtlVector python_args = { "build/tools/makepak64.py", CUtlString("build/funnygame/assets"), bStaticBuild ? CUtlString("%s/bin/%s.pak", szOutputDir.GetString(), "rtt") : CUtlString("%s/funnygame/%s.pak", szOutputDir.GetString(), "rtt"), }; runner->Run("python3", python_args); + filesystem2->CopyDirectory(CUtlString("%s/funnygame/core", szOutputDir.GetString()),"build/funnygame/assets"); + /* if (Target_t::DefaultTarget().kernel == TARGET_KERNEL_IOS ||Target_t::DefaultTarget().kernel == TARGET_KERNEL_DARWIN) { python_args = { @@ -66,15 +66,14 @@ DECLARE_BUILD_STAGE(assets) runner->Run("python3", python_args); } else { filesystem2->CopyDirectory(CUtlString("%s/funnygame", szOutputDir.GetString()),"build/funnygame/vulkan/shaders"); - /* python_args = { "build/tools/makepak64.py", CUtlString("build/funnygame/vulkan"), bStaticBuild ? CUtlString("%s/bin/%s.pak", szOutputDir.GetString(), "vulkan") : CUtlString("%s/funnygame/%s.pak", szOutputDir.GetString(), "vulkan"), }; runner->Run("python3", python_args); - */ } + */ runner->Wait(); if (bStaticBuild) diff --git a/funnyassets/shaders/flat.shader b/funnyassets/shaders/flat.shader new file mode 100644 index 0000000..7a9ee69 --- /dev/null +++ b/funnyassets/shaders/flat.shader @@ -0,0 +1,48 @@ +#define COMMON using namespace Common; namespace Common + +#ifdef VS_SHADER +#define VS using namespace VertexShader; namespace VertexShader +#else +#define VS namespace VertexShader_DO_NOT_USE +#endif + +#ifdef PS_SHADER +#define PS using namespace PixelShader; namespace PixelShader +#else +#define PS namespace PixelShader_DO_NOT_USE +#endif + +COMMON +{ + + struct PS_INPUT + { + float4 m_vPosition : SV_Position; + } +} +VS +{ + cbuffer CameraInfo + { + float4x4 m_viewProj; + }; + + struct VS_INPUT + { + float3 m_vPosition: POSITION; + } + + PS_INPUT vsMain( VS_INPUT i ) + { + PS_INPUT o; + o.m_vPosition = { i.m_vPosition, 1 }; + return o; + } +} +PS +{ + float4 psMain( PS_INPUT i ) + { + return float4(1); + } +} diff --git a/funnyassets/shaders/flat.shadermeta b/funnyassets/shaders/flat.shadermeta new file mode 100644 index 0000000..5e3e9ed --- /dev/null +++ b/funnyassets/shaders/flat.shadermeta @@ -0,0 +1,2 @@ +[Inputs] + diff --git a/funnyassets/shaders/flat.slang b/funnyassets/shaders/flat.slang deleted file mode 100644 index 96c494f..0000000 --- a/funnyassets/shaders/flat.slang +++ /dev/null @@ -1,23 +0,0 @@ -struct VS_INPUT -{ - float3 m_vPosition; -} - -struct PS_INPUT -{ - float4 m_vPosition; -} - -[shader("vertex")] -PS_INPUT vsMain( VS_INPUT i ) -{ - PS_INPUT o; - o.m_vPosition = { i.m_vPosition, 1 }; - return o; -} - -[shader("pixel")] -float4 psMain( PS_INPUT i ) -{ - return float4(1); -} diff --git a/game/client/milmoba/player.cpp b/game/client/milmoba/player.cpp index 8b5e091..f6baee4 100644 --- a/game/client/milmoba/player.cpp +++ b/game/client/milmoba/player.cpp @@ -83,7 +83,7 @@ void C_MOBAPlayer::Spawn() pVertexBuffer->Unmap(); m_pMesh = IMeshRendering::CreateMesh(); - m_pMesh->SetVertexBuffer(pVertexBuffer); + m_pMesh->SetVertexBuffer(0, pVertexBuffer); m_pMeshInstance = m_pMesh->CreateInstance(); }; diff --git a/launcher/launcher.cpp b/launcher/launcher.cpp index e30f8db..1af1425 100644 --- a/launcher/launcher.cpp +++ b/launcher/launcher.cpp @@ -82,6 +82,7 @@ int main( int argc, char **argv ) { // chdir to right directory dirname(szLauncherPath); chdir(szLauncherPath); + printf("%s\n",szLauncherPath); pEngineMain(argc, argv); dlclose(pEngineLib); diff --git a/materialsystem/__build.cpp b/materialsystem/__build.cpp index 53447b4..ccdb228 100644 --- a/materialsystem/__build.cpp +++ b/materialsystem/__build.cpp @@ -6,11 +6,15 @@ CUtlVector MaterialSystem_CompiledFiles = { "materialsystem/materialsystem.cpp", + "materialsystem/compiledshader.cpp", + "materialsystem/vulkan/shaderparser.cpp", "materialsystem/vulkan/rendercontext.cpp", - "materialsystem/vulkan/material.cpp", "materialsystem/vulkan/commandbuffer.cpp", - "materialsystem/vulkan/utils.cpp", + "materialsystem/vulkan/rendercommandlist.cpp", + "materialsystem/vulkan/material.cpp", "materialsystem/vulkan/shader.cpp", + "materialsystem/vulkan/utils.cpp", + "materialsystem/vulkan/vma.cpp", "materialsystem/vulkan/commands/draw.cpp", "materialsystem/vulkan/commands/base.cpp", "materialsystem/vulkan/libraries/raster.cpp", diff --git a/materialsystem/compiledshader.cpp b/materialsystem/compiledshader.cpp new file mode 100644 index 0000000..8765ba9 --- /dev/null +++ b/materialsystem/compiledshader.cpp @@ -0,0 +1,145 @@ +#include "shadercompiler/icompiler.h" +#include "materialsystem/compiledshadermgr.h" +#include "tier2/ifilesystem.h" + +uint32_t CCompiledShader::AllocateLump( uint32_t nSize ) +{ + m_lumps.AppendTail({V_malloc(nSize),nSize}); + + return m_lumps.GetSize()-1; +} + +void *CCompiledShader::GetLumpPtr( uint32_t nLump ) +{ + return m_lumps[nLump].m_pAddress; +} + +uint32_t CCompiledShader::GetLumpSize( uint32_t nLump ) +{ + return m_lumps[nLump].m_nSize; +} + +ShaderObject_t *CCompiledShader::AllocateShader() +{ + m_objects.AppendTail({}); + return &m_objects[m_objects.GetSize()-1]; +} + +ShaderObject_t *CCompiledShader::FindShaderObject( EShaderBackend eBackend, EShaderStage eStage ) +{ + for ( auto &o: m_objects ) + { + if ( o.m_eBackend != eBackend ) + continue; + + if ( o.m_eStage != eStage ) + continue; + + return &o; + } + return NULL; +} + + +CCompiledShader::~CCompiledShader() +{ + for ( auto l: m_lumps ) + V_free(l.m_pAddress); +} + + +class CCompiledShaderManager: public ICompiledShaderManager +{ +public: + virtual void WriteToFile( CCompiledShader *pShader, const char *szFile ) override; + virtual void ReadFromFile( CCompiledShader *pShader, const char *szFile ) override; +}; + +void CCompiledShaderManager::WriteToFile( CCompiledShader *pShader, const char *szFile ) +{ + IFileHandle *pFile; + ShaderHeader_t stHeader = {}; + uint32_t nTotalSize = sizeof(ShaderHeader_t); + + stHeader.m_cSignature[0] = 'f'; + stHeader.m_cSignature[1] = 's'; + stHeader.m_cSignature[2] = 'h'; + stHeader.m_cSignature[3] = 'o'; + stHeader.m_nNumLumps = pShader->m_lumps.GetSize(); + stHeader.m_nNumShaders = pShader->m_objects.GetSize(); + + pFile = filesystem->Open(szFile, FILEMODE_WRITE); + pFile->Write(&stHeader, sizeof(ShaderHeader_t)); + + // We want to get offset for the lump data + nTotalSize += sizeof(ShaderLump_t) * pShader->m_lumps.GetSize(); + nTotalSize += sizeof(ShaderObject_t) * pShader->m_objects.GetSize(); + + + // ShaderLump_t + for ( auto l: pShader->m_lumps ) + { + ShaderLump_t stLump = {}; + stLump.m_nOffset = nTotalSize; + stLump.m_nSize = l.m_nSize; + pFile->Write(&stLump, sizeof(ShaderLump_t)); + + nTotalSize += l.m_nSize; + } + + // ShaderObject_t + + for ( auto o: pShader->m_objects ) + { + + } + + // Lump Data + for ( auto l: pShader->m_lumps ) + { + pFile->Write(l.m_pAddress, l.m_nSize); + } + + + pFile->Close(); +} + +void CCompiledShaderManager::ReadFromFile( CCompiledShader *pShader, const char *szFile ) +{ + IFileHandle *pFile; + ShaderHeader_t stHeader = {}; + int i = 0; + CUtlVector lumps = {}; + CUtlVector objects = {}; + CUtlVector lumpsData = {}; + + pFile = filesystem->Open(szFile, FILEMODE_READ); + pFile->Read(&stHeader, sizeof(ShaderHeader_t)); + + objects.Resize(stHeader.m_nNumShaders); + lumps.Resize(stHeader.m_nNumLumps); + lumpsData.Resize(stHeader.m_nNumLumps); + + pFile->Read(lumps.GetData(), stHeader.m_nNumLumps * sizeof(ShaderLump_t)); + pFile->Read(objects.GetData(), stHeader.m_nNumShaders * sizeof(ShaderObject_t)); + + for ( i = 0; i < stHeader.m_nNumLumps; i++ ) + { + lumpsData[i].m_pAddress = V_malloc(lumps[i].m_nSize); + pFile->Seek(SEEKMODE_RELATIVE_START, lumps[i].m_nOffset); + pFile->Read(lumpsData[i].m_pAddress, lumps[i].m_nSize); + lumpsData[i].m_nSize = lumps[i].m_nSize; + }; + + pShader->m_objects = objects; + pShader->m_lumps = lumpsData; + + pFile->Close(); +} + + +ICompiledShaderManager *CompiledShaderManager() +{ + static CCompiledShaderManager s_CompiledShaderManager; + return &s_CompiledShaderManager; +} diff --git a/materialsystem/materialsystem.cpp b/materialsystem/materialsystem.cpp index 8900fc7..ac93844 100644 --- a/materialsystem/materialsystem.cpp +++ b/materialsystem/materialsystem.cpp @@ -6,31 +6,25 @@ public: virtual void Init() override; virtual void Frame( float fTime ) override; virtual void Shutdown() override; - - virtual IRenderContext *GetRenderContext( void ) override; }; + +extern IRenderContext *g_pVkRenderContext; +IRenderContext *g_pRenderContext; void CMaterialSystem::Init() { - GetRenderContext()->Init(); + g_pRenderContext = (IRenderContext*)CreateInterface(RENDER_CONTEXT_INTERFACE_NAME, NULL); + g_pRenderContext->Init(); } void CMaterialSystem::Frame( float fTime ) { - GetRenderContext()->Frame(fTime); + g_pRenderContext->Frame(fTime); } void CMaterialSystem::Shutdown() { - GetRenderContext()->Shutdown(); -} - -extern IRenderContext *g_pVkRenderContext; - - -IRenderContext *CMaterialSystem::GetRenderContext( void ) -{ - return g_pVkRenderContext; + g_pRenderContext->Shutdown(); } diff --git a/materialsystem/vulkan/commandbuffer.cpp b/materialsystem/vulkan/commandbuffer.cpp index 5231469..280ed55 100644 --- a/materialsystem/vulkan/commandbuffer.cpp +++ b/materialsystem/vulkan/commandbuffer.cpp @@ -240,9 +240,9 @@ void CVkCommandBuffer::TryBarrier( int iCurrent, int iCurrentBuffer ) imageMemoryBarrier.dstAccessMask = VulkanGetAccessFlags(barrier.m_eNewDependency); if (barrier.m_eOldDependency == DEPENDENCY_MODE_FROM_PREVIOUS) { - imageMemoryBarrier.oldLayout = VulkanGetImageLayout(pImage->m_eLastUsage); - imageMemoryBarrier.srcStageMask = VulkanGetStageFlags(pImage->m_eLastUsage); - imageMemoryBarrier.srcAccessMask = VulkanGetAccessFlags(pImage->m_eLastUsage); + imageMemoryBarrier.oldLayout = VulkanGetImageLayout(DEPENDENCY_MODE_ALL_COMMANDS); + imageMemoryBarrier.srcStageMask = VulkanGetStageFlags(DEPENDENCY_MODE_ALL_COMMANDS); + imageMemoryBarrier.srcAccessMask = VulkanGetAccessFlags(DEPENDENCY_MODE_ALL_COMMANDS); } else { imageMemoryBarrier.oldLayout = VulkanGetImageLayout(barrier.m_eOldDependency); imageMemoryBarrier.srcStageMask = VulkanGetStageFlags(barrier.m_eOldDependency); diff --git a/materialsystem/vulkan/commands.h b/materialsystem/vulkan/commands.h index d1da9aa..90df28b 100644 --- a/materialsystem/vulkan/commands.h +++ b/materialsystem/vulkan/commands.h @@ -13,16 +13,6 @@ BEGIN_VULKAN_COMMAND(ClearColor) IImage **ppSwapchainImages = NULL; END_VULKAN_COMMAND(ClearColor) -struct VulkanRenderOutput_t { - EResolveMode m_eResolveMode; - - VkFrameObject_t m_stImage; - VkFrameObject_t m_stResolveImage; - - ELoadMode m_eLoadMode; - EStoreMode m_eStoreMode; -}; - BEGIN_VULKAN_COMMAND(Begin) CUtlVector images; VulkanRenderOutput_t stDepthImage; @@ -35,6 +25,36 @@ END_VULKAN_COMMAND(Begin) BEGIN_VULKAN_COMMAND(End) END_VULKAN_COMMAND(End) +BEGIN_VULKAN_COMMAND(SetVertexBuffer) + uint32_t uBinding; + IVertexBuffer *pBuffer; +END_VULKAN_COMMAND(SetVertexBuffer) + +BEGIN_VULKAN_COMMAND(SetShader) + IShader *pShader; +END_VULKAN_COMMAND(SetShader) + +BEGIN_VULKAN_COMMAND(DrawPrimitives) + uint32_t nVertexCount; + uint32_t nFirstVertex; + uint32_t nInstanceCount; + uint32_t nFirstInstance; +END_VULKAN_COMMAND(DrawPrimitives) + +BEGIN_VULKAN_COMMAND(SetScissors) + uint32_t uX; + uint32_t uY; + uint32_t uWidth; + uint32_t uHeight; +END_VULKAN_COMMAND(SetScissors) + +BEGIN_VULKAN_COMMAND(SetViewport) + uint32_t uX; + uint32_t uY; + uint32_t uWidth; + uint32_t uHeight; +END_VULKAN_COMMAND(SetViewport) + BEGIN_VULKAN_COMMAND(Empty) END_VULKAN_COMMAND(Empty) diff --git a/materialsystem/vulkan/commands/draw.cpp b/materialsystem/vulkan/commands/draw.cpp index ff8bea2..774e3de 100644 --- a/materialsystem/vulkan/commands/draw.cpp +++ b/materialsystem/vulkan/commands/draw.cpp @@ -31,10 +31,10 @@ DECLARE_VULKAN_COMMAND(ClearColor) DECLARE_VULKAN_COMMAND(Begin) { VkRenderingInfo stRenderingInfo = {}; - CUtlVector attachments; + CUtlVector attachments = {}; for (auto i: images) { - VkRenderingAttachmentInfo a; + VkRenderingAttachmentInfo a = {}; a.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; a.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; a.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; @@ -47,6 +47,7 @@ DECLARE_VULKAN_COMMAND(Begin) stRenderingInfo.layerCount = 1; stRenderingInfo.colorAttachmentCount = attachments.GetSize(); stRenderingInfo.pColorAttachments = attachments.GetData(); + stRenderingInfo.renderArea = (VkRect2D){0,0,nResolutionX,nResolutionY}; vkCmdBeginRendering(hCommandBuffer, &stRenderingInfo); } @@ -55,3 +56,21 @@ DECLARE_VULKAN_COMMAND(End) { vkCmdEndRendering(hCommandBuffer); } + +DECLARE_VULKAN_COMMAND(SetShader) +{ + CVkShader *pVkShader = (CVkShader*)pShader; + vkCmdBindPipeline(hCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pVkShader->m_hPipeline); +} + +DECLARE_VULKAN_COMMAND(SetVertexBuffer) +{ + CVkBuffer *pVkBuffer = (CVkBuffer*)pBuffer; + VkDeviceSize uOffset = 0; + vkCmdBindVertexBuffers(hCommandBuffer, uBinding, 1, &pVkBuffer->m_buffer, &uOffset); +} + +DECLARE_VULKAN_COMMAND(DrawPrimitives) +{ + vkCmdDraw(hCommandBuffer, nVertexCount, nInstanceCount, nFirstVertex, nFirstInstance); +} diff --git a/materialsystem/vulkan/libraries/raster.cpp b/materialsystem/vulkan/libraries/raster.cpp index b7ab323..2073188 100644 --- a/materialsystem/vulkan/libraries/raster.cpp +++ b/materialsystem/vulkan/libraries/raster.cpp @@ -3,7 +3,8 @@ #include "tier1/utlbuffer.h" #include "tier1/utlvector.h" #include "tier2/ifilesystem.h" -#include "vulkan/vulkan_core.h" +#include "../shaderparser.h" + BEGIN_BUILD_PIPELINE_LIBRARY(VertexDescription) library.flags = VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT; @@ -48,3 +49,250 @@ void CVkVertexDescriptionPipelineLibrary::SetTopology( ETopologyMode eTopology ) { m_eTopology = VulkanGetTopology(eTopology); } +struct VulkanDescriptorInit_t +{ + CUtlVector m_bindings = {}; + VkDescriptorSetLayoutCreateInfo m_set = {}; +}; + +BEGIN_BUILD_PIPELINE_LIBRARY(VertexTransform) + library.flags = VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT; + + VkPipelineRasterizationStateCreateInfo rasterState = {}; + VkPipelineViewportStateCreateInfo viewportState = {}; + int i = 0; + + CUtlVector vertexDescriptors = ShaderParser()->GetDescriptors(m_pShader, SHADER_STAGE_VERTEX); + VulkanDescriptorInit_t inits[SHADER_STAGE_COUNT] = {}; + CUtlVector> spirvs = {}; + CUtlVector stages = {}; + CUtlVector stageShaders = {}; + + for ( auto desc: vertexDescriptors ) + { + VkDescriptorSetLayoutBinding binding = {}; + binding.descriptorCount = 1; + binding.descriptorType = desc.eDescriptorType; + binding.binding = desc.uBinding; + inits[desc.eDescriptorType].m_bindings.AppendTail(binding); + } + for ( i = 0; i < SHADER_STAGE_COUNT; i++) + { + inits[i].m_set.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + inits[i].m_set.bindingCount = inits[i].m_bindings.GetSize(); + inits[i].m_set.pBindings = inits[i].m_bindings.GetData(); + + vkCreateDescriptorSetLayout(g_vkDevice, &inits[i].m_set, NULL, &m_setLayouts[i] ); + } + + for ( i = 0; i < SHADER_STAGE_COUNT; i++) + { + if ( i == SHADER_STAGE_PIXEL ) + continue; + + CUtlBuffer code = ShaderParser()->GetShaderCode(m_pShader, (EShaderStage)i); + + // We may fail loading the specific stage + if (code.GetSize() == 0) + continue; + + VkShaderModuleCreateInfo mod = {}; + mod.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + mod.codeSize = code.GetSize(); + + + VkPipelineShaderStageCreateInfo shader = {}; + shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shader.pName = "main"; + shader.stage = VulkanGetShaderStage((EShaderStage)i); + + spirvs.AppendTail(code); + stageShaders.AppendTail(mod); + stages.AppendTail(shader); + } + + // Fix pointers + for ( i = 0; i < stages.GetSize(); i++ ) + { + stageShaders[i].pCode = (uint32_t*)spirvs[i].GetMemory(); + stages[i].pNext = &stageShaders[i]; + } + + VkPipelineLayoutCreateInfo stPipelineLayout = {}; + stPipelineLayout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + stPipelineLayout.setLayoutCount = SHADER_STAGE_COUNT; + stPipelineLayout.pSetLayouts = m_setLayouts; + stPipelineLayout.flags = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT ; + vkCreatePipelineLayout(g_vkDevice, &stPipelineLayout, NULL, &m_layout); + + rasterState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterState.polygonMode = VK_POLYGON_MODE_FILL; + rasterState.lineWidth = 1; + + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + + VkDynamicState dynamicStates[] = { + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT, + }; + VkPipelineDynamicStateCreateInfo dynamicState = {}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicState.dynamicStateCount = 2; + dynamicState.pDynamicStates = dynamicStates; + pipeline.stageCount = stages.GetSize(); + pipeline.pStages = stages.GetData(); + pipeline.pDynamicState = &dynamicState; + pipeline.pRasterizationState = &rasterState; + pipeline.pViewportState = &viewportState; + pipeline.layout = m_layout; +END_BUILD_PIPELINE_LIBRARY() + +void CVkVertexTransformPipelineLibrary::SetShader( CCompiledShader *pShader ) +{ + m_pShader = pShader; +} + +BEGIN_BUILD_PIPELINE_LIBRARY(PixelShader) + printf("--- PixelShader ---\n"); + + VkPipelineDepthStencilStateCreateInfo depthStencil = {}; + int i = 0; + CUtlVector vertexDescriptors = ShaderParser()->GetDescriptors(m_pShader, SHADER_STAGE_PIXEL); + VulkanDescriptorInit_t inits[SHADER_STAGE_COUNT] = {}; + for ( auto desc: vertexDescriptors ) + { + VkDescriptorSetLayoutBinding binding = {}; + binding.descriptorCount = 1; + binding.descriptorType = desc.eDescriptorType; + binding.binding = desc.uBinding; + inits[desc.eDescriptorType].m_bindings.AppendTail(binding); + } + for ( i = 0; i < SHADER_STAGE_COUNT; i++) + { + inits[i].m_set.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + inits[i].m_set.bindingCount = inits[i].m_bindings.GetSize(); + inits[i].m_set.pBindings = inits[i].m_bindings.GetData(); + + vkCreateDescriptorSetLayout(g_vkDevice, &inits[i].m_set, NULL, &m_setLayouts[i] ); + } + + VkPipelineLayoutCreateInfo stPipelineLayout = {}; + stPipelineLayout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + stPipelineLayout.setLayoutCount = SHADER_STAGE_COUNT; + stPipelineLayout.pSetLayouts = m_setLayouts; + stPipelineLayout.flags = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT ; + vkCreatePipelineLayout(g_vkDevice, &stPipelineLayout, NULL, &m_layout); + + CUtlBuffer spirv = {}; + VkPipelineShaderStageCreateInfo shader = {}; + VkShaderModuleCreateInfo mod = {}; + for ( auto desc: vertexDescriptors ) + { + VkDescriptorSetLayoutBinding binding = {}; + binding.descriptorCount = 1; + binding.descriptorType = desc.eDescriptorType; + binding.binding = desc.uBinding; + inits[desc.eDescriptorType].m_bindings.AppendTail(binding); + } + for ( i = 0; i < SHADER_STAGE_COUNT; i++) + { + inits[i].m_set.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + inits[i].m_set.bindingCount = inits[i].m_bindings.GetSize(); + inits[i].m_set.pBindings = inits[i].m_bindings.GetData(); + + vkCreateDescriptorSetLayout(g_vkDevice, &inits[i].m_set, NULL, &m_setLayouts[i] ); + } + + spirv = ShaderParser()->GetShaderCode(m_pShader, SHADER_STAGE_PIXEL); + + if (spirv.GetSize() == 0) + goto skipshader; + + mod.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + mod.codeSize = spirv.GetSize(); + mod.pCode = (uint32_t*)spirv.GetMemory(); + + shader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shader.pName = "main"; + shader.stage = VulkanGetShaderStage(SHADER_STAGE_PIXEL); + shader.pNext = &mod; + + pipeline.stageCount = 1; + pipeline.pStages = &shader; + + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.minDepthBounds = 0; + depthStencil.maxDepthBounds = 1; + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthBoundsTestEnable = VK_FALSE; + depthStencil.stencilTestEnable = VK_FALSE; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; + pipeline.pDepthStencilState = &depthStencil; + +skipshader: + + library.flags = VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT; + pipeline.layout = m_layout; +END_BUILD_PIPELINE_LIBRARY() + +void CVkPixelShaderPipelineLibrary::SetShader( CCompiledShader *pShader ) +{ + m_pShader = pShader; +} + +BEGIN_BUILD_PIPELINE_LIBRARY(PixelOutput) + printf("--- PixelOutput ---\n"); + VkPipelineMultisampleStateCreateInfo msaa = {}; + VkPipelineRenderingCreateInfo render = {}; + VkPipelineDepthStencilStateCreateInfo depthStencil = {}; + VkPipelineColorBlendStateCreateInfo blend = {}; + CUtlVector attachments = {}; + + msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + render.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; + render.colorAttachmentCount = m_eFormats.GetSize(); + render.pColorAttachmentFormats = m_eFormats.GetData(); + render.depthAttachmentFormat = VK_FORMAT_D32_SFLOAT;; + + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.minDepthBounds = 0; + depthStencil.maxDepthBounds = 1; + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthBoundsTestEnable = VK_FALSE; + depthStencil.stencilTestEnable = VK_FALSE; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; + + for ( auto e: m_eFormats ) + { + VkPipelineColorBlendAttachmentState a = {}; + a.blendEnable = VK_TRUE; + a.blendEnable = VK_TRUE; + a.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + a.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + a.colorBlendOp = VK_BLEND_OP_ADD; + a.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + a.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + a.alphaBlendOp = VK_BLEND_OP_ADD; + attachments.AppendTail(a); + } + blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + blend.attachmentCount = m_eFormats.GetSize(); + blend.pAttachments = attachments.GetData(); + + pipeline.pDepthStencilState = &depthStencil; + pipeline.pColorBlendState = &blend; + pipeline.pMultisampleState = &msaa; + render.pNext = pipeline.pNext; + pipeline.pNext = &render; + library.flags = VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT; + +END_BUILD_PIPELINE_LIBRARY() + +void CVkPixelOutputPipelineLibrary::AddAttachment( EImageFormat eFormat ) +{ + m_eFormats.AppendTail(CVkImage::GetImageFormat(eFormat)); +} diff --git a/materialsystem/vulkan/material.cpp b/materialsystem/vulkan/material.cpp index e69de29..0aac008 100644 --- a/materialsystem/vulkan/material.cpp +++ b/materialsystem/vulkan/material.cpp @@ -0,0 +1,36 @@ +#include "vulkan_state.h" +CVkMaterial::CVkMaterial( IShader *pShader ) +{ + m_pVkShader = (CVkShader*)pShader; +} + +CVkMaterial::~CVkMaterial() +{ + +} + +void CVkMaterial::VSSetShaderResource( uint32_t uRegister, IRenderingObject *pResource ) +{ + SetShaderResource(uRegister, SHADER_STAGE_VERTEX, pResource); +} + +void CVkMaterial::PSSetShaderResource( uint32_t uRegister, IRenderingObject *pResource ) +{ + SetShaderResource(uRegister, SHADER_STAGE_PIXEL, pResource); +} + +void CVkMaterial::VSSetConstantsBuffer( uint32_t uRegister, IBuffer *pConstants ) +{ + SetShaderResource(uRegister, SHADER_STAGE_VERTEX, pConstants); +} + +void CVkMaterial::PSSetConstantsBuffer( uint32_t uRegister, IBuffer *pConstants ) +{ + SetShaderResource(uRegister, SHADER_STAGE_PIXEL, pConstants); +} + +void CVkMaterial::SetShaderResource( uint32_t uRegister, uint32_t uSet, IRenderingObject *pObject) +{ + +} + diff --git a/materialsystem/vulkan/raster_libraries.h b/materialsystem/vulkan/raster_libraries.h index bea395e..8f4c5b8 100644 --- a/materialsystem/vulkan/raster_libraries.h +++ b/materialsystem/vulkan/raster_libraries.h @@ -1,4 +1,5 @@ #include "materialsystem/imaterialsystem.h" +#include "materialsystem/compiledshadermgr.h" #include "tier1/utlvector.h" #include "vulkan_state.h" @@ -13,11 +14,28 @@ BEGIN_DEFINE_PIPELINE_LIBRARY(VertexDescription) END_DEFINE_PIPELINE_LIBRARY() BEGIN_DEFINE_PIPELINE_LIBRARY(VertexTransform) + void SetShader( CCompiledShader *pShader ); + CCompiledShader *m_pShader; + + VkDescriptorSetLayout m_setLayouts[SHADER_STAGE_COUNT]; + VkPipelineLayout m_layout; END_DEFINE_PIPELINE_LIBRARY() -BEGIN_DEFINE_PIPELINE_LIBRARY(PixelShade) +BEGIN_DEFINE_PIPELINE_LIBRARY(PixelShader) + void SetShader( CCompiledShader *pShader ); + void SetDepthRequired( bool b ); + + CCompiledShader *m_pShader; + VkDescriptorSetLayout m_setLayouts[SHADER_STAGE_COUNT]; + VkPipelineLayout m_layout; + bool m_bIsDepthRequired = false; END_DEFINE_PIPELINE_LIBRARY() BEGIN_DEFINE_PIPELINE_LIBRARY(PixelOutput) + void AddAttachment( EImageFormat eFormat ); + void SetDepthRequired( bool b ); + + CUtlVector m_eFormats = {}; + bool m_bIsDepthRequired = false; END_DEFINE_PIPELINE_LIBRARY() diff --git a/materialsystem/vulkan/rendercommandlist.cpp b/materialsystem/vulkan/rendercommandlist.cpp new file mode 100644 index 0000000..a703ccc --- /dev/null +++ b/materialsystem/vulkan/rendercommandlist.cpp @@ -0,0 +1,193 @@ +#include "vulkan_state.h" +#include "commands.h" + +void CVkRenderCommandList::ResetRendering() +{ + /* + for ( auto m: m_materials) + { + delete m.m_pCommandBuffer; + } + */ + m_materials = {}; +} + +void CVkRenderCommandList::SetRenderTarget( uint32_t uIndex, IImage *pImage ) +{ + SwitchRenderingStage(RENDERING_STAGE_SETUP_RASTER); + VulkanRenderOutput_t *pOutput = FindOrCreateRenderOutput(uIndex); + pOutput->m_stImage.m_pSingle = pImage; +} + +void CVkRenderCommandList::SetClearColor( uint32_t uIndex, float r, float g, float b, float a ) +{ + SwitchRenderingStage(RENDERING_STAGE_SETUP_RASTER); + VulkanRenderOutput_t *pOutput = FindOrCreateRenderOutput(uIndex); + pOutput->m_fClearColor[0] = r; + pOutput->m_fClearColor[1] = g; + pOutput->m_fClearColor[2] = b; + pOutput->m_fClearColor[3] = a; +} + +void CVkRenderCommandList::SetDepthTarget( IImage *pDepth ) +{ + SwitchRenderingStage(RENDERING_STAGE_SETUP_RASTER); + m_depth.m_stImage.m_pSingle = pDepth; + +} +void CVkRenderCommandList::SetClearDepth( float fVal) +{ + SwitchRenderingStage(RENDERING_STAGE_SETUP_RASTER); + m_depth.m_fClearDepth = fVal; +} + +void CVkRenderCommandList::SetRenderResolution( uint32_t iWidth, uint32_t iHeight ) +{ + SwitchRenderingStage(RENDERING_STAGE_SETUP_RASTER); +} + + +void CVkRenderCommandList::SetScissors( uint32_t uX, uint32_t uY, uint32_t uWidth, uint32_t uHeight ) +{ + SwitchRenderingStage(RENDERING_STAGE_RASTER); +} + +void CVkRenderCommandList::SetViewport( uint32_t uX, uint32_t uY, uint32_t uWidth, uint32_t uHeight, float fMinDepth, float fMaxDepth ) +{ + SwitchRenderingStage(RENDERING_STAGE_RASTER); +} + + + + + +void CVkRenderCommandList::SetMaterial( IMaterial *pMaterial ) +{ + SwitchRenderingStage(RENDERING_STAGE_SETUP_RASTER); + bool bWasCreated = false; + m_pCurrentMaterialBuffer = FindOrCreateMaterialCommandBuffer(pMaterial, &bWasCreated); + if (bWasCreated) + { + m_pCurrentMaterialBuffer->Reset(); + CVkBeginCommand *pBeginCommand = CREATE_COMMAND(Begin); + pBeginCommand->images = m_pOutput; + pBeginCommand->nResolutionX = 1280; + pBeginCommand->nResolutionY = 720; + pBeginCommand->stDepthImage = m_depth; + for ( auto &i: pBeginCommand->images) + { + pBeginCommand->AddDependency(i.m_stImage.m_pSingle, DEPENDENCY_MODE_DRAWCALL_OUTPUT_IMAGE); + } + m_pCurrentMaterialBuffer->AddCommand(pBeginCommand); + + CVkSetShaderCommand *pSetShader = CREATE_COMMAND(SetShader); + pSetShader->pShader = ((CVkMaterial*)pMaterial)->m_pVkShader; + m_pCurrentMaterialBuffer->AddCommand(pSetShader); + + CVkSetScissorsCommand *pScissorsCommand = CREATE_COMMAND(SetScissors); + CVkSetViewportCommand *pViewportCommand = CREATE_COMMAND(SetViewport); + } +} + +void CVkRenderCommandList::SetVertexBuffer( uint32_t uBinding, IVertexBuffer *pBuffer ) +{ + SwitchRenderingStage(RENDERING_STAGE_RASTER); + CVkSetVertexBufferCommand *pCmd = CREATE_COMMAND(SetVertexBuffer); + pCmd->uBinding = uBinding; + pCmd->pBuffer = pBuffer; + m_pCurrentMaterialBuffer->AddCommand(pCmd); +} + +void CVkRenderCommandList::SetIndexBuffer( IVertexBuffer *pBuffer ) +{ + SwitchRenderingStage(RENDERING_STAGE_RASTER); +} + +void CVkRenderCommandList::DrawPrimitives( uint32_t nVertexCount, uint32_t nFirstVertex, uint32_t nInstanceCount, uint32_t nFirstInstance ) +{ + SwitchRenderingStage(RENDERING_STAGE_RASTER); + + CVkDrawPrimitivesCommand *pCmd = CREATE_COMMAND(DrawPrimitives); + pCmd->nVertexCount = nVertexCount; + pCmd->nFirstVertex = nFirstVertex; + pCmd->nInstanceCount = nInstanceCount; + pCmd->nFirstInstance = nFirstInstance; + m_pCurrentMaterialBuffer->AddCommand(pCmd); +} + +void CVkRenderCommandList::DrawPrimitivesIndexed( uint32_t nIndexCount, uint32_t nFirstIndex, uint32_t nVertexOffset, uint32_t nInstanceCount, uint32_t nFirstInstance ) +{ + SwitchRenderingStage(RENDERING_STAGE_RASTER); + +} + + +void CVkRenderCommandList::ResolveImage( IImage *pOriginal, IImage *pResolved ) +{ + SwitchRenderingStage(RENDERING_STAGE_POST_RASTER); + +} + + +void CVkRenderCommandList::StartRecording() +{ + ResetRendering(); +} + +void CVkRenderCommandList::EndRecording() +{ + for ( auto m: m_materials) + { + CVkEndCommand *pEndCommand = CREATE_COMMAND(End); + m.m_pCommandBuffer->AddCommand(pEndCommand); + m.m_pCommandBuffer->Render(); + } +} + +void CVkRenderCommandList::Submit() +{ + for ( auto m: m_materials) + { + m.m_pCommandBuffer->Submit(); + } +} + +void CVkRenderCommandList::SwitchRenderingStage( EVulkanRenderingStage eStage ) +{ + +} + +VulkanRenderOutput_t *CVkRenderCommandList::FindOrCreateRenderOutput( uint32_t uIndex ) +{ + for ( auto &v: m_pOutput ) + { + if (v.m_uIndex == uIndex) + return &v; + } + + VulkanRenderOutput_t output = {}; + output.m_uIndex = uIndex; + m_pOutput.AppendTail(output); + return &m_pOutput[m_pOutput.GetSize()-1]; +} + +IVkCommandBuffer *CVkRenderCommandList::FindOrCreateMaterialCommandBuffer( IMaterial *pMaterial, bool *pbWasCreated ) +{ + for (auto &m: m_materials) + { + if (m.m_pMaterial == pMaterial) + { + if (pbWasCreated) + *pbWasCreated = false; + return m.m_pCommandBuffer; + } + } + + VulkanMaterialCommandBuffer_t mat; + mat.m_pCommandBuffer = g_pCommandBufferManager->CreateCommandBuffer(); + mat.m_pMaterial = pMaterial; + m_materials.AppendTail(mat); + if (pbWasCreated) + *pbWasCreated = true; + return m_materials.GetLast().m_pCommandBuffer; +} diff --git a/materialsystem/vulkan/rendercontext.cpp b/materialsystem/vulkan/rendercontext.cpp index ff561d9..961f71d 100644 --- a/materialsystem/vulkan/rendercontext.cpp +++ b/materialsystem/vulkan/rendercontext.cpp @@ -31,17 +31,18 @@ VkQueue g_vkDrawQueue; VkQueue g_vkPresentQueue; VkInstance g_vkInstance; +VmaAllocator g_vkAllocator; VkPhysicalDevice g_vkPhysicalDevice; VkDevice g_vkDevice; VkSwapchainKHR g_vkSwapchain; -CUtlVector g_vkFences; -CUtlVector g_vkGraphicsSemaphores; -CUtlVector g_vkPresentSemaphores; +CUtlVector g_vkFences = {}; +CUtlVector g_vkGraphicsSemaphores = {}; +CUtlVector g_vkPresentSemaphores = {}; -CUtlVector g_vkCommandPools; +CUtlVector g_vkCommandPools = {}; -CUtlVector g_vkSwapchainImages; +CUtlVector g_vkSwapchainImages = {}; VkFormat g_vkWindowImageFormat; @@ -50,9 +51,14 @@ CVkImage::CVkImage() } -CVkImage::CVkImage( uint32_t nWidth, uint32_t nHeight, EImageFormat eFormat, EMultisampleType eMultisampleType) +CVkImage::CVkImage( uint32_t nWidth, uint32_t nHeight, uint32_t nDepth, EImageFormat eFormat, EMultisampleType eMultisampleType, EImageType eImageType, VkImageUsageFlagBits eUsage ) { - CreateImage(nWidth, nHeight, eFormat, eMultisampleType); + m_nWidth = nWidth; + m_nHeight = nHeight; + m_eMultisampleType = eMultisampleType; + m_eImageType = eImageType; + m_eFormat = eFormat; + CreateImage(nWidth, nHeight, eFormat, eMultisampleType, eUsage); CreateImageView(); } @@ -107,9 +113,26 @@ VkFormat CVkImage::GetImageFormat( enum EImageFormat eImageFormat ) } } -void CVkImage::CreateImage( uint32_t nWidth, uint32_t nHeight, EImageFormat eFormat, EMultisampleType eMultisampleType ) +void CVkImage::CreateImage( uint32_t nWidth, uint32_t nHeight, EImageFormat eFormat, EMultisampleType eMultisampleType, VkImageUsageFlagBits eUsage ) { + VkImageCreateInfo stCreateInfo = {}; + VmaAllocationCreateInfo stAlloc = {}; + stCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + stCreateInfo.imageType = VK_IMAGE_TYPE_2D; + stCreateInfo.extent.width = nWidth; + stCreateInfo.extent.height = nHeight; + stCreateInfo.extent.depth = 1; + stCreateInfo.mipLevels = 1; + stCreateInfo.arrayLayers = 1; + stCreateInfo.usage = eUsage; + stCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + stCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + stCreateInfo.format = GetImageFormat(eFormat); + stCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + stAlloc.usage = VMA_MEMORY_USAGE_AUTO; + + vmaCreateImage(g_vkAllocator, &stCreateInfo, &stAlloc, &m_image, &m_allocation, NULL); } void CVkImage::CreateImageView() @@ -159,6 +182,28 @@ EMultisampleType CVkImage::GetMultisampleType() CVkBuffer::CVkBuffer( uint32_t nSize, VkBufferUsageFlags2 eUsage, uint32_t nAlignment ) { + VkBufferUsageFlags2CreateInfo stUsage = {}; + VkBufferCreateInfo stBufferInfo = {}; + VmaAllocationCreateInfo stAllocInfo = {}; + VkBufferDeviceAddressInfo stAddress = {}; + + stUsage.sType = VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO; + stUsage.usage = eUsage | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT; + + stBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + stBufferInfo.size = nSize; + stBufferInfo.pNext = &stUsage; + + stAllocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; + stAllocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + + vmaCreateBuffer(g_vkAllocator, &stBufferInfo, &stAllocInfo, &m_buffer, &m_allocation, NULL); + + stAddress.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; + stAddress.buffer = m_buffer; + m_address = vkGetBufferDeviceAddress(g_vkDevice, &stAddress); + + m_nSize = nSize; } CVkBuffer::~CVkBuffer() @@ -169,12 +214,10 @@ CVkBuffer::~CVkBuffer() void CVkBuffer::SetDebugName( const char *szName ) { - } void CVkBuffer::Lock() { - } void CVkBuffer::Unlock() @@ -184,21 +227,22 @@ void CVkBuffer::Unlock() void *CVkBuffer::Map() { + void *pData; + pData = NULL; + vmaMapMemory(g_vkAllocator, m_allocation, &pData); + return pData; } void CVkBuffer::Unmap() { - + vmaUnmapMemory(g_vkAllocator, m_allocation); } uint32_t CVkBuffer::GetSize() { - + return m_nSize; } - - - class CVkRenderContext: public IRenderContext { public: @@ -206,8 +250,17 @@ public: virtual void Frame( float fDeltaTime ) override; virtual void Shutdown() override; + virtual void SetOutputImage( IImage *pImage ) override; + + virtual bool BIsOutputImageOutdated() override; + virtual uint32_t GetNewOutputImageWidth() override; + virtual uint32_t GetNewOutputImageHeight() override; + virtual EImageFormat GetNewOutputImageFormat() override; + virtual IVertexBuffer *CreateVertexBuffer( uint32_t nSize ) override; virtual IIndexBuffer *CreateIndexBuffer( uint32_t nSize ) override; + virtual IBuffer *CreateConstantBuffer( uint32_t nSize ) override; + virtual IBuffer *CreateStorageBuffer( uint32_t nSize ) override; virtual void DestroyBuffer( IBuffer *pBuffer ) override; virtual IImage *CreateRenderTarget( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType ) override; @@ -218,16 +271,14 @@ public: IBuffer *CreateBufferAligned( uint32_t nSize, uint32_t nAlignment, VkBufferUsageFlags2 eUsage ); virtual IShader *CreateShader( const char *szName ) override; - virtual void DestroyShader( IShader *pMaterial ) override; + virtual void DestroyShader( IShader *pShader ) override; virtual IMaterial *CreateMaterial( IShader *pShader ) override; virtual void DestroyMaterial( IMaterial *pMaterial ) override; - - virtual void SetMaterial( IMaterial *pMaterial ) override; - virtual void SetVertexBuffer( IVertexBuffer *pBuffer ) override; - virtual void SetIndexBuffer( IVertexBuffer *pBuffer ) override; - virtual void DrawPrimitives( uint32_t nVertexCount, uint32_t nFirstVertex, uint32_t nInstanceCount, uint32_t nFirstInstance ) override; - virtual void DrawPrimitivesIndexed( uint32_t nIndexCount, uint32_t nFirstIndex, uint32_t nVertexOffset, uint32_t nInstanceCount, uint32_t nFirstInstance ) override; + + virtual IRenderCommandList *CreateCommandList() override; + virtual void DestroyCommandList( IRenderCommandList *pCommandList ) override; + virtual void SubmitCommandList(IRenderCommandList *pList) override; private: VkPhysicalDevice SelectPhysicalDevice( CUtlVector physicalDevices ); CUtlVector GetDeviceExtensions(); @@ -236,17 +287,45 @@ private: void CreateSwapchain(); void DestroySwapchain(); -}; -CVkRenderContext s_vkRenderContext; -IRenderContext *g_pVkRenderContext = &s_vkRenderContext; + IImage *m_pOutputImage = NULL; + bool m_bOutputImageOutdated = true; +}; +EXPOSE_INTERFACE(CVkRenderContext, IRenderContext, RENDER_CONTEXT_VULKAN_INTERFACE_NAME); + +void CVkRenderContext::SetOutputImage( IImage *pImage ) +{ + m_pOutputImage = pImage; +} + + +bool CVkRenderContext::BIsOutputImageOutdated( ) +{ + return m_bOutputImageOutdated; +} + +uint32_t CVkRenderContext::GetNewOutputImageWidth() +{ + return 1280; +} + +uint32_t CVkRenderContext::GetNewOutputImageHeight() +{ + return 720; +} + +EImageFormat CVkRenderContext::GetNewOutputImageFormat() +{ + +} + //----------------------------------------------------------------------------- // Creates vertex buffer. Wrapper over CreateBuffer //----------------------------------------------------------------------------- IVertexBuffer *CVkRenderContext::CreateVertexBuffer( uint32_t nSize ) { - return (IVertexBuffer*)CreateBuffer(nSize, VK_BUFFER_USAGE_2_VERTEX_BUFFER_BIT); + return (IVertexBuffer*)CreateBuffer(nSize, VK_BUFFER_USAGE_2_VERTEX_BUFFER_BIT |VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT ); } //----------------------------------------------------------------------------- @@ -254,13 +333,28 @@ IVertexBuffer *CVkRenderContext::CreateVertexBuffer( uint32_t nSize ) //----------------------------------------------------------------------------- IIndexBuffer *CVkRenderContext::CreateIndexBuffer( uint32_t nSize ) { - return (IIndexBuffer*)CreateBuffer(nSize, VK_BUFFER_USAGE_2_INDEX_BUFFER_BIT); + return (IIndexBuffer*)CreateBuffer(nSize, VK_BUFFER_USAGE_2_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT); +} +//----------------------------------------------------------------------------- +// Creates storage buffer. Wrapper over CreateBuffer +//----------------------------------------------------------------------------- +IBuffer *CVkRenderContext::CreateStorageBuffer( uint32_t nSize ) +{ + return (IVertexBuffer*)CreateBuffer(nSize, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT); +} + +//----------------------------------------------------------------------------- +// Creates constant buffer. Wrapper over CreateBuffer +//----------------------------------------------------------------------------- +IBuffer *CVkRenderContext::CreateConstantBuffer( uint32_t nSize ) +{ + return (IIndexBuffer*)CreateBuffer(nSize, VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT); } //----------------------------------------------------------------------------- // Creates basic vulkan buffer //----------------------------------------------------------------------------- -IBuffer *CreateBuffer( uint32_t nSize, VkBufferUsageFlags2 eUsage ) +IBuffer *CVkRenderContext::CreateBuffer( uint32_t nSize, VkBufferUsageFlags2 eUsage ) { CVkBuffer *pBuffer = new CVkBuffer(nSize, eUsage, 0); return pBuffer; @@ -271,7 +365,7 @@ IBuffer *CreateBuffer( uint32_t nSize, VkBufferUsageFlags2 eUsage ) // Useful for everything eg: ray tracing, which requires them to be aligned // to the groupBaseAlignment. //----------------------------------------------------------------------------- -IBuffer *CreateBufferAligned( uint32_t nSize, uint32_t nAlignment, VkBufferUsageFlags2 eUsage ) +IBuffer *CVkRenderContext::CreateBufferAligned( uint32_t nSize, uint32_t nAlignment, VkBufferUsageFlags2 eUsage ) { } @@ -279,12 +373,15 @@ IBuffer *CreateBufferAligned( uint32_t nSize, uint32_t nAlignment, VkBufferUsage IImage *CVkRenderContext::CreateRenderTarget( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType ) { - + if (eFormat == IMAGE_FORMAT_D32_SFLOAT) + return new CVkImage(x, y, 1, eFormat, eMultisampleType, IMAGE_TYPE_2D, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); + else + return new CVkImage(x, y, 1, eFormat, eMultisampleType, IMAGE_TYPE_2D, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); } IImage *CVkRenderContext::CreateStorageImage( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType ) { - + return new CVkImage(x, y, 1, eFormat, eMultisampleType, IMAGE_TYPE_2D, VK_IMAGE_USAGE_STORAGE_BIT); } @@ -300,49 +397,69 @@ void CVkRenderContext::DestroyImage( IImage *pImage ) IShader *CVkRenderContext::CreateShader( const char *szName ) { + CCompiledShader stShader = {}; + CompiledShaderManager()->ReadFromFile(&stShader, szName); + CVkVertexDescriptionPipelineLibrary vertexDescription = {}; + vertexDescription.AddAttribute(0, 0, VERTEX_FORMAT_XYZ32_SFLOAT, 0); + vertexDescription.AddLayout(0, 12); + vertexDescription.SetTopology(TOPOLOGY_MODE_TRIANGLE_LIST); + vertexDescription.Build(); + + CVkVertexTransformPipelineLibrary vertexTransform = {}; + vertexTransform.SetShader(&stShader); + vertexTransform.Build(); + + CVkPixelShaderPipelineLibrary pixelShader = {}; + pixelShader.SetShader(&stShader); + pixelShader.Build(); + + CVkPixelOutputPipelineLibrary pixelOutput = {}; + pixelOutput.AddAttachment(IMAGE_FORMAT_RGBA8_UNORM); + pixelOutput.Build(); + + CVkShader *pShader = new CVkShader(); + pShader->AddShaderLibrary(&vertexDescription); + pShader->AddShaderLibrary(&vertexTransform); + pShader->AddShaderLibrary(&pixelShader); + pShader->AddShaderLibrary(&pixelOutput); + printf("--- general pipeline ---\n"); + pShader->Build(); + return pShader; } -void CVkRenderContext::DestroyShader( IShader *pMaterial ) +void CVkRenderContext::DestroyShader( IShader *pShader ) { - + delete pShader; } IMaterial *CVkRenderContext::CreateMaterial( IShader *pShader ) { - + return new CVkMaterial(pShader); } void CVkRenderContext::DestroyMaterial( IMaterial *pMaterial ) { - + delete pMaterial; } -void CVkRenderContext::SetMaterial( IMaterial *pMaterial ) + +IRenderCommandList *CVkRenderContext::CreateCommandList() +{ + return new CVkRenderCommandList; +} + +void CVkRenderContext::DestroyCommandList( IRenderCommandList *pCommandList ) { } -void CVkRenderContext::SetVertexBuffer( IVertexBuffer *pBuffer ) +void CVkRenderContext::SubmitCommandList(IRenderCommandList *pList) { - + CVkRenderCommandList *pVkList = (CVkRenderCommandList*)pList; + pVkList->Submit(); } -void CVkRenderContext::SetIndexBuffer( IVertexBuffer *pBuffer ) -{ - -} - -void CVkRenderContext::DrawPrimitives( uint32_t nVertexCount, uint32_t nFirstVertex, uint32_t nInstanceCount, uint32_t nFirstInstance ) -{ - -} - -void CVkRenderContext::DrawPrimitivesIndexed( uint32_t nIndexCount, uint32_t nFirstIndex, uint32_t nVertexOffset, uint32_t nInstanceCount, uint32_t nFirstInstance ) -{ - -} - -IVkCommandBuffer *pCommandBuffer; +VkPipelineLayout g_pLibraryEmptyLayout; static IVkCommandBuffer *s_pPresentCommandBuffer; void CVkRenderContext::Init() { @@ -436,21 +553,48 @@ void CVkRenderContext::Init() VkPhysicalDeviceVulkan13Features vk13Features = {}; vk13Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; - vk13Features.synchronization2 = VK_TRUE; vk13Features.pNext = &gplFeatures; + vk13Features.synchronization2 = VK_TRUE; + vk13Features.dynamicRendering = VK_TRUE; + + VkPhysicalDeviceVulkan12Features vk12Features = {}; + vk12Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; + vk12Features.pNext = &vk13Features; + vk12Features.bufferDeviceAddress = VK_TRUE; stDeviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; stDeviceCreateInfo.queueCreateInfoCount = 1; stDeviceCreateInfo.pQueueCreateInfos = &stDeviceQueueCreateInfo; stDeviceCreateInfo.enabledExtensionCount = enabledDeviceExtensions.GetSize(); stDeviceCreateInfo.ppEnabledExtensionNames = enabledDeviceExtensions.GetData(); - stDeviceCreateInfo.pNext = &vk13Features; + stDeviceCreateInfo.pNext = &vk12Features; r = vkCreateDevice(g_vkPhysicalDevice, &stDeviceCreateInfo, NULL, &g_vkDevice); VULKAN_RESULT_PRINT(r, vkEnumeratePhysicalDevices); for (auto &extension: enabledDeviceExtensions) V_printf("%s\n", extension); vkGetDeviceQueue(g_vkDevice, g_iDrawFamily, 0, &g_vkDrawQueue); vkGetDeviceQueue(g_vkDevice, g_iPresentFamily, 0, &g_vkPresentQueue); + volkLoadDevice(g_vkDevice); + + VmaAllocatorCreateInfo stAllocatorInfo = {}; + stAllocatorInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT + | VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT + ; + stAllocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4; + stAllocatorInfo.physicalDevice = g_vkPhysicalDevice; + stAllocatorInfo.device = g_vkDevice; + stAllocatorInfo.instance = g_vkInstance; + + VmaVulkanFunctions vulkanFunctions; + vmaImportVulkanFunctionsFromVolk(&stAllocatorInfo, &vulkanFunctions); + + stAllocatorInfo.pVulkanFunctions = &vulkanFunctions; + vmaCreateAllocator(&stAllocatorInfo, &g_vkAllocator); + + VkPipelineLayoutCreateInfo stPipelineLayout = {}; + stPipelineLayout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + stPipelineLayout.flags = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT; + vkCreatePipelineLayout(g_vkDevice, &stPipelineLayout, NULL, &g_pLibraryEmptyLayout); CreateSwapchain(); @@ -468,37 +612,12 @@ void CVkRenderContext::Init() g_pCommandBufferManager = (IVkCommandBufferManager*)CreateInterface(VULKAN_COMMAND_BUFFER_MANAGER_INTERFACE_NAME, NULL); g_pCommandBufferManager->Init(); - pCommandBuffer = g_pCommandBufferManager->CreateCommandBuffer(); - s_pPresentCommandBuffer = g_pCommandBufferManager->CreateCommandBuffer(); - - CVkClearColorCommand *pCommand = (CVkClearColorCommand*)g_pCommandBufferManager->CreateCommand("ClearColor"); - - pCommand->pImage = NULL; - pCommand->ppSwapchainImages = g_vkSwapchainImages.GetData(); - pCommand->r = 1; - pCommand->b = 1; - pCommand->g = 0; - pCommand->AddSwapchainDependency( (IRenderingObject**)g_vkSwapchainImages.GetData(), DEPENDENCY_MODE_COLOR_CLEAR_DESTINATION ); - - CVkVertexDescriptionPipelineLibrary vertexDescription = {}; - vertexDescription.AddAttribute(0, 0, VERTEX_FORMAT_XYZ32_SFLOAT, 0); - vertexDescription.AddLayout(0, 12); - vertexDescription.SetTopology(TOPOLOGY_MODE_TRIANGLE_LIST); - vertexDescription.Build(); - - CVkVertexTransformPipelineLibrary vertexTransform = {}; CVkEmptyCommand *pPresentCommand = (CVkEmptyCommand*)g_pCommandBufferManager->CreateCommand("Empty"); pPresentCommand->AddSwapchainDependency( (IRenderingObject**)g_vkSwapchainImages.GetData(), DEPENDENCY_MODE_IMAGE_PRESENT ); - CVkBeginCommand *pBeginCommand = (CVkBeginCommand*)g_pCommandBufferManager->CreateCommand("Empty"); - pBeginCommand->AddSwapchainDependency((IRenderingObject**)g_vkSwapchainImages.GetData(), DEPENDENCY_MODE_DRAWCALL_OUTPUT_IMAGE); - CVkBeginCommand *pEndCommand = (CVkBeginCommand*)g_pCommandBufferManager->CreateCommand("Empty"); - - pCommandBuffer->Reset(); - pCommandBuffer->AddCommand(pCommand); - pCommandBuffer->Render(); + s_pPresentCommandBuffer = g_pCommandBufferManager->CreateCommandBuffer(); s_pPresentCommandBuffer->Reset(); s_pPresentCommandBuffer->AddCommand(pPresentCommand); s_pPresentCommandBuffer->Render(); @@ -507,8 +626,7 @@ void CVkRenderContext::Init() void CVkRenderContext::Frame( float fDeltaTime ) { vkDeviceWaitIdle(g_vkDevice); - pCommandBuffer->Render(); - s_pPresentCommandBuffer->Render(); + m_bOutputImageOutdated = false; static uint32_t s_nImageIndex = 0; uint32_t nImageIndex = 0; @@ -518,9 +636,7 @@ void CVkRenderContext::Frame( float fDeltaTime ) vkResetFences(g_vkDevice, 1, &g_vkFences[s_nImageIndex]); - g_vkCommandBuffers = {}; - pCommandBuffer->Submit(nImageIndex); s_pPresentCommandBuffer->Submit(nImageIndex); VkPipelineStageFlags uPipelineStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; @@ -550,6 +666,7 @@ void CVkRenderContext::Frame( float fDeltaTime ) vkQueuePresentKHR(g_vkPresentQueue, &stPresentInfo); s_nImageIndex = (s_nImageIndex + 1) % g_vkSwapchainImages.GetSize(); + g_vkCommandBuffers = {}; } void CVkRenderContext::CreateSwapchain() diff --git a/materialsystem/vulkan/shader.cpp b/materialsystem/vulkan/shader.cpp index 97a39b1..c43a23a 100644 --- a/materialsystem/vulkan/shader.cpp +++ b/materialsystem/vulkan/shader.cpp @@ -1,3 +1,39 @@ #include "vulkan_state.h" +void CVkShader::AddShaderLibrary( CVkPipelineLibrary *pLibrary ) +{ + m_libraries.AppendTail(pLibrary); +} +void CVkShader::Build() +{ + CUtlVector libs = {}; + VkGraphicsPipelineCreateInfo createInfo = {}; + VkPipelineLibraryCreateInfoKHR libInfo = {}; + + createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + for ( auto l: m_libraries ) + { + libs.AppendTail(l->m_hPipeline); + }; + + libInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR; + libInfo.libraryCount = libs.GetSize(); + libInfo.pLibraries = libs.GetData(); + createInfo.pNext = &libInfo; + createInfo.flags = VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT; + createInfo.layout = g_pLibraryEmptyLayout; + + // Possibly schedule it? + vkCreateGraphicsPipelines(g_vkDevice, NULL, 1, &createInfo, NULL, &m_hPipeline); +} + +uint32_t CVkShader::PSGetResourceByName( const char *szName ) +{ + +} + +uint32_t CVkShader::VSGetResourceByName( const char *szName ) +{ + +} diff --git a/materialsystem/vulkan/shaderparser.cpp b/materialsystem/vulkan/shaderparser.cpp new file mode 100644 index 0000000..4994c26 --- /dev/null +++ b/materialsystem/vulkan/shaderparser.cpp @@ -0,0 +1,28 @@ +#include "shaderparser.h" + +CUtlVector CVkShaderParser::GetDescriptors( CCompiledShader *pShader, EShaderStage eStage ) +{ + CUtlVector descriptors = {}; + + return descriptors; +}; +CUtlBuffer CVkShaderParser::GetShaderCode( CCompiledShader *pShader, EShaderStage eStage ) +{ + for ( auto &o: pShader->m_objects ) + { + if (o.m_eStage != eStage) + continue; + + CUtlBuffer code = CUtlBuffer(pShader->GetLumpSize(o.m_nDataLump)); + V_memcpy(code, pShader->GetLumpPtr(o.m_nDataLump), code.GetSize()); + return code; + } + + return NULL; +}; + +CVkShaderParser *ShaderParser() +{ + static CVkShaderParser s_shaderParser = CVkShaderParser(); + return &s_shaderParser; +}; diff --git a/materialsystem/vulkan/shaderparser.h b/materialsystem/vulkan/shaderparser.h new file mode 100644 index 0000000..672f9f2 --- /dev/null +++ b/materialsystem/vulkan/shaderparser.h @@ -0,0 +1,17 @@ +#ifndef VULKAN_SHADER_PARSER_H +#define VULKAN_SHADER_PARSER_H + +#include "materialsystem/vulkan_shadermeta.h" +#include "materialsystem/compiledshadermgr.h" +#include "tier1/utlvector.h" + +class CVkShaderParser +{ +public: + CUtlVector GetDescriptors( CCompiledShader *pShader, EShaderStage eStage ); + CUtlBuffer GetShaderCode( CCompiledShader *pShader, EShaderStage eStage ); +}; + +CVkShaderParser *ShaderParser(); + +#endif diff --git a/materialsystem/vulkan/utils.cpp b/materialsystem/vulkan/utils.cpp index da08fde..0e91c6f 100644 --- a/materialsystem/vulkan/utils.cpp +++ b/materialsystem/vulkan/utils.cpp @@ -22,7 +22,7 @@ VkAccessFlags2 VulkanGetAccessFlags( EDependencyMode eMode ) case DEPENDENCY_MODE_COLOR_CLEAR_DESTINATION: return VK_ACCESS_2_TRANSFER_WRITE_BIT; case DEPENDENCY_MODE_IMAGE_PRESENT: return VK_ACCESS_2_NONE; default: - return 0; + return VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT; } } @@ -73,3 +73,14 @@ VkPrimitiveTopology VulkanGetTopology( ETopologyMode eMode ) case TOPOLOGY_MODE_TRIANGLE_STRIP: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; } } +VkShaderStageFlagBits VulkanGetShaderStage( EShaderStage eStage ) +{ + switch (eStage) + { + case SHADER_STAGE_VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; + case SHADER_STAGE_PIXEL: return VK_SHADER_STAGE_FRAGMENT_BIT; + default: + break; + } + return VK_SHADER_STAGE_VERTEX_BIT; +} diff --git a/materialsystem/vulkan/vma.cpp b/materialsystem/vulkan/vma.cpp new file mode 100644 index 0000000..5dc31f5 --- /dev/null +++ b/materialsystem/vulkan/vma.cpp @@ -0,0 +1,6 @@ +#define VMA_VULKAN_VERSION 1004000 +#define VMA_IMPLEMENTATION +#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0 +#define VMA_STATIC_VULKAN_FUNCTIONS 0 +#include "volk.h" +#include "vk_mem_alloc.h" diff --git a/materialsystem/vulkan/vulkan_state.h b/materialsystem/vulkan/vulkan_state.h index 59d8f3a..b6343fe 100644 --- a/materialsystem/vulkan/vulkan_state.h +++ b/materialsystem/vulkan/vulkan_state.h @@ -8,6 +8,7 @@ #include "tier1/utlvector.h" #include "tier2/iappsystem.h" #include "materialsystem/imaterialsystem.h" +#include "materialsystem/shaderinternals.h" #include "vulkan/vulkan_core.h" #define REQUIRED_EXTENSION(ext) bool bIsSupported_##ext; @@ -26,6 +27,7 @@ extern CUtlVector g_vkCommandPools; extern CUtlVector g_vkCommandBuffers; extern VkInstance g_vkInstance; +extern VmaAllocator g_vkAllocator; extern VkPhysicalDevice g_vkPhysicalDevice; extern VkDevice g_vkDevice; @@ -115,7 +117,7 @@ public: virtual void AddCommand( CVkCommand *pCommand ) = 0; virtual void Reset() = 0; - virtual void Submit( int iFrameIndex ) = 0; + virtual void Submit( int iFrameIndex = 0 ) = 0; virtual void Render() = 0; }; @@ -135,6 +137,8 @@ class CVkCommandRegistry public: CVkCommandRegistry( const char *szName, fnCreateVulkanCommand_t pfnCreate ); }; +#define CREATE_COMMAND(name) \ +(CVk##name##Command*)g_pCommandBufferManager->CreateCommand(#name) #define BEGIN_VULKAN_COMMAND( name ) \ class CVk##name##Command : public CVkCommand \ @@ -162,7 +166,7 @@ class CVkImage: public IImage { public: CVkImage(); - CVkImage( uint32_t nWidth, uint32_t nHeight, EImageFormat eFormat, EMultisampleType eMultisampleType ); + CVkImage( uint32_t nWidth, uint32_t nHeight, uint32_t nDepth, EImageFormat eFormat, EMultisampleType eMultisampleType, EImageType eImageType, VkImageUsageFlagBits eUsage ); ~CVkImage(); virtual void SetDebugName( const char *szName ) override; @@ -171,7 +175,7 @@ public: virtual EImageFormat GetImageFormat() override; virtual EMultisampleType GetMultisampleType() override; - void CreateImage( uint32_t nWidth, uint32_t nHeight, EImageFormat eFormat, EMultisampleType eMultisampleType ); + void CreateImage( uint32_t nWidth, uint32_t nHeight, EImageFormat eFormat, EMultisampleType eMultisampleType, VkImageUsageFlagBits eUsage ); void CreateImageView(); static VkImageViewType GetImageViewType( enum EImageType eImageType ); @@ -205,10 +209,10 @@ public: virtual void Unmap() override; virtual uint32_t GetSize() override; - VmaAllocation allocation; - VkBuffer buffer; - VkDeviceAddress address; - uint32_t nSize; + VmaAllocation m_allocation; + VkBuffer m_buffer; + VkDeviceAddress m_address; + uint32_t m_nSize; }; class CVkPipelineLibrary @@ -228,6 +232,7 @@ public: \ #define END_DEFINE_PIPELINE_LIBRARY() \ }; +extern VkPipelineLayout g_pLibraryEmptyLayout; #define BEGIN_BUILD_PIPELINE_LIBRARY(name) \ void CVk##name##PipelineLibrary::Build() \ { \ @@ -236,22 +241,59 @@ void CVk##name##PipelineLibrary::Build() \ pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; \ library.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT; \ pipeline.pNext = &library; \ - pipeline.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR; \ + pipeline.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; \ + pipeline.layout = g_pLibraryEmptyLayout; #define END_BUILD_PIPELINE_LIBRARY() \ vkCreateGraphicsPipelines(g_vkDevice, NULL, 1, &pipeline, NULL, &m_hPipeline); \ } -class CVkShader : IShader +class CVkShader : public IShader { public: void AddShaderLibrary( CVkPipelineLibrary *pLibrary ); void Build(); + virtual uint32_t PSGetResourceByName( const char *szName ) override; + virtual uint32_t VSGetResourceByName( const char *szName ) override; VkPipeline m_hPipeline = NULL; VkPipelineLayout m_hPipelineLayout; CUtlVector m_libraries; }; +class CVkMaterial: public IMaterial +{ +public: + CVkMaterial( IShader *pShader ); + virtual ~CVkMaterial() override; + + virtual void VSSetShaderResource( uint32_t uRegister, IRenderingObject *pResource ) override; + virtual void VSSetConstantsBuffer( uint32_t uRegister, IBuffer *pConstants ) override; + + virtual void PSSetShaderResource( uint32_t uRegister, IRenderingObject *pResource ) override; + virtual void PSSetConstantsBuffer( uint32_t uRegister, IBuffer *pConstants ) override; + + CVkShader *m_pVkShader; +private: + void SetShaderResource( uint32_t uRegister, uint32_t uSet, IRenderingObject *pObject); +}; + + + +enum EVulkanRenderingStage +{ + RENDERING_STAGE_SETUP_RASTER, + RENDERING_STAGE_RASTER, + RENDERING_STAGE_POST_RASTER, + RENDERING_STAGE_FINISHED, +}; + +struct VulkanMaterialCommandBuffer_t +{ + IMaterial *m_pMaterial; + IVkCommandBuffer *m_pCommandBuffer; +}; + + enum EVkFrameObjectType_t { FRAME_OBJECT_TYPE_SINGLE, @@ -267,6 +309,64 @@ struct VkFrameObject_t }; }; +struct VulkanRenderOutput_t { + VkFrameObject_t m_stImage; + VkFrameObject_t m_stResolveImage; + + float m_fClearColor[4]; + float m_fClearDepth; + + uint32_t m_uIndex; + EResolveMode m_eResolveMode; + ELoadMode m_eLoadMode; + EStoreMode m_eStoreMode; +}; + +class CVkRenderCommandList: public IRenderCommandList +{ +public: + virtual void ResetRendering() override; + + virtual void SetRenderTarget( uint32_t uIndex, IImage *pImage ) override; + virtual void SetClearColor( uint32_t uIndex, float r, float g, float b, float a ) override; + + virtual void SetDepthTarget( IImage *pDepth ) override; + virtual void SetClearDepth( float fVal ) override; + + virtual void SetRenderResolution( uint32_t iWidth, uint32_t iHeight ) override; + + // Should they apply per material or for all? + virtual void SetScissors( uint32_t uX, uint32_t uY, uint32_t uWidth, uint32_t uHeight ) override; + virtual void SetViewport( uint32_t uX, uint32_t uY, uint32_t uWidth, uint32_t uHeight, float fMinDepth, float fMaxDepth ) override; + + virtual void SetMaterial( IMaterial *pMaterial ) override; + virtual void SetVertexBuffer( uint32_t uBinding, IVertexBuffer *pBuffer ) override; + virtual void SetIndexBuffer( IVertexBuffer *pBuffer ) override; + virtual void DrawPrimitives( uint32_t nVertexCount, uint32_t nFirstVertex, uint32_t nInstanceCount, uint32_t nFirstInstance ) override; + virtual void DrawPrimitivesIndexed( uint32_t nIndexCount, uint32_t nFirstIndex, uint32_t nVertexOffset, uint32_t nInstanceCount, uint32_t nFirstInstance ) override; + + virtual void ResolveImage( IImage *pOriginal, IImage *pResolved ) override; + + virtual void StartRecording() override; + virtual void EndRecording() override; + + void Submit(); +private: + void SwitchRenderingStage( EVulkanRenderingStage eStage ); + + VulkanRenderOutput_t *FindOrCreateRenderOutput( uint32_t uIndex ); + IVkCommandBuffer *FindOrCreateMaterialCommandBuffer( IMaterial *pMaterial, bool *pbWasCreated = NULL ); + + VulkanRenderOutput_t m_depth; + + CUtlVector m_pOutput = {}; + CUtlSelfReferencingVector m_materials = {}; + IVkCommandBuffer *m_pPostRaster; + + IVkCommandBuffer *m_pCurrentMaterialBuffer = NULL; +}; + + IRenderingObject *VulkanGetObject( VkFrameObject_t stObject, int iIndex ); VkAccessFlags2 VulkanGetAccessFlags( EDependencyMode eMode ); @@ -274,4 +374,6 @@ VkPipelineStageFlags2 VulkanGetStageFlags( EDependencyMode eMode ); VkImageLayout VulkanGetImageLayout( EDependencyMode eMode ); VkFormat VulkanGetVertexFormat( EVertexFormat eFormat ); VkPrimitiveTopology VulkanGetTopology( ETopologyMode eMode ); +VkShaderStageFlagBits VulkanGetShaderStage( EShaderStage eStage ); + #endif diff --git a/public/materialsystem/compiledshadermgr.h b/public/materialsystem/compiledshadermgr.h new file mode 100644 index 0000000..bcce6cb --- /dev/null +++ b/public/materialsystem/compiledshadermgr.h @@ -0,0 +1,17 @@ +#ifndef SHADER_WRITER_H +#define SHADER_WRITER_H + +#include "tier1/interface.h" +#include "shadercompiler/icompiler.h" + + +abstract_class ICompiledShaderManager +{ +public: + virtual void WriteToFile( CCompiledShader *pShader, const char *szFile ) = 0; + virtual void ReadFromFile( CCompiledShader *pShader, const char *szFile ) = 0; +}; + +ICompiledShaderManager *CompiledShaderManager(); + +#endif diff --git a/public/materialsystem/imaterialsystem.h b/public/materialsystem/imaterialsystem.h index 4058602..aa37207 100644 --- a/public/materialsystem/imaterialsystem.h +++ b/public/materialsystem/imaterialsystem.h @@ -78,18 +78,25 @@ enum ETopologyMode }; +//----------------------------------------------------------------------------- +// Basic rendering object +//----------------------------------------------------------------------------- abstract_class IRenderingObject { public: + virtual ~IRenderingObject() = 0; virtual void SetDebugName( const char *szName ) = 0; }; +//----------------------------------------------------------------------------- +// Buffer object +//----------------------------------------------------------------------------- abstract_class IBuffer : public IRenderingObject { public: virtual void Lock() = 0; virtual void Unlock() = 0; -virtual void *Map() = 0; + virtual void *Map() = 0; virtual void Unmap() = 0; virtual uint32_t GetSize() = 0; @@ -98,6 +105,9 @@ virtual void *Map() = 0; typedef IBuffer IVertexBuffer; typedef IBuffer IIndexBuffer; +//----------------------------------------------------------------------------- +// Image object +//----------------------------------------------------------------------------- abstract_class IImage : public IRenderingObject { public: @@ -107,35 +117,83 @@ public: virtual EMultisampleType GetMultisampleType() = 0; }; +//----------------------------------------------------------------------------- +// Shader object +//----------------------------------------------------------------------------- abstract_class IShader { public: + virtual ~IShader() = 0; + virtual uint32_t PSGetResourceByName( const char *szName ) = 0; + virtual uint32_t VSGetResourceByName( const char *szName ) = 0; }; - -#define BEGIN_SHADER(name) \ -class CShader_##name \ -{ - -#define END_SHADER() \ -} - +//----------------------------------------------------------------------------- +// Material handle +// It allows to specify resources in shaders such as textures, buffers etc. +// +// Resources must be updated prior to the frame, which can be done +// prior to the frame. +//----------------------------------------------------------------------------- abstract_class IMaterial { public: - virtual void SetConstants( void *pData ) = 0; - - virtual void SetTexture( const char *szName, IImage *pImage ) = 0; - virtual void SetBuffer( const char *szName, IBuffer *pImage ) = 0; + virtual ~IMaterial() = 0; + virtual void VSSetShaderResource( uint32_t uRegister, IRenderingObject *pResource ) = 0; + virtual void PSSetShaderResource( uint32_t uRegister, IRenderingObject *pResource ) = 0; + virtual void VSSetConstantsBuffer( uint32_t uRegister, IBuffer *pImage ) = 0; + virtual void PSSetConstantsBuffer( uint32_t uRegister, IBuffer *pImage ) = 0; }; +abstract_class IRenderCommandList +{ +public: + virtual void ResetRendering() = 0; + + virtual void SetRenderTarget( uint32_t uIndex, IImage *pImage ) = 0; + virtual void SetClearColor( uint32_t uIndex, float r, float g, float b, float a ) = 0; + + virtual void SetDepthTarget( IImage *pDepth ) = 0; + virtual void SetClearDepth( float fVal ) = 0; + + virtual void SetRenderResolution( uint32_t iWidth, uint32_t iHeight ) = 0; + + virtual void SetScissors( uint32_t uX, uint32_t uY, uint32_t uWidth, uint32_t uHeight ) = 0; + virtual void SetViewport( uint32_t uX, uint32_t uY, uint32_t uWidth, uint32_t uHeight, float fMinDepth, float fMaxDepth ) = 0; + + virtual void SetMaterial( IMaterial *pMaterial ) = 0; + virtual void SetVertexBuffer( uint32_t uBinding, IVertexBuffer *pBuffer ) = 0; + virtual void SetIndexBuffer( IVertexBuffer *pBuffer ) = 0; + virtual void DrawPrimitives( uint32_t nVertexCount, uint32_t nFirstVertex, uint32_t nInstanceCount, uint32_t nFirstInstance ) = 0; + virtual void DrawPrimitivesIndexed( uint32_t nIndexCount, uint32_t nFirstIndex, uint32_t nVertexOffset, uint32_t nInstanceCount, uint32_t nFirstInstance ) = 0; + + virtual void ResolveImage( IImage *pOriginal, IImage *pResolved ) = 0; + + virtual void StartRecording() = 0; + virtual void EndRecording() = 0; +}; + +//----------------------------------------------------------------------------- +// Rendering context +// +// Responsible for the object handling +//----------------------------------------------------------------------------- abstract_class IRenderContext: public IAppSystem { public: virtual void Frame( float fTime ) = 0; + + virtual void SetOutputImage( IImage *pImage ) = 0; + + virtual bool BIsOutputImageOutdated() = 0; + virtual uint32_t GetNewOutputImageWidth() = 0; + virtual uint32_t GetNewOutputImageHeight() = 0; + virtual EImageFormat GetNewOutputImageFormat() = 0; virtual IVertexBuffer *CreateVertexBuffer( uint32_t nSize ) = 0; virtual IIndexBuffer *CreateIndexBuffer( uint32_t nSize ) = 0; + virtual IBuffer *CreateConstantBuffer( uint32_t nSize ) = 0; + virtual IBuffer *CreateStorageBuffer( uint32_t nSize ) = 0; virtual IImage *CreateRenderTarget( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType ) = 0; virtual IImage *CreateStorageImage( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType ) = 0; @@ -148,22 +206,22 @@ public: virtual IMaterial *CreateMaterial( IShader *pShader ) = 0; virtual void DestroyMaterial( IMaterial *pMaterial ) = 0; - virtual void SetMaterial( IMaterial *pMaterial ) = 0; - virtual void SetVertexBuffer( IVertexBuffer *pBuffer ) = 0; - virtual void SetIndexBuffer( IVertexBuffer *pBuffer ) = 0; - virtual void DrawPrimitives( uint32_t nVertexCount, uint32_t nFirstVertex, uint32_t nInstanceCount, uint32_t nFirstInstance ) = 0; - virtual void DrawPrimitivesIndexed( uint32_t nIndexCount, uint32_t nFirstIndex, uint32_t nVertexOffset, uint32_t nInstanceCount, uint32_t nFirstInstance ) = 0; + virtual IRenderCommandList *CreateCommandList() = 0; + virtual void DestroyCommandList( IRenderCommandList *pCommandList ) = 0; + virtual void SubmitCommandList(IRenderCommandList *pList) = 0; + }; +#define RENDER_CONTEXT_INTERFACE_NAME "RenderContext001" +#define RENDER_CONTEXT_VULKAN_INTERFACE_NAME RENDER_CONTEXT_INTERFACE_NAME abstract_class IMaterialSystem: public IAppSystem { public: virtual void Frame( float fTime ) = 0; - - virtual IRenderContext *GetRenderContext( void ) = 0; }; +extern IRenderContext *g_pRenderContext; IMaterialSystem *Materials( void ); #endif diff --git a/public/ilevelmgr.h b/public/materialsystem/metal_shaderinternals.h similarity index 100% rename from public/ilevelmgr.h rename to public/materialsystem/metal_shaderinternals.h diff --git a/public/materialsystem/shaderinternals.h b/public/materialsystem/shaderinternals.h new file mode 100644 index 0000000..ceb70c9 --- /dev/null +++ b/public/materialsystem/shaderinternals.h @@ -0,0 +1,70 @@ +//================= Copyright kotofyt, All rights reserved ==================// +// Purpose: Shader compilers. +// +// We kinda need to store shader contents in blobs so they can be parsed easily +// +// For now we store them like this +// ShaderHeader_t +// ShaderLump_t[m_nNumLump] +// ShaderObject_t[m_nNumShaders] +// ~An actual shader data~ +//===========================================================================// + +#ifndef SHADER_INTERNALS_H +#define SHADER_INTERNALS_H + +#include "stdint.h" + +enum EShaderBackend: uint32_t +{ + SHADER_BACKEND_SPIRV_VULKAN, + SHADER_BACKEND_CODE_METAL, +}; + +enum EShaderStage: uint32_t +{ + SHADER_STAGE_VERTEX, + SHADER_STAGE_TESSELATION_CONTROL, + SHADER_STAGE_TESSELATION_EVAL, + SHADER_STAGE_GEOMETRY, + SHADER_STAGE_PIXEL, + + SHADER_STAGE_COMPUTE, + + SHADER_STAGE_RAYGEN, + SHADER_STAGE_ANY_HIT, + SHADER_STAGE_CLOSEST_HIT, + SHADER_STAGE_MISS, + SHADER_STAGE_CALLABLE, + + SHADER_STAGE_TASK, + SHADER_STAGE_MESH, + + SHADER_STAGE_COMMON_DATA, + + SHADER_STAGE_MAX, + SHADER_STAGE_COUNT = SHADER_STAGE_MAX +}; + +struct ShaderHeader_t +{ + char m_cSignature[4]; + uint32_t m_nNumLumps; + uint32_t m_nNumShaders; +}; + +struct ShaderLump_t +{ + uint32_t m_nSize; + uint32_t m_nOffset; +}; + +struct ShaderObject_t +{ + EShaderBackend m_eBackend; + EShaderStage m_eStage; + uint32_t m_nMetadataLump; + uint32_t m_nDataLump; +}; + +#endif diff --git a/public/materialsystem/vulkan_shadermeta.h b/public/materialsystem/vulkan_shadermeta.h new file mode 100644 index 0000000..d19ddca --- /dev/null +++ b/public/materialsystem/vulkan_shadermeta.h @@ -0,0 +1,20 @@ +#ifndef VULKAN_METADATA_H +#define VULKAN_METADATA_H + +#include "shaderinternals.h" +#include "vulkan/vulkan.h" + +struct VulkanDescriptor_t +{ + VkDescriptorType eDescriptorType; + uint32_t uBinding; + uint32_t uSet; +}; + +struct VulkanInputMetaData_t +{ + uint32_t nDescriptorsCount; + uint32_t pDescriptorSets; +}; + +#endif diff --git a/public/shadercompiler/icompiler.h b/public/shadercompiler/icompiler.h new file mode 100644 index 0000000..05588fa --- /dev/null +++ b/public/shadercompiler/icompiler.h @@ -0,0 +1,41 @@ +#ifndef SHADER_COMPILER_H +#define SHADER_COMPILER_H + +#include "tier1/interface.h" +#include "tier1/utlvector.h" +#include "tier1/utlbuffer.h" +#include "tier2/iappsystem.h" +#include "materialsystem/shaderinternals.h" + +struct HostShaderLump_t +{ + void *m_pAddress; + uint32_t m_nSize; +}; + +class CCompiledShader +{ +public: + CUtlVector m_objects = {}; + CUtlVector m_lumps = {}; + + ~CCompiledShader(); + + uint32_t AllocateLump( uint32_t nSize ); + void *GetLumpPtr( uint32_t nLump ); + uint32_t GetLumpSize( uint32_t nLump ); + ShaderObject_t *AllocateShader(); + + ShaderObject_t *FindShaderObject( EShaderBackend eBackend, EShaderStage eStage ); +}; + +abstract_class IShaderCompiler: public IAppSystem +{ +public: + virtual void CompileShader( const char *szInput, CCompiledShader *pShader ) = 0; +}; + +#define SLANG_SHADER_COMPILER_SPIRV_VULKAN "ShaderCompilerSlangVulkanSpirv" +#define SLANG_SHADER_COMPILER_CODE_METAL "ShaderCompilerSlangMetalCode" + +#endif diff --git a/public/tier0/platform.h b/public/tier0/platform.h index a25229e..07a12d0 100644 --- a/public/tier0/platform.h +++ b/public/tier0/platform.h @@ -58,6 +58,9 @@ typedef void( *ListDirCallbackFn )( const char *szPath ); PLATFORM_INTERFACE void Plat_ListDirRecursive( const char *szPath, ListDirCallbackFn file, ListDirCallbackFn dir ); PLATFORM_INTERFACE void Plat_ListDir( const char *szPath, ListDirCallbackFn file, ListDirCallbackFn dir ); PLATFORM_INTERFACE char *Plat_GetExtension( const char *szPath ); + +PLATFORM_INTERFACE void Plat_MakeDir( const char *szPath, int iPermissions ); + PLATFORM_INTERFACE void Plat_TrapSignals( void (*pfn)() ); PLATFORM_INTERFACE void Plat_Backtrace( void ); @@ -65,6 +68,24 @@ PLATFORM_INTERFACE void *Plat_LoadLibrary( const char *psz ); PLATFORM_INTERFACE void *Plat_GetProc( void *lib, const char *psz ); PLATFORM_INTERFACE void Plat_UnloadLibrary( void *psz ); +PLATFORM_INTERFACE void Plat_SetEnv( const char *szVar, const char *psz ); +PLATFORM_INTERFACE const char *Plat_GetEnv( const char *szVar ); + +PLATFORM_INTERFACE void Plat_SetWorkingDir( const char *psz ); +PLATFORM_INTERFACE const char *Plat_GetWorkingDir( void ); + +PLATFORM_INTERFACE const char *Plat_GetExecutablePath( void ); +PLATFORM_INTERFACE const char *Plat_GetParentDir( const char *psz ); + +PLATFORM_INTERFACE const char *Plat_GetUNIXExecutable( const char *psz ); +PLATFORM_INTERFACE const char *Plat_GetWindowsExecutable( const char *psz ); +PLATFORM_INTERFACE const char *Plat_GetPlatformExecutable( const char *psz ); + +PLATFORM_INTERFACE const char *Plat_GetDarwinSharedLib( const char *psz ); +PLATFORM_INTERFACE const char *Plat_GetUNIXSharedLib( const char *psz ); +PLATFORM_INTERFACE const char *Plat_GetWindowsSharedLib( const char *psz ); +PLATFORM_INTERFACE const char *Plat_GetPlatformSharedLib( const char *psz ); + PLATFORM_INTERFACE double Plat_GetTime( void ); PLATFORM_INTERFACE void Plat_Exit( int status ); diff --git a/public/tier1/appinit.h b/public/tier1/appinit.h new file mode 100644 index 0000000..244ca1e --- /dev/null +++ b/public/tier1/appinit.h @@ -0,0 +1,7 @@ +#ifndef APPINIT_H +#define APPINIT_H + + +void AppInitializePath(); + +#endif diff --git a/public/tier1/interface.h b/public/tier1/interface.h index 846ad4f..0eb0cd0 100644 --- a/public/tier1/interface.h +++ b/public/tier1/interface.h @@ -6,6 +6,8 @@ typedef void *( *CreateInterfaceFn )( const char *szName, int *pReturnCode ); typedef void *( *InstantiateInterfaceFn )( void ); +CreateInterfaceFn Plat_GetInterfaceFactory( void *lib ); + class CInterfaceRegistry { public: diff --git a/public/tier1/utlstring.h b/public/tier1/utlstring.h index 767b158..5054d9e 100644 --- a/public/tier1/utlstring.h +++ b/public/tier1/utlstring.h @@ -23,6 +23,10 @@ public: void RemoveHead( size_t nCount ); void RemoveAt( size_t nPosition, size_t nCount ); + CUtlString GetFileName(); + CUtlString GetDirectory(); + CUtlString RemoveHeadFile(); + char *GetString( void ); size_t GetLenght( void ); operator char*( void ); diff --git a/public/tier1/utlvector.h b/public/tier1/utlvector.h index c8641d9..0c24440 100644 --- a/public/tier1/utlvector.h +++ b/public/tier1/utlvector.h @@ -306,6 +306,9 @@ public: void RemoveTail( void ); void RemoveAt( size_t nIndex ); + T &GetFirst(); + T &GetLast(); + size_t GetSize(); T operator[]( size_t nIndex ); @@ -428,4 +431,17 @@ void CUtlSelfReferencingVector::RemoveTail( void ) } +template +T &CUtlSelfReferencingVector::GetFirst() +{ + return m_pHead->data; +} + +template +T &CUtlSelfReferencingVector::GetLast() +{ + return m_pTail->data; +} + + #endif diff --git a/public/tier2/ifilesystem.h b/public/tier2/ifilesystem.h index 887bce0..8b787f5 100644 --- a/public/tier2/ifilesystem.h +++ b/public/tier2/ifilesystem.h @@ -59,6 +59,10 @@ public: // Some cool stuff virtual CUtlBuffer Read( IFileHandle *pFile ) = 0; + // Leaks memory + // Should be cleaned by the user + virtual const char *ReadString( IFileHandle *pFile ) = 0; + IFileSystem *m_pNext; void RegisterFileSystem(); diff --git a/shadercompiler/__build.cpp b/shadercompiler/__build.cpp new file mode 100644 index 0000000..0ad2a72 --- /dev/null +++ b/shadercompiler/__build.cpp @@ -0,0 +1,75 @@ +#include "c.h" +#include "helper.h" +#include "ld.h" +#include "target.h" + +CUtlString shadercompiler_lib; +CUtlString shadercompiler_exe; +DECLARE_BUILD_STAGE(libshadercompiler) +{ + CProject_t stProject; + LinkProject_t stLinkProject; + CUtlString szOutput; + + stProject.m_szName = "shadercompiler"; + stProject.m_target = Target_t::HostTarget(); + stProject.bFPIC = true; + stProject.includeDirectories = { + "public", + "external/slang/include", + "external/Vulkan-Headers/include", + }; + stProject.files = { + "shadercompiler/slang/vulkan_spirv.cpp", + "materialsystem/compiledshader.cpp", + }; + + stLinkProject = ccompiler->Compile(&stProject); + stLinkProject.linkType = ELINK_STATIC_LIBRARY; + szOutput = linker->Link(&stLinkProject); + shadercompiler_lib = szOutput; + + return 1; +} +DECLARE_BUILD_STAGE(shadercompiler) +{ + CProject_t stProject; + LinkProject_t stLinkProject; + CUtlString szOutput; + + stProject.m_szName = "fsc"; + stProject.m_target = Target_t::HostTarget(); + stProject.includeDirectories = {"public"}; + stProject.files = { + "shadercompiler/main.cpp", + }; + + stLinkProject = ccompiler->Compile(&stProject); + stLinkProject.linkType = ELINK_EXECUTABLE; + stLinkProject.objects.AppendTail((Object_t){tier0_lib}); + stLinkProject.objects.AppendTail((Object_t){tier1_lib}); + stLinkProject.objects.AppendTail((Object_t){tier2_lib}); + stLinkProject.objects.AppendTail((Object_t){shadercompiler_lib}); + stLinkProject.libraries = {"slang-compiler","slang-glslang-2025.24.2"}; + stLinkProject.libraryDirectories = {"external/linux"}; + szOutput = linker->Link(&stLinkProject); + filesystem2->MakeDirectory(CUtlString("%s/bin/tools", szOutputDir.GetString())); + filesystem2->CopyFile(CUtlString("%s/bin/tools", szOutputDir.GetString()), szOutput); + filesystem2->CopyFile(CUtlString("%s/bin/tools", szOutputDir.GetString()), "external/linux/libslang-compiler.so.0.2025.24.2"); + filesystem2->CopyFile(CUtlString("%s/bin/tools", szOutputDir.GetString()), "external/linux/libslang-glslang-2025.24.2.so"); + shadercompiler_exe = CUtlString("%s/bin/tools/fsc", szOutputDir.GetString()); + + return 1; +} + +DECLARE_BUILD_STAGE(compileshaders) +{ + if (CommandLine()->CheckParam("-nofsc")) + return 0; + + CUtlVector args = {"-i", "funnyassets", "-o", "build/funnygame/assets"}; + + runner->Run(shadercompiler_exe, args); + runner->Wait(); + return 0; +}; diff --git a/shadercompiler/main.cpp b/shadercompiler/main.cpp new file mode 100644 index 0000000..33e56c2 --- /dev/null +++ b/shadercompiler/main.cpp @@ -0,0 +1,61 @@ +#include "tier0/lib.h" +#include "tier1/commandline.h" +#include "tier1/appinit.h" +#include "tier1/utlstring.h" +#include "tier2/ifilesystem.h" +#include "shadercompiler/icompiler.h" +#include "materialsystem/compiledshadermgr.h" + +static IShaderCompiler *s_pVulkanSpirvCompiler; +static const char *s_szGameRoot; + +void CompileShader( const char *szShader ) +{ + CCompiledShader shader; + + if (V_strcmp("shader",Plat_GetExtension(szShader))) + return; + + s_pVulkanSpirvCompiler->CompileShader(szShader, &shader); + + Plat_MakeDir("build/funnygame/assets", 0755); + Plat_MakeDir("build/funnygame/assets/shaders", 0755); + + CUtlString szOutputDirectory = szShader; + szOutputDirectory.RemoveHead(strlen(s_szGameRoot)+1); + szOutputDirectory.AppendHead("build/funnygame/assets/"); + szOutputDirectory.AppendTail("_c"); + printf("%s\n",szOutputDirectory.GetString()); + + + CompiledShaderManager()->WriteToFile(&shader, szOutputDirectory); +}; + +void PrintHelp() +{ + printf("Usage: fsc -i [shader folder] -o [game root]"); + Plat_Exit(0); +} + +int main( int c, char **v ) +{ + CUtlString szExePath = Plat_GetExecutablePath(); + + CommandLine()->CreateCommandLine(c, v); + filesystem->Init(); + + s_pVulkanSpirvCompiler = (IShaderCompiler*)CreateInterface(SLANG_SHADER_COMPILER_SPIRV_VULKAN, NULL); + s_pVulkanSpirvCompiler->Init(); + + const char *szInputDirectory = CommandLine()->ParamValue("-i"); + if (!szInputDirectory) + PrintHelp(); + s_szGameRoot = szInputDirectory; + + CUtlString szShaderDirectory = CUtlString("%s/shaders\n", szInputDirectory); + + Plat_ListDirRecursive(szInputDirectory, CompileShader, NULL); + s_pVulkanSpirvCompiler->Shutdown(); + + return 0; +} diff --git a/shadercompiler/slang/metal_code.cpp b/shadercompiler/slang/metal_code.cpp new file mode 100644 index 0000000..e69de29 diff --git a/shadercompiler/slang/vulkan_spirv.cpp b/shadercompiler/slang/vulkan_spirv.cpp new file mode 100644 index 0000000..302284f --- /dev/null +++ b/shadercompiler/slang/vulkan_spirv.cpp @@ -0,0 +1,144 @@ +#include "shadercompiler/icompiler.h" +#include "slang.h" +#include "tier0/mem.h" +#include "tier1/utlstring.h" +#include "tier2/ifilesystem.h" +#include "vulkan/vulkan.h" + +using namespace slang; + +static IGlobalSession *s_pGlobalSession; +static ISession *s_pSession; +class CSlangVulkanSpirvShaderCompiler: public IShaderCompiler +{ +public: + virtual void Init() override; + virtual void Shutdown() override; + virtual void CompileShader( const char *szInput, CCompiledShader *pShader ) override; +private: + IBlob *m_pDiagnostics = NULL; + void CheckDiagnostics(); + + void CompileShaderStage( EShaderStage eStage, const char *szMain, ISession *pSession, IModule *pModule, CCompiledShader *pShader ); +}; + +EXPOSE_INTERFACE(CSlangVulkanSpirvShaderCompiler, IShaderCompiler, SLANG_SHADER_COMPILER_SPIRV_VULKAN) + +void CSlangVulkanSpirvShaderCompiler::CompileShaderStage( EShaderStage eStage, const char *szMain, ISession *pSession, IModule *pModule, CCompiledShader *pShader ) +{ + SlangStage eSlangStage; + IEntryPoint *pEntryPoint = NULL; + IComponentType *pLinked = NULL; + IBlob *pBinary = NULL; + ShaderObject_t *pShaderObject = NULL; + + switch (eStage) + { + case SHADER_STAGE_VERTEX: + eSlangStage = SLANG_STAGE_VERTEX; + break; + case SHADER_STAGE_PIXEL: + eSlangStage = SLANG_STAGE_PIXEL; + break; + default: + break; + } + + pModule->findAndCheckEntryPoint(szMain, eSlangStage, &pEntryPoint, &m_pDiagnostics); + CheckDiagnostics(); + + pEntryPoint->link(&pLinked, &m_pDiagnostics); + CheckDiagnostics(); + + pLinked->getEntryPointCode(0, 0, &pBinary, &m_pDiagnostics); + CheckDiagnostics(); + + pShaderObject = pShader->AllocateShader(); + pShaderObject->m_eBackend = SHADER_BACKEND_SPIRV_VULKAN; + pShaderObject->m_eStage = eStage; + pShaderObject->m_nDataLump = pShader->AllocateLump(pBinary->getBufferSize()); + V_memcpy(pShader->GetLumpPtr(pShaderObject->m_nDataLump), pBinary->getBufferPointer(), pBinary->getBufferSize()); + + pEntryPoint->release(); +} + +void CSlangVulkanSpirvShaderCompiler::CompileShader( const char *szInput, CCompiledShader *pShader ) +{ + SessionDesc stSessionDesc = {}; + TargetDesc stTargetDesc = {}; + PreprocessorMacroDesc stStageMacroDesc = {}; + const char *szMainName; + IModule *pModule = NULL; + ISession *pSession = NULL; + IBlob *pShaderSourceBlob = NULL; + + IFileHandle *pFile = filesystem->Open(szInput, FILEMODE_READ); + const char *szShaderSource = filesystem->ReadString(pFile); + + int i = 0; + + pShaderSourceBlob = slang_createBlob(szShaderSource, pFile->Size()); + filesystem->Close(pFile); + + printf(" SLANG %s\n", szInput); + + stSessionDesc.targetCount = 1; + stSessionDesc.targets = &stTargetDesc; + + stTargetDesc.format = SLANG_SPIRV; + stTargetDesc.profile = s_pGlobalSession->findProfile("spirv_1_6"); + + + for ( i = 0; icreateSession(stSessionDesc, &pSession); + + pModule = pSession->loadModuleFromSource("main", szInput, pShaderSourceBlob, &m_pDiagnostics); + CheckDiagnostics(); + + CompileShaderStage((EShaderStage)i, szMainName, pSession, pModule, pShader); + pModule->release(); + pSession->release(); + } + + V_free((void*)szShaderSource); +} +void CSlangVulkanSpirvShaderCompiler::CheckDiagnostics() +{ + + if (m_pDiagnostics) + { + V_printf("%s\n",(const char*)m_pDiagnostics->getBufferPointer()); + Plat_Exit(0); + } +}; + +void CSlangVulkanSpirvShaderCompiler::Init() +{ + createGlobalSession(&s_pGlobalSession); +} + +void CSlangVulkanSpirvShaderCompiler::Shutdown() +{ + s_pGlobalSession->Release(); +} + diff --git a/tier0/__build.cpp b/tier0/__build.cpp index bcdc59e..954cbdb 100644 --- a/tier0/__build.cpp +++ b/tier0/__build.cpp @@ -15,6 +15,7 @@ DECLARE_BUILD_STAGE(tier0) { CProject_t compileProject = {}; LinkProject_t ldProject = {}; + CUtlString szOutputProject = ""; compileProject.m_szName = "tier0"; compileProject.files = tier0_CompiledFiles; @@ -22,18 +23,21 @@ DECLARE_BUILD_STAGE(tier0) compileProject.bFPIC = true; ldProject = ccompiler->Compile(&compileProject); if (bStaticBuild) - ldProject.linkType = ELINK_STATIC_LIBRARY; - else - ldProject.linkType = ELINK_DYNAMIC_LIBRARY; - - CUtlString outputProject = linker->Link(&ldProject); - - if (!bStaticBuild) { + ldProject.linkType = ELINK_STATIC_LIBRARY; + szOutputProject = linker->Link(&ldProject); + tier0_lib = szOutputProject; + } + else + { + ldProject.linkType = ELINK_DYNAMIC_LIBRARY; + szOutputProject = linker->Link(&ldProject); filesystem2->MakeDirectory(CUtlString("%s/bin",szOutputDir.GetString())); - filesystem2->CopyFile(CUtlString("%s/bin", szOutputDir.GetString()), outputProject); - } else { - tier0_lib = outputProject; + filesystem2->CopyFile(CUtlString("%s/bin", szOutputDir.GetString()), szOutputProject); + + ldProject.linkType = ELINK_STATIC_LIBRARY; + szOutputProject = linker->Link(&ldProject); + tier0_lib = szOutputProject; } return 0; diff --git a/tier0/platform.cpp b/tier0/platform.cpp index 7530854..823946f 100644 --- a/tier0/platform.cpp +++ b/tier0/platform.cpp @@ -117,6 +117,10 @@ PLATFORM_INTERFACE char *Plat_GetExtension( const char *szPath ) } return last+1; } +PLATFORM_INTERFACE void Plat_MakeDir( const char *szPath, int iPermissions ) +{ + mkdir(szPath, ACCESSPERMS); +} PLATFORM_INTERFACE void Plat_Backtrace( void ) { @@ -196,6 +200,45 @@ PLATFORM_INTERFACE void *Plat_GetProc( void *lib, const char *psz ) return (void*)GetProcAddress((HMODULE)lib, psz); #endif } + +PLATFORM_INTERFACE void Plat_SetEnv( const char *szVar, const char *psz ) +{ + setenv(szVar, psz, true); +} + +PLATFORM_INTERFACE const char *Plat_GetEnv( const char *szVar ) +{ + return getenv(szVar); +} + + +PLATFORM_INTERFACE void Plat_SetWorkingDir( const char *psz ) +{ + +} + +PLATFORM_INTERFACE const char *Plat_GetWorkingDir( void ) +{ + +} + +#ifndef MAX_PATH +#define MAX_PATH 4096 +#endif + +static char s_szExecutablePath[MAX_PATH]; +#ifdef __linux__ +static ssize_t s_iExecutablePathSize = readlink("/proc/self/exe", s_szExecutablePath, MAX_PATH); +#endif + +PLATFORM_INTERFACE const char *Plat_GetExecutablePath( void ) +{ + return s_szExecutablePath; +} +PLATFORM_INTERFACE const char *Plat_GetParentDir( const char *psz ) +{ +} + PLATFORM_INTERFACE void Plat_UnloadLibrary( void *lib ) { #ifdef __linux__ diff --git a/tier1/__build.cpp b/tier1/__build.cpp index 583dcd3..14422e5 100644 --- a/tier1/__build.cpp +++ b/tier1/__build.cpp @@ -6,6 +6,7 @@ CUtlVector tier1_CompiledFiles = { "tier1/interface.cpp", + "tier1/appinit.cpp", "tier1/commandline.cpp", "tier1/utlbuffer.cpp", "tier1/utlmap.cpp", diff --git a/tier1/appinit.cpp b/tier1/appinit.cpp new file mode 100644 index 0000000..805aa0a --- /dev/null +++ b/tier1/appinit.cpp @@ -0,0 +1,13 @@ +#include "tier1/appinit.h" +#include "tier1/utlstring.h" +#include "tier0/platform.h" + +void AppInitializePath() +{ + const char *szPath = Plat_GetExecutablePath(); + CUtlString szEnv = Plat_GetEnv("PATH"); + printf("%s\n",szEnv.GetString()); + szEnv.AppendTail(":"); + szEnv.AppendTail(szPath); + Plat_SetEnv("PATH", szEnv); +} diff --git a/tier1/interface.cpp b/tier1/interface.cpp index 199f921..21e0c2b 100644 --- a/tier1/interface.cpp +++ b/tier1/interface.cpp @@ -27,3 +27,8 @@ void *CreateInterface( const char *szName, int *pReturnCode ) *pReturnCode = 1; return 0; } + +CreateInterfaceFn Plat_GetInterfaceFactory( void *lib ) +{ + return (CreateInterfaceFn)Plat_GetProc(lib, "CreateInterface"); +} diff --git a/tier1/utlstring.cpp b/tier1/utlstring.cpp index 7323533..25f1991 100644 --- a/tier1/utlstring.cpp +++ b/tier1/utlstring.cpp @@ -62,16 +62,83 @@ void CUtlString::AppendAt( size_t nPosition, const char *psz ) void CUtlString::RemoveTail( size_t nCount ) { - + m_data.RemoveTail(nCount); + m_data[m_data.GetSize()-1] = 0; } void CUtlString::RemoveHead( size_t nCount ) { - + m_data.RemoveHead(nCount); } void CUtlString::RemoveAt( size_t nPosition, size_t nCount ) { } +CUtlString CUtlString::GetFileName() +{ + CUtlString szFileName = GetString(); + + char *pLast = &m_data[GetLenght()-1]; + while (pLast != m_data.GetData()) + { + if (*pLast=='/') + break; + pLast--; + } + + return pLast; +} +CUtlString CUtlString::GetDirectory() +{ + if (GetLenght() == 0) + return NULL; + size_t iNumDeleted = 0; + char *pLast = &m_data[GetLenght()-1]; + CUtlString szDirectory = GetString(); + while (pLast != m_data.GetData()) + { + if (*pLast=='/') + { + iNumDeleted++; + break; + } + pLast--; + iNumDeleted++; + } + + szDirectory.RemoveTail(iNumDeleted); + + return szDirectory; +} +CUtlString CUtlString::RemoveHeadFile() +{ + size_t iLenght = GetLenght(); + size_t iNumDeleted = 0; + char *pc = GetString(); + CUtlString szDirectory = pc; + + if (GetLenght() == 0) + return NULL; + while ( iNumDeleted < iLenght ) + { + if (*pc == '/') + goto remove_slashes; + pc++; + iNumDeleted++; + } + return NULL; +remove_slashes: + while ( iNumDeleted < iLenght ) + { + if (*pc != '/') + { + szDirectory.RemoveHead(iNumDeleted); + return szDirectory; + } + pc++; + iNumDeleted++; + } + return NULL; +} char *CUtlString::GetString( void ) { diff --git a/tier2/filesystem.cpp b/tier2/filesystem.cpp index 8694cc5..e31c151 100644 --- a/tier2/filesystem.cpp +++ b/tier2/filesystem.cpp @@ -94,6 +94,12 @@ public: return buffer; } + virtual const char *ReadString( IFileHandle *pFile ) override { + char *szString = (char*)V_malloc(Size(pFile)+1); + Read(pFile, szString, Size(pFile)); + szString[Size(pFile)] = 0; + return szString; + }; }; diff --git a/tier2/filesystem_libc.cpp b/tier2/filesystem_libc.cpp index 11dd076..9ef0282 100644 --- a/tier2/filesystem_libc.cpp +++ b/tier2/filesystem_libc.cpp @@ -1,6 +1,7 @@ #include "tier2/ifilesystem.h" #include "tier1/interface.h" #include "tier0/lib.h" +#include "errno.h" class CLIBCFileHandle : public IFileHandle { @@ -29,6 +30,9 @@ public: case FILEMODE_READ: szOperation = "rb"; break; + case FILEMODE_WRITE: + szOperation = "wb"; + break; default: V_printf("Operation is not supported\n"); break; @@ -36,7 +40,10 @@ public: pFile = V_fopen(szFileName, szOperation); if (!pFile) + { + Plat_FatalErrorFunc("Failed to open %s: %s\n",strerror(errno)); return NULL; + } pHandle = new CLIBCFileHandle; pHandle->m_pFileSystem = this; @@ -48,7 +55,10 @@ public: } virtual size_t Write( IFileHandle *pFile, const void *pData, size_t nDataSize ) override { - return 0; + CLIBCFileHandle *pHandle = (CLIBCFileHandle*)pFile; + if (!pHandle) + return 0; + return V_fwrite( pData, 1, nDataSize, pHandle->m_pFile); } virtual size_t Read( IFileHandle *pFile, void *pData, size_t nDataSize ) override { @@ -109,6 +119,7 @@ public: } virtual CUtlBuffer Read( IFileHandle *pFile ) override { return NULL; }; + virtual const char *ReadString( IFileHandle *pFile ) override { return NULL; }; }; EXPOSE_FILESYSTEM(CLIBCFileSystem, "sysfs");