diff --git a/src/common/rendering/gl/gl_framebuffer.cpp b/src/common/rendering/gl/gl_framebuffer.cpp index 5be590cbc1..e4d9f09adc 100644 --- a/src/common/rendering/gl/gl_framebuffer.cpp +++ b/src/common/rendering/gl/gl_framebuffer.cpp @@ -561,6 +561,11 @@ void OpenGLFrameBuffer::PostProcessScene(bool swscene, int fixedcm, float flash, GLRenderer->PostProcessScene(fixedcm, flash, afterBloomDrawEndScene2D); } +bool OpenGLFrameBuffer::CompileNextShader() +{ + return GLRenderer->mShaderManager->CompileNextShader(); +} + //========================================================================== // // OpenGLFrameBuffer :: WipeStartScreen diff --git a/src/common/rendering/gl/gl_framebuffer.h b/src/common/rendering/gl/gl_framebuffer.h index 1455ead3ed..84242d7921 100644 --- a/src/common/rendering/gl/gl_framebuffer.h +++ b/src/common/rendering/gl/gl_framebuffer.h @@ -23,7 +23,7 @@ public: explicit OpenGLFrameBuffer() {} OpenGLFrameBuffer(void *hMonitor, bool fullscreen) ; ~OpenGLFrameBuffer(); - + bool CompileNextShader() override; void InitializeState() override; void Update() override; diff --git a/src/common/rendering/gl/gl_shader.cpp b/src/common/rendering/gl/gl_shader.cpp index 88596b367f..0366d8f476 100644 --- a/src/common/rendering/gl/gl_shader.cpp +++ b/src/common/rendering/gl/gl_shader.cpp @@ -672,7 +672,7 @@ bool FShader::Bind() FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType) { FString defines; - defines += shaderdefines; + if (shaderdefines) defines += shaderdefines; // this can't be in the shader code due to ATI strangeness. if (!usediscard) defines += "#define NO_ALPHATEST\n"; if (passType == GBUFFER_PASS) defines += "#define GBUFFER_PASS\n"; @@ -707,6 +707,20 @@ FShaderManager::FShaderManager() mPassShaders.Push(new FShaderCollection((EPassType)passType)); } +bool FShaderManager::CompileNextShader() +{ + if (mPassShaders[mCompilePass]->CompileNextShader()) + { + mCompilePass++; + if (mCompilePass >= MAX_PASS_TYPES) + { + mCompilePass = -1; + return true; + } + } + return false; +} + FShaderManager::~FShaderManager() { glUseProgram(0); @@ -727,7 +741,7 @@ void FShaderManager::SetActiveShader(FShader *sh) FShader *FShaderManager::BindEffect(int effect, EPassType passType) { - if (passType < mPassShaders.Size()) + if (passType < mPassShaders.Size() && mCompilePass > -1) return mPassShaders[passType]->BindEffect(effect); else return nullptr; @@ -735,7 +749,11 @@ FShader *FShaderManager::BindEffect(int effect, EPassType passType) FShader *FShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType) { - if (r_skipmats && eff >= 3 && eff <= 4) + if (mCompilePass > -1) + { + return mPassShaders[0]->Get(0, false); + } + if ((r_skipmats && eff >= 3 && eff <= 4)) eff = 0; if (passType < mPassShaders.Size()) @@ -752,7 +770,14 @@ FShader *FShaderManager::Get(unsigned int eff, bool alphateston, EPassType passT FShaderCollection::FShaderCollection(EPassType passType) { - CompileShaders(passType); + mPassType = passType; + mMaterialShaders.Clear(); + mMaterialShadersNAT.Clear(); + for (int i = 0; i < MAX_EFFECTS; i++) + { + mEffectShaders[i] = NULL; + } + CompileNextShader(); } //========================================================================== @@ -772,35 +797,46 @@ FShaderCollection::~FShaderCollection() // //========================================================================== -void FShaderCollection::CompileShaders(EPassType passType) +bool FShaderCollection::CompileNextShader() { - mMaterialShaders.Clear(); - mMaterialShadersNAT.Clear(); - for (int i = 0; i < MAX_EFFECTS; i++) + int i = mCompileIndex; + if (mCompileState == 0) { - mEffectShaders[i] = NULL; - } - - for(int i=0;defaultshaders[i].ShaderName != NULL;i++) - { - FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, passType); + FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, mPassType); mMaterialShaders.Push(shc); - if (i < SHADER_NoTexture) + mCompileIndex++; + if (defaultshaders[mCompileIndex].ShaderName == nullptr) { - FShader *shc1 = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, passType); - mMaterialShadersNAT.Push(shc1); + mCompileIndex = 0; + mCompileState++; + } } - - for(unsigned i = 0; i < usershaders.Size(); i++) + else if (mCompileState == 1) + { + FShader *shc1 = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, mPassType); + mMaterialShadersNAT.Push(shc1); + mCompileIndex++; + if (mCompileIndex >= SHADER_NoTexture) + { + mCompileIndex = 0; + mCompileState++; + if (usershaders.Size() == 0) mCompileState++; + } + } + else if (mCompileState == 2) { FString name = ExtractFileBase(usershaders[i].shader); FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines; - FShader *shc = Compile(name, usershaders[i].shader, defaultshaders[usershaders[i].shaderType].lightfunc, defines, true, passType); + FShader *shc = Compile(name, usershaders[i].shader, defaultshaders[usershaders[i].shaderType].lightfunc, defines, true, mPassType); mMaterialShaders.Push(shc); + if (mCompileIndex >= (int)usershaders.Size()) + { + mCompileIndex = 0; + mCompileState++; + } } - - for(int i=0;iLoad(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].fp1, @@ -809,7 +845,13 @@ void FShaderCollection::CompileShaders(EPassType passType) delete eff; } else mEffectShaders[i] = eff; + mCompileIndex++; + if (mCompileIndex >= MAX_EFFECTS) + { + return true; + } } + return false; } //========================================================================== diff --git a/src/common/rendering/gl/gl_shader.h b/src/common/rendering/gl/gl_shader.h index ec22898331..33381b6dc9 100644 --- a/src/common/rendering/gl/gl_shader.h +++ b/src/common/rendering/gl/gl_shader.h @@ -309,10 +309,12 @@ public: FShader *Get(unsigned int eff, bool alphateston, EPassType passType); void SetActiveShader(FShader *sh); + bool CompileNextShader(); private: FShader *mActiveShader = nullptr; TArray mPassShaders; + int mCompilePass = 0; friend class FShader; }; @@ -322,21 +324,23 @@ class FShaderCollection TArray mMaterialShaders; TArray mMaterialShadersNAT; FShader *mEffectShaders[MAX_EFFECTS]; + int mCompileState = 0, mCompileIndex = 0; + EPassType mPassType; void Clean(); - void CompileShaders(EPassType passType); public: FShaderCollection(EPassType passType); ~FShaderCollection(); FShader *Compile(const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType); int Find(const char *mame); + bool CompileNextShader(); FShader *BindEffect(int effect); FShader *Get(unsigned int eff, bool alphateston) { // indices 0-2 match the warping modes, 3 no texture, the following are custom - if (!alphateston && eff <= 2) + if (!alphateston && eff < SHADER_NoTexture) { return mMaterialShadersNAT[eff]; // Non-alphatest shaders are only created for default, warp1+2 and brightmap. The rest won't get used anyway } diff --git a/src/common/rendering/gles/gles_framebuffer.h b/src/common/rendering/gles/gles_framebuffer.h index d550b8f108..9e7d14fdca 100644 --- a/src/common/rendering/gles/gles_framebuffer.h +++ b/src/common/rendering/gles/gles_framebuffer.h @@ -26,6 +26,7 @@ public: void InitializeState() override; void Update() override; + int GetShaderCount() override { return 0; } void FirstEye() override; void NextEye(int eyecount) override; diff --git a/src/common/rendering/gles/gles_shader.cpp b/src/common/rendering/gles/gles_shader.cpp index f67aa375e8..daba34f6d1 100644 --- a/src/common/rendering/gles/gles_shader.cpp +++ b/src/common/rendering/gles/gles_shader.cpp @@ -733,7 +733,7 @@ bool FShader::Bind(ShaderFlavourData& flavour) //========================================================================== // -// Since all shaders are REQUIRED, any error here needs to be fatal +// // //========================================================================== @@ -744,21 +744,8 @@ FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderP // this can't be in the shader code due to ATI strangeness. if (!usediscard) defines += "#define NO_ALPHATEST\n"; - FShader *shader = NULL; - try - { - shader = new FShader(ShaderName); - if (!shader->Configure(ShaderName, "shaders_gles/glsl/main.vp", "shaders_gles/glsl/main.fp", ShaderPath, LightModePath, defines.GetChars())) - { - I_FatalError("Unable to load shader %s\n", ShaderName); - } - } - catch(CRecoverableError &err) - { - if (shader != NULL) delete shader; - shader = NULL; - I_FatalError("Unable to load shader %s:\n%s\n", ShaderName, err.GetMessage()); - } + FShader *shader = new FShader(ShaderName); + shader->Configure(ShaderName, "shaders_gles/glsl/main.vp", "shaders_gles/glsl/main.fp", ShaderPath, LightModePath, defines.GetChars()); return shader; } diff --git a/src/common/rendering/hwrenderer/data/hw_shaderpatcher.cpp b/src/common/rendering/hwrenderer/data/hw_shaderpatcher.cpp index 2bb1747d30..50fed5a948 100644 --- a/src/common/rendering/hwrenderer/data/hw_shaderpatcher.cpp +++ b/src/common/rendering/hwrenderer/data/hw_shaderpatcher.cpp @@ -34,7 +34,11 @@ */ +#include "cmdlib.h" #include "hw_shaderpatcher.h" +#include "textures.h" +#include "hw_renderstate.h" +#include "v_video.h" static bool IsGlslWhitespace(char c) @@ -296,3 +300,12 @@ const FEffectShader effectshaders[] = { "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, { "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, }; + +int DFrameBuffer::GetShaderCount() +{ + int i; + for (i = 0; defaultshaders[i].ShaderName != nullptr; i++); + + return MAX_PASS_TYPES * (countof(defaultshaders) - 1 + usershaders.Size() + MAX_EFFECTS + SHADER_NoTexture); +} + diff --git a/src/common/rendering/hwrenderer/data/hw_shaderpatcher.h b/src/common/rendering/hwrenderer/data/hw_shaderpatcher.h index 7133441a29..4a3a1c39fd 100644 --- a/src/common/rendering/hwrenderer/data/hw_shaderpatcher.h +++ b/src/common/rendering/hwrenderer/data/hw_shaderpatcher.h @@ -28,3 +28,4 @@ struct FEffectShader extern const FDefaultShader defaultshaders[]; extern const FEffectShader effectshaders[]; + diff --git a/src/common/rendering/polyrenderer/backend/poly_framebuffer.h b/src/common/rendering/polyrenderer/backend/poly_framebuffer.h index 76eae0cedd..9be76481f3 100644 --- a/src/common/rendering/polyrenderer/backend/poly_framebuffer.h +++ b/src/common/rendering/polyrenderer/backend/poly_framebuffer.h @@ -26,6 +26,7 @@ public: PolyFrameBuffer(void *hMonitor, bool fullscreen); ~PolyFrameBuffer(); + int GetShaderCount() override { return 0; } void Update() override; diff --git a/src/common/rendering/v_video.h b/src/common/rendering/v_video.h index 4322165bf6..30b120eac3 100644 --- a/src/common/rendering/v_video.h +++ b/src/common/rendering/v_video.h @@ -158,6 +158,8 @@ public: virtual void InitializeState() = 0; // For stuff that needs 'screen' set. virtual bool IsVulkan() { return false; } virtual bool IsPoly() { return false; } + virtual int GetShaderCount(); + virtual bool CompileNextShader() { return true; } void SetAABBTree(hwrenderer::LevelAABBTree * tree) { mShadowMap.SetAABBTree(tree); diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index 05042807b1..4059c78755 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -28,51 +28,93 @@ #include "version.h" #include +bool VkShaderManager::CompileNextShader() +{ + const char *mainvp = "shaders/glsl/main.vp"; + const char *mainfp = "shaders/glsl/main.fp"; + int i = compileIndex; + + if (compileState == 0) + { + // regular material shaders + + VkShaderProgram prog; + prog.vert = LoadVertShader(defaultshaders[i].ShaderName, mainvp, defaultshaders[i].Defines); + prog.frag = LoadFragShader(defaultshaders[i].ShaderName, mainfp, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, compilePass == GBUFFER_PASS); + mMaterialShaders[compilePass].push_back(std::move(prog)); + + compileIndex++; + if (defaultshaders[compileIndex].ShaderName == nullptr) + { + compileIndex = 0; + compileState++; + } + } + else if (compileState == 1) + { + // NAT material shaders + + VkShaderProgram natprog; + natprog.vert = LoadVertShader(defaultshaders[i].ShaderName, mainvp, defaultshaders[i].Defines); + natprog.frag = LoadFragShader(defaultshaders[i].ShaderName, mainfp, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, compilePass == GBUFFER_PASS); + mMaterialShadersNAT[compilePass].push_back(std::move(natprog)); + + compileIndex++; + if (compileIndex == SHADER_NoTexture) + { + compileIndex = 0; + compileState++; + if (usershaders.Size() == 0) compileState++; + } + } + else if (compileState == 2) + { + // user shaders + + const FString& name = ExtractFileBase(usershaders[i].shader); + FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines; + + VkShaderProgram prog; + prog.vert = LoadVertShader(name, mainvp, defines); + prog.frag = LoadFragShader(name, mainfp, usershaders[i].shader, defaultshaders[usershaders[i].shaderType].lightfunc, defines, true, compilePass == GBUFFER_PASS); + mMaterialShaders[compilePass].push_back(std::move(prog)); + + compileIndex++; + if (compileIndex >= (int)usershaders.Size()) + { + compileIndex = 0; + compileState++; + } + } + else if (compileState == 3) + { + // Effect shaders + + VkShaderProgram prog; + prog.vert = LoadVertShader(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].defines); + prog.frag = LoadFragShader(effectshaders[i].ShaderName, effectshaders[i].fp1, effectshaders[i].fp2, effectshaders[i].fp3, effectshaders[i].defines, true, compilePass == GBUFFER_PASS); + mEffectShaders[compilePass].push_back(std::move(prog)); + + compileIndex++; + if (compileIndex >= MAX_EFFECTS) + { + compileIndex = 0; + if (compilePass == MAX_PASS_TYPES) + { + compileIndex = -1; // we're done. + return true; + } + compileState = 0; + compilePass++; + } + } + return false; +} + VkShaderManager::VkShaderManager(VulkanDevice *device) : device(device) { ShInitialize(); - - const char *mainvp = "shaders/glsl/main.vp"; - const char *mainfp = "shaders/glsl/main.fp"; - - for (int j = 0; j < MAX_PASS_TYPES; j++) - { - bool gbufferpass = j; - for (int i = 0; defaultshaders[i].ShaderName != nullptr; i++) - { - VkShaderProgram prog; - prog.vert = LoadVertShader(defaultshaders[i].ShaderName, mainvp, defaultshaders[i].Defines); - prog.frag = LoadFragShader(defaultshaders[i].ShaderName, mainfp, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, gbufferpass); - mMaterialShaders[j].push_back(std::move(prog)); - - if (i < SHADER_NoTexture) - { - VkShaderProgram natprog; - natprog.vert = LoadVertShader(defaultshaders[i].ShaderName, mainvp, defaultshaders[i].Defines); - natprog.frag = LoadFragShader(defaultshaders[i].ShaderName, mainfp, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, gbufferpass); - mMaterialShadersNAT[j].push_back(std::move(natprog)); - } - } - - for (unsigned i = 0; i < usershaders.Size(); i++) - { - FString name = ExtractFileBase(usershaders[i].shader); - FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines; - - VkShaderProgram prog; - prog.vert = LoadVertShader(name, mainvp, defines); - prog.frag = LoadFragShader(name, mainfp, usershaders[i].shader, defaultshaders[usershaders[i].shaderType].lightfunc, defines, true, gbufferpass); - mMaterialShaders[j].push_back(std::move(prog)); - } - - for (int i = 0; i < MAX_EFFECTS; i++) - { - VkShaderProgram prog; - prog.vert = LoadVertShader(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].defines); - prog.frag = LoadFragShader(effectshaders[i].ShaderName, effectshaders[i].fp1, effectshaders[i].fp2, effectshaders[i].fp3, effectshaders[i].defines, true, gbufferpass); - mEffectShaders[j].push_back(std::move(prog)); - } - } + CompileNextShader(); } VkShaderManager::~VkShaderManager() @@ -82,7 +124,7 @@ VkShaderManager::~VkShaderManager() VkShaderProgram *VkShaderManager::GetEffect(int effect, EPassType passType) { - if (effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[passType][effect].frag) + if (compileIndex > -1 && effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[passType][effect].frag) { return &mEffectShaders[passType][effect]; } @@ -91,8 +133,9 @@ VkShaderProgram *VkShaderManager::GetEffect(int effect, EPassType passType) VkShaderProgram *VkShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType) { + if (compileIndex != -1) return &mMaterialShaders[0][0]; // indices 0-2 match the warping modes, 3 no texture, the following are custom - if (!alphateston && eff <= 2) + if (!alphateston && eff <= SHADER_NoTexture) { return &mMaterialShadersNAT[passType][eff]; // Non-alphatest shaders are only created for default, warp1+2. The rest won't get used anyway } diff --git a/src/common/rendering/vulkan/shaders/vk_shader.h b/src/common/rendering/vulkan/shaders/vk_shader.h index daa9dc845c..0b610ca330 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.h +++ b/src/common/rendering/vulkan/shaders/vk_shader.h @@ -65,6 +65,7 @@ public: VkShaderProgram *GetEffect(int effect, EPassType passType); VkShaderProgram *Get(unsigned int eff, bool alphateston, EPassType passType); + bool CompileNextShader(); private: std::unique_ptr LoadVertShader(FString shadername, const char *vert_lump, const char *defines); @@ -79,4 +80,6 @@ private: std::vector mMaterialShaders[MAX_PASS_TYPES]; std::vector mMaterialShadersNAT[MAX_PASS_TYPES]; std::vector mEffectShaders[MAX_PASS_TYPES]; + uint8_t compilePass = 0, compileState = 0; + int compileIndex = 0; }; diff --git a/src/common/rendering/vulkan/system/vk_framebuffer.cpp b/src/common/rendering/vulkan/system/vk_framebuffer.cpp index 213cf56a4c..b0a35399a1 100644 --- a/src/common/rendering/vulkan/system/vk_framebuffer.cpp +++ b/src/common/rendering/vulkan/system/vk_framebuffer.cpp @@ -207,6 +207,11 @@ void VulkanFrameBuffer::Update() Super::Update(); } +bool VulkanFrameBuffer::CompileNextShader() +{ + return mShaderManager->CompileNextShader(); +} + void VulkanFrameBuffer::DeleteFrameObjects(bool uploadOnly) { FrameTextureUpload.Buffers.clear(); diff --git a/src/common/rendering/vulkan/system/vk_framebuffer.h b/src/common/rendering/vulkan/system/vk_framebuffer.h index 4098fd7ff8..d234505cb6 100644 --- a/src/common/rendering/vulkan/system/vk_framebuffer.h +++ b/src/common/rendering/vulkan/system/vk_framebuffer.h @@ -77,7 +77,7 @@ public: void Update() override; void InitializeState() override; - + bool CompileNextShader() override; void PrecacheMaterial(FMaterial *mat, int translation) override; void UpdatePalette() override; const char* DeviceName() const override; diff --git a/src/d_main.cpp b/src/d_main.cpp index 43f3685521..9091e7889b 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -3356,6 +3356,10 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr } V_Init2(); + while(!screen->CompileNextShader()) + { + // here we can do some visual updates later + } twod->fullscreenautoaspect = gameinfo.fullscreenautoaspect; // Initialize the size of the 2D drawer so that an attempt to access it outside the draw code won't crash. twod->Begin(screen->GetWidth(), screen->GetHeight());