diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index 48e01626f5..e7d136bdd9 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -413,7 +413,7 @@ void CRenderer::RenderFrame(const bool needsPresent) if (m_ShouldPreloadResourcesBeforeNextFrame) { m_ShouldPreloadResourcesBeforeNextFrame = false; - // We don't meed to render logger for the preload. + // We don't need to render logger for the preload. RenderFrameImpl(true, false); } @@ -421,12 +421,13 @@ void CRenderer::RenderFrame(const bool needsPresent) { RenderBigScreenShot(needsPresent); } + else if (m_ScreenShotType == ScreenShotType::DEFAULT) + { + RenderScreenShot(needsPresent); + } else { - if (m_ScreenShotType == ScreenShotType::DEFAULT) - RenderScreenShot(); - else - RenderFrameImpl(true, true); + RenderFrameImpl(true, true); m->deviceCommandContext->Flush(); if (needsPresent) @@ -541,7 +542,7 @@ void CRenderer::RenderFrame2D(const bool renderGUI, const bool renderLogger) } } -void CRenderer::RenderScreenShot() +void CRenderer::RenderScreenShot(const bool needsPresent) { m_ScreenShotType = ScreenShotType::NONE; @@ -551,23 +552,25 @@ void CRenderer::RenderScreenShot() VfsPath filename; vfs::NextNumberedFilename(g_VFS, filenameFormat, g_NextScreenShotNumber, filename); - const size_t w = (size_t)g_xres, h = (size_t)g_yres; + const size_t width = static_cast(g_xres), height = static_cast(g_yres); const size_t bpp = 24; - GLenum fmt = GL_RGB; - int flags = TEX_BOTTOM_UP; // Hide log messages and re-render RenderFrameImpl(true, false); - const size_t img_size = w * h * bpp / 8; + const size_t img_size = width * height * bpp / 8; const size_t hdr_size = tex_hdr_size(filename); std::shared_ptr buf; AllocateAligned(buf, hdr_size + img_size, maxSectorSize); - GLvoid* img = buf.get() + hdr_size; + void* img = buf.get() + hdr_size; Tex t; - if (t.wrap(w, h, bpp, flags, buf, hdr_size) < 0) + if (t.wrap(width, height, bpp, TEX_BOTTOM_UP, buf, hdr_size) < 0) return; - glReadPixels(0, 0, (GLsizei)w, (GLsizei)h, fmt, GL_UNSIGNED_BYTE, img); + + m->deviceCommandContext->ReadbackFramebufferSync(0, 0, width, height, img); + m->deviceCommandContext->Flush(); + if (needsPresent) + g_VideoMode.GetBackendDevice()->Present(); if (tex_write(&t, filename) == INFO::OK) { @@ -590,7 +593,7 @@ void CRenderer::RenderBigScreenShot(const bool needsPresent) // If the game hasn't started yet then use WriteScreenshot to generate the image. if (!g_Game) - return RenderScreenShot(); + return RenderScreenShot(needsPresent); int tiles = 4, tileWidth = 256, tileHeight = 256; CFG_GET_VAL("screenshot.tiles", tiles); @@ -614,15 +617,6 @@ void CRenderer::RenderBigScreenShot(const bool needsPresent) const int imageWidth = tileWidth * tiles, imageHeight = tileHeight * tiles; const int bpp = 24; - // we want writing BMP to be as fast as possible, - // so read data from OpenGL in BMP format to obviate conversion. -#if CONFIG2_GLES // GLES doesn't support BGR - const GLenum fmt = GL_RGB; - const int flags = TEX_BOTTOM_UP; -#else - const GLenum fmt = GL_BGR; - const int flags = TEX_BOTTOM_UP | TEX_BGR; -#endif const size_t imageSize = imageWidth * imageHeight * bpp / 8; const size_t tileSize = tileWidth * tileHeight * bpp / 8; @@ -638,7 +632,7 @@ void CRenderer::RenderBigScreenShot(const bool needsPresent) Tex t; GLvoid* img = imageBuffer.get() + headerSize; - if (t.wrap(imageWidth, imageHeight, bpp, flags, imageBuffer, headerSize) < 0) + if (t.wrap(imageWidth, imageHeight, bpp, TEX_BOTTOM_UP, imageBuffer, headerSize) < 0) { free(tileData); return; @@ -672,18 +666,18 @@ void CRenderer::RenderBigScreenShot(const bool needsPresent) RenderFrameImpl(false, false); + m->deviceCommandContext->ReadbackFramebufferSync(0, 0, tileWidth, tileHeight, tileData); + m->deviceCommandContext->Flush(); + if (needsPresent) + g_VideoMode.GetBackendDevice()->Present(); + // Copy the tile pixels into the main image - glReadPixels(0, 0, tileWidth, tileHeight, fmt, GL_UNSIGNED_BYTE, tileData); for (int y = 0; y < tileHeight; ++y) { void* dest = static_cast(img) + ((tileY * tileHeight + y) * imageWidth + (tileX * tileWidth)) * bpp / 8; void* src = static_cast(tileData) + y * tileWidth * bpp / 8; memcpy(dest, src, tileWidth * bpp / 8); } - - m->deviceCommandContext->Flush(); - if (needsPresent) - g_VideoMode.GetBackendDevice()->Present(); } } diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h index e3f3eb4df9..d1aa616430 100644 --- a/source/renderer/Renderer.h +++ b/source/renderer/Renderer.h @@ -150,7 +150,7 @@ protected: void RenderFrameImpl(const bool renderGUI, const bool renderLogger); void RenderFrame2D(const bool renderGUI, const bool renderLogger); - void RenderScreenShot(); + void RenderScreenShot(const bool needsPresent); void RenderBigScreenShot(const bool needsPresent); // SetRenderPath: Select the preferred render path. diff --git a/source/renderer/backend/gl/DeviceCommandContext.cpp b/source/renderer/backend/gl/DeviceCommandContext.cpp index 61c3d79737..bed0e29847 100644 --- a/source/renderer/backend/gl/DeviceCommandContext.cpp +++ b/source/renderer/backend/gl/DeviceCommandContext.cpp @@ -725,6 +725,15 @@ void CDeviceCommandContext::SetFramebuffer(CFramebuffer* framebuffer) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->GetHandle()); } +void CDeviceCommandContext::ReadbackFramebufferSync( + const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height, + void* data) +{ + ENSURE(m_Framebuffer); + glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); + ogl_WarnIfError(); +} + void CDeviceCommandContext::SetScissors(const uint32_t scissorCount, const Rect* scissors) { ENSURE(scissorCount <= 1); diff --git a/source/renderer/backend/gl/DeviceCommandContext.h b/source/renderer/backend/gl/DeviceCommandContext.h index 4bca70965d..58ec05abaf 100644 --- a/source/renderer/backend/gl/DeviceCommandContext.h +++ b/source/renderer/backend/gl/DeviceCommandContext.h @@ -57,6 +57,9 @@ public: void ClearFramebuffer(); void ClearFramebuffer(const bool color, const bool depth, const bool stencil); void SetFramebuffer(CFramebuffer* framebuffer); + void ReadbackFramebufferSync( + const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height, + void* data); void UploadTexture(CTexture* texture, const Format dataFormat, const void* data, const size_t dataSize,