Fix #9147: Delay making screenshots until the next draw tick as we may not access the video buffer from the game thread.

(cherry picked from commit 1f159f79de)
This commit is contained in:
Michael Lutz
2021-05-01 19:55:46 +02:00
committed by Jonathan G Rennison
parent 1b46ef756e
commit 2e6cadb005
3 changed files with 33 additions and 11 deletions

View File

@@ -1514,7 +1514,7 @@ DEF_CONSOLE_CMD(ConScreenShot)
ScreenshotType type = SC_VIEWPORT; ScreenshotType type = SC_VIEWPORT;
uint32 width = 0; uint32 width = 0;
uint32 height = 0; uint32 height = 0;
const char *name = nullptr; std::string name{};
uint32 arg_index = 1; uint32 arg_index = 1;
if (argc > arg_index) { if (argc > arg_index) {

View File

@@ -892,7 +892,7 @@ static ScreenshotType _confirmed_screenshot_type; ///< Screenshot type the curre
*/ */
static void ScreenshotConfirmationCallback(Window *w, bool confirmed) static void ScreenshotConfirmationCallback(Window *w, bool confirmed)
{ {
if (confirmed) MakeScreenshot(_confirmed_screenshot_type, nullptr); if (confirmed) MakeScreenshot(_confirmed_screenshot_type, {});
} }
/** /**
@@ -918,7 +918,7 @@ void MakeScreenshotWithConfirm(ScreenshotType t)
ShowQuery(STR_WARNING_SCREENSHOT_SIZE_CAPTION, STR_WARNING_SCREENSHOT_SIZE_MESSAGE, nullptr, ScreenshotConfirmationCallback); ShowQuery(STR_WARNING_SCREENSHOT_SIZE_CAPTION, STR_WARNING_SCREENSHOT_SIZE_MESSAGE, nullptr, ScreenshotConfirmationCallback);
} else { } else {
/* Less than 64M pixels, just do it */ /* Less than 64M pixels, just do it */
MakeScreenshot(t, nullptr); MakeScreenshot(t, {});
} }
} }
@@ -944,18 +944,14 @@ static void ShowScreenshotResultMessage(ScreenshotType t, bool ret)
/** /**
* Make a screenshot. * Make a screenshot.
* Unconditionally take a screenshot of the requested type.
* @param t the type of screenshot to make. * @param t the type of screenshot to make.
* @param name the name to give to the screenshot. * @param name the name to give to the screenshot.
* @param width the width of the screenshot of, or 0 for current viewport width (only works for SC_ZOOMEDIN and SC_DEFAULTZOOM). * @param width the width of the screenshot of, or 0 for current viewport width (only works for SC_ZOOMEDIN and SC_DEFAULTZOOM).
* @param height the height of the screenshot of, or 0 for current viewport height (only works for SC_ZOOMEDIN and SC_DEFAULTZOOM). * @param height the height of the screenshot of, or 0 for current viewport height (only works for SC_ZOOMEDIN and SC_DEFAULTZOOM).
* @return true iff the screenshot was made successfully * @return true iff the screenshot was made successfully
* @see MakeScreenshotWithConfirm
*/ */
bool MakeScreenshot(ScreenshotType t, const char *name, uint32 width, uint32 height) static bool RealMakeScreenshot(ScreenshotType t, std::string name, uint32 width, uint32 height)
{ {
VideoDriver::VideoBufferLocker lock;
if (t == SC_VIEWPORT) { if (t == SC_VIEWPORT) {
/* First draw the dirty parts of the screen and only then change the name /* First draw the dirty parts of the screen and only then change the name
* of the screenshot. This way the screenshot will always show the name * of the screenshot. This way the screenshot will always show the name
@@ -968,7 +964,7 @@ bool MakeScreenshot(ScreenshotType t, const char *name, uint32 width, uint32 hei
} }
_screenshot_name[0] = '\0'; _screenshot_name[0] = '\0';
if (name != nullptr) strecpy(_screenshot_name, name, lastof(_screenshot_name)); if (!name.empty()) strecpy(_screenshot_name, name.c_str(), lastof(_screenshot_name));
bool ret; bool ret;
switch (t) { switch (t) {
@@ -997,7 +993,7 @@ bool MakeScreenshot(ScreenshotType t, const char *name, uint32 width, uint32 hei
} }
case SC_MINIMAP: case SC_MINIMAP:
ret = MakeMinimapWorldScreenshot(name); ret = MakeMinimapWorldScreenshot(name.empty() ? nullptr : name.c_str());
break; break;
default: default:
@@ -1009,6 +1005,32 @@ bool MakeScreenshot(ScreenshotType t, const char *name, uint32 width, uint32 hei
return ret; return ret;
} }
/**
* Schedule making a screenshot.
* Unconditionally take a screenshot of the requested type.
* @param t the type of screenshot to make.
* @param name the name to give to the screenshot.
* @param width the width of the screenshot of, or 0 for current viewport width (only works for SC_ZOOMEDIN and SC_DEFAULTZOOM).
* @param height the height of the screenshot of, or 0 for current viewport height (only works for SC_ZOOMEDIN and SC_DEFAULTZOOM).
* @return true iff the screenshot was successfully made.
* @see MakeScreenshotWithConfirm
*/
bool MakeScreenshot(ScreenshotType t, std::string name, uint32 width, uint32 height)
{
if (t == SC_CRASHLOG) {
/* Video buffer might or might not be locked. */
VideoDriver::VideoBufferLocker lock;
return RealMakeScreenshot(t, name, width, height);
}
VideoDriver::GetInstance()->QueueOnMainThread([=] { // Capture by value to not break scope.
RealMakeScreenshot(t, name, width, height);
});
return true;
}
/** /**
* Callback for generating a smallmap screenshot. * Callback for generating a smallmap screenshot.
* @param userdata SmallMapWindow window pointer * @param userdata SmallMapWindow window pointer

View File

@@ -33,7 +33,7 @@ void SetupScreenshotViewport(ScreenshotType t, struct Viewport *vp, uint32 width
bool MakeHeightmapScreenshot(const char *filename); bool MakeHeightmapScreenshot(const char *filename);
bool MakeSmallMapScreenshot(unsigned int width, unsigned int height, SmallMapWindow *window); bool MakeSmallMapScreenshot(unsigned int width, unsigned int height, SmallMapWindow *window);
void MakeScreenshotWithConfirm(ScreenshotType t); void MakeScreenshotWithConfirm(ScreenshotType t);
bool MakeScreenshot(ScreenshotType t, const char *name, uint32 width = 0, uint32 height = 0); bool MakeScreenshot(ScreenshotType t, std::string name, uint32 width = 0, uint32 height = 0);
bool MakeMinimapWorldScreenshot(const char *name); bool MakeMinimapWorldScreenshot(const char *name);
void SetScreenshotAuxiliaryText(const char *key, const char *value); void SetScreenshotAuxiliaryText(const char *key, const char *value);
inline void ClearScreenshotAuxiliaryText() { SetScreenshotAuxiliaryText(nullptr, nullptr); } inline void ClearScreenshotAuxiliaryText() { SetScreenshotAuxiliaryText(nullptr, nullptr); }