Refactor: improve error handling for the animation player
- Pass the exit code back from WM_main_playanim instead of calling exit. - Errors are printed to the stderr. - Resolve some leaks on exit. Note that this addresses noisy leaks reported by ASAN which were flooding the output, but doesn't attempt to address all leaks.
This commit is contained in:
parent
608f017a41
commit
8cdccb0154
@ -1909,7 +1909,7 @@ void WM_draw_region_free(ARegion *region);
|
||||
GPUViewport *WM_draw_region_get_viewport(ARegion *region);
|
||||
GPUViewport *WM_draw_region_get_bound_viewport(ARegion *region);
|
||||
|
||||
void WM_main_playanim(int argc, const char **argv);
|
||||
int WM_main_playanim(int argc, const char **argv);
|
||||
|
||||
/**
|
||||
* Debugging only, convenience function to write on crash.
|
||||
|
@ -93,6 +93,9 @@ static struct {
|
||||
|
||||
static CLG_LogRef LOG = {"wm.playanim"};
|
||||
|
||||
/** Used in user viable messages. */
|
||||
static const char *message_prefix = "Animation Player";
|
||||
|
||||
struct PlayState;
|
||||
static void playanim_window_zoom(PlayState &ps, const float zoom_offset);
|
||||
static bool playanim_window_font_scale_from_dpi(PlayState &ps);
|
||||
@ -1690,7 +1693,7 @@ static bool playanim_window_font_scale_from_dpi(PlayState &ps)
|
||||
* \return True when `args_next` is filled with arguments used to re-run this function
|
||||
* (used for drag & drop).
|
||||
*/
|
||||
static bool wm_main_playanim_intern(int argc, const char **argv, PlayArgs *args_next)
|
||||
static std::optional<int> wm_main_playanim_intern(int argc, const char **argv, PlayArgs *args_next)
|
||||
{
|
||||
ImBuf *ibuf = nullptr;
|
||||
blender::int2 window_pos = {0, 0};
|
||||
@ -1805,67 +1808,90 @@ static bool wm_main_playanim_intern(int argc, const char **argv, PlayArgs *args_
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
printf("%s: no filepath argument given\n", __func__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char *filepath = argv[0];
|
||||
|
||||
if (MOV_is_movie_file(filepath)) {
|
||||
/* OCIO_TODO: support different input color spaces. */
|
||||
MovieReader *anim = MOV_open_file(filepath, IB_byte_data, 0, nullptr);
|
||||
if (anim) {
|
||||
ibuf = MOV_decode_frame(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
|
||||
MOV_close(anim);
|
||||
anim = nullptr;
|
||||
}
|
||||
}
|
||||
else if (!IMB_test_image(filepath)) {
|
||||
printf("%s: '%s' not an image file\n", __func__, filepath);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (ibuf == nullptr) {
|
||||
/* OCIO_TODO: support different input color space. */
|
||||
ibuf = IMB_load_image_from_filepath(filepath, IB_byte_data);
|
||||
}
|
||||
|
||||
if (ibuf == nullptr) {
|
||||
printf("%s: '%s' couldn't open\n", __func__, filepath);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Select GPU backend. */
|
||||
GPU_backend_type_selection_detect();
|
||||
|
||||
/* Init GHOST and open window. */
|
||||
const char *filepath = nullptr;
|
||||
GHOST_EventConsumerHandle ghost_event_consumer = nullptr;
|
||||
|
||||
{
|
||||
ghost_event_consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);
|
||||
std::optional<int> exit_code = [&]() -> std::optional<int> {
|
||||
if (argc == 0) {
|
||||
fprintf(stderr, "%s: no filepath argument given\n", message_prefix);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace);
|
||||
filepath = argv[0];
|
||||
if (MOV_is_movie_file(filepath)) {
|
||||
/* OCIO_TODO: support different input color spaces. */
|
||||
MovieReader *anim = MOV_open_file(filepath, IB_byte_data, 0, nullptr);
|
||||
if (anim) {
|
||||
ibuf = MOV_decode_frame(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
|
||||
MOV_close(anim);
|
||||
anim = nullptr;
|
||||
}
|
||||
}
|
||||
else if (IMB_test_image(filepath)) {
|
||||
/* Pass. */
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%s: '%s' not an image file\n", message_prefix, filepath);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ps.ghost_data.system = GHOST_CreateSystem();
|
||||
GPU_backend_ghost_system_set(ps.ghost_data.system);
|
||||
if (ibuf == nullptr) {
|
||||
/* OCIO_TODO: support different input color space. */
|
||||
ibuf = IMB_load_image_from_filepath(filepath, IB_byte_data);
|
||||
}
|
||||
|
||||
if (UNLIKELY(ps.ghost_data.system == nullptr)) {
|
||||
/* GHOST will have reported the back-ends that failed to load. */
|
||||
CLOG_WARN(&LOG, "GHOST: unable to initialize, exiting!");
|
||||
/* This will leak memory, it's preferable to crashing. */
|
||||
exit(EXIT_FAILURE);
|
||||
if (ibuf == nullptr) {
|
||||
fprintf(stderr, "%s: '%s' couldn't open\n", message_prefix, filepath);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Select GPU backend. */
|
||||
GPU_backend_type_selection_detect();
|
||||
|
||||
/* Init GHOST and open window. */
|
||||
GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace);
|
||||
|
||||
ps.ghost_data.system = GHOST_CreateSystem();
|
||||
if (UNLIKELY(ps.ghost_data.system == nullptr)) {
|
||||
/* GHOST will have reported the back-ends that failed to load. */
|
||||
fprintf(stderr, "%s: unable to initialize GHOST, exiting!\n", message_prefix);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
GPU_backend_ghost_system_set(ps.ghost_data.system);
|
||||
|
||||
GHOST_UseNativePixels();
|
||||
|
||||
ps.ghost_data.window = playanim_window_open(ps.ghost_data.system,
|
||||
"Blender Animation Player",
|
||||
window_pos[0],
|
||||
window_pos[1],
|
||||
ibuf->x,
|
||||
ibuf->y);
|
||||
|
||||
if (UNLIKELY(ps.ghost_data.window == nullptr)) {
|
||||
fprintf(stderr, "%s: unable to create window, exiting!\n", message_prefix);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ghost_event_consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);
|
||||
GHOST_AddEventConsumer(ps.ghost_data.system, ghost_event_consumer);
|
||||
|
||||
return std::nullopt;
|
||||
}();
|
||||
|
||||
if (exit_code) {
|
||||
if (ps.ghost_data.system) {
|
||||
GHOST_DisposeSystem(ps.ghost_data.system);
|
||||
}
|
||||
if (ibuf) {
|
||||
IMB_freeImBuf(ibuf);
|
||||
}
|
||||
IMB_exit();
|
||||
MOV_exit();
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
GHOST_AddEventConsumer(ps.ghost_data.system, ghost_event_consumer);
|
||||
|
||||
GHOST_UseNativePixels();
|
||||
|
||||
ps.ghost_data.window = playanim_window_open(ps.ghost_data.system,
|
||||
"Blender Animation Player",
|
||||
window_pos[0],
|
||||
window_pos[1],
|
||||
ibuf->x,
|
||||
ibuf->y);
|
||||
}
|
||||
|
||||
// GHOST_ActivateWindowDrawingContext(ps.ghost_data.window);
|
||||
@ -2165,24 +2191,16 @@ static bool wm_main_playanim_intern(int argc, const char **argv, PlayArgs *args_
|
||||
if (ps.argv_next) {
|
||||
args_next->argc = ps.argc_next;
|
||||
args_next->argv = ps.argv_next;
|
||||
return true;
|
||||
/* No exit code, keep running. */
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
GHOST_DisposeSystem(ps.ghost_data.system);
|
||||
|
||||
#if 0
|
||||
const int totblock = MEM_get_memory_blocks_in_use();
|
||||
if (totblock != 0) {
|
||||
/* Prints many `bAKey`, `bArgument` messages which are tricky to fix. */
|
||||
printf("Error Totblock: %d\n", totblock);
|
||||
MEM_printmemlist();
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void WM_main_playanim(int argc, const char **argv)
|
||||
int WM_main_playanim(int argc, const char **argv)
|
||||
{
|
||||
#ifdef WITH_AUDASPACE
|
||||
{
|
||||
@ -2200,19 +2218,20 @@ void WM_main_playanim(int argc, const char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
std::optional<int> exit_code = std::nullopt;
|
||||
PlayArgs args_next = {0};
|
||||
do {
|
||||
PlayArgs args_free = args_next;
|
||||
args_next = {0};
|
||||
|
||||
if (wm_main_playanim_intern(argc, argv, &args_next)) {
|
||||
argc = args_next.argc;
|
||||
argv = const_cast<const char **>(args_next.argv);
|
||||
}
|
||||
else {
|
||||
if ((exit_code = wm_main_playanim_intern(argc, argv, &args_next))) {
|
||||
argc = 0;
|
||||
argv = nullptr;
|
||||
}
|
||||
else {
|
||||
argc = args_next.argc;
|
||||
argv = const_cast<const char **>(args_next.argv);
|
||||
}
|
||||
|
||||
if (args_free.argv) {
|
||||
for (int i = 0; i < args_free.argc; i++) {
|
||||
@ -2221,9 +2240,23 @@ void WM_main_playanim(int argc, const char **argv)
|
||||
MEM_freeN(args_free.argv);
|
||||
}
|
||||
} while (argv != nullptr);
|
||||
/* Set in the loop. */
|
||||
BLI_assert(exit_code.has_value());
|
||||
|
||||
#ifdef WITH_AUDASPACE
|
||||
AUD_exit(g_audaspace.audio_device);
|
||||
AUD_exitOnce();
|
||||
#endif
|
||||
|
||||
/* NOTE(@ideasman42): Not useful unless all subsystems are properly shutdown. */
|
||||
if (false) {
|
||||
const int totblock = MEM_get_memory_blocks_in_use();
|
||||
if (totblock != 0) {
|
||||
/* Prints many `bAKey`, `bArgument` messages which are tricky to fix. */
|
||||
printf("Error Totblock: %d\n", totblock);
|
||||
MEM_printmemlist();
|
||||
}
|
||||
}
|
||||
|
||||
return exit_code.value();
|
||||
}
|
||||
|
@ -1699,9 +1699,9 @@ static int arg_handle_playback_mode(int argc, const char **argv, void * /*data*/
|
||||
/* Ignore the animation player if `-b` was given first. */
|
||||
if (G.background == 0) {
|
||||
/* Skip this argument (`-a`). */
|
||||
WM_main_playanim(argc - 1, argv + 1);
|
||||
const int exit_code = WM_main_playanim(argc - 1, argv + 1);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
return -2;
|
||||
|
Loading…
x
Reference in New Issue
Block a user