diff --git a/src/g_game.cpp b/src/g_game.cpp index 1c5388ac1..a73758f1c 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -82,9 +82,6 @@ static FRandom pr_dmspawn ("DMSpawn"); static FRandom pr_pspawn ("PlayerSpawn"); -const int SAVEPICWIDTH = 216; -const int SAVEPICHEIGHT = 162; - bool G_CheckDemoStatus (void); void G_ReadDemoTiccmd (ticcmd_t *cmd, int player); void G_WriteDemoTiccmd (ticcmd_t *cmd, int player, int buf); diff --git a/src/g_game.h b/src/g_game.h index 2ac019059..7ac49a413 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -102,5 +102,7 @@ class AInventory; extern const AInventory *SendItemUse, *SendItemDrop; extern int SendItemDropAmount; +const int SAVEPICWIDTH = 216; +const int SAVEPICHEIGHT = 162; #endif diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 154fae2d6..c753e261e 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -35,6 +35,7 @@ #include "p_effect.h" #include "d_player.h" #include "a_dynlight.h" +#include "g_game.h" #include "swrenderer/r_swscene.h" #include "hwrenderer/utility/hw_clock.h" @@ -96,6 +97,8 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) mLights = nullptr; mTonemapPalette = nullptr; mBuffers = nullptr; + mScreenBuffers = nullptr; + mSaveBuffers = nullptr; mPresentShader = nullptr; mPresent3dCheckerShader = nullptr; mPresent3dColumnShader = nullptr; @@ -122,7 +125,9 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) void FGLRenderer::Initialize(int width, int height) { - mBuffers = new FGLRenderBuffers(); + mScreenBuffers = new FGLRenderBuffers(); + mSaveBuffers = new FGLRenderBuffers(); + mBuffers = mScreenBuffers; mLinearDepthShader = new FLinearDepthShader(); mDepthBlurShader = new FDepthBlurShader(); mSSAOShader = new FSSAOShader(); @@ -400,7 +405,9 @@ void FGLRenderer::WriteSavePic(player_t *player, FileWriter *file, int width, in void FGLRenderer::BeginFrame() { - buffersActive = GLRenderer->mBuffers->Setup(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height); + buffersActive = GLRenderer->mScreenBuffers->Setup(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height); + if (buffersActive) + buffersActive = GLRenderer->mSaveBuffers->Setup(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT); } //=========================================================================== diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 7cdf3b01d..22b77acef 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -100,6 +100,8 @@ public: int mOldFBID; FGLRenderBuffers *mBuffers; + FGLRenderBuffers *mScreenBuffers; + FGLRenderBuffers *mSaveBuffers; FLinearDepthShader *mLinearDepthShader; FSSAOShader *mSSAOShader; FDepthBlurShader *mDepthBlurShader; diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index ad7a7e494..d4aea2768 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -656,7 +656,7 @@ sector_t * GLSceneDrawer::RenderViewpoint (AActor * camera, IntRect * bounds, fl SetFixedColormap(camera->player); // reiterate color map for each eye, so night vision goggles work in both eyes const s3d::EyePose * eye = stereo3dMode.getEyePose(eye_ix); eye->SetUp(); - screen->SetOutputViewport(bounds); + screen->SetViewportRects(bounds); Set3DViewport(mainview); GLRenderer->mDrawingScene2D = true; GLRenderer->mCurrentFoV = fov; @@ -713,20 +713,24 @@ sector_t * GLSceneDrawer::RenderViewpoint (AActor * camera, IntRect * bounds, fl void GLSceneDrawer::WriteSavePic (player_t *player, FileWriter *file, int width, int height) { IntRect bounds; + bounds.left = 0; + bounds.top = 0; + bounds.width = width; + bounds.height = height; + + // if GLRenderer->mVBO is persistently mapped we must be sure the GPU finished reading from it before we fill it with new data. + glFinish(); + + // Switch to render buffers dimensioned for the savepic + GLRenderer->mBuffers = GLRenderer->mSaveBuffers; P_FindParticleSubsectors(); // make sure that all recently spawned particles have a valid subsector. - bounds.left=0; - bounds.top=0; - bounds.width=width; - bounds.height=height; - glFlush(); SetFixedColormap(player); gl_RenderState.SetVertexBuffer(GLRenderer->mVBO); GLRenderer->mVBO->Reset(); if (!gl.legacyMode) GLRenderer->mLights->Clear(); - sector_t *viewsector = RenderViewpoint(players[consoleplayer].camera, &bounds, - r_viewpoint.FieldOfView.Degrees, 1.6f, 1.6f, true, false); + sector_t *viewsector = RenderViewpoint(players[consoleplayer].camera, &bounds, r_viewpoint.FieldOfView.Degrees, 1.6f, 1.6f, true, false); glDisable(GL_STENCIL_TEST); gl_RenderState.SetFixedColormap(CM_DEFAULT); gl_RenderState.SetSoftLightLevel(-1); @@ -737,12 +741,16 @@ void GLSceneDrawer::WriteSavePic (player_t *player, FileWriter *file, int width, screen->Draw2D(); } GLRenderer->CopyToBackbuffer(&bounds, false); - glFlush(); - screen->SetOutputViewport(nullptr); + // strictly speaking not needed as the glReadPixels should block until the scene is rendered, but this is to safeguard against shitty drivers + glFinish(); uint8_t * scr = (uint8_t *)M_Malloc(width * height * 3); glReadPixels(0,0,width, height,GL_RGB,GL_UNSIGNED_BYTE,scr); M_CreatePNG (file, scr + ((height-1) * width * 3), NULL, SS_RGB, width, height, -width * 3, Gamma); M_Free(scr); + + // Switch back the screen render buffers + screen->SetViewportRects(nullptr); + GLRenderer->mBuffers = GLRenderer->mScreenBuffers; } diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 81cbd7eeb..02326afd1 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -136,7 +136,7 @@ void OpenGLFrameBuffer::InitializeState() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GLRenderer->Initialize(GetWidth(), GetHeight()); - SetOutputViewport(nullptr); + SetViewportRects(nullptr); } //========================================================================== @@ -164,14 +164,11 @@ void OpenGLFrameBuffer::Update() int clientHeight = ViewportScaledHeight(initialWidth, initialHeight); if (clientWidth > 0 && clientHeight > 0 && (Width != clientWidth || Height != clientHeight)) { - // Do not call Resize here because it's only for software canvases Width = clientWidth; Height = clientHeight; V_OutputResized(Width, Height); GLRenderer->mVBO->OutputResized(Width, Height); } - - SetOutputViewport(nullptr); } //=========================================================================== @@ -392,10 +389,11 @@ bool OpenGLFrameBuffer::RenderBuffersEnabled() return FGLRenderBuffers::IsEnabled(); } -void OpenGLFrameBuffer::SetOutputViewport(IntRect *bounds) +void OpenGLFrameBuffer::SetViewportRects(IntRect *bounds) { - Super::SetOutputViewport(bounds); - s3d::Stereo3DMode::getCurrentMode().AdjustViewports(); + Super::SetViewportRects(bounds); + if (!bounds) + s3d::Stereo3DMode::getCurrentMode().AdjustViewports(); } @@ -431,6 +429,7 @@ void OpenGLFrameBuffer::SetClearColor(int color) void OpenGLFrameBuffer::BeginFrame() { + SetViewportRects(nullptr); if (GLRenderer != nullptr) GLRenderer->BeginFrame(); } diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index 898820cc9..9a92c1f44 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -42,7 +42,7 @@ public: void ResetFixedColormap() override; void BeginFrame() override; bool RenderBuffersEnabled() override; - void SetOutputViewport(IntRect *bounds) override; + void SetViewportRects(IntRect *bounds) override; void BlurScene(float amount) override; // Retrieves a buffer containing image data for a screenshot. diff --git a/src/v_video.cpp b/src/v_video.cpp index 1441a1966..0f754d4c3 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1005,7 +1005,7 @@ void DFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, i // //========================================================================== -void DFrameBuffer::SetOutputViewport(IntRect *bounds) +void DFrameBuffer::SetViewportRects(IntRect *bounds) { if (bounds) { diff --git a/src/v_video.h b/src/v_video.h index f88a65e65..66e38fca5 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -501,7 +501,7 @@ public: // Calculate gamma table void CalcGamma(float gamma, uint8_t gammalookup[256]); - virtual void SetOutputViewport(IntRect *bounds); + virtual void SetViewportRects(IntRect *bounds); int ScreenToWindowX(int x); int ScreenToWindowY(int y);