From 2d1043d1d378436b7a4938da7f9697c31d137825 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Sep 2018 11:34:18 +0200 Subject: [PATCH 01/22] - added profiling for postprocessing code. --- src/gl/scene/gl_scene.cpp | 2 ++ src/hwrenderer/utility/hw_clock.cpp | 7 ++++--- src/hwrenderer/utility/hw_clock.h | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index fa7b9f7a7..4e1aa844b 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -493,6 +493,7 @@ sector_t * FGLRenderer::RenderViewpoint (FRenderViewpoint &mainvp, AActor * came if (mainview) { + PostProcess.Clock(); if (toscreen) di->EndDrawScene(mainvp.sector); // do not call this for camera textures. if (gl_RenderState.GetPassType() == GBUFFER_PASS) // Turn off ssao draw buffers @@ -506,6 +507,7 @@ sector_t * FGLRenderer::RenderViewpoint (FRenderViewpoint &mainvp, AActor * came FGLDebug::PopGroup(); // MainView PostProcessScene(cm, [&]() { di->DrawEndScene2D(mainvp.sector); }); + PostProcess.Unclock(); } di->EndDrawInfo(); if (vrmode->mEyeCount > 1) diff --git a/src/hwrenderer/utility/hw_clock.cpp b/src/hwrenderer/utility/hw_clock.cpp index 74aa096a4..40c61924b 100644 --- a/src/hwrenderer/utility/hw_clock.cpp +++ b/src/hwrenderer/utility/hw_clock.cpp @@ -46,7 +46,7 @@ glcycle_t RenderWall,SetupWall,ClipWall; glcycle_t RenderFlat,SetupFlat; glcycle_t RenderSprite,SetupSprite; glcycle_t All, Finish, PortalAll, Bsp; -glcycle_t ProcessAll; +glcycle_t ProcessAll, PostProcess; glcycle_t RenderAll; glcycle_t Dirty; glcycle_t drawcalls; @@ -64,6 +64,7 @@ void ResetProfilingData() PortalAll.Reset(); RenderAll.Reset(); ProcessAll.Reset(); + PostProcess.Reset(); RenderWall.Reset(); SetupWall.Reset(); ClipWall.Reset(); @@ -94,13 +95,13 @@ static void AppendRenderTimes(FString &str) "F: Render=%2.3f, Setup=%2.3f\n" "S: Render=%2.3f, Setup=%2.3f\n" "2D: %2.3f Finish3D: %2.3f\n" - "All=%2.3f, Render=%2.3f, Setup=%2.3f, Portal=%2.3f, Drawcalls=%2.3f, Finish=%2.3f\n", + "All=%2.3f, Render=%2.3f, Setup=%2.3f, Portal=%2.3f, Drawcalls=%2.3f, Postprocess=%2.3f, Finish=%2.3f\n", bsp, clipwall, RenderWall.TimeMS(), setupwall, RenderFlat.TimeMS(), SetupFlat.TimeMS(), RenderSprite.TimeMS(), SetupSprite.TimeMS(), twoD.TimeMS(), Flush3D.TimeMS() - twoD.TimeMS(), - All.TimeMS() + Finish.TimeMS(), RenderAll.TimeMS(), ProcessAll.TimeMS(), PortalAll.TimeMS(), drawcalls.TimeMS(), Finish.TimeMS()); + All.TimeMS() + Finish.TimeMS(), RenderAll.TimeMS(), ProcessAll.TimeMS(), PortalAll.TimeMS(), drawcalls.TimeMS(), PostProcess.TimeMS(), Finish.TimeMS()); } static void AppendRenderStats(FString &out) diff --git a/src/hwrenderer/utility/hw_clock.h b/src/hwrenderer/utility/hw_clock.h index 7cb82fedc..243ec4924 100644 --- a/src/hwrenderer/utility/hw_clock.h +++ b/src/hwrenderer/utility/hw_clock.h @@ -9,7 +9,7 @@ extern glcycle_t RenderWall,SetupWall,ClipWall; extern glcycle_t RenderFlat,SetupFlat; extern glcycle_t RenderSprite,SetupSprite; extern glcycle_t All, Finish, PortalAll, Bsp; -extern glcycle_t ProcessAll; +extern glcycle_t ProcessAll, PostProcess; extern glcycle_t RenderAll; extern glcycle_t Dirty; extern glcycle_t drawcalls, twoD, Flush3D; From ecf6e3f6207a227da8ca7cb7db448556e0c33731 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Aug 2018 12:58:57 +0200 Subject: [PATCH 02/22] Sanitized the Being/End2D interface so that it can be used to keep the attribute buffer mapped while processing 2D commands. For this to work the 2D mode has to be properly set and unset at the right places so that no double mapping occurs and no render operation can happen while in 2D mode. # Conflicts: # src/d_main.cpp # src/v_video.h --- src/d_main.cpp | 194 +++++++++++++++---------------- src/gl/system/gl_framebuffer.cpp | 1 - src/gl/system/gl_framebuffer.h | 2 +- src/v_video.h | 13 ++- 4 files changed, 102 insertions(+), 108 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 4d113c4d7..a08ce7ae1 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -733,112 +733,99 @@ void D_Display () { wipe = false; } - + + screen->FrameTime = I_msTimeFS(); + TexMan.UpdateAnimations(screen->FrameTime); + R_UpdateSky(screen->FrameTime); + screen->BeginFrame(); + screen->ClearClipRect(); + if ((gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL) && gametic != 0) { - screen->FrameTime = I_msTimeFS(); - TexMan.UpdateAnimations(screen->FrameTime); - R_UpdateSky(screen->FrameTime); - screen->BeginFrame(); - screen->ClearClipRect(); + // [ZZ] execute event hook that we just started the frame + //E_RenderFrame(); + // + + // Check for the presence of dynamic lights at the start of the frame once. + if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4)) + { + TThinkerIterator it(STAT_DLIGHT); + level.HasDynamicLights = !!it.Next(); + } + else level.HasDynamicLights = false; // lights are off so effectively we have none. + + viewsec = screen->RenderView(&players[consoleplayer]); + screen->Begin2D(); + screen->DrawBlend(viewsec); + if (automapactive) + { + AM_Drawer (hud_althud? viewheight : StatusBar->GetTopOfStatusbar()); + } + if (!automapactive || viewactive) + { + screen->RefreshViewBorder (); + } + + // for timing the statusbar code. + //cycle_t stb; + //stb.Reset(); + //stb.Clock(); + if (hud_althud && viewheight == SCREENHEIGHT && screenblocks > 10) + { + StatusBar->DrawBottomStuff (HUD_AltHud); + if (DrawFSHUD || automapactive) DrawHUD(); + if (players[consoleplayer].camera && players[consoleplayer].camera->player && !automapactive) + { + StatusBar->DrawCrosshair(); + } + StatusBar->CallDraw (HUD_AltHud, vp.TicFrac); + StatusBar->DrawTopStuff (HUD_AltHud); + } + else if (viewheight == SCREENHEIGHT && viewactive && screenblocks > 10) + { + EHudState state = DrawFSHUD ? HUD_Fullscreen : HUD_None; + StatusBar->DrawBottomStuff (state); + StatusBar->CallDraw (state, vp.TicFrac); + StatusBar->DrawTopStuff (state); + } + else + { + StatusBar->DrawBottomStuff (HUD_StatusBar); + StatusBar->CallDraw (HUD_StatusBar, vp.TicFrac); + StatusBar->DrawTopStuff (HUD_StatusBar); + } + //stb.Unclock(); + //Printf("Stbar = %f\n", stb.TimeMS()); + } + else + { + screen->Begin2D(); switch (gamestate) { - case GS_FULLCONSOLE: - screen->Begin2D(false); - C_DrawConsole (); - M_Drawer (); - screen->End2D(); - screen->Update (); - return; - - case GS_LEVEL: - case GS_TITLELEVEL: - if (!gametic) - { - screen->Begin2D(false); + case GS_FULLCONSOLE: + screen->Begin2D(); + C_DrawConsole (); + M_Drawer (); + screen->End2DAndUpdate (); + return; + + case GS_INTERMISSION: + WI_Drawer (); + break; + + case GS_FINALE: + F_Drawer (); + break; + + case GS_DEMOSCREEN: + D_PageDrawer (); + break; + + default: break; - } - - // [ZZ] execute event hook that we just started the frame - //E_RenderFrame(); - // - - // Check for the presence of dynamic lights at the start of the frame once. - if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4)) - { - TThinkerIterator it(STAT_DLIGHT); - level.HasDynamicLights = !!it.Next(); - } - else level.HasDynamicLights = false; // lights are off so effectively we have none. - - viewsec = screen->RenderView(&players[consoleplayer]); - screen->Begin2D(false); - screen->DrawBlend(viewsec); - // returns with 2S mode set. - if (automapactive) - { - AM_Drawer (hud_althud? viewheight : StatusBar->GetTopOfStatusbar()); - } - if (!automapactive || viewactive) - { - screen->RefreshViewBorder (); - } - - // for timing the statusbar code. - //cycle_t stb; - //stb.Reset(); - //stb.Clock(); - if (hud_althud && viewheight == SCREENHEIGHT && screenblocks > 10) - { - StatusBar->DrawBottomStuff (HUD_AltHud); - if (DrawFSHUD || automapactive) DrawHUD(); - if (players[consoleplayer].camera && players[consoleplayer].camera->player && !automapactive) - { - StatusBar->DrawCrosshair(); - } - StatusBar->CallDraw (HUD_AltHud, vp.TicFrac); - StatusBar->DrawTopStuff (HUD_AltHud); - } - else - if (viewheight == SCREENHEIGHT && viewactive && screenblocks > 10) - { - EHudState state = DrawFSHUD ? HUD_Fullscreen : HUD_None; - StatusBar->DrawBottomStuff (state); - StatusBar->CallDraw (state, vp.TicFrac); - StatusBar->DrawTopStuff (state); - } - else - { - StatusBar->DrawBottomStuff (HUD_StatusBar); - StatusBar->CallDraw (HUD_StatusBar, vp.TicFrac); - StatusBar->DrawTopStuff (HUD_StatusBar); - } - //stb.Unclock(); - //Printf("Stbar = %f\n", stb.TimeMS()); - CT_Drawer (); - break; - - case GS_INTERMISSION: - screen->Begin2D(false); - WI_Drawer (); - CT_Drawer (); - break; - - case GS_FINALE: - screen->Begin2D(false); - F_Drawer (); - CT_Drawer (); - break; - - case GS_DEMOSCREEN: - screen->Begin2D(false); - D_PageDrawer (); - CT_Drawer (); - break; - - default: - break; } } + CT_Drawer (); + // draw pause pic if ((paused || pauseext) && menuactive == MENU_Off) { @@ -887,7 +874,7 @@ void D_Display () C_DrawConsole (); // draw console M_Drawer (); // menu is drawn even on top of everything FStat::PrintStat (); - screen->Update (); // page flip or blit buffer + screen->End2DAndUpdate (); } else { @@ -897,6 +884,7 @@ void D_Display () GSnd->SetSfxPaused(true, 1); I_FreezeTime(true); + screen->End2D(); screen->WipeEndScreen (); wipestart = I_msTime(); @@ -912,16 +900,16 @@ void D_Display () } while (diff < 1); wipestart = nowtime; done = screen->WipeDo (1); + screen->Begin2D(); C_DrawConsole (); // console and M_Drawer (); // menu are drawn even on top of wipes - screen->Update (); // page flip or blit buffer + screen->End2DAndUpdate (); NetUpdate (); // [RH] not sure this is needed anymore } while (!done); screen->WipeCleanup(); I_FreezeTime(false); GSnd->SetSfxPaused(false, 1); } - screen->End2D(); cycles.Unclock(); FrameCycles = cycles; } diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index cb5c92534..2af278c5f 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -151,7 +151,6 @@ void OpenGLFrameBuffer::Update() twoD.Reset(); Flush3D.Reset(); - DrawRateStuff(); Flush3D.Clock(); GLRenderer->Flush(); Flush3D.Unclock(); diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index e1cd3a18e..762cf69cf 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -20,7 +20,7 @@ public: ~OpenGLFrameBuffer(); void InitializeState(); - void Update(); + void Update() override; // Color correction void SetGamma(); diff --git a/src/v_video.h b/src/v_video.h index ec0e43f3d..29d4a7e39 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -441,11 +441,18 @@ public: virtual IUniformBuffer *CreateUniformBuffer(size_t size, bool staticuse = false) { return nullptr; } virtual IShaderProgram *CreateShaderProgram() { return nullptr; } - // Begin 2D drawing operations. - // Returns true if hardware-accelerated 2D has been entered, false if not. - void Begin2D(bool copy3d) { isIn2D = true; } + // Begin/End 2D drawing operations. + void Begin2D() { isIn2D = true; } void End2D() { isIn2D = false; } + void End2DAndUpdate() + { + DrawRateStuff(); + End2D(); + Update(); + } + + // Returns true if Begin2D has been called and 2D drawing is now active bool HasBegun2D() { return isIn2D; } From 9af01c4667741ee3b4dbf6d1726db4328803b170 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Aug 2018 15:11:35 +0200 Subject: [PATCH 03/22] - Untested wipe refactor # Conflicts: # src/gl/renderer/gl_renderer.cpp # src/gl/system/gl_wipe.cpp # src/hwrenderer/scene/hw_attributebuffer.cpp --- src/d_main.cpp | 18 +- src/f_wipe.cpp | 284 +++++++++++++++++++ src/f_wipe.h | 31 +- src/gl/renderer/gl_renderer.cpp | 12 +- src/gl/system/gl_framebuffer.h | 32 +-- src/gl/system/gl_wipe.cpp | 482 ++------------------------------ src/v_2ddrawer.cpp | 1 + src/v_2ddrawer.h | 1 + src/v_draw.cpp | 5 + src/v_framebuffer.cpp | 7 +- src/v_video.h | 7 +- 11 files changed, 363 insertions(+), 517 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index a08ce7ae1..163ef9d64 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -638,7 +638,8 @@ CVAR(Bool, vid_activeinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) void D_Display () { - bool wipe; + FTexture *wipe; + int wipe_type; sector_t *viewsec; if (nodrawers || screen == NULL) @@ -703,35 +704,36 @@ void D_Display () if (NoWipe) { NoWipe--; - wipe = false; + wipe = nullptr; wipegamestate = gamestate; } // No wipes when in a stereo3D VR mode else if (gamestate != wipegamestate && gamestate != GS_FULLCONSOLE && gamestate != GS_TITLELEVEL && (vr_mode == 0 || vid_rendermode != 4)) { // save the current screen if about to wipe + wipe = screen->WipeStartScreen (); switch (wipegamestate) { default: - wipe = screen->WipeStartScreen (wipetype); + wipe_type = wipetype; break; case GS_FORCEWIPEFADE: - wipe = screen->WipeStartScreen (wipe_Fade); + wipe_type = wipe_Fade; break; case GS_FORCEWIPEBURN: - wipe = screen->WipeStartScreen (wipe_Burn); + wipe_type =wipe_Burn; break; case GS_FORCEWIPEMELT: - wipe = screen->WipeStartScreen (wipe_Melt); + wipe_type = wipe_Melt; break; } wipegamestate = gamestate; } else { - wipe = false; + wipe = nullptr; } screen->FrameTime = I_msTimeFS(); @@ -885,7 +887,7 @@ void D_Display () GSnd->SetSfxPaused(true, 1); I_FreezeTime(true); screen->End2D(); - screen->WipeEndScreen (); + auto wipend = screen->WipeEndScreen (); wipestart = I_msTime(); NetUpdate(); // send out any new accumulation diff --git a/src/f_wipe.cpp b/src/f_wipe.cpp index 31edce0fd..1f94c29df 100644 --- a/src/f_wipe.cpp +++ b/src/f_wipe.cpp @@ -27,6 +27,36 @@ #include "m_random.h" #include "f_wipe.h" #include "templates.h" +#include "textures/bitmap.h" +#include "hwrenderer/textures/hw_material.h" + +class FBurnTexture : public FTexture +{ + uint32_t *WorkBuffer; +public: + FBurnTexture(int w, int h) + { + Width = w; + Height = h; + WorkBuffer = new uint32_t[w * h]; + } + + ~FBurnTexture() + { + delete [] WorkBuffer; + } + + int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) override + { + bmp->CopyPixelDataRGB(x, y, (uint8_t*)WorkBuffer, Width, Height, 4, Width*4, rotate, CF_RGBA, inf); + return 0; + } + + uint32_t *GetBuffer() + { + return WorkBuffer; + } +}; int wipe_CalcBurn (uint8_t *burnarray, int width, int height, int density) { @@ -112,3 +142,257 @@ int wipe_CalcBurn (uint8_t *burnarray, int width, int height, int density) return -1; } + +// TYPES ------------------------------------------------------------------- + +class Wiper_Crossfade : public Wiper +{ +public: + bool Run(int ticks) override; + +private: + int Clock = 0; +}; + +class Wiper_Melt : public Wiper +{ +public: + Wiper_Melt(); + bool Run(int ticks) override; + +private: + static const int WIDTH = 320, HEIGHT = 200; + int y[WIDTH]; +}; + +class Wiper_Burn : public Wiper +{ +public: + Wiper_Burn(); + ~Wiper_Burn(); + bool Run(int ticks) override; + void SetTextures(FTexture *startscreen, FTexture *endscreen) override; + +private: + static const int WIDTH = 64, HEIGHT = 64; + uint8_t BurnArray[WIDTH * (HEIGHT + 5)] = {0}; + FBurnTexture *BurnTexture = nullptr; + int Density = 4; + int BurnTime = 8; +}; + +//=========================================================================== +// +// Screen wipes +// +//=========================================================================== + +Wiper *Wiper::Create(int type) +{ + switch(type) + { + case wipe_Burn: + return new Wiper_Burn; + + case wipe_Fade: + return new Wiper_Crossfade; + + case wipe_Melt: + return new Wiper_Melt; + + default: + return nullptr; + } +} + + + + +//========================================================================== +// +// OpenGLFrameBuffer :: WipeCleanup +// +// Release any resources that were specifically created for the wipe. +// +//========================================================================== + +Wiper::~Wiper() +{ + if (startScreen != nullptr) delete startScreen; + if (endScreen != nullptr) delete endScreen; +} + +//========================================================================== +// +// WIPE: CROSSFADE --------------------------------------------------------- +// +//========================================================================== + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Crossfade :: Run +// +// Fades the old screen into the new one over 32 ticks. +// +//========================================================================== + +bool Wiper_Crossfade::Run(int ticks) +{ + Clock += ticks; + screen->DrawTexture(startScreen, 0, 0, TAG_DONE); + screen->DrawTexture(endScreen, 0, 0, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE); + return Clock >= 32; +} + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Melt Constructor +// +//========================================================================== + +Wiper_Melt::Wiper_Melt() +{ + int i, r; + + // setup initial column positions + // (y<0 => not ready to scroll yet) + y[0] = -(M_Random() & 15); + for (i = 1; i < WIDTH; ++i) + { + r = (M_Random()%3) - 1; + y[i] = clamp(y[i-1] + r, -15, 0); + } +} + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Melt :: Run +// +// Melts the old screen into the new one over 32 ticks. +// +//========================================================================== + +bool Wiper_Melt::Run(int ticks) +{ + bool done; + screen->DrawTexture(endScreen, 0, 0, TAG_DONE); + + // Copy the old screen in vertical strips on top of the new one. + while (ticks--) + { + done = true; + for (int i = 0; i < WIDTH; i++) + { + if (y[i] < 0) + { + y[i]++; + done = false; + } + else if (y[i] < HEIGHT) + { + int dy = (y[i] < 16) ? y[i] + 1 : 8; + y[i] = MIN(y[i] + dy, HEIGHT); + done = false; + } + if (ticks == 0) + { + struct { + int32_t x; + int32_t y; + } dpt; + struct { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; + } rect; + + // Only draw for the final tick. + // No need for optimization. Wipes won't ever be drawn with anything else. + + int w = startScreen->GetWidth(); + int h = startScreen->GetHeight(); + dpt.x = i * h / WIDTH; + dpt.y = MAX(0, y[i] * h / HEIGHT); + rect.left = dpt.x; + rect.top = 0; + rect.right = (i + 1) * w / WIDTH; + rect.bottom = w - dpt.y; + if (rect.bottom > rect.top) + { + screen->DrawTexture(startScreen, 0, rect.top, DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, TAG_DONE); + } + } + } + } + return done; +} + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Burn Constructor +// +//========================================================================== + +void Wiper_Burn::SetTextures(FTexture *startscreen, FTexture *endscreen) +{ + startScreen = startscreen; + endScreen = endscreen; + BurnTexture = new FBurnTexture(WIDTH, HEIGHT); + auto mat = FMaterial::ValidateTexture(startscreen, false); + mat->AddTextureLayer(BurnTexture); +} + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Burn Destructor +// +//========================================================================== + +Wiper_Burn::~Wiper_Burn() +{ + if (BurnTexture != nullptr) delete BurnTexture; +} + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper_Burn :: Run +// +//========================================================================== + +bool Wiper_Burn::Run(int ticks) +{ + bool done; + + + BurnTime += ticks; + ticks *= 2; + + // Make the fire burn + done = false; + while (!done && ticks--) + { + Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density); + done = (Density < 0); + } + + auto mat = FMaterial::ValidateTexture(BurnTexture, false); + mat->Clean(true); + const uint8_t *src = BurnArray; + uint32_t *dest = (uint32_t *)BurnTexture->GetBuffer(); + for (int y = HEIGHT; y != 0; --y) + { + for (int x = WIDTH; x != 0; --x) + { + uint8_t s = clamp((*src++)*2, 0, 255); + *dest++ = MAKEARGB(s,255,255,255); + } + } + + screen->DrawTexture(startScreen, 0, 0, TAG_DONE); + screen->DrawTexture(endScreen, 0, 0, DTA_Burn, true, TAG_DONE); + + // The fire may not always stabilize, so the wipe is forced to end + // after an arbitrary maximum time. + return done || (BurnTime > 40); +} diff --git a/src/f_wipe.h b/src/f_wipe.h index dc4cfb8cc..c639307aa 100644 --- a/src/f_wipe.h +++ b/src/f_wipe.h @@ -26,19 +26,9 @@ #ifndef __F_WIPE_H__ #define __F_WIPE_H__ -// -// SCREEN WIPE PACKAGE -// +#include "stdint.h" -#if 0 -bool wipe_StartScreen (int type); -void wipe_EndScreen (void); -bool wipe_ScreenWipe (int ticks); -void wipe_Cleanup (); - -// The buffer must have an additional 5 rows not included in height -// to use for a seeding area. -#endif +class FTexture; int wipe_CalcBurn(uint8_t *buffer, int width, int height, int density); enum @@ -50,4 +40,21 @@ enum wipe_NUMWIPES }; +class Wiper +{ +protected: + FTexture *startScreen = nullptr, *endScreen = nullptr; +public: + virtual ~Wiper(); + virtual bool Run(int ticks) = 0; + virtual void SetTextures(FTexture *startscreen, FTexture *endscreen) + { + startScreen = startscreen; + endScreen = endscreen; + } + + static Wiper *Create(int type); +}; + + #endif diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 47d82c965..17cd6b6b1 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -428,12 +428,6 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer) const auto &mScreenViewport = screen->mScreenViewport; glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); - HWViewpointUniforms matrices; - matrices.SetDefaults(); - matrices.mProjectionMatrix.ortho(0, screen->GetWidth(), screen->GetHeight(), 0, -1.0f, 1.0f); - matrices.CalcDependencies(); - GLRenderer->mShaderManager->ApplyMatrices(&matrices, NORMAL_PASS); - glDisable(GL_DEPTH_TEST); // Korshun: ENABLE AUTOMAP ANTIALIASING!!! @@ -530,6 +524,10 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer) gl_RenderState.mTextureMatrix.translate(0.f, 1.f, 0.0f); gl_RenderState.EnableTextureMatrix(true); } + if (cmd.mFlags & F2DDrawer::DTF_Burn) + { + gl_RenderState.SetEffect(EFF_BURN); + } } else { @@ -555,6 +553,8 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer) gl_RenderState.SetObjectColor(0xffffffff); gl_RenderState.SetObjectColor2(0); gl_RenderState.EnableTextureMatrix(false); + gl_RenderState.SetEffect(EFF_NONE); + } glDisable(GL_SCISSOR_TEST); diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index 762cf69cf..44a380b3a 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -49,10 +49,6 @@ public: // points to the last row in the buffer, which will be the first row output. virtual void GetScreenshotBuffer(const uint8_t *&buffer, int &pitch, ESSType &color_type, float &gamma) override; - bool WipeStartScreen(int type); - void WipeEndScreen(); - bool WipeDo(int ticks); - void WipeCleanup(); void Swap(); bool IsHWGammaActive() const { return HWGammaActive; } @@ -63,33 +59,11 @@ public: bool HWGammaActive = false; // Are we using hardware or software gamma? std::shared_ptr mDebug; // Debug API + + FTexture *WipeStartScreen() override; + FTexture *WipeEndScreen() override; private: int camtexcount = 0; - - class Wiper - { - - protected: - FSimpleVertexBuffer *mVertexBuf; - - void MakeVBO(OpenGLFrameBuffer *fb); - - public: - Wiper(); - virtual ~Wiper(); - virtual bool Run(int ticks, OpenGLFrameBuffer *fb) = 0; - }; - - class Wiper_Melt; friend class Wiper_Melt; - class Wiper_Burn; friend class Wiper_Burn; - class Wiper_Crossfade; friend class Wiper_Crossfade; - - Wiper *ScreenWipe; - FHardwareTexture *wipestartscreen; - FHardwareTexture *wipeendscreen; - - -public: }; diff --git a/src/gl/system/gl_wipe.cpp b/src/gl/system/gl_wipe.cpp index ac5b924cd..bf1c6b45a 100644 --- a/src/gl/system/gl_wipe.cpp +++ b/src/gl/system/gl_wipe.cpp @@ -40,49 +40,21 @@ #include "gl/data/gl_vertexbuffer.h" -//=========================================================================== -// -// Screen wipes -// -//=========================================================================== - -// TYPES ------------------------------------------------------------------- - -class OpenGLFrameBuffer::Wiper_Crossfade : public OpenGLFrameBuffer::Wiper +class FGLWipeTexture : public FTexture { public: - Wiper_Crossfade(); - bool Run(int ticks, OpenGLFrameBuffer *fb); - -private: - int Clock; -}; - -class OpenGLFrameBuffer::Wiper_Melt : public OpenGLFrameBuffer::Wiper -{ -public: - Wiper_Melt(); - int MakeVBO(int ticks, OpenGLFrameBuffer *fb, bool &done); - bool Run(int ticks, OpenGLFrameBuffer *fb); - -private: - static const int WIDTH = 320, HEIGHT = 200; - int y[WIDTH]; -}; - -class OpenGLFrameBuffer::Wiper_Burn : public OpenGLFrameBuffer::Wiper -{ -public: - Wiper_Burn(); - ~Wiper_Burn(); - bool Run(int ticks, OpenGLFrameBuffer *fb); - -private: - static const int WIDTH = 64, HEIGHT = 64; - uint8_t BurnArray[WIDTH * (HEIGHT + 5)]; - FHardwareTexture *BurnTexture; - int Density; - int BurnTime; + + FGLWipeTexture(int w, int h) + { + Width = w; + Height = h; + WidthBits = 4; + UseType = ETextureType::SWCanvas; + bNoCompress = true; + SystemTexture[0] = screen->CreateHardwareTexture(this); + } + + // This is just a wrapper around the hardware texture being extracted below so that it can be passed to the 2D code. }; //========================================================================== @@ -95,46 +67,18 @@ private: // //========================================================================== -bool OpenGLFrameBuffer::WipeStartScreen(int type) +FTexture *OpenGLFrameBuffer::WipeStartScreen() { - switch (type) - { - case wipe_Burn: - ScreenWipe = new Wiper_Burn; - break; - - case wipe_Fade: - ScreenWipe = new Wiper_Crossfade; - break; - - case wipe_Melt: - ScreenWipe = new Wiper_Melt; - break; - - default: - return false; - } - const auto &viewport = screen->mScreenViewport; - wipestartscreen = new FHardwareTexture(true); - wipestartscreen->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeStartScreen"); - GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER, -1); - GLRenderer->mSamplerManager->Bind(1, CLAMP_NONE, -1); + + FGLWipeTexture *tex = new FGLWipeTexture(viewport.width, viewport.height); + tex->SystemTexture[0]->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, 0, "WipeStartScreen"); glFinish(); - wipestartscreen->Bind(0, false, false); - - const auto copyPixels = [&viewport]() - { - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); - }; + static_cast(tex->SystemTexture[0])->Bind(0, false, false); GLRenderer->mBuffers->BindCurrentFB(); - copyPixels(); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - return true; + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); + return tex; } //========================================================================== @@ -145,392 +89,16 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type) // //========================================================================== -void OpenGLFrameBuffer::WipeEndScreen() +FTexture *OpenGLFrameBuffer::WipeEndScreen() { GLRenderer->Flush(); const auto &viewport = screen->mScreenViewport; - wipeendscreen = new FHardwareTexture(true); - wipeendscreen->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeEndScreen"); - GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER, -1); + FGLWipeTexture *tex = new FGLWipeTexture(viewport.width, viewport.height); + tex->SystemTexture[0]->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeEndScreen"); glFinish(); - wipeendscreen->Bind(0, false, false); - + static_cast(tex->SystemTexture[0])->Bind(0, false, false); GLRenderer->mBuffers->BindCurrentFB(); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + return tex; } -//========================================================================== -// -// OpenGLFrameBuffer :: WipeDo -// -// Perform the actual wipe animation. The number of tics since the last -// time this function was called is passed in. Returns true when the wipe -// is over. The first time this function has been called, the screen is -// still locked from before and EndScene() still has not been called. -// Successive times need to call BeginScene(). -// -//========================================================================== - -bool OpenGLFrameBuffer::WipeDo(int ticks) -{ - bool done = true; - // Sanity checks. - if (wipestartscreen != nullptr && wipeendscreen != nullptr) - { - gl_RenderState.EnableTexture(true); - gl_RenderState.EnableFog(false); - glDisable(GL_DEPTH_TEST); - glDepthMask(false); - - GLRenderer->mBuffers->BindCurrentFB(); - const auto &bounds = screen->mScreenViewport; - glViewport(bounds.left, bounds.top, bounds.width, bounds.height); - - done = ScreenWipe->Run(ticks, this); - glDepthMask(true); - } - gl_RenderState.SetVertexBuffer(GLRenderer->mVBO); - return done; -} - -//========================================================================== -// -// OpenGLFrameBuffer :: WipeCleanup -// -// Release any resources that were specifically created for the wipe. -// -//========================================================================== - -void OpenGLFrameBuffer::WipeCleanup() -{ - if (ScreenWipe != NULL) - { - delete ScreenWipe; - ScreenWipe = NULL; - } - if (wipestartscreen != NULL) - { - delete wipestartscreen; - wipestartscreen = NULL; - } - if (wipeendscreen != NULL) - { - delete wipeendscreen; - wipeendscreen = NULL; - } - gl_RenderState.ClearLastMaterial(); -} - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper Constructor -// -//========================================================================== -OpenGLFrameBuffer::Wiper::Wiper() -{ - mVertexBuf = new FSimpleVertexBuffer; -} - -OpenGLFrameBuffer::Wiper::~Wiper() -{ - delete mVertexBuf; -} - -void OpenGLFrameBuffer::Wiper::MakeVBO(OpenGLFrameBuffer *fb) -{ - FSimpleVertex make[4]; - FSimpleVertex *ptr = make; - - float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); - float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight()); - - ptr->Set(0, 0, 0, 0, vb); - ptr++; - ptr->Set(0, fb->GetHeight(), 0, 0, 0); - ptr++; - ptr->Set(fb->GetWidth(), 0, 0, ur, vb); - ptr++; - ptr->Set(fb->GetWidth(), fb->GetHeight(), 0, ur, 0); - mVertexBuf->set(make, 4); -} - -// WIPE: CROSSFADE --------------------------------------------------------- - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Crossfade Constructor -// -//========================================================================== - -OpenGLFrameBuffer::Wiper_Crossfade::Wiper_Crossfade() -: Clock(0) -{ -} - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Crossfade :: Run -// -// Fades the old screen into the new one over 32 ticks. -// -//========================================================================== - -bool OpenGLFrameBuffer::Wiper_Crossfade::Run(int ticks, OpenGLFrameBuffer *fb) -{ - Clock += ticks; - - MakeVBO(fb); - - gl_RenderState.SetTextureMode(TM_OPAQUE); - gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); - gl_RenderState.ResetColor(); - gl_RenderState.Apply(); - fb->wipestartscreen->Bind(0, 0, false); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - float a = clamp(Clock / 32.f, 0.f, 1.f); - gl_RenderState.SetColorAlpha(0xffffff, a); - gl_RenderState.Apply(); - fb->wipeendscreen->Bind(0, 0, false); - mVertexBuf->EnableColorArray(false); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f); - gl_RenderState.SetTextureMode(TM_MODULATE); - - return Clock >= 32; -} - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Melt Constructor -// -//========================================================================== - -OpenGLFrameBuffer::Wiper_Melt::Wiper_Melt() -{ - int i, r; - - // setup initial column positions - // (y<0 => not ready to scroll yet) - y[0] = -(M_Random() & 15); - for (i = 1; i < WIDTH; ++i) - { - r = (M_Random()%3) - 1; - y[i] = clamp(y[i-1] + r, -15, 0); - } -} - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Melt :: Run -// -// Fades the old screen into the new one over 32 ticks. -// -//========================================================================== - -int OpenGLFrameBuffer::Wiper_Melt::MakeVBO(int ticks, OpenGLFrameBuffer *fb, bool &done) -{ - FSimpleVertex *make = new FSimpleVertex[321*4]; - FSimpleVertex *ptr = make; - int dy; - - float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); - float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight()); - - ptr->Set(0, 0, 0, 0, vb); - ptr++; - ptr->Set(0, fb->GetHeight(), 0, 0, 0); - ptr++; - ptr->Set(fb->GetWidth(), 0, 0, ur, vb); - ptr++; - ptr->Set(fb->GetWidth(), fb->GetHeight(), 0, ur, 0); - ptr++; - - // Copy the old screen in vertical strips on top of the new one. - while (ticks--) - { - done = true; - for (int i = 0; i < WIDTH; i++) - { - if (y[i] < 0) - { - y[i]++; - done = false; - } - else if (y[i] < HEIGHT) - { - dy = (y[i] < 16) ? y[i] + 1 : 8; - y[i] = MIN(y[i] + dy, HEIGHT); - done = false; - } - if (ticks == 0) - { - struct { - int32_t x; - int32_t y; - } dpt; - struct { - int32_t left; - int32_t top; - int32_t right; - int32_t bottom; - } rect; - - // Only draw for the final tick. - // No need for optimization. Wipes won't ever be drawn with anything else. - - dpt.x = i * fb->GetWidth() / WIDTH; - dpt.y = MAX(0, y[i] * fb->GetHeight() / HEIGHT); - rect.left = dpt.x; - rect.top = 0; - rect.right = (i + 1) * fb->GetWidth() / WIDTH; - rect.bottom = fb->GetHeight() - dpt.y; - if (rect.bottom > rect.top) - { - float tw = (float)FHardwareTexture::GetTexDimension(fb->GetWidth()); - float th = (float)FHardwareTexture::GetTexDimension(fb->GetHeight()); - rect.bottom = fb->GetHeight() - rect.bottom; - rect.top = fb->GetHeight() - rect.top; - - ptr->Set(rect.left, rect.bottom, 0, rect.left / tw, rect.top / th); - ptr++; - ptr->Set(rect.left, rect.top, 0, rect.left / tw, rect.bottom / th); - ptr++; - ptr->Set(rect.right, rect.bottom, 0, rect.right / tw, rect.top / th); - ptr++; - ptr->Set(rect.right, rect.top, 0, rect.right / tw, rect.bottom / th); - ptr++; - } - } - } - } - int numverts = int(ptr - make); - mVertexBuf->set(make, numverts); - delete[] make; - return numverts; -} - -bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb) -{ - bool done = false; - int maxvert = MakeVBO(ticks, fb, done); - - // Draw the new screen on the bottom. - gl_RenderState.SetTextureMode(TM_OPAQUE); - gl_RenderState.ResetColor(); - gl_RenderState.Apply(); - fb->wipeendscreen->Bind(0, 0, false); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - fb->wipestartscreen->Bind(0, 0, false); - gl_RenderState.SetTextureMode(TM_MODULATE); - for (int i = 4; i < maxvert; i += 4) - { - glDrawArrays(GL_TRIANGLE_STRIP, i, 4); - } - return done; -} - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Burn Constructor -// -//========================================================================== - -OpenGLFrameBuffer::Wiper_Burn::Wiper_Burn() -{ - Density = 4; - BurnTime = 0; - memset(BurnArray, 0, sizeof(BurnArray)); - BurnTexture = NULL; -} - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Burn Destructor -// -//========================================================================== - -OpenGLFrameBuffer::Wiper_Burn::~Wiper_Burn() -{ - if (BurnTexture != NULL) - { - delete BurnTexture; - BurnTexture = NULL; - } -} - -//========================================================================== -// -// OpenGLFrameBuffer :: Wiper_Burn :: Run -// -//========================================================================== - -bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb) -{ - bool done; - - MakeVBO(fb); - - BurnTime += ticks; - ticks *= 2; - - // Make the fire burn - done = false; - while (!done && ticks--) - { - Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density); - done = (Density < 0); - } - - if (BurnTexture != NULL) delete BurnTexture; - BurnTexture = new FHardwareTexture(true); - - // Update the burn texture with the new burn data - uint8_t rgb_buffer[WIDTH*HEIGHT*4]; - - const uint8_t *src = BurnArray; - uint32_t *dest = (uint32_t *)rgb_buffer; - for (int y = HEIGHT; y != 0; --y) - { - for (int x = WIDTH; x != 0; --x) - { - uint8_t s = clamp((*src++)*2, 0, 255); - *dest++ = MAKEARGB(s,255,255,255); - } - } - - float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); - float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight()); - - - // Put the initial screen back to the buffer. - gl_RenderState.SetTextureMode(TM_OPAQUE); - gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); - gl_RenderState.ResetColor(); - gl_RenderState.Apply(); - fb->wipestartscreen->Bind(0, 0, false); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - gl_RenderState.SetTextureMode(TM_MODULATE); - gl_RenderState.SetEffect(EFF_BURN); - gl_RenderState.ResetColor(); - gl_RenderState.Apply(); - - // Burn the new screen on top of it. - fb->wipeendscreen->Bind(0, 0, false); - - BurnTexture->CreateTexture(rgb_buffer, WIDTH, HEIGHT, 1, true, 0, "BurnTexture"); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - gl_RenderState.SetEffect(EFF_NONE); - - // The fire may not always stabilize, so the wipe is forced to end - // after an arbitrary maximum time. - return done || (BurnTime > 40); -} diff --git a/src/v_2ddrawer.cpp b/src/v_2ddrawer.cpp index a09ecd5fd..2bbdec8ee 100644 --- a/src/v_2ddrawer.cpp +++ b/src/v_2ddrawer.cpp @@ -242,6 +242,7 @@ bool F2DDrawer::SetStyle(FTexture *tex, DrawParms &parms, PalEntry &vertexcolor, else if (quad.mDrawMode == DTM_Invert) quad.mDrawMode = DTM_InvertOpaque; } quad.mRenderStyle = parms.style; // this contains the blend mode and blend equation settings. + if (parms.burn) quad.mFlags |= DTF_Burn; return true; } diff --git a/src/v_2ddrawer.h b/src/v_2ddrawer.h index f60665e9e..5cef4f719 100644 --- a/src/v_2ddrawer.h +++ b/src/v_2ddrawer.h @@ -53,6 +53,7 @@ public: { DTF_Wrap = 1, DTF_Scissor = 2, + DTF_Burn = 4, }; diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 765b20003..e3babb060 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -511,6 +511,7 @@ bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint3 parms->srcy = 0.; parms->srcwidth = 1.; parms->srcheight = 1.; + parms->burn = false; // Parse the tag list for attributes. (For floating point attributes, // consider that the C ABI dictates that all floats be promoted to @@ -862,6 +863,10 @@ bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint3 case DTA_CellY: parms->celly = ListGetInt(tags); break; + + case DTA_Burn: + parms->burn = true; + break; } tag = ListGetInt(tags); diff --git a/src/v_framebuffer.cpp b/src/v_framebuffer.cpp index 6debe64e0..d0eb961f6 100644 --- a/src/v_framebuffer.cpp +++ b/src/v_framebuffer.cpp @@ -320,9 +320,9 @@ void DFrameBuffer::SetVSync (bool vsync) // //========================================================================== -bool DFrameBuffer::WipeStartScreen(int type) +FTexture *DFrameBuffer::WipeStartScreen() { - return false; + return nullptr; } //========================================================================== @@ -334,8 +334,9 @@ bool DFrameBuffer::WipeStartScreen(int type) // //========================================================================== -void DFrameBuffer::WipeEndScreen() +FTexture *DFrameBuffer::WipeEndScreen() { + return nullptr; } //========================================================================== diff --git a/src/v_video.h b/src/v_video.h index 29d4a7e39..f0dafa3ae 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -47,6 +47,7 @@ struct sector_t; class IShaderProgram; +class FTexture; enum EHWCaps { @@ -205,6 +206,7 @@ enum DTA_SrcWidth, DTA_SrcHeight, DTA_LegacyRenderStyle, // takes an old-style STYLE_* constant instead of an FRenderStyle + DTA_Burn, // activates the burn shader for this element }; @@ -261,6 +263,7 @@ struct DrawParms bool virtBottom; double srcx, srcy; double srcwidth, srcheight; + bool burn; }; struct Va_List @@ -467,8 +470,8 @@ public: virtual sector_t *RenderView(player_t *player) { return nullptr; } // Screen wiping - virtual bool WipeStartScreen(int type); - virtual void WipeEndScreen(); + virtual FTexture *WipeStartScreen(); + virtual FTexture *WipeEndScreen(); virtual bool WipeDo(int ticks); virtual void WipeCleanup(); From e4a40c98ce96257504d6aa751be45561cc92221b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Aug 2018 15:11:47 +0200 Subject: [PATCH 04/22] - wasn't saved --- src/f_wipe.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/f_wipe.cpp b/src/f_wipe.cpp index 1f94c29df..3104e1a3a 100644 --- a/src/f_wipe.cpp +++ b/src/f_wipe.cpp @@ -168,7 +168,6 @@ private: class Wiper_Burn : public Wiper { public: - Wiper_Burn(); ~Wiper_Burn(); bool Run(int ticks) override; void SetTextures(FTexture *startscreen, FTexture *endscreen) override; From 29a54c33b273666fdb127af3188b80512d28eab2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Aug 2018 20:25:07 +0200 Subject: [PATCH 05/22] - temporarily disabled wipe code and removed old function stubs. This still needs work. # Conflicts: # src/gl/data/gl_attributebuffer.cpp --- src/d_main.cpp | 5 ++++- src/v_framebuffer.cpp | 25 ------------------------- src/v_video.h | 2 -- 3 files changed, 4 insertions(+), 28 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 163ef9d64..980deaaa9 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -888,10 +888,12 @@ void D_Display () I_FreezeTime(true); screen->End2D(); auto wipend = screen->WipeEndScreen (); + auto wiper = Wiper::Create(wipe_type); wipestart = I_msTime(); NetUpdate(); // send out any new accumulation + /* do { do @@ -908,7 +910,8 @@ void D_Display () screen->End2DAndUpdate (); NetUpdate (); // [RH] not sure this is needed anymore } while (!done); - screen->WipeCleanup(); + */ + delete wiper; I_FreezeTime(false); GSnd->SetSfxPaused(false, 1); } diff --git a/src/v_framebuffer.cpp b/src/v_framebuffer.cpp index d0eb961f6..0b1338d37 100644 --- a/src/v_framebuffer.cpp +++ b/src/v_framebuffer.cpp @@ -339,31 +339,6 @@ FTexture *DFrameBuffer::WipeEndScreen() return nullptr; } -//========================================================================== -// -// DFrameBuffer :: WipeDo -// -// Draws one frame of a screenwipe. Should be called no more than 35 -// times per second. If called less than that, ticks indicates how many -// ticks have passed since the last call. -// -//========================================================================== - -bool DFrameBuffer::WipeDo(int ticks) -{ - return false; -} - -//========================================================================== -// -// DFrameBuffer :: WipeCleanup -// -//========================================================================== - -void DFrameBuffer::WipeCleanup() -{ -} - //========================================================================== // // DFrameBuffer :: InitPalette diff --git a/src/v_video.h b/src/v_video.h index f0dafa3ae..8fe4a2b2f 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -472,8 +472,6 @@ public: // Screen wiping virtual FTexture *WipeStartScreen(); virtual FTexture *WipeEndScreen(); - virtual bool WipeDo(int ticks); - virtual void WipeCleanup(); virtual void PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) { if (afterBloomDrawEndScene2D) afterBloomDrawEndScene2D(); } From 6e0ed3e930c451de2b11bcbf004d8bcd96be088c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Aug 2018 22:58:21 +0200 Subject: [PATCH 06/22] - crossfade wipe is working again. The other two types still need work. --- src/d_main.cpp | 5 ++--- src/f_wipe.cpp | 12 ++++++------ src/v_video.h | 5 +++++ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 980deaaa9..6f5259fbb 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -889,11 +889,11 @@ void D_Display () screen->End2D(); auto wipend = screen->WipeEndScreen (); auto wiper = Wiper::Create(wipe_type); + wiper->SetTextures(wipe, wipend); wipestart = I_msTime(); NetUpdate(); // send out any new accumulation - /* do { do @@ -903,14 +903,13 @@ void D_Display () diff = (nowtime - wipestart) * 40 / 1000; // Using 35 here feels too slow. } while (diff < 1); wipestart = nowtime; - done = screen->WipeDo (1); screen->Begin2D(); + done = wiper->Run(1); C_DrawConsole (); // console and M_Drawer (); // menu are drawn even on top of wipes screen->End2DAndUpdate (); NetUpdate (); // [RH] not sure this is needed anymore } while (!done); - */ delete wiper; I_FreezeTime(false); GSnd->SetSfxPaused(false, 1); diff --git a/src/f_wipe.cpp b/src/f_wipe.cpp index 3104e1a3a..52c63f766 100644 --- a/src/f_wipe.cpp +++ b/src/f_wipe.cpp @@ -238,8 +238,8 @@ Wiper::~Wiper() bool Wiper_Crossfade::Run(int ticks) { Clock += ticks; - screen->DrawTexture(startScreen, 0, 0, TAG_DONE); - screen->DrawTexture(endScreen, 0, 0, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE); + screen->DrawTexture(startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), TAG_DONE); + screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE); return Clock >= 32; } @@ -274,7 +274,7 @@ Wiper_Melt::Wiper_Melt() bool Wiper_Melt::Run(int ticks) { bool done; - screen->DrawTexture(endScreen, 0, 0, TAG_DONE); + screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Color, PalEntry(255, 255, 0, 0), TAG_DONE); // Copy the old screen in vertical strips on top of the new one. while (ticks--) @@ -319,7 +319,7 @@ bool Wiper_Melt::Run(int ticks) rect.bottom = w - dpt.y; if (rect.bottom > rect.top) { - screen->DrawTexture(startScreen, 0, rect.top, DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, TAG_DONE); + screen->DrawTexture(startScreen, 0, rect.top, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, TAG_DONE); } } } @@ -388,8 +388,8 @@ bool Wiper_Burn::Run(int ticks) } } - screen->DrawTexture(startScreen, 0, 0, TAG_DONE); - screen->DrawTexture(endScreen, 0, 0, DTA_Burn, true, TAG_DONE); + screen->DrawTexture(startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), TAG_DONE); + screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Burn, true, DTA_LegacyRenderStyle, STYLE_Translucent, TAG_DONE); // The fire may not always stabilize, so the wipe is forced to end // after an arbitrary maximum time. diff --git a/src/v_video.h b/src/v_video.h index 8fe4a2b2f..72ae6e0a5 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -459,6 +459,11 @@ public: // Returns true if Begin2D has been called and 2D drawing is now active bool HasBegun2D() { return isIn2D; } + // This is overridable in case Vulkan does it differently. + virtual bool RenderTextureIsFlipped() const + { + return true; + } // Report a game restart void InitPalette(); From 775ddfa0a80a942e96fc2410c0fed3c52493873a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Aug 2018 23:26:35 +0200 Subject: [PATCH 07/22] - fixed the melt wipe. --- src/f_wipe.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/f_wipe.cpp b/src/f_wipe.cpp index 52c63f766..9d6214fec 100644 --- a/src/f_wipe.cpp +++ b/src/f_wipe.cpp @@ -274,7 +274,7 @@ Wiper_Melt::Wiper_Melt() bool Wiper_Melt::Run(int ticks) { bool done; - screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Color, PalEntry(255, 255, 0, 0), TAG_DONE); + screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), TAG_DONE); // Copy the old screen in vertical strips on top of the new one. while (ticks--) @@ -311,15 +311,15 @@ bool Wiper_Melt::Run(int ticks) int w = startScreen->GetWidth(); int h = startScreen->GetHeight(); - dpt.x = i * h / WIDTH; + dpt.x = i * w / WIDTH; dpt.y = MAX(0, y[i] * h / HEIGHT); rect.left = dpt.x; rect.top = 0; rect.right = (i + 1) * w / WIDTH; - rect.bottom = w - dpt.y; + rect.bottom = h - dpt.y; if (rect.bottom > rect.top) { - screen->DrawTexture(startScreen, 0, rect.top, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, TAG_DONE); + screen->DrawTexture(startScreen, 0, dpt.y, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, TAG_DONE); } } } From bec588eaf45ea12a9f5c73dae752195d9d221622 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Aug 2018 23:36:13 +0200 Subject: [PATCH 08/22] - moved the two remaining functions from gl_wipe.cpp to gl_framebuffer.cpp and deleted the file. The single most hideous thing in the GL renderer is finally gone. :) --- src/CMakeLists.txt | 1 - src/gl/system/gl_framebuffer.cpp | 68 ++++++++++++++++++++ src/gl/system/gl_wipe.cpp | 104 ------------------------------- 3 files changed, 68 insertions(+), 105 deletions(-) delete mode 100644 src/gl/system/gl_wipe.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0c880459d..110c20fc3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1061,7 +1061,6 @@ set (PCH_SOURCES gl_load/gl_interface.cpp gl/system/gl_framebuffer.cpp gl/system/gl_debug.cpp - gl/system/gl_wipe.cpp gl/textures/gl_hwtexture.cpp gl/textures/gl_samplers.cpp hwrenderer/data/flatvertices.cpp diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 2af278c5f..729ecad1f 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -483,3 +483,71 @@ void OpenGLFrameBuffer::PostProcessScene(int fixedcm, const std::functionPostProcessScene(fixedcm, afterBloomDrawEndScene2D); } + +//========================================================================== +// +// This is just a wrapper around the hardware texture being extracted below so that it can be passed to the 2D code. +// +//========================================================================== + +class FGLWipeTexture : public FTexture +{ +public: + + FGLWipeTexture(int w, int h) + { + Width = w; + Height = h; + WidthBits = 4; + UseType = ETextureType::SWCanvas; + bNoCompress = true; + SystemTexture[0] = screen->CreateHardwareTexture(this); + } + +}; + +//========================================================================== +// +// OpenGLFrameBuffer :: WipeStartScreen +// +// Called before the current screen has started rendering. This needs to +// save what was drawn the previous frame so that it can be animated into +// what gets drawn this frame. +// +//========================================================================== + +FTexture *OpenGLFrameBuffer::WipeStartScreen() +{ + const auto &viewport = screen->mScreenViewport; + + FGLWipeTexture *tex = new FGLWipeTexture(viewport.width, viewport.height); + tex->SystemTexture[0]->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, 0, "WipeStartScreen"); + glFinish(); + static_cast(tex->SystemTexture[0])->Bind(0, false, false); + + GLRenderer->mBuffers->BindCurrentFB(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); + return tex; +} + +//========================================================================== +// +// OpenGLFrameBuffer :: WipeEndScreen +// +// The screen we want to animate to has just been drawn. +// +//========================================================================== + +FTexture *OpenGLFrameBuffer::WipeEndScreen() +{ + GLRenderer->Flush(); + const auto &viewport = screen->mScreenViewport; + FGLWipeTexture *tex = new FGLWipeTexture(viewport.width, viewport.height); + tex->SystemTexture[0]->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeEndScreen"); + glFinish(); + static_cast(tex->SystemTexture[0])->Bind(0, false, false); + GLRenderer->mBuffers->BindCurrentFB(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); + return tex; +} + diff --git a/src/gl/system/gl_wipe.cpp b/src/gl/system/gl_wipe.cpp deleted file mode 100644 index bf1c6b45a..000000000 --- a/src/gl/system/gl_wipe.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// -//--------------------------------------------------------------------------- -// -// Copyright(C) 2008-2016 Christoph Oelckers -// All rights reserved. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//-------------------------------------------------------------------------- -// -/* -** Screen wipe stuff -** -*/ - -#include "gl_load/gl_system.h" -#include "f_wipe.h" -#include "m_random.h" -#include "w_wad.h" -#include "v_palette.h" -#include "templates.h" - -#include "gl_load/gl_interface.h" -#include "gl/renderer/gl_renderer.h" -#include "gl/renderer/gl_renderstate.h" -#include "gl/renderer/gl_renderbuffers.h" -#include "gl/system/gl_framebuffer.h" -#include "gl/textures/gl_samplers.h" -#include "gl/data/gl_vertexbuffer.h" - - -class FGLWipeTexture : public FTexture -{ -public: - - FGLWipeTexture(int w, int h) - { - Width = w; - Height = h; - WidthBits = 4; - UseType = ETextureType::SWCanvas; - bNoCompress = true; - SystemTexture[0] = screen->CreateHardwareTexture(this); - } - - // This is just a wrapper around the hardware texture being extracted below so that it can be passed to the 2D code. -}; - -//========================================================================== -// -// OpenGLFrameBuffer :: WipeStartScreen -// -// Called before the current screen has started rendering. This needs to -// save what was drawn the previous frame so that it can be animated into -// what gets drawn this frame. -// -//========================================================================== - -FTexture *OpenGLFrameBuffer::WipeStartScreen() -{ - const auto &viewport = screen->mScreenViewport; - - FGLWipeTexture *tex = new FGLWipeTexture(viewport.width, viewport.height); - tex->SystemTexture[0]->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, 0, "WipeStartScreen"); - glFinish(); - static_cast(tex->SystemTexture[0])->Bind(0, false, false); - - GLRenderer->mBuffers->BindCurrentFB(); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); - return tex; -} - -//========================================================================== -// -// OpenGLFrameBuffer :: WipeEndScreen -// -// The screen we want to animate to has just been drawn. -// -//========================================================================== - -FTexture *OpenGLFrameBuffer::WipeEndScreen() -{ - GLRenderer->Flush(); - const auto &viewport = screen->mScreenViewport; - FGLWipeTexture *tex = new FGLWipeTexture(viewport.width, viewport.height); - tex->SystemTexture[0]->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeEndScreen"); - glFinish(); - static_cast(tex->SystemTexture[0])->Bind(0, false, false); - GLRenderer->mBuffers->BindCurrentFB(); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); - return tex; -} - From bec1825e8c52239db6e60e6e203d433d914916cc Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Sep 2018 12:30:40 +0200 Subject: [PATCH 09/22] - fixed: The wipe textures need to be rendered with DTA_Masked set to false because they contain bogus alpha values where a stencil got rendered. --- src/f_wipe.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/f_wipe.cpp b/src/f_wipe.cpp index 9d6214fec..6d34936fd 100644 --- a/src/f_wipe.cpp +++ b/src/f_wipe.cpp @@ -238,8 +238,8 @@ Wiper::~Wiper() bool Wiper_Crossfade::Run(int ticks) { Clock += ticks; - screen->DrawTexture(startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), TAG_DONE); - screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE); + screen->DrawTexture(startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE); + screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, DTA_Alpha, clamp(Clock / 32.f, 0.f, 1.f), TAG_DONE); return Clock >= 32; } @@ -274,7 +274,7 @@ Wiper_Melt::Wiper_Melt() bool Wiper_Melt::Run(int ticks) { bool done; - screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), TAG_DONE); + screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE); // Copy the old screen in vertical strips on top of the new one. while (ticks--) @@ -319,7 +319,7 @@ bool Wiper_Melt::Run(int ticks) rect.bottom = h - dpt.y; if (rect.bottom > rect.top) { - screen->DrawTexture(startScreen, 0, dpt.y, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, TAG_DONE); + screen->DrawTexture(startScreen, 0, dpt.y, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_ClipLeft, rect.left, DTA_ClipRight, rect.right, DTA_Masked, false, TAG_DONE); } } } @@ -388,8 +388,8 @@ bool Wiper_Burn::Run(int ticks) } } - screen->DrawTexture(startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), TAG_DONE); - screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Burn, true, DTA_LegacyRenderStyle, STYLE_Translucent, TAG_DONE); + screen->DrawTexture(startScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Masked, false, TAG_DONE); + screen->DrawTexture(endScreen, 0, 0, DTA_FlipY, screen->RenderTextureIsFlipped(), DTA_Burn, true, DTA_Masked, false, TAG_DONE); // The fire may not always stabilize, so the wipe is forced to end // after an arbitrary maximum time. From b570f2859772686924f89b0f7c1babd2f6c38124 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Sep 2018 12:43:13 +0200 Subject: [PATCH 10/22] - restored block of code that got deleted by a bad merge of a cherry-picked commit. --- src/gl/renderer/gl_renderer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 17cd6b6b1..a27effd06 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -428,6 +428,12 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer) const auto &mScreenViewport = screen->mScreenViewport; glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); + HWViewpointUniforms matrices; + matrices.SetDefaults(); + matrices.mProjectionMatrix.ortho(0, screen->GetWidth(), screen->GetHeight(), 0, -1.0f, 1.0f); + matrices.CalcDependencies(); + GLRenderer->mShaderManager->ApplyMatrices(&matrices, NORMAL_PASS); + glDisable(GL_DEPTH_TEST); // Korshun: ENABLE AUTOMAP ANTIALIASING!!! From 207988bb1bf38fac6d76df65d9ef9fdafa60a916 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 2 Sep 2018 15:15:38 +0300 Subject: [PATCH 11/22] - fixed crash when wipe type is set to none --- src/d_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 6f5259fbb..4f023e81e 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -868,7 +868,7 @@ void D_Display () GSnd->DrawWaveDebug(snd_drawoutput); } - if (!wipe || NoWipe < 0) + if (!wipe || NoWipe < 0 || wipe_type == wipe_None) { NetUpdate (); // send out any new accumulation // normal update From 4571aa52f05a5bd9d627cbde585bd708f5ded216 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Sep 2018 18:20:08 +0200 Subject: [PATCH 12/22] - fixed bad code for OP_SRL_KR. --- src/scripting/vm/vmexec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index feaf80243..fa6b267af 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -1033,7 +1033,7 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) NEXTOP; OP(SRL_KR): ASSERTD(a); ASSERTKD(B); ASSERTD(C); - reg.d[a] = (unsigned)konstd[B] >> C; + reg.d[a] = (unsigned)konstd[B] >> reg.d[C]; NEXTOP; OP(SRA_RR): From 5e39890118c650fb2161b79f824890ac70402d5f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 11 Aug 2018 18:25:15 +0200 Subject: [PATCH 13/22] - use a uniform buffer for per-scene data like rotation matrices. --- src/CMakeLists.txt | 1 + src/gl/data/gl_viewpointbuffer.cpp | 173 +++++++++++++++++++++++++++ src/gl/data/gl_viewpointbuffer.h | 35 ++++++ src/gl/renderer/gl_renderer.cpp | 35 ++---- src/gl/renderer/gl_renderer.h | 34 +++--- src/gl/scene/gl_drawinfo.cpp | 1 + src/gl/scene/gl_drawinfo.h | 1 + src/gl/scene/gl_portal.cpp | 8 +- src/gl/scene/gl_scene.cpp | 25 ++-- src/gl/scene/gl_skydome.cpp | 1 - src/gl/shaders/gl_shader.cpp | 109 ++++------------- src/gl/shaders/gl_shader.h | 15 --- src/hwrenderer/data/shaderuniforms.h | 3 +- wadsrc/static/shaders/glsl/main.vp | 4 + 14 files changed, 278 insertions(+), 167 deletions(-) create mode 100644 src/gl/data/gl_viewpointbuffer.cpp create mode 100644 src/gl/data/gl_viewpointbuffer.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 110c20fc3..30a98487b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1044,6 +1044,7 @@ set (PCH_SOURCES g_statusbar/shared_sbar.cpp gl/data/gl_vertexbuffer.cpp gl/data/gl_uniformbuffer.cpp + gl/data/gl_viewpointbuffer.cpp gl/dynlights/gl_lightbuffer.cpp gl/dynlights/gl_shadowmap.cpp gl/models/gl_models.cpp diff --git a/src/gl/data/gl_viewpointbuffer.cpp b/src/gl/data/gl_viewpointbuffer.cpp new file mode 100644 index 000000000..7b9039bf3 --- /dev/null +++ b/src/gl/data/gl_viewpointbuffer.cpp @@ -0,0 +1,173 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2018 Christoph Oelckers +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_viewpointbuffer.cpp +** Buffer data maintenance for per viewpoint uniform data +** +**/ + +#include "gl_load/gl_system.h" +#include "gl_load/gl_interface.h" +#include "hwrenderer/data/shaderuniforms.h" +#include "hwrenderer/scene/hw_viewpointuniforms.h" +#include "gl_viewpointbuffer.h" + +static const int INITIAL_BUFFER_SIZE = 100; // 100 viewpoints per frame should nearly always be enough + +GLViewpointBuffer::GLViewpointBuffer() +{ + mBufferSize = INITIAL_BUFFER_SIZE; + mBlockAlign = ((sizeof(HWViewpointUniforms) / gl.uniformblockalignment) + 1) * gl.uniformblockalignment; + mByteSize = mBufferSize * mBlockAlign; + Allocate(); + Clear(); + mLastMappedIndex = UINT_MAX; +} + +GLViewpointBuffer::~GLViewpointBuffer() +{ + glBindBuffer(GL_UNIFORM_BUFFER, 0); + glDeleteBuffers(1, &mBufferId); +} + +void GLViewpointBuffer::Allocate() +{ + glGenBuffers(1, &mBufferId); + glBindBufferBase(GL_UNIFORM_BUFFER, VIEWPOINT_BINDINGPOINT, mBufferId); + glBindBuffer(GL_UNIFORM_BUFFER, mBufferId); // Note: Some older AMD drivers don't do that in glBindBufferBase, as they should. + if (gl.flags & RFL_BUFFER_STORAGE) + { + glBufferStorage(GL_UNIFORM_BUFFER, mByteSize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); + mBufferPointer = glMapBufferRange(GL_UNIFORM_BUFFER, 0, mByteSize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT); + } + else + { + glBufferData(GL_UNIFORM_BUFFER, mByteSize, NULL, GL_STATIC_DRAW); + mBufferPointer = NULL; + } +} + +void GLViewpointBuffer::CheckSize() +{ + if (mUploadIndex >= mBufferSize) + { + // reallocate the buffer with twice the size + unsigned int oldbuffer = mBufferId; + + mBufferSize *= 2; + mByteSize *= 2; + + // first unmap the old buffer + glBindBuffer(GL_UNIFORM_BUFFER, mBufferId); + glUnmapBuffer(GL_UNIFORM_BUFFER); + + Allocate(); + glBindBuffer(GL_COPY_READ_BUFFER, oldbuffer); + + // copy contents and delete the old buffer. + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_UNIFORM_BUFFER, 0, 0, mByteSize / 2); // old size is half of the current one. + glBindBuffer(GL_COPY_READ_BUFFER, 0); + glDeleteBuffers(1, &oldbuffer); + } +} + +void GLViewpointBuffer::Map() +{ + if (!(gl.flags & RFL_BUFFER_STORAGE)) + { + glBindBuffer(GL_UNIFORM_BUFFER, mBufferId); + mBufferPointer = (float*)glMapBufferRange(GL_UNIFORM_BUFFER, 0, mByteSize, GL_MAP_WRITE_BIT); + } +} + +void GLViewpointBuffer::Unmap() +{ + if (!(gl.flags & RFL_BUFFER_STORAGE)) + { + glBindBuffer(GL_UNIFORM_BUFFER, mBufferId); + glUnmapBuffer(GL_UNIFORM_BUFFER); + mBufferPointer = nullptr; + } + else + { + glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT); + } +} + +int GLViewpointBuffer::Bind(unsigned int index) +{ + if (index != mLastMappedIndex) + { + mLastMappedIndex = index; + glBindBufferRange(GL_UNIFORM_BUFFER, VIEWPOINT_BINDINGPOINT, mBufferId, index * mBlockAlign, mBlockAlign); + + // Update the viewpoint-related clip plane setting. + auto *vp = (HWViewpointUniforms*)(((char*)mBufferPointer) + mUploadIndex * mBlockAlign); + if (!(gl.flags & RFL_NO_CLIP_PLANES)) + { + if (index > 0 && (vp->mClipHeightDirection != 0.f || vp->mClipLine.X > -10000000.0f)) + { + glEnable(GL_CLIP_DISTANCE0); + } + else + { + glDisable(GL_CLIP_DISTANCE0); + } + } + } + return index; +} + +void GLViewpointBuffer::Set2D(int width, int height) +{ + if (width != m2DWidth || height != m2DHeight) + { + HWViewpointUniforms matrices; + matrices.SetDefaults(); + matrices.mProjectionMatrix.ortho(0, width, height, 0, -1.0f, 1.0f); + matrices.CalcDependencies(); + Map(); + memcpy(mBufferPointer, &matrices, sizeof(matrices)); + Unmap(); + m2DWidth = width; + m2DHeight = height; + mLastMappedIndex = -1; + } + Bind(0); +} + +int GLViewpointBuffer::SetViewpoint(HWViewpointUniforms *vp) +{ + CheckSize(); + Map(); + memcpy(((char*)mBufferPointer) + mUploadIndex * mBlockAlign, vp, sizeof(*vp)); + Unmap(); + + return Bind(mUploadIndex++); +} + +void GLViewpointBuffer::Clear() +{ + // Index 0 is reserved for the 2D projection. + mUploadIndex = 1; +} + diff --git a/src/gl/data/gl_viewpointbuffer.h b/src/gl/data/gl_viewpointbuffer.h new file mode 100644 index 000000000..208a42a5d --- /dev/null +++ b/src/gl/data/gl_viewpointbuffer.h @@ -0,0 +1,35 @@ + +#include "tarray.h" + +struct HWViewpointUniforms; + +class GLViewpointBuffer +{ + unsigned int mBufferId; + unsigned int mBufferSize; + unsigned int mBlockAlign; + unsigned int mUploadIndex; + unsigned int mLastMappedIndex; + unsigned int mByteSize; + void * mBufferPointer; + + unsigned int m2DWidth = ~0u, m2DHeight = ~0u; + + unsigned int mBlockSize; + + void CheckSize(); + void Allocate(); + +public: + + GLViewpointBuffer(); + ~GLViewpointBuffer(); + void Clear(); + void Map(); + void Unmap(); + int Bind(unsigned int index); + void Set2D(int width, int height); + int SetViewpoint(HWViewpointUniforms *vp); + unsigned int GetBlockSize() const { return mBlockSize; } +}; + diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index a27effd06..0bcdf7db6 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -57,6 +57,7 @@ #include "gl/shaders/gl_postprocessshaderinstance.h" #include "gl/textures/gl_samplers.h" #include "gl/dynlights/gl_lightbuffer.h" +#include "gl/data/gl_viewpointbuffer.h" #include "r_videoscale.h" EXTERN_CVAR(Int, screenblocks) @@ -79,21 +80,6 @@ extern bool NoInterpolateView; FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) { framebuffer = fb; - mMirrorCount = 0; - mPlaneMirrorCount = 0; - mVBO = nullptr; - mSkyVBO = nullptr; - mShaderManager = nullptr; - mLights = nullptr; - mBuffers = nullptr; - mScreenBuffers = nullptr; - mSaveBuffers = nullptr; - mPresentShader = nullptr; - mPresent3dCheckerShader = nullptr; - mPresent3dColumnShader = nullptr; - mPresent3dRowShader = nullptr; - mShadowMapShader = nullptr; - mCustomPostProcessShaders = nullptr; } void FGLRenderer::Initialize(int width, int height) @@ -118,6 +104,7 @@ void FGLRenderer::Initialize(int width, int height) mVBO = new FFlatVertexBuffer(width, height); mSkyVBO = new FSkyVertexBuffer; mLights = new FLightBuffer(); + mViewpoints = new GLViewpointBuffer; gl_RenderState.SetVertexBuffer(mVBO); mFBID = 0; mOldFBID = 0; @@ -132,11 +119,12 @@ FGLRenderer::~FGLRenderer() FlushModels(); AActor::DeleteAllAttachedLights(); FMaterial::FlushAll(); - if (mShaderManager != NULL) delete mShaderManager; - if (mSamplerManager != NULL) delete mSamplerManager; - if (mVBO != NULL) delete mVBO; - if (mSkyVBO != NULL) delete mSkyVBO; - if (mLights != NULL) delete mLights; + if (mShaderManager != nullptr) delete mShaderManager; + if (mSamplerManager != nullptr) delete mSamplerManager; + if (mVBO != nullptr) delete mVBO; + if (mSkyVBO != nullptr) delete mSkyVBO; + if (mLights != nullptr) delete mLights; + if (mViewpoints != nullptr) delete mViewpoints; if (mFBID != 0) glDeleteFramebuffers(1, &mFBID); if (mVAOID != 0) { @@ -427,12 +415,7 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer) mBuffers->BindCurrentFB(); const auto &mScreenViewport = screen->mScreenViewport; glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); - - HWViewpointUniforms matrices; - matrices.SetDefaults(); - matrices.mProjectionMatrix.ortho(0, screen->GetWidth(), screen->GetHeight(), 0, -1.0f, 1.0f); - matrices.CalcDependencies(); - GLRenderer->mShaderManager->ApplyMatrices(&matrices, NORMAL_PASS); + GLRenderer->mViewpoints->Set2D(screen->GetWidth(), screen->GetHeight()); glDisable(GL_DEPTH_TEST); diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 7551d4428..3a48a9ccb 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -35,6 +35,7 @@ class FHardwareTexture; class FShadowMapShader; class FCustomPostProcessShaders; class SWSceneDrawer; +class GLViewpointBuffer; struct FRenderViewpoint; #define NOQUEUE nullptr // just some token to be used as a placeholder @@ -51,33 +52,34 @@ class FGLRenderer public: OpenGLFrameBuffer *framebuffer; - int mMirrorCount; - int mPlaneMirrorCount; - FShaderManager *mShaderManager; - FSamplerManager *mSamplerManager; + int mMirrorCount = 0; + int mPlaneMirrorCount = 0; + FShaderManager *mShaderManager = nullptr; + FSamplerManager *mSamplerManager = nullptr; unsigned int mFBID; unsigned int mVAOID; unsigned int PortalQueryObject; int mOldFBID; - FGLRenderBuffers *mBuffers; - FGLRenderBuffers *mScreenBuffers; - FGLRenderBuffers *mSaveBuffers; - FPresentShader *mPresentShader; - FPresent3DCheckerShader *mPresent3dCheckerShader; - FPresent3DColumnShader *mPresent3dColumnShader; - FPresent3DRowShader *mPresent3dRowShader; - FShadowMapShader *mShadowMapShader; - FCustomPostProcessShaders *mCustomPostProcessShaders; + FGLRenderBuffers *mBuffers = nullptr; + FGLRenderBuffers *mScreenBuffers = nullptr; + FGLRenderBuffers *mSaveBuffers = nullptr; + FPresentShader *mPresentShader = nullptr; + FPresent3DCheckerShader *mPresent3dCheckerShader = nullptr; + FPresent3DColumnShader *mPresent3dColumnShader = nullptr; + FPresent3DRowShader *mPresent3dRowShader = nullptr; + FShadowMapShader *mShadowMapShader = nullptr; + FCustomPostProcessShaders *mCustomPostProcessShaders = nullptr; FShadowMap mShadowMap; //FRotator mAngles; - FFlatVertexBuffer *mVBO; - FSkyVertexBuffer *mSkyVBO; - FLightBuffer *mLights; + FFlatVertexBuffer *mVBO = nullptr; + FSkyVertexBuffer *mSkyVBO = nullptr; + FLightBuffer *mLights = nullptr; + GLViewpointBuffer *mViewpoints = nullptr; SWSceneDrawer *swdrawer = nullptr; FPortalSceneState mPortalState; diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index fbc5aa60c..7cddfdec4 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -213,6 +213,7 @@ void FDrawInfo::StartScene() decals[0].Clear(); decals[1].Clear(); hudsprites.Clear(); + vpIndex = 0; // Fullbright information needs to be propagated from the main view. if (outer != nullptr) FullbrightFlags = outer->FullbrightFlags; diff --git a/src/gl/scene/gl_drawinfo.h b/src/gl/scene/gl_drawinfo.h index e41e718a2..702c3981c 100644 --- a/src/gl/scene/gl_drawinfo.h +++ b/src/gl/scene/gl_drawinfo.h @@ -38,6 +38,7 @@ struct FDrawInfo : public HWDrawInfo HWDrawList drawlists[GLDL_TYPES]; TArray hudsprites; // These may just be stored by value. TArray decals[2]; // the second slot is for mirrors which get rendered in a separate pass. + int vpIndex; void ApplyVPUniforms() override; diff --git a/src/gl/scene/gl_portal.cpp b/src/gl/scene/gl_portal.cpp index 6f721a7dc..3ef4e2e3e 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -42,6 +42,7 @@ #include "gl/data/gl_vertexbuffer.h" #include "hwrenderer/scene/hw_clipper.h" #include "gl/scene/gl_portal.h" +#include "gl/data/gl_viewpointbuffer.h" //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -66,9 +67,7 @@ void GLPortal::ClearScreen(HWDrawInfo *di) { bool multi = !!glIsEnabled(GL_MULTISAMPLE); - di->VPUniforms.mViewMatrix.loadIdentity(); - di->VPUniforms.mProjectionMatrix.ortho(0, SCREENWIDTH, SCREENHEIGHT, 0, -1.0f, 1.0f); - di->ApplyVPUniforms(); + GLRenderer->mViewpoints->Set2D(SCREENWIDTH, SCREENHEIGHT); gl_RenderState.SetColor(0, 0, 0); gl_RenderState.Apply(); @@ -236,7 +235,7 @@ void GLPortal::End(HWDrawInfo *di, bool usestencil) Clocker c(PortalAll); di = static_cast(di)->EndDrawInfo(); - di->ApplyVPUniforms(); + GLRenderer->mViewpoints->Bind(static_cast(di)->vpIndex); if (usestencil) { auto &vp = di->Viewpoint; @@ -295,7 +294,6 @@ void GLPortal::End(HWDrawInfo *di, bool usestencil) // Restore the old view if (vp.camera != nullptr) vp.camera->renderflags = (vp.camera->renderflags & ~RF_MAYBEINVISIBLE) | savedvisibility; - di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(mState->MirrorFlag & 1), !!(mState->PlaneMirrorFlag & 1)); // This draws a valid z-buffer into the stencil's contents to ensure it // doesn't get overwritten by the level's geometry. diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 4e1aa844b..8c6b5ce39 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -50,6 +50,7 @@ #include "gl/renderer/gl_renderstate.h" #include "gl/renderer/gl_renderbuffers.h" #include "gl/data/gl_vertexbuffer.h" +#include "gl/data/gl_viewpointbuffer.h" #include "hwrenderer/scene/hw_clipper.h" #include "hwrenderer/scene/hw_portal.h" #include "gl/scene/gl_drawinfo.h" @@ -76,19 +77,7 @@ EXTERN_CVAR (Bool, r_drawvoxels) void FDrawInfo::ApplyVPUniforms() { VPUniforms.CalcDependencies(); - GLRenderer->mShaderManager->ApplyMatrices(&VPUniforms, gl_RenderState.GetPassType()); - - if (!(gl.flags & RFL_NO_CLIP_PLANES)) - { - if (VPUniforms.mClipHeightDirection != 0.f || VPUniforms.mClipLine.X > -10000000.0f) - { - glEnable(GL_CLIP_DISTANCE0); - } - else - { - glDisable(GL_CLIP_DISTANCE0); - } - } + vpIndex = GLRenderer->mViewpoints->SetViewpoint(&VPUniforms); } @@ -337,7 +326,7 @@ void FDrawInfo::DrawScene(int drawmode) GLRenderer->mBuffers->BindSceneFB(true); gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount()); gl_RenderState.Apply(); - ApplyVPUniforms(); + GLRenderer->mViewpoints->Bind(vpIndex); } // Handle all portals after rendering the opaque objects but before @@ -383,9 +372,10 @@ void FDrawInfo::DrawEndScene2D(sector_t * viewsector) const bool renderHUDModel = IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player); auto vrmode = VRMode::GetVRMode(true); - VPUniforms.mViewMatrix.loadIdentity(); - VPUniforms.mProjectionMatrix = vrmode->GetHUDSpriteProjection(); - ApplyVPUniforms(); + HWViewpointUniforms vp = VPUniforms; + vp.mViewMatrix.loadIdentity(); + vp.mProjectionMatrix = vrmode->GetHUDSpriteProjection(); + GLRenderer->mViewpoints->SetViewpoint(&vp); glDisable(GL_DEPTH_TEST); glDisable(GL_MULTISAMPLE); @@ -459,6 +449,7 @@ sector_t * FGLRenderer::RenderViewpoint (FRenderViewpoint &mainvp, AActor * came // Render (potentially) multiple views for stereo 3d // Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode. auto vrmode = VRMode::GetVRMode(mainview && toscreen); + mViewpoints->Clear(); for (int eye_ix = 0; eye_ix < vrmode->mEyeCount; ++eye_ix) { const auto &eye = vrmode->mEyes[eye_ix]; diff --git a/src/gl/scene/gl_skydome.cpp b/src/gl/scene/gl_skydome.cpp index 9feaad5b0..afc4d16dd 100644 --- a/src/gl/scene/gl_skydome.cpp +++ b/src/gl/scene/gl_skydome.cpp @@ -269,7 +269,6 @@ void GLSkyPortal::DrawContents(HWDrawInfo *di) } } gl_RenderState.SetVertexBuffer(GLRenderer->mVBO); - di->ApplyVPUniforms(); ::level.lightmode = oldlightmode; gl_RenderState.SetDepthClamp(oldClamp); } diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index 5f3fae934..e0d656038 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -49,18 +49,30 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * static char buffer[10000]; FString error; - FString i_data; - - // these settings are actually pointless but there seem to be some old ATI drivers that fail to compile the shader without setting the precision here. - i_data += "precision highp int;\n"; - i_data += "precision highp float;\n"; + FString i_data = R"( + // these settings are actually pointless but there seem to be some old ATI drivers that fail to compile the shader without setting the precision here. + precision highp int; + precision highp float; - i_data += "uniform vec4 uCameraPos;\n"; + // This must match the HWViewpointUniforms struct + layout(std140) uniform ViewpointUBO { + mat4 ProjectionMatrix; + mat4 ViewMatrix; + mat4 NormalViewMatrix; + + vec4 uCameraPos; + vec4 uClipLine; + + float uGlobVis; // uGlobVis = R_GetGlobVis(r_visibility) / 32.0 + int uPalLightLevels; + int uViewHeight; // Software fuzz scaling + float uClipHeight; + float uClipHeightDirection; + }; + )"; + i_data += "uniform int uTextureMode;\n"; - i_data += "uniform float uClipHeight;\n"; - i_data += "uniform float uClipHeightDirection;\n"; i_data += "uniform vec2 uClipSplit;\n"; - i_data += "uniform vec4 uClipLine;\n"; i_data += "uniform float uAlphaThreshold;\n"; // colors @@ -87,15 +99,10 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * i_data += "#define uLightFactor uLightAttr.g\n"; i_data += "#define uLightDist uLightAttr.r\n"; i_data += "uniform int uFogEnabled;\n"; - i_data += "uniform int uPalLightLevels;\n"; - i_data += "uniform float uGlobVis;\n"; // uGlobVis = R_GetGlobVis(r_visibility) / 32.0 // dynamic lights i_data += "uniform int uLightIndex;\n"; - // Software fuzz scaling - i_data += "uniform int uViewHeight;\n"; - // Blinn glossiness and specular level i_data += "uniform vec2 uSpecularMaterial;\n"; @@ -107,10 +114,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * i_data += "#endif\n"; // matrices - i_data += "uniform mat4 ProjectionMatrix;\n"; - i_data += "uniform mat4 ViewMatrix;\n"; i_data += "uniform mat4 ModelMatrix;\n"; - i_data += "uniform mat4 NormalViewMatrix;\n"; i_data += "uniform mat4 NormalModelMatrix;\n"; i_data += "uniform mat4 TextureMatrix;\n"; @@ -348,28 +352,20 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * lights_index = glGetUniformLocation(hShader, "lights"); fakevb_index = glGetUniformLocation(hShader, "fakeVB"); - projectionmatrix_index = glGetUniformLocation(hShader, "ProjectionMatrix"); - viewmatrix_index = glGetUniformLocation(hShader, "ViewMatrix"); modelmatrix_index = glGetUniformLocation(hShader, "ModelMatrix"); texturematrix_index = glGetUniformLocation(hShader, "TextureMatrix"); vertexmatrix_index = glGetUniformLocation(hShader, "uQuadVertices"); texcoordmatrix_index = glGetUniformLocation(hShader, "uQuadTexCoords"); - normalviewmatrix_index = glGetUniformLocation(hShader, "NormalViewMatrix"); normalmodelmatrix_index = glGetUniformLocation(hShader, "NormalModelMatrix"); quadmode_index = glGetUniformLocation(hShader, "uQuadMode"); - viewheight_index = glGetUniformLocation(hShader, "uViewHeight"); - camerapos_index = glGetUniformLocation(hShader, "uCameraPos"); - pallightlevels_index = glGetUniformLocation(hShader, "uPalLightLevels"); - globvis_index = glGetUniformLocation(hShader, "uGlobVis"); - clipheight_index = glGetUniformLocation(hShader, "uClipHeight"); - clipheightdirection_index = glGetUniformLocation(hShader, "uClipHeightDirection"); - clipline_index = glGetUniformLocation(hShader, "uClipLine"); if (lightbuffertype == GL_UNIFORM_BUFFER) { int tempindex = glGetUniformBlockIndex(hShader, "LightBufferUBO"); if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, LIGHTBUF_BINDINGPOINT); } + int tempindex = glGetUniformBlockIndex(hShader, "ViewpointUBO"); + if (tempindex != -1) glUniformBlockBinding(hShader, tempindex, VIEWPOINT_BINDINGPOINT); glUseProgram(hShader); if (quadmode_index > 0) glUniform1i(quadmode_index, 0); @@ -448,27 +444,6 @@ FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderP return shader; } -//========================================================================== -// -// -// -//========================================================================== - -void FShader::ApplyMatrices(HWViewpointUniforms *u) -{ - Bind(); - glUniformMatrix4fv(projectionmatrix_index, 1, false, u->mProjectionMatrix.get()); - glUniformMatrix4fv(viewmatrix_index, 1, false, u->mViewMatrix.get()); - glUniformMatrix4fv(normalviewmatrix_index, 1, false, u->mNormalViewMatrix.get()); - - glUniform4fv(camerapos_index, 1, &u->mCameraPos[0]); - glUniform1i(viewheight_index, u->mViewHeight); - glUniform1i(pallightlevels_index, u->mPalLightLevels); - glUniform1f(globvis_index, u->mGlobVis); - glUniform1f(clipheight_index, u->mClipHeight); - glUniform1f(clipheightdirection_index, u->mClipHeightDirection); -} - //========================================================================== // // @@ -566,15 +541,6 @@ FShader *FShaderManager::Get(unsigned int eff, bool alphateston, EPassType passT return nullptr; } -void FShaderManager::ApplyMatrices(HWViewpointUniforms *u, EPassType passType) -{ - if (passType < mPassShaders.Size()) - mPassShaders[passType]->ApplyMatrices(u); - - if (mActiveShader) - mActiveShader->Bind(); -} - //========================================================================== // // @@ -706,35 +672,6 @@ FShader *FShaderCollection::BindEffect(int effect) } -//========================================================================== -// -// -// -//========================================================================== -EXTERN_CVAR(Int, gl_fuzztype) - -void FShaderCollection::ApplyMatrices(HWViewpointUniforms *u) -{ - for (int i = 0; i < SHADER_NoTexture; i++) - { - mMaterialShaders[i]->ApplyMatrices(u); - mMaterialShadersNAT[i]->ApplyMatrices(u); - } - mMaterialShaders[SHADER_NoTexture]->ApplyMatrices(u); - if (gl_fuzztype != 0) - { - mMaterialShaders[SHADER_NoTexture + gl_fuzztype]->ApplyMatrices(u); - } - for (unsigned i = FIRST_USER_SHADER; i < mMaterialShaders.Size(); i++) - { - mMaterialShaders[i]->ApplyMatrices(u); - } - for (int i = 0; i < MAX_EFFECTS; i++) - { - mEffectShaders[i]->ApplyMatrices(u); - } -} - //========================================================================== // // diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index cb63b502d..46ba3c793 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -267,16 +267,6 @@ class FShader int normalmodelmatrix_index; int texturematrix_index; - int projectionmatrix_index; - int viewmatrix_index; - int normalviewmatrix_index; - int viewheight_index; - int camerapos_index; - int pallightlevels_index; - int globvis_index; - int clipheight_index; - int clipheightdirection_index; - int clipline_index; public: int vertexmatrix_index; @@ -308,9 +298,6 @@ public: bool Bind(); unsigned int GetHandle() const { return hShader; } - - void ApplyMatrices(HWViewpointUniforms *u); - }; //========================================================================== @@ -329,7 +316,6 @@ public: FShader *BindEffect(int effect, EPassType passType); FShader *Get(unsigned int eff, bool alphateston, EPassType passType); - void ApplyMatrices(HWViewpointUniforms *u, EPassType passType); private: FShader *mActiveShader = nullptr; @@ -351,7 +337,6 @@ public: FShader *Compile(const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType); int Find(const char *mame); FShader *BindEffect(int effect); - void ApplyMatrices(HWViewpointUniforms *u); FShader *Get(unsigned int eff, bool alphateston) { diff --git a/src/hwrenderer/data/shaderuniforms.h b/src/hwrenderer/data/shaderuniforms.h index 9400fa0a5..4ec9c2393 100644 --- a/src/hwrenderer/data/shaderuniforms.h +++ b/src/hwrenderer/data/shaderuniforms.h @@ -7,7 +7,8 @@ enum { LIGHTBUF_BINDINGPOINT = 1, - POSTPROCESS_BINDINGPOINT = 2 + POSTPROCESS_BINDINGPOINT = 2, + VIEWPOINT_BINDINGPOINT = 3 }; enum class UniformType diff --git a/wadsrc/static/shaders/glsl/main.vp b/wadsrc/static/shaders/glsl/main.vp index 1089cadcb..e25438c02 100644 --- a/wadsrc/static/shaders/glsl/main.vp +++ b/wadsrc/static/shaders/glsl/main.vp @@ -87,6 +87,10 @@ void main() { gl_ClipDistance[0] = -( (worldcoord.z - uClipLine.y) * uClipLine.z + (uClipLine.x - worldcoord.x) * uClipLine.w ) + 1.0/32768.0; // allow a tiny bit of imprecisions for colinear linedefs. } + else + { + gl_ClipDistance[0] = 1; + } // clip planes used for translucency splitting gl_ClipDistance[1] = worldcoord.y - uClipSplit.x; From 22e8c57a59b074db5beeb9f5b0a58a4455183d3b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Sep 2018 20:05:36 +0200 Subject: [PATCH 14/22] - reset the viewpoint buffer only once per scene, not per viewpoint. This doesn't work for camera textures because they are a separate viewpoint. --- src/gl/renderer/gl_renderer.cpp | 5 ++++- src/gl/scene/gl_scene.cpp | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 0bcdf7db6..d4b6197f9 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -135,6 +135,7 @@ FGLRenderer::~FGLRenderer() if (swdrawer) delete swdrawer; if (mBuffers) delete mBuffers; + if (mSaveBuffers) delete mSaveBuffers; if (mPresentShader) delete mPresentShader; if (mPresent3dCheckerShader) delete mPresent3dCheckerShader; if (mPresent3dColumnShader) delete mPresent3dColumnShader; @@ -221,6 +222,7 @@ sector_t *FGLRenderer::RenderView(player_t* player) P_FindParticleSubsectors(); mLights->Clear(); + mViewpoints->Clear(); // NoInterpolateView should have no bearing on camera textures, but needs to be preserved for the main view below. bool saved_niv = NoInterpolateView; @@ -322,7 +324,8 @@ void FGLRenderer::WriteSavePic (player_t *player, FileWriter *file, int width, i gl_RenderState.SetVertexBuffer(mVBO); mVBO->Reset(); mLights->Clear(); - + mViewpoints->Clear(); + // This shouldn't overwrite the global viewpoint even for a short time. FRenderViewpoint savevp; sector_t *viewsector = RenderViewpoint(savevp, players[consoleplayer].camera, &bounds, r_viewpoint.FieldOfView.Degrees, 1.6f, 1.6f, true, false); diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 8c6b5ce39..1a83521f1 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -449,7 +449,6 @@ sector_t * FGLRenderer::RenderViewpoint (FRenderViewpoint &mainvp, AActor * came // Render (potentially) multiple views for stereo 3d // Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode. auto vrmode = VRMode::GetVRMode(mainview && toscreen); - mViewpoints->Clear(); for (int eye_ix = 0; eye_ix < vrmode->mEyeCount; ++eye_ix) { const auto &eye = vrmode->mEyes[eye_ix]; From f007473a9fee530b64c905e15dd14048c70bb392 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Sep 2018 21:13:36 +0200 Subject: [PATCH 15/22] - fixed memory leak with wipes set to pff. In this case the start screen's texture wasn't destroyed. --- src/d_main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 4f023e81e..01c97b2ae 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -638,7 +638,7 @@ CVAR(Bool, vid_activeinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) void D_Display () { - FTexture *wipe; + FTexture *wipe = nullptr; int wipe_type; sector_t *viewsec; @@ -870,6 +870,8 @@ void D_Display () if (!wipe || NoWipe < 0 || wipe_type == wipe_None) { + if (wipe != nullptr) delete wipe; + wipe = nullptr; NetUpdate (); // send out any new accumulation // normal update // draw ZScript UI stuff From 7cbc98e1d04dd2aea5b8dcc1716460183743e6d9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 3 Sep 2018 23:06:32 +0200 Subject: [PATCH 16/22] - fixed incorrect trigger types in compatibility setter. These were caused by some bogus comment in the original compatibility.txt which erroneously added a "SPAC_PCross" remark to a line which actually set "SPAC_Cross". --- wadsrc/static/zscript/level_compatibility.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/zscript/level_compatibility.txt b/wadsrc/static/zscript/level_compatibility.txt index 08ac52a15..a932a0b18 100644 --- a/wadsrc/static/zscript/level_compatibility.txt +++ b/wadsrc/static/zscript/level_compatibility.txt @@ -73,7 +73,7 @@ class LevelCompatibility play AddSectorTag(35, 15); for(int i=605; i<609;i++) { - SetLineActivation(i, SPAC_PCross); + SetLineActivation(i, SPAC_Cross); SetLineSpecial(i, Door_Open, 15, 64); } break; @@ -187,7 +187,7 @@ class LevelCompatibility play ClearSectorTags(197); AddSectorTag(197, 8); SetLineSpecial(1279, Floor_LowerToLowest, 8, 32); - SetLineActivation(1240, SPAC_PCross); + SetLineActivation(1240, SPAC_Cross); SetLineSpecial(1240, Floor_LowerToLowest, 38, 32); break; } From 0e6af7137615eeeb70f8ed42b520771d6abfe1bd Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 4 Sep 2018 13:03:15 +0300 Subject: [PATCH 17/22] - improved SDL_GetWindowBordersSize() pointer loading https://forum.zdoom.org/viewtopic.php?t=61913 --- src/posix/sdl/gl_sysfb.h | 6 +----- src/posix/sdl/sdlglvideo.cpp | 18 +++++++++--------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/posix/sdl/gl_sysfb.h b/src/posix/sdl/gl_sysfb.h index ee2713bc5..44b92cf1a 100644 --- a/src/posix/sdl/gl_sysfb.h +++ b/src/posix/sdl/gl_sysfb.h @@ -52,11 +52,7 @@ protected: static const int MIN_WIDTH = 320; static const int MIN_HEIGHT = 200; - - typedef DECLSPEC int SDLCALL (*SDL_GetWindowBordersSizePtr)(SDL_Window *, int *, int *, int *, int *); - - SDL_GetWindowBordersSizePtr SDL_GetWindowBordersSize_; - void *sdl_lib; }; #endif // __POSIX_SDL_GL_SYSFB_H__ + diff --git a/src/posix/sdl/sdlglvideo.cpp b/src/posix/sdl/sdlglvideo.cpp index 15c0e4944..b270fcdab 100644 --- a/src/posix/sdl/sdlglvideo.cpp +++ b/src/posix/sdl/sdlglvideo.cpp @@ -35,6 +35,7 @@ #include "doomtype.h" +#include "i_module.h" #include "i_system.h" #include "i_video.h" #include "m_argv.h" @@ -172,6 +173,11 @@ IVideo *gl_CreateVideo() // FrameBuffer implementation ----------------------------------------------- +FModule sdl_lib("SDL2"); + +typedef int (*SDL_GetWindowBordersSizePtr)(SDL_Window *, int *, int *, int *, int *); +static TOptProc SDL_GetWindowBordersSize_("SDL_GetWindowBordersSize"); + SystemGLFrameBuffer::SystemGLFrameBuffer (void *, bool fullscreen) : DFrameBuffer (vid_defwidth, vid_defheight) { @@ -180,10 +186,9 @@ SystemGLFrameBuffer::SystemGLFrameBuffer (void *, bool fullscreen) // SDL_GetWindowBorderSize() is only available since 2.0.5, but because // GZDoom supports platforms with older SDL2 versions, this function // has to be dynamically loaded - sdl_lib = SDL_LoadObject("libSDL2.so"); - if (sdl_lib != nullptr) + if (!sdl_lib.IsLoaded()) { - SDL_GetWindowBordersSize_ = (SDL_GetWindowBordersSizePtr)SDL_LoadFunction(sdl_lib,"SDL_GetWindowBordersSize"); + sdl_lib.Load({ "libSDL2.so", "libSDL2-2.0.so" }); } // NOTE: Core profiles were added with GL 3.2, so there's no sense trying @@ -261,11 +266,6 @@ SystemGLFrameBuffer::SystemGLFrameBuffer (void *, bool fullscreen) SystemGLFrameBuffer::~SystemGLFrameBuffer () { - if (sdl_lib != nullptr) - { - SDL_UnloadObject(sdl_lib); - } - if (Screen) { ResetGammaTable(); @@ -391,7 +391,7 @@ void SystemGLFrameBuffer::SetWindowSize(int w, int h) void SystemGLFrameBuffer::GetWindowBordersSize(int &top, int &left) { - if (SDL_GetWindowBordersSize_ != nullptr) + if (SDL_GetWindowBordersSize_) { SDL_GetWindowBordersSize_(Screen, &top, &left, nullptr, nullptr); } From 8b26b6dd1ed67127fe241418e63fad27faea76f0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 6 Sep 2018 19:14:30 +0200 Subject: [PATCH 18/22] - reworked fog uniforms to move the global fog mode setting to the viewpoint buffer. --- src/gl/data/gl_viewpointbuffer.cpp | 1 + src/gl/renderer/gl_renderstate.cpp | 24 ++++----------------- src/gl/scene/gl_scene.cpp | 1 + src/gl/shaders/gl_shader.cpp | 4 ++-- src/gl/shaders/gl_shader.h | 1 - src/hwrenderer/scene/hw_drawinfo.cpp | 1 + src/hwrenderer/scene/hw_viewpointuniforms.h | 1 + wadsrc/static/shaders/glsl/fogboundary.fp | 2 +- wadsrc/static/shaders/glsl/main.fp | 16 +++++++------- 9 files changed, 19 insertions(+), 32 deletions(-) diff --git a/src/gl/data/gl_viewpointbuffer.cpp b/src/gl/data/gl_viewpointbuffer.cpp index 7b9039bf3..7af26ca52 100644 --- a/src/gl/data/gl_viewpointbuffer.cpp +++ b/src/gl/data/gl_viewpointbuffer.cpp @@ -144,6 +144,7 @@ void GLViewpointBuffer::Set2D(int width, int height) HWViewpointUniforms matrices; matrices.SetDefaults(); matrices.mProjectionMatrix.ortho(0, width, height, 0, -1.0f, 1.0f); + matrices.mFogEnabled = 3; matrices.CalcDependencies(); Map(); memcpy(mBufferPointer, &matrices, sizeof(matrices)); diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index e585296f6..a5de63896 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -119,7 +119,7 @@ bool FRenderState::ApplyShader() static uint64_t firstFrame = 0; // if firstFrame is not yet initialized, initialize it to current time // if we're going to overflow a float (after ~4.6 hours, or 24 bits), re-init to regain precision - if ((firstFrame == 0) || (screen->FrameTime - firstFrame >= 1<<24) || level.ShaderStartTime >= firstFrame) + if ((firstFrame == 0) || (screen->FrameTime - firstFrame >= 1 << 24) || level.ShaderStartTime >= firstFrame) firstFrame = screen->FrameTime; static const float nulvec[] = { 0.f, 0.f, 0.f, 0.f }; @@ -133,31 +133,15 @@ bool FRenderState::ApplyShader() activeShader->Bind(); } - int fogset = 0; - - if (mFogEnabled) - { - if (mFogEnabled == 2) - { - fogset = -3; // 2D rendering with 'foggy' overlay. - } - else if ((mFogColor & 0xffffff) == 0) - { - fogset = gl_fogmode; - } - else - { - fogset = -gl_fogmode; - } - } - glVertexAttrib4fv(VATTR_COLOR, mColor.vec); glVertexAttrib4fv(VATTR_NORMAL, mNormal.vec); activeShader->muDesaturation.Set(mDesaturation / 255.f); - activeShader->muFogEnabled.Set(fogset); activeShader->muTextureMode.Set(mTextureMode == TM_MODULATE && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode); + float fds = mLightParms[2]; + if (!mFogEnabled) mLightParms[2] = 0; activeShader->muLightParms.Set(mLightParms); + mLightParms[2] = fds; activeShader->muFogColor.Set(mFogColor); activeShader->muObjectColor.Set(mObjectColor); activeShader->muObjectColor2.Set(mObjectColor2); diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 1a83521f1..3044d4bd6 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -375,6 +375,7 @@ void FDrawInfo::DrawEndScene2D(sector_t * viewsector) HWViewpointUniforms vp = VPUniforms; vp.mViewMatrix.loadIdentity(); vp.mProjectionMatrix = vrmode->GetHUDSpriteProjection(); + vp.mFogEnabled = 0; GLRenderer->mViewpoints->SetViewpoint(&vp); glDisable(GL_DEPTH_TEST); glDisable(GL_MULTISAMPLE); diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index e0d656038..19d30ed47 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -68,6 +68,8 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * int uViewHeight; // Software fuzz scaling float uClipHeight; float uClipHeightDirection; + int uFogEnabled; + }; )"; @@ -98,7 +100,6 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * i_data += "#define uFogDensity uLightAttr.b\n"; i_data += "#define uLightFactor uLightAttr.g\n"; i_data += "#define uLightDist uLightAttr.r\n"; - i_data += "uniform int uFogEnabled;\n"; // dynamic lights i_data += "uniform int uLightIndex;\n"; @@ -330,7 +331,6 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * muDesaturation.Init(hShader, "uDesaturationFactor"); - muFogEnabled.Init(hShader, "uFogEnabled"); muTextureMode.Init(hShader, "uTextureMode"); muLightParms.Init(hShader, "uLightAttr"); muClipSplit.Init(hShader, "uClipSplit"); diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index 46ba3c793..2d1d28f76 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -242,7 +242,6 @@ class FShader FName mName; FBufferedUniform1f muDesaturation; - FBufferedUniform1i muFogEnabled; FBufferedUniform1i muTextureMode; FBufferedUniform4f muLightParms; FBufferedUniform2f muClipSplit; diff --git a/src/hwrenderer/scene/hw_drawinfo.cpp b/src/hwrenderer/scene/hw_drawinfo.cpp index b5dce2247..bf04aef6c 100644 --- a/src/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/hwrenderer/scene/hw_drawinfo.cpp @@ -280,5 +280,6 @@ void HWViewpointUniforms::SetDefaults() mGlobVis = (float)R_GetGlobVis(r_viewwindow, r_visibility) / 32.f; mPalLightLevels = static_cast(gl_bandedswlight) | (static_cast(gl_fogmode) << 8); mClipLine.X = -10000000.0f; + mFogEnabled = gl_fogmode; } diff --git a/src/hwrenderer/scene/hw_viewpointuniforms.h b/src/hwrenderer/scene/hw_viewpointuniforms.h index 27a78aef4..675ee71eb 100644 --- a/src/hwrenderer/scene/hw_viewpointuniforms.h +++ b/src/hwrenderer/scene/hw_viewpointuniforms.h @@ -16,6 +16,7 @@ struct HWViewpointUniforms int mViewHeight = 0; float mClipHeight = 0.f; float mClipHeightDirection = 0.f; + int mFogEnabled = 0; void CalcDependencies() { diff --git a/wadsrc/static/shaders/glsl/fogboundary.fp b/wadsrc/static/shaders/glsl/fogboundary.fp index 9dcdb4850..81880f984 100644 --- a/wadsrc/static/shaders/glsl/fogboundary.fp +++ b/wadsrc/static/shaders/glsl/fogboundary.fp @@ -15,7 +15,7 @@ void main() // // calculate fog factor // - if (uFogEnabled == -1) + if (uFogEnabled == 1) { fogdist = pixelpos.w; } diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index d5283b26c..c4caa785e 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -358,7 +358,7 @@ vec4 getLightColor(Material material, float fogdist, float fogfactor) float newlightlevel = 1.0 - R_DoomLightingEquation(uLightLevel); color.rgb *= newlightlevel; } - else if (uFogEnabled > 0) + else if (uFogColor.rgb == vec3(0.0)) { // brightening around the player for light mode 2 if (fogdist < uLightDist) @@ -421,7 +421,7 @@ vec3 AmbientOcclusionColor() // // calculate fog factor // - if (uFogEnabled == -1) + if (uFogEnabled == 1) { fogdist = pixelpos.w; } @@ -449,17 +449,17 @@ void main() if (frag.a <= uAlphaThreshold) discard; #endif - if (uFogEnabled != -3) // check for special 2D 'fog' mode. + if (uFogEnabled != 3) // check for special 2D 'fog' mode. { float fogdist = 0.0; - float fogfactor = 0.0; + float fogfactor = 1.0; // // calculate fog factor // - if (uFogEnabled != 0) + if (uFogEnabled != 0 && uFogDensity != 0) { - if (uFogEnabled == 1 || uFogEnabled == -1) + if (uFogEnabled == 1) { fogdist = pixelpos.w; } @@ -476,7 +476,7 @@ void main() // // colored fog // - if (uFogEnabled < 0) + if (uFogColor.rgb != vec3(0.0)) { frag = applyFog(frag, fogfactor); } @@ -494,7 +494,7 @@ void main() vec4 cm = (uObjectColor + gray * (uObjectColor2 - uObjectColor)) * 2; frag = vec4(clamp(cm.rgb, 0.0, 1.0), frag.a); } - frag = frag * ProcessLight(material, vColor); + frag = frag * ProcessLight(material, vColor); frag.rgb = frag.rgb + uFogColor.rgb; } FragColor = frag; From dd971805af003e481b1ef6b789a330e27f7ae223 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 18 Aug 2018 22:29:22 +0200 Subject: [PATCH 19/22] - fixed: The viewpoint buffer was mapped write only but read from. On old hardware it wasn't even mapped. Changed to cache the needed value in a CPU-side array so that the buffer access is not needed. --- src/gl/data/gl_viewpointbuffer.cpp | 6 ++++-- src/gl/data/gl_viewpointbuffer.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gl/data/gl_viewpointbuffer.cpp b/src/gl/data/gl_viewpointbuffer.cpp index 7b9039bf3..611db9e40 100644 --- a/src/gl/data/gl_viewpointbuffer.cpp +++ b/src/gl/data/gl_viewpointbuffer.cpp @@ -41,6 +41,7 @@ GLViewpointBuffer::GLViewpointBuffer() Allocate(); Clear(); mLastMappedIndex = UINT_MAX; + mClipPlaneInfo.Push(0); } GLViewpointBuffer::~GLViewpointBuffer() @@ -121,10 +122,9 @@ int GLViewpointBuffer::Bind(unsigned int index) glBindBufferRange(GL_UNIFORM_BUFFER, VIEWPOINT_BINDINGPOINT, mBufferId, index * mBlockAlign, mBlockAlign); // Update the viewpoint-related clip plane setting. - auto *vp = (HWViewpointUniforms*)(((char*)mBufferPointer) + mUploadIndex * mBlockAlign); if (!(gl.flags & RFL_NO_CLIP_PLANES)) { - if (index > 0 && (vp->mClipHeightDirection != 0.f || vp->mClipLine.X > -10000000.0f)) + if (mClipPlaneInfo[index]) { glEnable(GL_CLIP_DISTANCE0); } @@ -162,6 +162,7 @@ int GLViewpointBuffer::SetViewpoint(HWViewpointUniforms *vp) memcpy(((char*)mBufferPointer) + mUploadIndex * mBlockAlign, vp, sizeof(*vp)); Unmap(); + mClipPlaneInfo.Push(vp->mClipHeightDirection != 0.f || vp->mClipLine.X > -10000000.0f); return Bind(mUploadIndex++); } @@ -169,5 +170,6 @@ void GLViewpointBuffer::Clear() { // Index 0 is reserved for the 2D projection. mUploadIndex = 1; + mClipPlaneInfo.Resize(1); } diff --git a/src/gl/data/gl_viewpointbuffer.h b/src/gl/data/gl_viewpointbuffer.h index 208a42a5d..3ec1093df 100644 --- a/src/gl/data/gl_viewpointbuffer.h +++ b/src/gl/data/gl_viewpointbuffer.h @@ -12,6 +12,7 @@ class GLViewpointBuffer unsigned int mLastMappedIndex; unsigned int mByteSize; void * mBufferPointer; + TArray mClipPlaneInfo; unsigned int m2DWidth = ~0u, m2DHeight = ~0u; From 1c3d4b46c66e43c829ef74265401e383cf104b7e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 8 Sep 2018 13:08:04 +0200 Subject: [PATCH 20/22] - fixed the use of Doom-Legacy-style 3D floor lighting in light mode 8. Legacy used some strange blending formula to calculate its colormaps for colored 3D floor lighting, this is not available in the software lighting mode, so for these the engine has to temporarily revert to light mode 2 to render them correctly. --- src/gl/renderer/gl_lightdata.cpp | 12 ++++++------ src/gl/renderer/gl_renderstate.h | 4 ++-- src/gl/scene/gl_sprite.cpp | 2 +- src/hwrenderer/scene/hw_weapon.cpp | 2 +- src/hwrenderer/utility/hw_lighting.cpp | 26 ++++++++++++++++---------- src/hwrenderer/utility/hw_lighting.h | 4 ++-- src/v_2ddrawer.cpp | 1 + 7 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/gl/renderer/gl_lightdata.cpp b/src/gl/renderer/gl_lightdata.cpp index 7566c0f12..635e6b292 100644 --- a/src/gl/renderer/gl_lightdata.cpp +++ b/src/gl/renderer/gl_lightdata.cpp @@ -103,10 +103,10 @@ void gl_SetColor(int sectorlightlevel, int rellight, bool fullbright, const FCol } else { - int hwlightlevel = hw_CalcLightLevel(sectorlightlevel, rellight, weapon); + int hwlightlevel = hw_CalcLightLevel(sectorlightlevel, rellight, weapon, cm.BlendFactor); PalEntry pe = hw_CalcLightColor(hwlightlevel, cm.LightColor, cm.BlendFactor); gl_RenderState.SetColorAlpha(pe, alpha, cm.Desaturation); - gl_RenderState.SetSoftLightLevel(hw_ClampLight(sectorlightlevel + rellight)); + gl_RenderState.SetSoftLightLevel(hw_ClampLight(sectorlightlevel + rellight), cm.BlendFactor); } } @@ -163,7 +163,7 @@ void gl_SetFog(int lightlevel, int rellight, bool fullbright, const FColormap *c else if (cmap != NULL && !fullbright) { fogcolor = cmap->FadeColor; - fogdensity = hw_GetFogDensity(lightlevel, fogcolor, cmap->FogDensity); + fogdensity = hw_GetFogDensity(lightlevel, fogcolor, cmap->FogDensity, cmap->BlendFactor); fogcolor.a=0; } else @@ -184,9 +184,9 @@ void gl_SetFog(int lightlevel, int rellight, bool fullbright, const FColormap *c } else { - if (level.lightmode == 2 && fogcolor == 0) + if ((level.lightmode == 2 || (level.lightmode == 8) && cmap->BlendFactor > 0) && fogcolor == 0) { - float light = hw_CalcLightLevel(lightlevel, rellight, false); + float light = hw_CalcLightLevel(lightlevel, rellight, false, cmap->BlendFactor); gl_SetShaderLight(light, lightlevel); } else @@ -205,7 +205,7 @@ void gl_SetFog(int lightlevel, int rellight, bool fullbright, const FColormap *c gl_RenderState.SetFog(fogcolor, fogdensity); // Korshun: fullbright fog like in software renderer. - if (level.lightmode == 8 && level.brightfog && fogdensity != 0 && fogcolor != 0) + if (level.lightmode == 8 && cmap->BlendFactor == 0 && level.brightfog && fogdensity != 0 && fogcolor != 0) { gl_RenderState.SetSoftLightLevel(255); } diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index e3a7615b3..c046d3f61 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -290,9 +290,9 @@ public: mGlowBottom.Set(b[0], b[1], b[2], b[3]); } - void SetSoftLightLevel(int llevel) + void SetSoftLightLevel(int llevel, int blendfactor = 0) { - if (level.lightmode == 8) mLightParms[3] = llevel / 255.f; + if (level.lightmode == 8 && blendfactor == 0) mLightParms[3] = llevel / 255.f; else mLightParms[3] = -1.f; } diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index a17241142..985286a2a 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -113,7 +113,7 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass) if (!sprite->Colormap.FadeColor.isBlack()) { float dist=Dist2(vp.Pos.X, vp.Pos.Y, sprite->x, sprite->y); - int fogd = hw_GetFogDensity(sprite->lightlevel, sprite->Colormap.FadeColor, sprite->Colormap.FogDensity); + int fogd = hw_GetFogDensity(sprite->lightlevel, sprite->Colormap.FadeColor, sprite->Colormap.FogDensity, sprite->Colormap.BlendFactor); // this value was determined by trial and error and is scale dependent! float factor = 0.05f + exp(-fogd*dist / 62500.f); diff --git a/src/hwrenderer/scene/hw_weapon.cpp b/src/hwrenderer/scene/hw_weapon.cpp index b0861e8bd..8e3650310 100644 --- a/src/hwrenderer/scene/hw_weapon.cpp +++ b/src/hwrenderer/scene/hw_weapon.cpp @@ -190,7 +190,7 @@ static WeaponLighting GetWeaponLighting(sector_t *viewsector, const DVector3 &po if (level.flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) l.cm.ClearColor(); } - l.lightlevel = hw_CalcLightLevel(l.lightlevel, getExtraLight(), true); + l.lightlevel = hw_CalcLightLevel(l.lightlevel, getExtraLight(), true, 0); if (level.lightmode == 8 || l.lightlevel < 92) { diff --git a/src/hwrenderer/utility/hw_lighting.cpp b/src/hwrenderer/utility/hw_lighting.cpp index 04836a51c..83e2acd7d 100644 --- a/src/hwrenderer/utility/hw_lighting.cpp +++ b/src/hwrenderer/utility/hw_lighting.cpp @@ -82,13 +82,15 @@ CUSTOM_CVAR(Int,gl_fogmode,1,CVAR_ARCHIVE|CVAR_NOINITCALL) // //========================================================================== -int hw_CalcLightLevel(int lightlevel, int rellight, bool weapon) +int hw_CalcLightLevel(int lightlevel, int rellight, bool weapon, int blendfactor) { int light; if (lightlevel == 0) return 0; - if ((level.lightmode & 2) && lightlevel < 192 && !weapon) + bool darklightmode = (level.lightmode & 2) || (level.lightmode == 8 && blendfactor > 0); + + if (darklightmode && lightlevel < 192 && !weapon) { if (lightlevel > 100) { @@ -126,12 +128,13 @@ PalEntry hw_CalcLightColor(int light, PalEntry pe, int blendfactor) { int r,g,b; - if (level.lightmode == 8) - { - return pe; - } - else if (blendfactor == 0) + if (blendfactor == 0) { + if (level.lightmode == 8) + { + return pe; + } + r = pe.r * light / 255; g = pe.g * light / 255; b = pe.b * light / 255; @@ -167,11 +170,14 @@ PalEntry hw_CalcLightColor(int light, PalEntry pe, int blendfactor) // //========================================================================== -float hw_GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity) +float hw_GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity, int blendfactor) { float density; - if (level.lightmode & 4) + int lightmode = level.lightmode; + if (lightmode == 8 && blendfactor > 0) lightmode = 2; // The blendfactor feature does not work with software-style lighting. + + if (lightmode & 4) { // uses approximations of Legacy's default settings. density = level.fogdensity ? (float)level.fogdensity : 18; @@ -184,7 +190,7 @@ float hw_GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity) else if ((fogcolor.d & 0xffffff) == 0) { // case 2: black fog - if (level.lightmode != 8 && !(level.flags3 & LEVEL3_NOLIGHTFADE)) + if ((lightmode != 8 || blendfactor > 0) && !(level.flags3 & LEVEL3_NOLIGHTFADE)) { density = distfogtable[level.lightmode != 0][hw_ClampLight(lightlevel)]; } diff --git a/src/hwrenderer/utility/hw_lighting.h b/src/hwrenderer/utility/hw_lighting.h index 9acb1578d..94304b014 100644 --- a/src/hwrenderer/utility/hw_lighting.h +++ b/src/hwrenderer/utility/hw_lighting.h @@ -7,9 +7,9 @@ struct Colormap; -int hw_CalcLightLevel(int lightlevel, int rellight, bool weapon); +int hw_CalcLightLevel(int lightlevel, int rellight, bool weapon, int blendfactor); PalEntry hw_CalcLightColor(int light, PalEntry pe, int blendfactor); -float hw_GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity); +float hw_GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity, int blendfactor); bool hw_CheckFog(sector_t *frontsector, sector_t *backsector); inline int hw_ClampLight(int lightlevel) diff --git a/src/v_2ddrawer.cpp b/src/v_2ddrawer.cpp index 2bbdec8ee..a2388b65b 100644 --- a/src/v_2ddrawer.cpp +++ b/src/v_2ddrawer.cpp @@ -428,6 +428,7 @@ void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints, // is necessary in order to best reproduce Doom's original lighting. double fadelevel; + // The hardware renderer's light modes 0, 1 and 4 use a linear light scale which must be used here as well. Otherwise the automap gets too dark. if (vid_rendermode != 4 || (level.lightmode >= 2 && level.lightmode != 4)) { double map = (NUMCOLORMAPS * 2.) - ((lightlevel + 12) * (NUMCOLORMAPS / 128.)); From 1eb1d8d280d86370f3f5dd022c0e97334bc0896c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 9 Sep 2018 08:57:50 +0200 Subject: [PATCH 21/22] - fixed math imprecisions in horizon vertex generation. Floats are not precise enough to be used as a loop counter. --- src/gl/scene/gl_portal.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gl/scene/gl_portal.cpp b/src/gl/scene/gl_portal.cpp index 3ef4e2e3e..5820f11df 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -343,10 +343,12 @@ GLHorizonPortal::GLHorizonPortal(FPortalSceneState *s, GLHorizonInfo * pt, FRend // Draw to some far away boundary // This is not drawn as larger strips because it causes visual glitches. FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - for (float x = -32768 + vx; x<32768 + vx; x += 4096) + for (int xx = -32768; xx < 32768; xx += 4096) { - for (float y = -32768 + vy; y<32768 + vy; y += 4096) + float x = xx + vx; + for (int yy = -32768; yy < 32768; yy += 4096) { + float y = yy + vy; ptr->Set(x, z, y, x / 64, -y / 64); ptr++; ptr->Set(x + 4096, z, y, x / 64 + 64, -y / 64); From 2d53ad6f1081f93787aff007c9dca330f41c2c04 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 9 Sep 2018 19:18:22 +0200 Subject: [PATCH 22/22] - fixed misplaced parenthesis. --- src/gl/renderer/gl_lightdata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gl/renderer/gl_lightdata.cpp b/src/gl/renderer/gl_lightdata.cpp index 635e6b292..4668af261 100644 --- a/src/gl/renderer/gl_lightdata.cpp +++ b/src/gl/renderer/gl_lightdata.cpp @@ -184,7 +184,7 @@ void gl_SetFog(int lightlevel, int rellight, bool fullbright, const FColormap *c } else { - if ((level.lightmode == 2 || (level.lightmode == 8) && cmap->BlendFactor > 0) && fogcolor == 0) + if ((level.lightmode == 2 || (level.lightmode == 8 && cmap->BlendFactor > 0)) && fogcolor == 0) { float light = hw_CalcLightLevel(lightlevel, rellight, false, cmap->BlendFactor); gl_SetShaderLight(light, lightlevel);