diff --git a/TombEngine/Renderer/Renderer.cpp b/TombEngine/Renderer/Renderer.cpp index ae5002354..9c5dd75e9 100644 --- a/TombEngine/Renderer/Renderer.cpp +++ b/TombEngine/Renderer/Renderer.cpp @@ -61,6 +61,18 @@ namespace TEN::Renderer _isLocked = true; } + void Renderer::ReloadShaders() + { + try + { + _shaderManager.LoadAllShaders(_screenWidth, _screenHeight); + } + catch (const std::exception& e) + { + TENLog("An exception occured during shader reload: " + std::string(e.what()), LogLevel::Error); + } + } + int Renderer::Synchronize() { // Sync the renderer diff --git a/TombEngine/Renderer/Renderer.h b/TombEngine/Renderer/Renderer.h index 0734448ad..123e579ad 100644 --- a/TombEngine/Renderer/Renderer.h +++ b/TombEngine/Renderer/Renderer.h @@ -53,6 +53,7 @@ #include "Renderer/Graphics/Texture2DArray.h" #include "Renderer/Graphics/VertexBuffer.h" #include "Renderer/Graphics/Vertices/PostProcessVertex.h" +#include "Renderer/ShaderManager/ShaderManager.h" #include "Renderer/Structures/RendererItem.h" #include "Renderer/Structures/RendererEffect.h" #include "Renderer/Structures/RendererLine3D.h" @@ -65,7 +66,6 @@ #include "Renderer/Structures/RendererRoomAmbientMap.h" #include "Renderer/Structures/RendererObject.h" #include "Renderer/Structures/RendererStar.h" -#include "Structures/RendererShader.h" enum GAME_OBJECT_ID : short; enum class SphereSpaceType; @@ -81,6 +81,7 @@ namespace TEN::Renderer using namespace TEN::Renderer::ConstantBuffers; using namespace TEN::Renderer::Graphics; using namespace TEN::Renderer::Structures; + using namespace TEN::Renderer::Utils; using namespace DirectX::SimpleMath; using TexturePair = std::tuple; @@ -123,34 +124,6 @@ namespace TEN::Renderer RenderTarget2D _tempRoomAmbientRenderTarget4; Texture2DArray _shadowMap; - // Shaders - - RendererShader _sRooms; - RendererShader _sRoomsAnimated; - RendererShader _sRoomsTransparent; - RendererShader _sRoomAmbient; - RendererShader _sRoomAmbientSky; - RendererShader _sItems; - RendererShader _sStatics; - RendererShader _sInstancedStatics; - RendererShader _sSprites; - RendererShader _sInstancedSprites; - RendererShader _sSky; - RendererShader _sSolid; - RendererShader _sInventory; - RendererShader _sFullScreenQuad; - RendererShader _sShadowMap; - RendererShader _sHUD; - RendererShader _sHUDColor; - RendererShader _sHUDTexture; - RendererShader _sHUDBarColor; - RendererShader _sGBuffer; - RendererShader _sGBufferRooms; - RendererShader _sGBufferRoomsAnimated; - RendererShader _sGBufferItems; - RendererShader _sGBufferStatics; - RendererShader _sGBufferInstancedStatics; - // Constant buffers RenderView _gameCamera; @@ -341,14 +314,6 @@ namespace TEN::Renderer RenderTarget2D _SMAAEdgesRenderTarget; RenderTarget2D _SMAABlendRenderTarget; - RendererShader _sSMAAEdgeDetection; - RendererShader _sSMAALumaEdgeDetection; - RendererShader _sSMAAColorEdgeDetection; - RendererShader _sSMAADepthEdgeDetection; - RendererShader _sSMAABlendingWeightCalculation; - RendererShader _sSMAANeighborhoodBlending; - RendererShader _sFXAA; - // Post-process PostProcessMode _postProcessMode = PostProcessMode::None; @@ -357,12 +322,6 @@ namespace TEN::Renderer VertexBuffer _fullscreenTriangleVertexBuffer; ComPtr _fullscreenTriangleInputLayout = nullptr; - RendererShader _sPostProcess; - RendererShader _sPostProcessMonochrome; - RendererShader _sPostProcessNegative; - RendererShader _sPostProcessExclusion; - RendererShader _sPostProcessFinalPass; - RendererShader _sPostProcessLensFlare; bool _doingFullscreenPass = false; @@ -373,9 +332,6 @@ namespace TEN::Renderer RenderTarget2D _SSAOBlurredRenderTarget; std::vector _SSAOKernel; - RendererShader _sSSAO; - RendererShader _sSSAOBlur; - // New ambient light techinque RenderTarget2D _roomAmbientMapFront; @@ -398,10 +354,9 @@ namespace TEN::Renderer float _interpolationFactor = 0.0f; bool _graphicsSettingsChanged = false; - // Private functions + // Shader manager. - RendererShader CompileOrLoadShader(const std::string& fileName, const std::string& funcName, ShaderType type, const D3D_SHADER_MACRO* defines = nullptr); - void BindShader(const RendererShader& shader); + ShaderManager _shaderManager; void ApplySMAA(RenderTarget2D* renderTarget, RenderView& view); void ApplyFXAA(RenderTarget2D* renderTarget, RenderView& view); @@ -643,6 +598,7 @@ namespace TEN::Renderer void DrawBar(float percent, const RendererHudBar& bar, GAME_OBJECT_ID textureSlot, int frame, bool poison); void Create(); void Initialize(int w, int h, bool windowed, HWND handle); + void ReloadShaders(); void Render(float interpFactor); void RenderTitle(float interpFactor); void Lock(); diff --git a/TombEngine/Renderer/RendererAntialiasing.cpp b/TombEngine/Renderer/RendererAntialiasing.cpp index b78fd9b1b..5395c690d 100644 --- a/TombEngine/Renderer/RendererAntialiasing.cpp +++ b/TombEngine/Renderer/RendererAntialiasing.cpp @@ -14,7 +14,7 @@ namespace TEN::Renderer ResetScissor(); // Common vertex shader to all fullscreen effects - BindShader(_sPostProcess); + _shaderManager.Bind(Shader::PostProcess); // We draw a fullscreen triangle _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); @@ -40,8 +40,8 @@ namespace TEN::Renderer SetCullMode(CullMode::CounterClockwise); _context->OMSetRenderTargets(1, _SMAAEdgesRenderTarget.RenderTargetView.GetAddressOf(), nullptr); - BindShader(_sSMAAEdgeDetection); - BindShader(_sSMAAColorEdgeDetection); + _shaderManager.Bind(Shader::SMAAEdgeDetection); + _shaderManager.Bind(Shader::SMAAColorEdgeDetection); _stSMAABuffer.BlendFactor = 1.0f; _cbSMAABuffer.UpdateData(_stSMAABuffer, _context.Get()); @@ -59,7 +59,7 @@ namespace TEN::Renderer // 2) Blend weights calculation. _context->OMSetRenderTargets(1, _SMAABlendRenderTarget.RenderTargetView.GetAddressOf(), nullptr); - BindShader(_sSMAABlendingWeightCalculation); + _shaderManager.Bind(Shader::SMAABlendingWeightCalculation); _stSMAABuffer.SubsampleIndices = Vector4::Zero; _cbSMAABuffer.UpdateData(_stSMAABuffer, _context.Get()); @@ -76,7 +76,7 @@ namespace TEN::Renderer // 3) Neighborhood blending. _context->OMSetRenderTargets(1, renderTarget->RenderTargetView.GetAddressOf(), nullptr); - BindShader(_sSMAANeighborhoodBlending); + _shaderManager.Bind(Shader::SMAANeighborhoodBlending); BindRenderTargetAsTexture(static_cast(0), &_SMAASceneRenderTarget, SamplerStateRegister::LinearClamp); BindRenderTargetAsTexture(static_cast(1), &_SMAASceneSRGBRenderTarget, SamplerStateRegister::LinearClamp); @@ -100,7 +100,7 @@ namespace TEN::Renderer ResetScissor(); // Common vertex shader to all fullscreen effects - BindShader(_sPostProcess); + _shaderManager.Bind(Shader::PostProcess); // We draw a fullscreen triangle _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); @@ -123,7 +123,7 @@ namespace TEN::Renderer _context->ClearRenderTargetView(renderTarget->RenderTargetView.Get(), Colors::Black); _context->OMSetRenderTargets(1, renderTarget->RenderTargetView.GetAddressOf(), nullptr); - BindShader(_sFXAA); + _shaderManager.Bind(Shader::FXAA); _stPostProcessBuffer.ViewportWidth = _screenWidth; _stPostProcessBuffer.ViewportHeight = _screenHeight; diff --git a/TombEngine/Renderer/RendererDraw.cpp b/TombEngine/Renderer/RendererDraw.cpp index 55b536b4d..1b3d12275 100644 --- a/TombEngine/Renderer/RendererDraw.cpp +++ b/TombEngine/Renderer/RendererDraw.cpp @@ -167,7 +167,7 @@ namespace TEN::Renderer UINT offset = 0; // Set shaders - BindShader(_sShadowMap); + _shaderManager.Bind(Shader::ShadowMap); _context->IASetVertexBuffers(0, 1, _moveablesVertexBuffer.Buffer.GetAddressOf(), &stride, &offset); _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); @@ -284,7 +284,7 @@ namespace TEN::Renderer { auto& moveableObject = *_moveableObjects[objectID]; - BindShader(_sInstancedStatics); + _shaderManager.Bind(Shader::InstancedStatics); unsigned int stride = sizeof(Vertex); unsigned int offset = 0; @@ -361,7 +361,7 @@ namespace TEN::Renderer SetDepthState(DepthState::Read); SetCullMode(CullMode::None); - BindShader(_sSolid); + _shaderManager.Bind(Shader::Solid); auto worldMatrix = Matrix::CreateOrthographicOffCenter(0, _screenWidth, _screenHeight, 0, _viewport.MinDepth, _viewport.MaxDepth); _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); @@ -531,12 +531,12 @@ namespace TEN::Renderer { if (rendererPass == RendererPass::GBuffer) { - BindShader(_sGBuffer); - BindShader(_sGBufferStatics); + _shaderManager.Bind(Shader::GBuffer); + _shaderManager.Bind(Shader::GBufferStatics); } else { - BindShader(_sStatics); + _shaderManager.Bind(Shader::Statics); } UINT stride = sizeof(Vertex); @@ -656,12 +656,12 @@ namespace TEN::Renderer { if (rendererPass == RendererPass::GBuffer) { - BindShader(_sGBuffer); - BindShader(_sGBufferStatics); + _shaderManager.Bind(Shader::GBuffer); + _shaderManager.Bind(Shader::GBufferStatics); } else { - BindShader(_sStatics); + _shaderManager.Bind(Shader::Statics); } unsigned int stride = sizeof(Vertex); @@ -792,12 +792,12 @@ namespace TEN::Renderer { if (rendererPass == RendererPass::GBuffer) { - BindShader(_sGBuffer); - BindShader(_sGBufferInstancedStatics); + _shaderManager.Bind(Shader::GBuffer); + _shaderManager.Bind(Shader::GBufferInstancedStatics); } else { - BindShader(_sInstancedStatics); + _shaderManager.Bind(Shader::InstancedStatics); } unsigned int stride = sizeof(Vertex); @@ -919,12 +919,12 @@ namespace TEN::Renderer { if (rendererPass == RendererPass::GBuffer) { - BindShader(_sGBuffer); - BindShader(_sGBufferInstancedStatics); + _shaderManager.Bind(Shader::GBuffer); + _shaderManager.Bind(Shader::GBufferInstancedStatics); } else { - BindShader(_sInstancedStatics); + _shaderManager.Bind(Shader::InstancedStatics); } unsigned int stride = sizeof(Vertex); @@ -1026,12 +1026,12 @@ namespace TEN::Renderer { if (rendererPass == RendererPass::GBuffer) { - BindShader(_sGBuffer); - BindShader(_sGBufferStatics); + _shaderManager.Bind(Shader::GBuffer); + _shaderManager.Bind(Shader::GBufferStatics); } else { - BindShader(_sStatics); + _shaderManager.Bind(Shader::Statics); } unsigned int stride = sizeof(Vertex); @@ -1089,7 +1089,7 @@ namespace TEN::Renderer SetBlendMode(BlendMode::Additive); SetCullMode(CullMode::None); - BindShader(_sSolid); + _shaderManager.Bind(Shader::Solid); _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); @@ -1122,7 +1122,7 @@ namespace TEN::Renderer SetBlendMode(BlendMode::Additive); SetCullMode(CullMode::None); - BindShader(_sSolid); + _shaderManager.Bind(Shader::Solid); _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _context->IASetInputLayout(_inputLayout.Get()); @@ -1926,7 +1926,7 @@ namespace TEN::Renderer SetBlendMode(BlendMode::Opaque); SetCullMode(CullMode::CounterClockwise); - BindShader(_sRoomAmbient); + _shaderManager.Bind(Shader::RoomAmbient); // Bind and clear render target _context->ClearRenderTargetView(renderTarget->RenderTargetView.Get(), Colors::Black); @@ -1976,7 +1976,7 @@ namespace TEN::Renderer if (levelPtr->Horizon) { - BindShader(_sRoomAmbientSky); + _shaderManager.Bind(Shader::RoomAmbientSky); if (Lara.Control.Look.OpticRange != 0) AlterFOV(ANGLE(DEFAULT_FOV) - Lara.Control.Look.OpticRange, false); @@ -2058,7 +2058,7 @@ namespace TEN::Renderer _context->ClearDepthStencilView(renderTarget->DepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); } - BindShader(_sRoomAmbient); + _shaderManager.Bind(Shader::RoomAmbient); // Draw rooms UINT stride = sizeof(Vertex); @@ -2264,12 +2264,12 @@ namespace TEN::Renderer // Set shaders. if (rendererPass == RendererPass::GBuffer) { - BindShader(_sGBuffer); - BindShader(_sGBufferItems); + _shaderManager.Bind(Shader::GBuffer); + _shaderManager.Bind(Shader::GBufferItems); } else { - BindShader(_sItems); + _shaderManager.Bind(Shader::Items); } BindRenderTargetAsTexture(TextureRegister::SSAO, &_SSAOBlurredRenderTarget, SamplerStateRegister::PointWrap); @@ -2406,12 +2406,12 @@ namespace TEN::Renderer #ifdef DISABLE_INSTANCING if (rendererPass == RendererPass::GBuffer) { - BindShader(_sGBuffer); - BindShader(_sGBufferStatics); + _shaderManager.Bind(Shader::GBuffer); + _shaderManager.Bind(Shader::GBufferStatics); } else { - BindShader(_sStatics); + _shaderManager.Bind(Shader::Statics); } // Bind vertex and index buffer @@ -2487,12 +2487,12 @@ namespace TEN::Renderer #else if (rendererPass == RendererPass::GBuffer) { - BindShader(_sGBuffer); - BindShader(_sGBufferInstancedStatics); + _shaderManager.Bind(Shader::GBuffer); + _shaderManager.Bind(Shader::GBufferInstancedStatics); } else { - BindShader(_sInstancedStatics); + _shaderManager.Bind(Shader::InstancedStatics); } // Bind vertex and index buffer @@ -2682,11 +2682,11 @@ namespace TEN::Renderer { if (rendererPass == RendererPass::GBuffer) { - BindShader(_sGBuffer); + _shaderManager.Bind(Shader::GBuffer); } else { - BindShader(_sRooms); + _shaderManager.Bind(Shader::Rooms); } UINT stride = sizeof(Vertex); @@ -2750,11 +2750,11 @@ namespace TEN::Renderer { if (rendererPass != RendererPass::GBuffer) { - if (animated == 0) BindShader(_sRooms); else BindShader(_sRoomsAnimated); + if (animated == 0) _shaderManager.Bind(Shader::Rooms); else _shaderManager.Bind(Shader::RoomsAnimated); } else { - if (animated == 0) BindShader(_sGBufferRooms); else BindShader(_sGBufferRoomsAnimated); + if (animated == 0) _shaderManager.Bind(Shader::GBufferRooms); else _shaderManager.Bind(Shader::GBufferRoomsAnimated); } for (const auto& bucket : room.Buckets) @@ -2853,7 +2853,7 @@ namespace TEN::Renderer // Draw sky. auto rotation = Matrix::CreateRotationX(PI); - BindShader(_sSky); + _shaderManager.Bind(Shader::Sky); BindTexture(TextureRegister::ColorMap, &_skyTexture, SamplerStateRegister::AnisotropicClamp); _context->IASetVertexBuffers(0, 1, _skyVertexBuffer.Buffer.GetAddressOf(), &stride, &offset); @@ -2894,7 +2894,7 @@ namespace TEN::Renderer _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - BindShader(_sInstancedSprites); + _shaderManager.Bind(Shader::InstancedSprites); // Set up vertex buffer and parameters. UINT stride = sizeof(Vertex); @@ -3033,7 +3033,7 @@ namespace TEN::Renderer _context->IASetVertexBuffers(0, 1, _moveablesVertexBuffer.Buffer.GetAddressOf(), &stride, &offset); _context->IASetIndexBuffer(_moveablesIndexBuffer.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0); - BindShader(_sSky); + _shaderManager.Bind(Shader::Sky); auto& moveableObj = *_moveableObjects[ID_HORIZON]; @@ -3077,7 +3077,7 @@ namespace TEN::Renderer _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - BindShader(_sInstancedSprites); + _shaderManager.Bind(Shader::InstancedSprites); // Set up vertex buffer and parameters. unsigned int stride = sizeof(Vertex); @@ -3504,7 +3504,7 @@ namespace TEN::Renderer ROOM_INFO* nativeRoom = &g_Level.Rooms[objectInfo->Room->RoomNumber]; - BindShader(_sRooms); + _shaderManager.Bind(Shader::Rooms); UINT stride = sizeof(Vertex); UINT offset = 0; @@ -3521,7 +3521,7 @@ namespace TEN::Renderer SetScissor(objectInfo->Room->ClipBounds); if (objectInfo->Bucket->Animated != 0) - BindShader(_sRoomsAnimated); + _shaderManager.Bind(Shader::RoomsAnimated); SetBlendMode(objectInfo->Bucket->BlendMode); SetAlphaTest(AlphaTestMode::None, ALPHA_TEST_THRESHOLD); @@ -3587,7 +3587,7 @@ namespace TEN::Renderer SetBlendMode(objectInfo->Bucket->BlendMode); SetAlphaTest(AlphaTestMode::None, ALPHA_TEST_THRESHOLD); - BindShader(_sItems); + _shaderManager.Bind(Shader::Items); // Bind main item properties. Matrix world = objectInfo->Item->InterpolatedWorld; @@ -3627,7 +3627,7 @@ namespace TEN::Renderer _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _context->IASetInputLayout(_inputLayout.Get()); - BindShader(_sStatics); + _shaderManager.Bind(Shader::Statics); Matrix world = objectInfo->Static->World; _stStatic.World = world; @@ -3665,7 +3665,7 @@ namespace TEN::Renderer _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _context->IASetInputLayout(_inputLayout.Get()); - BindShader(_sStatics); + _shaderManager.Bind(Shader::Statics); Matrix world = objectInfo->World; _stStatic.World = world; @@ -3704,10 +3704,10 @@ namespace TEN::Renderer SetDepthState(DepthState::Write); // Common vertex shader to all full screen effects - BindShader(_sPostProcess); + _shaderManager.Bind(Shader::PostProcess); // SSAO pixel shader - BindShader(_sSSAO); + _shaderManager.Bind(Shader::SSAO); _context->ClearRenderTargetView(_SSAORenderTarget.RenderTargetView.Get(), Colors::White); _context->OMSetRenderTargets(1, _SSAORenderTarget.RenderTargetView.GetAddressOf(), nullptr); @@ -3751,7 +3751,7 @@ namespace TEN::Renderer DrawTriangles(3, 0); // Blur step - BindShader(_sSSAOBlur); + _shaderManager.Bind(Shader::SSAOBlur); _context->ClearRenderTargetView(_SSAOBlurredRenderTarget.RenderTargetView.Get(), Colors::Black); _context->OMSetRenderTargets(1, _SSAOBlurredRenderTarget.RenderTargetView.GetAddressOf(), nullptr); diff --git a/TombEngine/Renderer/RendererDraw2D.cpp b/TombEngine/Renderer/RendererDraw2D.cpp index 698b9dea9..065c109a0 100644 --- a/TombEngine/Renderer/RendererDraw2D.cpp +++ b/TombEngine/Renderer/RendererDraw2D.cpp @@ -132,8 +132,8 @@ namespace TEN::Renderer _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _context->IASetIndexBuffer(bar.IndexBufferBorder.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0); - BindShader(_sHUD); - BindShader(_sHUDTexture); + _shaderManager.Bind(Shader::HUD); + _shaderManager.Bind(Shader::HUDTexture); SetBlendMode(BlendMode::Opaque); SetDepthState(DepthState::None); @@ -161,8 +161,8 @@ namespace TEN::Renderer _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _context->IASetIndexBuffer(bar.InnerIndexBuffer.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0); - BindShader(_sHUD); - BindShader(_sHUDBarColor); + _shaderManager.Bind(Shader::HUD); + _shaderManager.Bind(Shader::HUDBarColor); _stHUDBar.Percent = percent; _stHUDBar.Poisoned = isPoisoned; @@ -195,8 +195,8 @@ namespace TEN::Renderer _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _context->IASetIndexBuffer(g_LoadingBar->IndexBufferBorder.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0); - BindShader(_sHUD); - BindShader(_sHUDTexture); + _shaderManager.Bind(Shader::HUD); + _shaderManager.Bind(Shader::HUDTexture); SetBlendMode(BlendMode::Opaque); SetDepthState(DepthState::None); @@ -220,8 +220,8 @@ namespace TEN::Renderer _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _context->IASetIndexBuffer(g_LoadingBar->InnerIndexBuffer.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0); - BindShader(_sHUD); - BindShader(_sHUDBarColor); + _shaderManager.Bind(Shader::HUD); + _shaderManager.Bind(Shader::HUDBarColor); _stHUDBar.Percent = percentage / 100.0f; _stHUDBar.Poisoned = false; @@ -305,7 +305,7 @@ namespace TEN::Renderer vertices[3].UV.y = 1.0f; vertices[3].Color = Vector4(1.0f, 0.0f, 0.0f, 1.0f); - BindShader(_sFullScreenQuad); + _shaderManager.Bind(Shader::FullScreenQuad); _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _context->IASetInputLayout(_inputLayout.Get()); @@ -341,7 +341,7 @@ namespace TEN::Renderer if (renderView.DisplaySpritesToDraw.empty()) return; - BindShader(_sFullScreenQuad); + _shaderManager.Bind(Shader::FullScreenQuad); _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); _context->IASetInputLayout(_inputLayout.Get()); @@ -463,7 +463,7 @@ namespace TEN::Renderer vertices[3].UV.y = uvEnd.y; vertices[3].Color = colorVec4; - BindShader(_sFullScreenQuad); + _shaderManager.Bind(Shader::FullScreenQuad); _context->PSSetShaderResources(0, 1, &texture); @@ -540,7 +540,7 @@ namespace TEN::Renderer vertices[3].UV.y = uvEnd.y; vertices[3].Color = Vector4(color.x, color.y, color.z, 1.0f); - BindShader(_sFullScreenQuad); + _shaderManager.Bind(Shader::FullScreenQuad); _context->PSSetShaderResources(0, 1, &texture); auto* sampler = _renderStates->AnisotropicClamp(); diff --git a/TombEngine/Renderer/RendererDrawEffect.cpp b/TombEngine/Renderer/RendererDrawEffect.cpp index eed4aecb9..2e49bea8d 100644 --- a/TombEngine/Renderer/RendererDrawEffect.cpp +++ b/TombEngine/Renderer/RendererDrawEffect.cpp @@ -1022,7 +1022,7 @@ namespace TEN::Renderer if (!settings.MuzzleFlash) return false; - BindShader(_sStatics); + _shaderManager.Bind(Shader::Statics); unsigned int stride = sizeof(Vertex); unsigned int offset = 0; @@ -1143,7 +1143,7 @@ namespace TEN::Renderer void Renderer::DrawBaddyGunflashes(RenderView& view) { - BindShader(_sStatics); + _shaderManager.Bind(Shader::Statics); unsigned int stride = sizeof(Vertex); unsigned int offset = 0; @@ -1369,7 +1369,7 @@ namespace TEN::Renderer void Renderer::DrawEffects(RenderView& view, RendererPass rendererPass) { - BindShader(_sStatics); + _shaderManager.Bind(Shader::Statics); unsigned int stride = sizeof(Vertex); unsigned int offset = 0; @@ -1410,7 +1410,7 @@ namespace TEN::Renderer if (activeDebrisExist) { - BindShader(_sStatics); + _shaderManager.Bind(Shader::Statics); SetCullMode(CullMode::None); diff --git a/TombEngine/Renderer/RendererDrawMenu.cpp b/TombEngine/Renderer/RendererDrawMenu.cpp index 168ff42ff..b5cb7612a 100644 --- a/TombEngine/Renderer/RendererDrawMenu.cpp +++ b/TombEngine/Renderer/RendererDrawMenu.cpp @@ -816,7 +816,7 @@ namespace TEN::Renderer _context->IASetIndexBuffer(_moveablesIndexBuffer.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0); // Set shaders. - BindShader(_sInventory); + _shaderManager.Bind(Shader::Inventory); // Set matrices. CCameraMatrixBuffer hudCamera; @@ -1009,7 +1009,7 @@ namespace TEN::Renderer _context->IASetIndexBuffer(_moveablesIndexBuffer.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0); // Set shaders - BindShader(_sInventory); + _shaderManager.Bind(Shader::Inventory); if (CurrentLevel == 0) { diff --git a/TombEngine/Renderer/RendererInit.cpp b/TombEngine/Renderer/RendererInit.cpp index 31b1a8155..9d041e5fb 100644 --- a/TombEngine/Renderer/RendererInit.cpp +++ b/TombEngine/Renderer/RendererInit.cpp @@ -19,11 +19,6 @@ extern GameConfiguration g_Configuration; using namespace TEN::Renderer::Utils; -static std::wstring GetAssetPath(const wchar_t* fileName) -{ - return TEN::Utils::ToWString(g_GameFlow->GetGameDir()) + fileName; -} - namespace TEN::Renderer { void Renderer::Initialize(int w, int h, bool windowed, HWND handle) @@ -36,13 +31,12 @@ namespace TEN::Renderer InitializeScreen(w, h, handle, false); InitializeCommonTextures(); + // Load shaders + _shaderManager.LoadAllShaders(w, h); + // Initialize render states _renderStates = std::make_unique(_device.Get()); - // Load shaders - const D3D_SHADER_MACRO roomDefinesAnimated[] = { "ANIMATED", "", nullptr, nullptr }; - const D3D_SHADER_MACRO roomDefinesShadowMap[] = { "SHADOW_MAP", "", nullptr, nullptr }; - // Initialize input layout using first vertex shader. D3D11_INPUT_ELEMENT_DESC inputLayoutItems[] = { @@ -60,40 +54,8 @@ namespace TEN::Renderer { "HASH", 0, DXGI_FORMAT_R32_SINT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 } }; - _sRooms = CompileOrLoadShader("Rooms", "", ShaderType::PixelAndVertex); - Utils::throwIfFailed(_device->CreateInputLayout(inputLayoutItems, 12, _sRooms.Vertex.Blob->GetBufferPointer(), _sRooms.Vertex.Blob->GetBufferSize(), &_inputLayout)); - - _sRoomsAnimated = CompileOrLoadShader("Rooms", "", ShaderType::Vertex, &roomDefinesAnimated[0]); - _sItems = CompileOrLoadShader("Items", "", ShaderType::PixelAndVertex); - _sStatics = CompileOrLoadShader("Statics", "", ShaderType::PixelAndVertex); - _sSky = CompileOrLoadShader("Sky", "", ShaderType::PixelAndVertex); - _sSprites = CompileOrLoadShader("Sprites", "", ShaderType::PixelAndVertex); - _sSolid = CompileOrLoadShader("Solid", "", ShaderType::PixelAndVertex); - _sInventory = CompileOrLoadShader("Inventory", "", ShaderType::PixelAndVertex); - _sFullScreenQuad = CompileOrLoadShader("FullScreenQuad", "", ShaderType::PixelAndVertex); - _sShadowMap = CompileOrLoadShader("ShadowMap", "", ShaderType::PixelAndVertex, &roomDefinesShadowMap[0]); - _sHUD = CompileOrLoadShader("HUD", "", ShaderType::Vertex); - _sHUDColor = CompileOrLoadShader("HUD", "ColoredHUD", ShaderType::Pixel); - _sHUDTexture = CompileOrLoadShader("HUD", "TexturedHUD", ShaderType::Pixel); - _sHUDBarColor = CompileOrLoadShader("HUD", "TexturedHUDBar", ShaderType::Pixel); - _sInstancedStatics = CompileOrLoadShader("InstancedStatics", "", ShaderType::PixelAndVertex); - _sInstancedSprites = CompileOrLoadShader("InstancedSprites", "", ShaderType::PixelAndVertex); - - _sGBuffer = CompileOrLoadShader("GBuffer", "", ShaderType::Pixel); - _sGBufferRooms = CompileOrLoadShader("GBuffer", "Rooms", ShaderType::Vertex); - _sGBufferRoomsAnimated = CompileOrLoadShader("GBuffer", "Rooms", ShaderType::Vertex, &roomDefinesAnimated[0]); - _sGBufferItems = CompileOrLoadShader("GBuffer", "Items", ShaderType::Vertex); - _sGBufferStatics = CompileOrLoadShader("GBuffer", "Statics", ShaderType::Vertex); - _sGBufferInstancedStatics = CompileOrLoadShader("GBuffer", "InstancedStatics", ShaderType::Vertex); - - _sRoomAmbient = CompileOrLoadShader("RoomAmbient", "", ShaderType::PixelAndVertex); - _sRoomAmbientSky = CompileOrLoadShader("RoomAmbient", "Sky", ShaderType::Vertex); - _sFXAA = CompileOrLoadShader("FXAA", "", ShaderType::Pixel); - _sSSAO = CompileOrLoadShader("SSAO", "", ShaderType::Pixel); - _sSSAOBlur = CompileOrLoadShader("SSAO", "Blur", ShaderType::Pixel); - - const D3D_SHADER_MACRO transparentDefines[] = { "TRANSPARENT", "", nullptr, nullptr }; - _sRoomsTransparent = CompileOrLoadShader("Rooms", "", ShaderType::Pixel, &transparentDefines[0]); + auto& roomShader = _shaderManager.Get(Shader::Rooms); + Utils::throwIfFailed(_device->CreateInputLayout(inputLayoutItems, 12, roomShader.Vertex.Blob->GetBufferPointer(), roomShader.Vertex.Blob->GetBufferSize(), &_inputLayout)); // Initialize constant buffers _cbCameraMatrices = CreateConstantBuffer(); @@ -220,7 +182,7 @@ namespace TEN::Renderer shadowSamplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL; shadowSamplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT; Utils::throwIfFailed(_device->CreateSamplerState(&shadowSamplerDesc, _shadowSampler.GetAddressOf())); - _shadowSampler->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof("ShadowSampler") + 1, "ShadowSampler"); + _shadowSampler->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof("ShadowSampler") - 1, "ShadowSampler"); D3D11_RASTERIZER_DESC rasterizerStateDesc = {}; @@ -285,8 +247,6 @@ namespace TEN::Renderer _fullscreenTriangleVertexBuffer = VertexBuffer(_device.Get(), 3, &vertices[0]); - _sPostProcess = CompileOrLoadShader("PostProcess", "", ShaderType::PixelAndVertex); - D3D11_INPUT_ELEMENT_DESC postProcessInputLayoutItems[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, @@ -294,14 +254,9 @@ namespace TEN::Renderer { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 } }; + auto& ppShader = _shaderManager.Get(Shader::PostProcess); Utils::throwIfFailed(_device->CreateInputLayout(postProcessInputLayoutItems, 3, - _sPostProcess.Vertex.Blob->GetBufferPointer(), _sPostProcess.Vertex.Blob->GetBufferSize(), &_fullscreenTriangleInputLayout)); - - _sPostProcessMonochrome = CompileOrLoadShader("PostProcess", "Monochrome", ShaderType::Pixel); - _sPostProcessNegative = CompileOrLoadShader("PostProcess", "Negative", ShaderType::Pixel); - _sPostProcessExclusion = CompileOrLoadShader("PostProcess", "Exclusion", ShaderType::Pixel); - _sPostProcessFinalPass = CompileOrLoadShader("PostProcess", "FinalPass", ShaderType::Pixel); - _sPostProcessLensFlare = CompileOrLoadShader("PostProcess", "LensFlare", ShaderType::Pixel); + ppShader.Vertex.Blob->GetBufferPointer(), ppShader.Vertex.Blob->GetBufferSize(), &_fullscreenTriangleInputLayout)); } void Renderer::CreateSSAONoiseTexture() @@ -382,8 +337,9 @@ namespace TEN::Renderer void Renderer::InitializeSky() { - Vertex vertices[SKY_VERTICES_COUNT]; - int indices[SKY_INDICES_COUNT]; + std::vector vertices(SKY_VERTICES_COUNT); + std::vector indices(SKY_INDICES_COUNT); + int size = SKY_SIZE; int lastVertex = 0; @@ -452,8 +408,8 @@ namespace TEN::Renderer } } - _skyVertexBuffer = VertexBuffer(_device.Get(), SKY_VERTICES_COUNT, vertices); - _skyIndexBuffer = IndexBuffer(_device.Get(), SKY_INDICES_COUNT, indices); + _skyVertexBuffer = VertexBuffer(_device.Get(), SKY_VERTICES_COUNT, vertices.data()); + _skyIndexBuffer = IndexBuffer(_device.Get(), SKY_INDICES_COUNT, indices.data()); } void Renderer::InitializeScreen(int w, int h, HWND handle, bool reset) @@ -561,40 +517,6 @@ namespace TEN::Renderer _SMAASceneSRGBRenderTarget = RenderTarget2D(_device.Get(), &_SMAASceneRenderTarget, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB); _SMAAEdgesRenderTarget = RenderTarget2D(_device.Get(), w, h, DXGI_FORMAT_R8G8_UNORM, false, DXGI_FORMAT_UNKNOWN); _SMAABlendRenderTarget = RenderTarget2D(_device.Get(), w, h, DXGI_FORMAT_R8G8B8A8_UNORM, false, DXGI_FORMAT_UNKNOWN); - - auto string = std::stringstream{}; - auto defines = std::vector{}; - - // Set up pixel size macro. - string << "float4(1.0 / " << w << ", 1.0 / " << h << ", " << w << ", " << h << ")"; - auto pixelSizeText = string.str(); - auto renderTargetMetricsMacro = D3D10_SHADER_MACRO{ "SMAA_RT_METRICS", pixelSizeText.c_str() }; - defines.push_back(renderTargetMetricsMacro); - - if (g_Configuration.AntialiasingMode == AntialiasingMode::Medium) - { - defines.push_back({ "SMAA_PRESET_HIGH", nullptr }); - } - else - { - defines.push_back({ "SMAA_PRESET_ULTRA", nullptr }); - } - - // defines.push_back({ "SMAA_PREDICATION", "1" }); - - // Set up target macro. - auto dx101Macro = D3D10_SHADER_MACRO{ "SMAA_HLSL_4_1", "1" }; - defines.push_back(dx101Macro); - - auto null = D3D10_SHADER_MACRO{ nullptr, nullptr }; - defines.push_back(null); - - _sSMAALumaEdgeDetection = CompileOrLoadShader("SMAA", "LumaEdgeDetection", ShaderType::Pixel, defines.data()); - _sSMAAColorEdgeDetection = CompileOrLoadShader("SMAA", "ColorEdgeDetection", ShaderType::Pixel, defines.data()); - _sSMAADepthEdgeDetection = CompileOrLoadShader("SMAA", "DepthEdgeDetection", ShaderType::Pixel, defines.data()); - _sSMAABlendingWeightCalculation = CompileOrLoadShader("SMAA", "BlendingWeightCalculation", ShaderType::PixelAndVertex, defines.data()); - _sSMAANeighborhoodBlending = CompileOrLoadShader("SMAA", "NeighborhoodBlending", ShaderType::PixelAndVertex, defines.data()); - _sSMAAEdgeDetection = CompileOrLoadShader("SMAA", "EdgeDetection", ShaderType::Vertex, defines.data()); } void Renderer::InitializeCommonTextures() @@ -641,6 +563,9 @@ namespace TEN::Renderer } Utils::throwIfFailed(res); + + // Initialize shader manager + _shaderManager.Initialize(_device, _context); } void Renderer::ToggleFullScreen(bool force) @@ -676,152 +601,4 @@ namespace TEN::Renderer UpdateWindow(WindowsHandle); } - - void Renderer::BindShader(const RendererShader& shader) - { - if (shader.Vertex.Shader != nullptr) _context->VSSetShader(shader.Vertex.Shader.Get(), nullptr, 0); - if (shader.Pixel.Shader != nullptr) _context->PSSetShader(shader.Pixel.Shader.Get(), nullptr, 0); - if (shader.Compute.Shader != nullptr) _context->CSSetShader(shader.Compute.Shader.Get(), nullptr, 0); - } - - RendererShader Renderer::CompileOrLoadShader(const std::string& fileName, const std::string& funcName, ShaderType type, const D3D_SHADER_MACRO* defines) - { - RendererShader result = {}; - - // We need to increment the counter to avoid overwriting compiled shaders with the same source file name. - static int compileCounter = 0; - - // Define paths for native (uncompiled) shaders and compiled shaders. - std::wstring shaderPath = GetAssetPath(L"Shaders\\"); - std::wstring compiledShaderPath = shaderPath + L"Bin\\"; - std::wstring wideFileName = TEN::Utils::ToWString(fileName); - - // Ensure the /Bin subdirectory exists. - std::filesystem::create_directories(compiledShaderPath); - - // Helper function to load or compile a shader. - auto loadOrCompileShader = [this, type, defines, shaderPath, compiledShaderPath] - (const std::wstring& baseFileName, const std::string& shaderType, const std::string& functionName, const char* model, ComPtr& bytecode) - { - // Construct the full paths using GetAssetPath. - auto prefix = ((compileCounter < 10) ? L"0" : L"") + std::to_wstring(compileCounter) + L"_"; - auto csoFileName = compiledShaderPath + prefix + baseFileName + L"." + std::wstring(shaderType.begin(), shaderType.end()) + L".cso"; - auto srcFileName = shaderPath + baseFileName; - - // Try both .hlsl and .fx extensions for the source shader. - auto srcFileNameWithExtension = srcFileName + L".hlsl"; - if (!std::filesystem::exists(srcFileNameWithExtension)) - { - srcFileNameWithExtension = srcFileName + L".fx"; - if (!std::filesystem::exists(srcFileNameWithExtension)) - { - TENLog("Shader source file not found: " + TEN::Utils::ToString(srcFileNameWithExtension), LogLevel::Error); - throw std::runtime_error("Shader source file not found"); - } - } - - // Check modification dates of the source and compiled files. - bool shouldRecompile = false; - if (std::filesystem::exists(csoFileName)) - { - auto csoTime = std::filesystem::last_write_time(csoFileName); - auto srcTime = std::filesystem::last_write_time(srcFileNameWithExtension); - shouldRecompile = srcTime > csoTime; // Recompile if the source is newer. - } - - // Load compiled shader if it exists and is up to date. - if (!shouldRecompile) - { - std::ifstream csoFile(csoFileName, std::ios::binary); - - if (csoFile.is_open()) - { - // Load compiled shader. - csoFile.seekg(0, std::ios::end); - size_t fileSize = csoFile.tellg(); - csoFile.seekg(0, std::ios::beg); - - std::vector buffer(fileSize); - csoFile.read(buffer.data(), fileSize); - csoFile.close(); - - D3DCreateBlob(fileSize, &bytecode); - memcpy(bytecode->GetBufferPointer(), buffer.data(), fileSize); - - return; - } - } - - // Set up compilation flags according to the build configuration. - unsigned int flags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR; - - if constexpr (DebugBuild) - flags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; - else - flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_IEEE_STRICTNESS; - - auto trimmedFileName = std::filesystem::path(srcFileNameWithExtension).filename().string(); - TENLog("Compiling shader: " + trimmedFileName, LogLevel::Info); - - // Compile shader. - ComPtr errors; - HRESULT res = D3DCompileFromFile(srcFileNameWithExtension.c_str(), defines, D3D_COMPILE_STANDARD_FILE_INCLUDE, - (shaderType + functionName).c_str(), model, flags, 0, bytecode.GetAddressOf(), errors.GetAddressOf()); - - if (FAILED(res)) - { - if (errors) - { - auto error = std::string(static_cast(errors->GetBufferPointer())); - TENLog(error, LogLevel::Error); - throw std::runtime_error(error); - } - else - { - TENLog("Error while compiling shader: " + trimmedFileName, LogLevel::Error); - throwIfFailed(res); - } - } - - // Save compiled shader to .cso file. - std::ofstream outCsoFile(csoFileName, std::ios::binary); - if (outCsoFile.is_open()) - { - outCsoFile.write(reinterpret_cast(bytecode->GetBufferPointer()), bytecode->GetBufferSize()); - outCsoFile.close(); - } - }; - - // Load or compile and create pixel shader. - if (type == ShaderType::Pixel || type == ShaderType::PixelAndVertex) - { - loadOrCompileShader(wideFileName, "PS", funcName, "ps_5_0", result.Pixel.Blob); - throwIfFailed(_device->CreatePixelShader(result.Pixel.Blob->GetBufferPointer(), result.Pixel.Blob->GetBufferSize(), - nullptr, result.Pixel.Shader.GetAddressOf() - )); - } - - // Load or compile and create vertex shader. - if (type == ShaderType::Vertex || type == ShaderType::PixelAndVertex) - { - loadOrCompileShader(wideFileName, "VS", funcName, "vs_5_0", result.Vertex.Blob); - throwIfFailed(_device->CreateVertexShader(result.Vertex.Blob->GetBufferPointer(), result.Vertex.Blob->GetBufferSize(), - nullptr, result.Vertex.Shader.GetAddressOf() - )); - } - - // Load or compile and create compute shader. - if (type == ShaderType::Compute) - { - loadOrCompileShader(wideFileName, "CS", funcName, "cs_5_0", result.Compute.Blob); - throwIfFailed(_device->CreateComputeShader(result.Compute.Blob->GetBufferPointer(), result.Compute.Blob->GetBufferSize(), - nullptr, result.Compute.Shader.GetAddressOf() - )); - } - - // Increment the compile counter. - compileCounter++; - - return result; - } } \ No newline at end of file diff --git a/TombEngine/Renderer/RendererPostProcess.cpp b/TombEngine/Renderer/RendererPostProcess.cpp index 2abdceec2..8308186b7 100644 --- a/TombEngine/Renderer/RendererPostProcess.cpp +++ b/TombEngine/Renderer/RendererPostProcess.cpp @@ -42,7 +42,7 @@ namespace TEN::Renderer _cbPostProcessBuffer.UpdateData(_stPostProcessBuffer, _context.Get()); // Common vertex shader to all fullscreen effects. - BindShader(_sPostProcess); + _shaderManager.Bind(Shader::PostProcess); // Draw fullscreen triangle. _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); @@ -71,7 +71,7 @@ namespace TEN::Renderer _context->ClearRenderTargetView(_postProcessRenderTarget[destRenderTarget].RenderTargetView.Get(), clearColor); _context->OMSetRenderTargets(1, _postProcessRenderTarget[destRenderTarget].RenderTargetView.GetAddressOf(), nullptr); - BindShader(_sPostProcessLensFlare); + _shaderManager.Bind(Shader::PostProcessLensFlare); for (int i = 0; i < view.LensFlaresToDraw.size(); i++) { @@ -97,15 +97,15 @@ namespace TEN::Renderer switch (_postProcessMode) { case PostProcessMode::Monochrome: - BindShader(_sPostProcessMonochrome); + _shaderManager.Bind(Shader::PostProcessMonochrome); break; case PostProcessMode::Negative: - BindShader(_sPostProcessNegative); + _shaderManager.Bind(Shader::PostProcessNegative); break; case PostProcessMode::Exclusion: - BindShader(_sPostProcessExclusion); + _shaderManager.Bind(Shader::PostProcessExclusion); break; default: @@ -120,7 +120,7 @@ namespace TEN::Renderer } // Do final pass. - BindShader(_sPostProcessFinalPass); + _shaderManager.Bind(Shader::PostProcessFinalPass); _context->ClearRenderTargetView(renderTarget->RenderTargetView.Get(), Colors::Black); _context->OMSetRenderTargets(1, renderTarget->RenderTargetView.GetAddressOf(), nullptr); @@ -172,7 +172,7 @@ namespace TEN::Renderer ResetScissor(); // Common vertex shader to all fullscreen effects - BindShader(_sPostProcess); + _shaderManager.Bind(Shader::PostProcess); // We draw a fullscreen triangle _context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); diff --git a/TombEngine/Renderer/RendererSprites.cpp b/TombEngine/Renderer/RendererSprites.cpp index a4cc72c7c..a0b5e2624 100644 --- a/TombEngine/Renderer/RendererSprites.cpp +++ b/TombEngine/Renderer/RendererSprites.cpp @@ -279,7 +279,7 @@ namespace TEN::Renderer SetDepthState(DepthState::Read); SetCullMode(CullMode::None); - BindShader(_sInstancedSprites); + _shaderManager.Bind(Shader::InstancedSprites); // Set up vertex buffer and parameters. unsigned int stride = sizeof(Vertex); @@ -340,7 +340,7 @@ namespace TEN::Renderer SetDepthState(DepthState::Read); SetCullMode(CullMode::None); - BindShader(_sSprites); + _shaderManager.Bind(Shader::Sprites); wasGPUSet = true; } @@ -411,7 +411,7 @@ namespace TEN::Renderer SetBlendMode(object->Sprite->BlendMode); SetAlphaTest(AlphaTestMode::GreatherThan, ALPHA_TEST_THRESHOLD); - BindShader(_sInstancedSprites); + _shaderManager.Bind(Shader::InstancedSprites); // Set up vertex buffer and parameters. UINT stride = sizeof(Vertex); @@ -456,7 +456,7 @@ namespace TEN::Renderer SetBlendMode(object->Sprite->BlendMode); SetAlphaTest(AlphaTestMode::GreatherThan, ALPHA_TEST_THRESHOLD); - BindShader(_sSprites); + _shaderManager.Bind(Shader::Sprites); _stSprite.IsSoftParticle = object->Sprite->SoftParticle ? 1 : 0; _stSprite.RenderType = (int)object->Sprite->renderType; @@ -501,7 +501,7 @@ namespace TEN::Renderer UINT stride = sizeof(Vertex); UINT offset = 0; - BindShader(_sSprites); + _shaderManager.Bind(Shader::Sprites); _sortedPolygonsVertexBuffer.Update(_context.Get(), _sortedPolygonsVertices.data(), 0, (int)_sortedPolygonsVertices.size()); diff --git a/TombEngine/Renderer/RendererUtils.cpp b/TombEngine/Renderer/RendererUtils.cpp index ae6b6a030..dc5efe4b1 100644 --- a/TombEngine/Renderer/RendererUtils.cpp +++ b/TombEngine/Renderer/RendererUtils.cpp @@ -8,8 +8,9 @@ #include #include "Renderer/Renderer.h" +#include "Renderer/Structures/RendererShader.h" +#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h" #include "Specific/trutils.h" -#include "Structures/RendererShader.h" namespace TEN::Renderer::Utils { @@ -42,4 +43,9 @@ namespace TEN::Renderer::Utils throw std::runtime_error("An error occured!"); } } + + std::wstring GetAssetPath(const wchar_t* fileName) + { + return TEN::Utils::ToWString(g_GameFlow->GetGameDir()) + fileName; + } } diff --git a/TombEngine/Renderer/RendererUtils.h b/TombEngine/Renderer/RendererUtils.h index 8fc12b203..d9336688c 100644 --- a/TombEngine/Renderer/RendererUtils.h +++ b/TombEngine/Renderer/RendererUtils.h @@ -9,4 +9,6 @@ namespace TEN::Renderer::Utils void throwIfFailed(const HRESULT& res); void throwIfFailed(const HRESULT& res, const std::string& info); void throwIfFailed(const HRESULT& res, const std::wstring& info); + + std::wstring GetAssetPath(const wchar_t* fileName); } diff --git a/TombEngine/Renderer/ShaderManager/ShaderManager.cpp b/TombEngine/Renderer/ShaderManager/ShaderManager.cpp new file mode 100644 index 000000000..498b4cfc1 --- /dev/null +++ b/TombEngine/Renderer/ShaderManager/ShaderManager.cpp @@ -0,0 +1,306 @@ +#include "framework.h" +#include "Renderer/ShaderManager/ShaderManager.h" + +#include +#include +#include + +#include "Renderer/RendererUtils.h" +#include "Specific/configuration.h" +#include "Specific/trutils.h" + +namespace TEN::Renderer::Utils +{ + void ShaderManager::LoadAllShaders(int width, int height) + { + TENLog("Loading shaders...", LogLevel::Info); + + // Unbind any currently bound shader. + Bind(Shader::None); + + // Reset compile counter. + _compileCounter = 0; + + // Generic shaders. + + const D3D_SHADER_MACRO roomDefinesAnimated[] = { "ANIMATED", "", nullptr, nullptr }; + const D3D_SHADER_MACRO roomDefinesShadowMap[] = { "SHADOW_MAP", "", nullptr, nullptr }; + + Load(Shader::Rooms, "Rooms", "", ShaderType::PixelAndVertex); + Load(Shader::RoomsAnimated, "Rooms", "", ShaderType::Vertex, &roomDefinesAnimated[0]); + Load(Shader::Items, "Items", "", ShaderType::PixelAndVertex); + Load(Shader::Statics, "Statics", "", ShaderType::PixelAndVertex); + Load(Shader::Sky, "Sky", "", ShaderType::PixelAndVertex); + Load(Shader::Sprites, "Sprites", "", ShaderType::PixelAndVertex); + Load(Shader::Solid, "Solid", "", ShaderType::PixelAndVertex); + Load(Shader::Inventory, "Inventory", "", ShaderType::PixelAndVertex); + Load(Shader::FullScreenQuad, "FullScreenQuad", "", ShaderType::PixelAndVertex); + Load(Shader::ShadowMap, "ShadowMap", "", ShaderType::PixelAndVertex, roomDefinesShadowMap); + + Load(Shader::HUD, "HUD", "", ShaderType::Vertex); + Load(Shader::HUDColor, "HUD", "ColoredHUD", ShaderType::Pixel); + Load(Shader::HUDTexture, "HUD", "TexturedHUD", ShaderType::Pixel); + Load(Shader::HUDBarColor, "HUD", "TexturedHUDBar", ShaderType::Pixel); + Load(Shader::InstancedStatics, "InstancedStatics", "", ShaderType::PixelAndVertex); + Load(Shader::InstancedSprites, "InstancedSprites", "", ShaderType::PixelAndVertex); + + Load(Shader::GBuffer, "GBuffer", "", ShaderType::Pixel); + Load(Shader::GBufferRooms, "GBuffer", "Rooms", ShaderType::Vertex); + Load(Shader::GBufferRoomsAnimated, "GBuffer", "Rooms", ShaderType::Vertex, roomDefinesAnimated); + Load(Shader::GBufferItems, "GBuffer", "Items", ShaderType::Vertex); + Load(Shader::GBufferStatics, "GBuffer", "Statics", ShaderType::Vertex); + Load(Shader::GBufferInstancedStatics, "GBuffer", "InstancedStatics", ShaderType::Vertex); + + Load(Shader::RoomAmbient, "RoomAmbient", "", ShaderType::PixelAndVertex); + Load(Shader::RoomAmbientSky, "RoomAmbient", "Sky", ShaderType::Vertex); + Load(Shader::FXAA, "FXAA", "", ShaderType::Pixel); + Load(Shader::SSAO, "SSAO", "", ShaderType::Pixel); + Load(Shader::SSAOBlur, "SSAO", "Blur", ShaderType::Pixel); + + const D3D_SHADER_MACRO transparentDefines[] = { "TRANSPARENT", "", nullptr, nullptr }; + Load(Shader::RoomsTransparent, "Rooms", "", ShaderType::Pixel, transparentDefines); + + // Post-process shaders. + + Load(Shader::PostProcess, "PostProcess", "", ShaderType::PixelAndVertex); + + Load(Shader::PostProcessMonochrome, "PostProcess", "Monochrome", ShaderType::Pixel); + Load(Shader::PostProcessNegative, "PostProcess", "Negative", ShaderType::Pixel); + Load(Shader::PostProcessExclusion, "PostProcess", "Exclusion", ShaderType::Pixel); + Load(Shader::PostProcessFinalPass, "PostProcess", "FinalPass", ShaderType::Pixel); + Load(Shader::PostProcessLensFlare, "PostProcess", "LensFlare", ShaderType::Pixel); + + // SMAA shaders. + + auto string = std::stringstream{}; + auto defines = std::vector{}; + + // Set up pixel size macro. + + string << "float4(1.0 / " << width << ", 1.0 / " << height << ", " << width << ", " << height << ")"; + auto pixelSizeText = string.str(); + auto renderTargetMetricsMacro = D3D10_SHADER_MACRO{ "SMAA_RT_METRICS", pixelSizeText.c_str() }; + defines.push_back(renderTargetMetricsMacro); + + if (g_Configuration.AntialiasingMode == AntialiasingMode::Medium) + { + defines.push_back({ "SMAA_PRESET_HIGH", nullptr }); + } + else + { + defines.push_back({ "SMAA_PRESET_ULTRA", nullptr }); + } + + // defines.push_back({ "SMAA_PREDICATION", "1" }); + + // Set up target macro. + auto dx101Macro = D3D10_SHADER_MACRO{ "SMAA_HLSL_4_1", "1" }; + defines.push_back(dx101Macro); + + auto null = D3D10_SHADER_MACRO{ nullptr, nullptr }; + defines.push_back(null); + + Load(Shader::SMAAEdgeDetection, "SMAA", "EdgeDetection", ShaderType::Vertex, defines.data()); + Load(Shader::SMAALumaEdgeDetection, "SMAA", "LumaEdgeDetection", ShaderType::Pixel, defines.data()); + Load(Shader::SMAAColorEdgeDetection, "SMAA", "ColorEdgeDetection", ShaderType::Pixel, defines.data()); + Load(Shader::SMAADepthEdgeDetection, "SMAA", "DepthEdgeDetection", ShaderType::Pixel, defines.data()); + Load(Shader::SMAABlendingWeightCalculation, "SMAA", "BlendingWeightCalculation", ShaderType::PixelAndVertex, defines.data()); + Load(Shader::SMAANeighborhoodBlending, "SMAA", "NeighborhoodBlending", ShaderType::PixelAndVertex, defines.data()); + } + + void ShaderManager::Initialize(ComPtr& device, ComPtr& context) + { + _device = device; + _context = context; + } + + ShaderManager::~ShaderManager() + { + _device = nullptr; + _context = nullptr; + + for (int i = 0; i < (int)Shader::Count; i++) + Destroy((Shader)i); + } + + void ShaderManager::Destroy(Shader shader) + { + auto& shaderData = _shaders[(int)shader]; + + if (shaderData.Vertex.Shader != nullptr) + { + shaderData.Vertex.Shader.Reset(); + shaderData.Vertex.Blob.Reset(); + } + + if (shaderData.Pixel.Shader != nullptr) + { + shaderData.Pixel.Shader.Reset(); + shaderData.Pixel.Blob.Reset(); + } + + if (shaderData.Compute.Shader != nullptr) + { + shaderData.Compute.Shader.Reset(); + shaderData.Compute.Blob.Reset(); + } + } + + RendererShader ShaderManager::LoadOrCompile(const std::string& fileName, const std::string& funcName, ShaderType type, const D3D_SHADER_MACRO* defines) + { + RendererShader result = {}; + + // Define paths for native (uncompiled) shaders and compiled shaders. + std::wstring shaderPath = GetAssetPath(L"Shaders\\"); + std::wstring compiledShaderPath = shaderPath + L"Bin\\"; + std::wstring wideFileName = TEN::Utils::ToWString(fileName); + + // Ensure the /Bin subdirectory exists. + std::filesystem::create_directories(compiledShaderPath); + + // Helper function to load or compile a shader. + auto loadOrCompileShader = [this, type, defines, shaderPath, compiledShaderPath] + (const std::wstring& baseFileName, const std::string& shaderType, const std::string& functionName, const char* model, ComPtr& bytecode) + { + // Construct the full paths using GetAssetPath. + auto prefix = ((_compileCounter < 10) ? L"0" : L"") + std::to_wstring(_compileCounter) + L"_"; + auto csoFileName = compiledShaderPath + prefix + baseFileName + L"." + std::wstring(shaderType.begin(), shaderType.end()) + L".cso"; + auto srcFileName = shaderPath + baseFileName; + + // Try both .hlsl and .fx extensions for the source shader. + auto srcFileNameWithExtension = srcFileName + L".hlsl"; + if (!std::filesystem::exists(srcFileNameWithExtension)) + { + srcFileNameWithExtension = srcFileName + L".fx"; + if (!std::filesystem::exists(srcFileNameWithExtension)) + { + TENLog("Shader source file not found: " + TEN::Utils::ToString(srcFileNameWithExtension), LogLevel::Error); + throw std::runtime_error("Shader source file not found"); + } + } + + // Check modification dates of the source and compiled files. + bool shouldRecompile = true; + if (std::filesystem::exists(csoFileName)) + { + auto csoTime = std::filesystem::last_write_time(csoFileName); + auto srcTime = std::filesystem::last_write_time(srcFileNameWithExtension); + shouldRecompile = srcTime > csoTime; // Recompile if the source is newer. + } + + // Load compiled shader if it exists and is up to date. + if (!shouldRecompile) + { + std::ifstream csoFile(csoFileName, std::ios::binary); + + if (csoFile.is_open()) + { + // Load compiled shader. + csoFile.seekg(0, std::ios::end); + size_t fileSize = csoFile.tellg(); + csoFile.seekg(0, std::ios::beg); + + std::vector buffer(fileSize); + csoFile.read(buffer.data(), fileSize); + csoFile.close(); + + D3DCreateBlob(fileSize, &bytecode); + memcpy(bytecode->GetBufferPointer(), buffer.data(), fileSize); + + return; + } + } + + // Set up compilation flags according to the build configuration. + unsigned int flags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR; + + if constexpr (DebugBuild) + flags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; + else + flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_IEEE_STRICTNESS; + + auto trimmedFileName = std::filesystem::path(srcFileNameWithExtension).filename().string(); + TENLog("Compiling shader: " + trimmedFileName, LogLevel::Info); + + // Compile shader. + ComPtr errors; + HRESULT res = D3DCompileFromFile(srcFileNameWithExtension.c_str(), defines, D3D_COMPILE_STANDARD_FILE_INCLUDE, + (shaderType + functionName).c_str(), model, flags, 0, bytecode.GetAddressOf(), errors.GetAddressOf()); + + if (FAILED(res)) + { + if (errors) + { + auto error = std::string(static_cast(errors->GetBufferPointer())); + TENLog(error, LogLevel::Error); + throw std::runtime_error(error); + } + else + { + TENLog("Error while compiling shader: " + trimmedFileName, LogLevel::Error); + throwIfFailed(res); + } + } + + // Save compiled shader to .cso file. + std::ofstream outCsoFile(csoFileName, std::ios::binary); + if (outCsoFile.is_open()) + { + outCsoFile.write(reinterpret_cast(bytecode->GetBufferPointer()), bytecode->GetBufferSize()); + outCsoFile.close(); + } + }; + + // Load or compile and create pixel shader. + if (type == ShaderType::Pixel || type == ShaderType::PixelAndVertex) + { + loadOrCompileShader(wideFileName, "PS", funcName, "ps_5_0", result.Pixel.Blob); + throwIfFailed(_device->CreatePixelShader(result.Pixel.Blob->GetBufferPointer(), result.Pixel.Blob->GetBufferSize(), + nullptr, result.Pixel.Shader.GetAddressOf() + )); + } + + // Load or compile and create vertex shader. + if (type == ShaderType::Vertex || type == ShaderType::PixelAndVertex) + { + loadOrCompileShader(wideFileName, "VS", funcName, "vs_5_0", result.Vertex.Blob); + throwIfFailed(_device->CreateVertexShader(result.Vertex.Blob->GetBufferPointer(), result.Vertex.Blob->GetBufferSize(), + nullptr, result.Vertex.Shader.GetAddressOf() + )); + } + + // Load or compile and create compute shader. + if (type == ShaderType::Compute) + { + loadOrCompileShader(wideFileName, "CS", funcName, "cs_5_0", result.Compute.Blob); + throwIfFailed(_device->CreateComputeShader(result.Compute.Blob->GetBufferPointer(), result.Compute.Blob->GetBufferSize(), + nullptr, result.Compute.Shader.GetAddressOf() + )); + } + + // Increment the compile counter. + _compileCounter++; + + return result; + } + + void ShaderManager::Load(Shader shader, const std::string& fileName, const std::string& funcName, ShaderType type, const D3D_SHADER_MACRO* defines) + { + Destroy(shader); + _shaders[(int)shader] = LoadOrCompile(fileName, funcName, type, defines); + } + + void ShaderManager::Bind(Shader shader) + { + auto& shaderObj = _shaders[(int)shader]; + + if (shaderObj.Vertex.Shader != nullptr) _context->VSSetShader(shaderObj.Vertex.Shader.Get(), nullptr, 0); + if (shaderObj.Pixel.Shader != nullptr) _context->PSSetShader(shaderObj.Pixel.Shader.Get(), nullptr, 0); + if (shaderObj.Compute.Shader != nullptr) _context->CSSetShader(shaderObj.Compute.Shader.Get(), nullptr, 0); + } + + const RendererShader& ShaderManager::Get(Shader shader) + { + return _shaders[(int)shader]; + } +} \ No newline at end of file diff --git a/TombEngine/Renderer/ShaderManager/ShaderManager.h b/TombEngine/Renderer/ShaderManager/ShaderManager.h new file mode 100644 index 000000000..ffd64c645 --- /dev/null +++ b/TombEngine/Renderer/ShaderManager/ShaderManager.h @@ -0,0 +1,84 @@ +#pragma once +#include "framework.h" +#include "Renderer/Structures/RendererShader.h" + +namespace TEN::Renderer::Utils +{ + using namespace TEN::Renderer::Structures; + + enum class Shader + { + None, + Rooms, + RoomsAnimated, + RoomsTransparent, + RoomAmbient, + RoomAmbientSky, + Items, + Statics, + InstancedStatics, + Sprites, + InstancedSprites, + Sky, + Solid, + Inventory, + FullScreenQuad, + ShadowMap, + + HUD, + HUDColor, + HUDTexture, + HUDBarColor, + + GBuffer, + GBufferRooms, + GBufferRoomsAnimated, + GBufferItems, + GBufferStatics, + GBufferInstancedStatics, + + SMAAEdgeDetection, + SMAALumaEdgeDetection, + SMAAColorEdgeDetection, + SMAADepthEdgeDetection, + SMAABlendingWeightCalculation, + SMAANeighborhoodBlending, + FXAA, + + PostProcess, + PostProcessMonochrome, + PostProcessNegative, + PostProcessExclusion, + PostProcessFinalPass, + PostProcessLensFlare, + + SSAO, + SSAOBlur, + + Count + }; + + class ShaderManager + { + private: + ComPtr _device = nullptr; + ComPtr _context = nullptr; + + int _compileCounter = 0; + std::array _shaders = {}; + + RendererShader LoadOrCompile(const std::string& fileName, const std::string& funcName, ShaderType type, const D3D_SHADER_MACRO* defines); + void Load(Shader shader, const std::string& fileName, const std::string& funcName, ShaderType type, const D3D_SHADER_MACRO* defines = nullptr); + void Destroy(Shader shader); + + public: + ShaderManager() = default; + ~ShaderManager(); + + void Initialize(ComPtr& device, ComPtr& context); + void LoadAllShaders(int width, int height); + + void Bind(Shader shader); + const RendererShader& Get(Shader shader); + }; +} \ No newline at end of file diff --git a/TombEngine/Specific/IO/Streams.h b/TombEngine/Specific/IO/Streams.h index 04c206dc6..93cce4c3b 100644 --- a/TombEngine/Specific/IO/Streams.h +++ b/TombEngine/Specific/IO/Streams.h @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/TombEngine/Specific/Input/Input.cpp b/TombEngine/Specific/Input/Input.cpp index 6a1779225..88beb88d2 100644 --- a/TombEngine/Specific/Input/Input.cpp +++ b/TombEngine/Specific/Input/Input.cpp @@ -651,6 +651,11 @@ namespace TEN::Input if ((KeyMap[KC_F10] || KeyMap[KC_F11]) && dbDebugPage) g_Renderer.SwitchDebugPage(KeyMap[KC_F10]); dbDebugPage = !(KeyMap[KC_F10] || KeyMap[KC_F11]); + + // Reload shaders. + static bool dbReloadShaders = true; + if (KeyMap[KC_F9] && dbReloadShaders) + g_Renderer.ReloadShaders(); } static void UpdateRumble() diff --git a/TombEngine/TombEngine.vcxproj b/TombEngine/TombEngine.vcxproj index 26cebdd14..83de13079 100644 --- a/TombEngine/TombEngine.vcxproj +++ b/TombEngine/TombEngine.vcxproj @@ -822,6 +822,7 @@ if not exist "%ScriptsDir%\Strings.lua" xcopy /Y "$(SolutionDir)Scripts\Strings. + @@ -1316,6 +1317,7 @@ if not exist "%ScriptsDir%\Strings.lua" xcopy /Y "$(SolutionDir)Scripts\Strings. +