diff --git a/CHANGELOG.md b/CHANGELOG.md index 53d2af3d9fa2fc920b4d2775d40c9e1c4a67b9f4..37b09781901c5fff22ff426515fc04a1fd7ad6b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ This file logs the changes that are actually interesting to users (new features, changed functionality, fixed bugs). +## Version 2.3 (in development) + +- Changed how progressive rendering works. Nonuniform tasks are now supported. This requires + Flamenco Server 2.2 or newer. Progressive render jobs generated by older versions of Flamenco + Server are no longer supported. + + ## Version 2.2.1 (2019-01-14) - Fixed bug where an uncaught exception could make the Worker stop requesting tasks or go into an diff --git a/flamenco_worker/commands.py b/flamenco_worker/commands.py index 588b0481044ca7fc25587d61e9bdce3659bbb871..b169a7dc13d9597e19830639bf0068f08a73a1d3 100644 --- a/flamenco_worker/commands.py +++ b/flamenco_worker/commands.py @@ -868,18 +868,31 @@ class BlenderRenderCommand(AbstractSubprocessCommand): @command_executor('blender_render_progressive') class BlenderRenderProgressiveCommand(BlenderRenderCommand): def validate(self, settings: Settings): + if 'cycles_chunk' in settings: + return '"cycles_chunk" is an obsolete setting. Recreate the job using Flamenco ' \ + 'Server 2.2 or newer, or use an older Worker.' + err = super().validate(settings) - if err: return err + if err: + return err cycles_num_chunks, err = self._setting(settings, 'cycles_num_chunks', True, int) - if err: return err + if err: + return err if cycles_num_chunks < 1: return '"cycles_num_chunks" must be a positive integer' - cycles_chunk, err = self._setting(settings, 'cycles_chunk', True, int) - if err: return err - if cycles_chunk < 1: - return '"cycles_chunk" must be a positive integer' + cycles_chunk_start, err = self._setting(settings, 'cycles_chunk_start', True, int) + if err: + return err + if cycles_chunk_start < 1: + return '"cycles_chunk_start" must be a positive integer' + + cycles_chunk_end, err = self._setting(settings, 'cycles_chunk_end', True, int) + if err: + return err + if cycles_chunk_end < 1: + return '"cycles_chunk_end" must be a positive integer' async def _build_blender_cmd(self, settings): cmd = await super()._build_blender_cmd(settings) @@ -887,7 +900,8 @@ class BlenderRenderProgressiveCommand(BlenderRenderCommand): return cmd + [ '--', '--cycles-resumable-num-chunks', str(settings['cycles_num_chunks']), - '--cycles-resumable-current-chunk', str(settings['cycles_chunk']), + '--cycles-resumable-start-chunk', str(settings['cycles_chunk_start']), + '--cycles-resumable-end-chunk', str(settings['cycles_chunk_end']), ] diff --git a/tests/test_commands_blender_render_progressive.py b/tests/test_commands_blender_render_progressive.py new file mode 100644 index 0000000000000000000000000000000000000000..f1368f01f9d73cb5d4871f5ad0791b6d35221a3d --- /dev/null +++ b/tests/test_commands_blender_render_progressive.py @@ -0,0 +1,67 @@ +from pathlib import Path +import subprocess +import tempfile +from unittest import mock + +from unittest.mock import patch + +from tests.test_runner import AbstractCommandTest + + +class BlenderRenderProgressiveTest(AbstractCommandTest): + thisfile = Path(__file__).as_posix() + + def setUp(self): + super().setUp() + + from flamenco_worker.commands import BlenderRenderProgressiveCommand + + self.cmd = BlenderRenderProgressiveCommand( + worker=self.fworker, + task_id='12345', + command_idx=0, + ) + + def test_cli_args(self): + """Test that CLI arguments in the blender_cmd setting are handled properly.""" + from tests.mock_responses import CoroMock + + filepath = Path(__file__).parent.as_posix() + settings = { + # Point blender_cmd to this file so that we're sure it exists. + 'blender_cmd': f'{self.thisfile!r} --with --cli="args for CLI"', + 'chunk_size': 100, + 'frames': '1..2', + 'format': 'EXR', + 'filepath': filepath, + 'render_output': '/some/path/there.exr', + 'cycles_num_chunks': 400, + 'cycles_chunk_start': 223, + 'cycles_chunk_end': 311, + } + + cse = CoroMock(...) + cse.coro.return_value.wait = CoroMock(return_value=0) + cse.coro.return_value.pid = 47 + with patch('asyncio.create_subprocess_exec', new=cse) as mock_cse: + self.loop.run_until_complete(self.cmd.run(settings)) + + mock_cse.assert_called_once_with( + self.thisfile, + '--with', + '--cli=args for CLI', + '--enable-autoexec', + '-noaudio', + '--background', + filepath, + '--render-output', '/some/path/there.exr', + '--render-format', 'EXR', + '--render-frame', '1..2', + '--', + '--cycles-resumable-num-chunks', '400', + '--cycles-resumable-start-chunk', '223', + '--cycles-resumable-end-chunk', '311', + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + )