From 41149ca134ff1ffe1029e3eebf1c6b3e95ef4422 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Thu, 15 Mar 2018 20:43:08 +0100 Subject: [PATCH 1/4] GHOST: Support Unity taskbar progress API Unity itself is deprecated, but the API is also supported by KDE and the GNOME Dock extension, which means that it will be useful for a wide variety of distributions. To get a progress bar, the system must have a blender.desktop file and libunity installed. The need for libunity is annoying, but the only alternative would be to integrate a DBus library... Reviewers: campbellbarton, brecht Differential Revision: https://developer.blender.org/D3106 --- intern/ghost/CMakeLists.txt | 2 + intern/ghost/intern/GHOST_TaskbarX11.cpp | 130 +++++++++++++++++++++++ intern/ghost/intern/GHOST_TaskbarX11.h | 45 ++++++++ intern/ghost/intern/GHOST_WindowX11.cpp | 22 ++++ intern/ghost/intern/GHOST_WindowX11.h | 7 ++ 5 files changed, 206 insertions(+) create mode 100644 intern/ghost/intern/GHOST_TaskbarX11.cpp create mode 100644 intern/ghost/intern/GHOST_TaskbarX11.h diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 5a97da28d17..ba569ff4166 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -177,10 +177,12 @@ elseif(WITH_X11) intern/GHOST_DisplayManagerX11.cpp intern/GHOST_SystemX11.cpp intern/GHOST_WindowX11.cpp + intern/GHOST_TaskbarX11.cpp intern/GHOST_DisplayManagerX11.h intern/GHOST_SystemX11.h intern/GHOST_WindowX11.h + intern/GHOST_TaskbarX11.h ) if(NOT WITH_GL_EGL) diff --git a/intern/ghost/intern/GHOST_TaskbarX11.cpp b/intern/ghost/intern/GHOST_TaskbarX11.cpp new file mode 100644 index 00000000000..b47068df39f --- /dev/null +++ b/intern/ghost/intern/GHOST_TaskbarX11.cpp @@ -0,0 +1,130 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): + * Lukas Stockner + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_TaskbarX11.cpp + * \ingroup GHOST + */ + +#include "GHOST_TaskbarX11.h" + +#include +#include +#include +#include + +typedef void*(*unity_get_entry_t)(const char*); +typedef void(*unity_set_progress_t)(void*, double); +typedef void(*unity_set_progress_visible_t)(void*, int); +typedef int(*unity_event_loop_t)(void*, int); + +static unity_get_entry_t unity_get_entry; +static unity_set_progress_t unity_set_progress; +static unity_set_progress_visible_t unity_set_progress_visible; +static unity_event_loop_t unity_event_loop; + +static bool libunity_initialized = false; +static bool libunity_available = false; +void* libunity_handle = NULL; + +void GHOST_TaskBarX11::free() +{ + if(libunity_handle) { + dlclose(libunity_handle); + libunity_handle = NULL; + } +} + +bool GHOST_TaskBarX11::init() +{ + if(libunity_initialized) { + return libunity_available; + } + + libunity_initialized = true; + + const char *libunity_names[] = {"libunity.so.4", "libunity.so.6", "libunity.so.9", "libunity.so", NULL}; + for(int i = 0; libunity_names[i]; i++) { + libunity_handle = dlopen(libunity_names[i], RTLD_LAZY); + if(libunity_handle) { + break; + } + } + + if(!libunity_handle) { + return false; + } + + unity_get_entry = (unity_get_entry_t) dlsym(libunity_handle, "unity_launcher_entry_get_for_desktop_id"); + if(!unity_get_entry) { + fprintf(stderr, "failed to load libunity: %s\n", dlerror()); + return false; + } + unity_set_progress = (unity_set_progress_t) dlsym(libunity_handle, "unity_launcher_entry_set_progress"); + if(!unity_set_progress) { + fprintf(stderr, "failed to load libunity: %s\n", dlerror()); + return false; + } + unity_set_progress_visible = (unity_set_progress_visible_t) dlsym(libunity_handle, "unity_launcher_entry_set_progress_visible"); + if(!unity_set_progress_visible) { + fprintf(stderr, "failed to load libunity: %s\n", dlerror()); + return false; + } + unity_event_loop = (unity_event_loop_t) dlsym(libunity_handle, "g_main_context_iteration"); + if(!unity_event_loop) { + fprintf(stderr, "failed to load libunity: %s\n", dlerror()); + return false; + } + + atexit(GHOST_TaskBarX11::free); + + libunity_available = true; + return true; +} + +GHOST_TaskBarX11::GHOST_TaskBarX11(const char *name) +{ + if(GHOST_TaskBarX11::init()) { + handle = unity_get_entry(name); + } + else { + handle = NULL; + } +} + +bool GHOST_TaskBarX11::is_valid() +{ + return (handle != NULL); +} + +void GHOST_TaskBarX11::set_progress(double progress) +{ + assert(is_valid()); + unity_set_progress(handle, progress); +} + +void GHOST_TaskBarX11::set_progress_enabled(bool enabled) +{ + assert(is_valid()); + unity_set_progress_visible(handle, enabled ? 1 : 0); + unity_event_loop(NULL, 0); +} \ No newline at end of file diff --git a/intern/ghost/intern/GHOST_TaskbarX11.h b/intern/ghost/intern/GHOST_TaskbarX11.h new file mode 100644 index 00000000000..ed0e5f9b329 --- /dev/null +++ b/intern/ghost/intern/GHOST_TaskbarX11.h @@ -0,0 +1,45 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): + * Lukas Stockner + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_TaskbarX11.h + * \ingroup GHOST + */ +#ifndef __GHOST_TASKBARX11_H__ +#define __GHOST_TASKBARX11_H__ + +class GHOST_TaskBarX11 +{ +public: + static bool init(); + static void free(); + + GHOST_TaskBarX11(const char *name); + + bool is_valid(); + void set_progress(double progress); + void set_progress_enabled(bool enabled); +private: + void *handle; +}; + +#endif /*__GHOST_TASKBARX11_H__*/ diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 1abdec37403..13fef7d1db1 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -334,6 +334,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system, m_empty_cursor(None), m_custom_cursor(None), m_visible_cursor(None), + m_taskbar("blender.desktop"), #ifdef WITH_XDND m_dropTarget(NULL), #endif @@ -1717,3 +1718,24 @@ getDPIHint() int dpi = pixelDiagonal / inchDiagonal; return dpi; } + +GHOST_TSuccess GHOST_WindowX11::setProgressBar(float progress) +{ + if (m_taskbar.is_valid()) { + m_taskbar.set_progress(progress); + m_taskbar.set_progress_enabled(true); + return GHOST_kSuccess; + } + + return GHOST_kFailure; +} + +GHOST_TSuccess GHOST_WindowX11::endProgressBar() +{ + if (m_taskbar.is_valid()) { + m_taskbar.set_progress_enabled(false); + return GHOST_kSuccess; + } + + return GHOST_kFailure; +} diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 5c54c1e8162..236fe0b76b0 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -41,6 +41,8 @@ # include #endif +#include "GHOST_TaskbarX11.h" + #include class STR_String; @@ -166,6 +168,9 @@ public: invalidate( ); + GHOST_TSuccess setProgressBar(float progress); + GHOST_TSuccess endProgressBar(); + /** * Destructor. * Closes the window and disposes resources allocated. @@ -347,6 +352,8 @@ private: /** Cache of XC_* ID's to XCursor structures */ std::map m_standard_cursors; + GHOST_TaskBarX11 m_taskbar; + #ifdef WITH_XDND GHOST_DropTargetX11 *m_dropTarget; #endif From e56fd59f22cb45ed4780b443b7245483dd5509ad Mon Sep 17 00:00:00 2001 From: Guillaume Chereau Date: Thu, 15 Mar 2018 22:07:37 +0100 Subject: [PATCH 2/4] Code refactor: move OIIO image buffer writing outside session, into callback. Original patch by Guillaume, modifications by Brecht. Differential Revision: https://developer.blender.org/D3102 --- intern/cycles/app/cycles_standalone.cpp | 32 +++++++++++++++++++++++- intern/cycles/render/buffers.cpp | 33 ------------------------- intern/cycles/render/buffers.h | 1 - intern/cycles/render/session.cpp | 10 +++++--- intern/cycles/render/session.h | 8 +++--- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp index 2d4b0d35e54..c682744f5fa 100644 --- a/intern/cycles/app/cycles_standalone.cpp +++ b/intern/cycles/app/cycles_standalone.cpp @@ -51,6 +51,7 @@ struct Options { SessionParams session_params; bool quiet; bool show_help, interactive, pause; + string output_path; } options; static void session_print(const string& str) @@ -86,6 +87,34 @@ static void session_print_status() session_print(status); } +static bool write_render(const uchar *pixels, int w, int h, int channels) +{ + string msg = string_printf("Writing image %s", options.output_path.c_str()); + session_print(msg); + + ImageOutput *out = ImageOutput::create(options.output_path); + if(!out) { + return false; + } + + ImageSpec spec(w, h, channels, TypeDesc::UINT8); + if(!out->open(options.output_path, spec)) { + return false; + } + + /* conversion for different top/bottom convention */ + out->write_image(TypeDesc::UINT8, + pixels + (h - 1) * w * channels, + AutoStride, + -w * channels, + AutoStride); + + out->close(); + delete out; + + return true; +} + static BufferParams& session_buffer_params() { static BufferParams buffer_params; @@ -120,6 +149,7 @@ static void scene_init() static void session_init() { + options.session_params.write_render_cb = write_render; options.session = new Session(options.session_params); if(options.session_params.background && !options.quiet) @@ -364,7 +394,7 @@ static void options_parse(int argc, const char **argv) "--background", &options.session_params.background, "Render in background, without user interface", "--quiet", &options.quiet, "In background mode, don't print progress messages", "--samples %d", &options.session_params.samples, "Number of samples to render", - "--output %s", &options.session_params.output_path, "File path to write output image", + "--output %s", &options.output_path, "File path to write output image", "--threads %d", &options.session_params.threads, "CPU Rendering Threads", "--width %d", &options.width, "Window width in pixel", "--height %d", &options.height, "Window height in pixel", diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index 84d10cc477e..6f560380b40 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -21,7 +21,6 @@ #include "util/util_foreach.h" #include "util/util_hash.h" -#include "util/util_image.h" #include "util/util_math.h" #include "util/util_opengl.h" #include "util/util_time.h" @@ -448,37 +447,5 @@ bool DisplayBuffer::draw_ready() return (draw_width != 0 && draw_height != 0); } -void DisplayBuffer::write(const string& filename) -{ - int w = draw_width; - int h = draw_height; - - if(w == 0 || h == 0) - return; - - if(half_float) - return; - - /* read buffer from device */ - uchar4 *pixels = rgba_byte.copy_from_device(0, w, h); - - /* write image */ - ImageOutput *out = ImageOutput::create(filename); - ImageSpec spec(w, h, 4, TypeDesc::UINT8); - - out->open(filename, spec); - - /* conversion for different top/bottom convention */ - out->write_image(TypeDesc::UINT8, - (uchar*)(pixels + (h-1)*w), - AutoStride, - -w*sizeof(uchar4), - AutoStride); - - out->close(); - - delete out; -} - CCL_NAMESPACE_END diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h index 028bfb83735..dfc98fe2061 100644 --- a/intern/cycles/render/buffers.h +++ b/intern/cycles/render/buffers.h @@ -113,7 +113,6 @@ public: ~DisplayBuffer(); void reset(BufferParams& params); - void write(const string& filename); void draw_set(int width, int height); void draw(Device *device, const DeviceDrawParams& draw_params); diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 41156038558..bb636dd962a 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -55,7 +55,7 @@ Session::Session(const SessionParams& params_) device = Device::create(params.device, stats, params.background); - if(params.background && params.output_path.empty()) { + if(params.background && !params.write_render_cb) { buffers = NULL; display = NULL; } @@ -101,7 +101,7 @@ Session::~Session() wait(); } - if(!params.output_path.empty()) { + if(params.write_render_cb) { /* tonemap and write out image if requested */ delete display; @@ -109,8 +109,10 @@ Session::~Session() display->reset(buffers->params); tonemap(params.samples); - progress.set_status("Writing Image", params.output_path); - display->write(params.output_path); + int w = display->draw_width; + int h = display->draw_height; + uchar4 *pixels = display->rgba_byte.copy_from_device(0, w, h); + params.write_render_cb((uchar*)pixels, w, h, 4); } /* clean up */ diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 8495d95666b..e63cad0d977 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -45,7 +45,6 @@ public: DeviceInfo device; bool background; bool progressive_refine; - string output_path; bool progressive; bool experimental; @@ -71,11 +70,15 @@ public: ShadingSystem shadingsystem; + function write_render_cb; + SessionParams() { background = false; progressive_refine = false; - output_path = ""; progressive = false; experimental = false; @@ -106,7 +109,6 @@ public: { return !(device == params.device && background == params.background && progressive_refine == params.progressive_refine - && output_path == params.output_path /* && samples == params.samples */ && progressive == params.progressive && experimental == params.experimental From 07b07e53ea0831ffb0c2a3aff0a33b40aa935c5c Mon Sep 17 00:00:00 2001 From: Cheryl Chen Date: Thu, 15 Mar 2018 23:36:15 +0100 Subject: [PATCH 3/4] Fix T53971: single layer render showing the wrong render layer in image editor. Original patch Cheryl Chen, extra fixes by Brecht. Differential Revision: https://developer.blender.org/D3098 --- .../blender/editors/render/render_internal.c | 22 +++++++++++++---- .../render/extern/include/RE_pipeline.h | 2 ++ .../blender/render/intern/source/pipeline.c | 24 ++++++++++++++----- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 58b4c0fe222..c27570aabc5 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -521,10 +521,8 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, int layer = BLI_findstringindex(&main_rr->layers, (char *)rr->renlay->name, offsetof(RenderLayer, name)); - if (layer != rj->last_layer) { - sima->iuser.layer = layer; - rj->last_layer = layer; - } + sima->iuser.layer = layer; + rj->last_layer = layer; } iuser->pass = sima->iuser.pass; @@ -621,7 +619,21 @@ static void render_image_restore_layer(RenderJob *rj) if (sa == rj->sa) { if (sa->spacetype == SPACE_IMAGE) { SpaceImage *sima = sa->spacedata.first; - sima->iuser.layer = rj->orig_layer; + + if (RE_HasSingleLayer(rj->re)) { + /* For single layer renders keep the active layer + * visible, or show the compositing result. */ + RenderResult *rr = RE_AcquireResultRead(rj->re); + if(RE_HasCombinedLayer(rr)) { + sima->iuser.layer = 0; + } + RE_ReleaseResult(rj->re); + } + else { + /* For multiple layer render, set back the layer + * that was set at the start of rendering. */ + sima->iuser.layer = rj->orig_layer; + } } return; } diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index bb056675887..de71b8d1023 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -236,6 +236,8 @@ void RE_render_result_rect_from_ibuf( struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name); float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, const char *name, const char *viewname); +bool RE_HasSingleLayer(struct Render *re); + /* add passes for grease pencil */ struct RenderPass *RE_create_gp_pass(struct RenderResult *rr, const char *layername, const char *viewname); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 7cab5f43aca..e17a503cd4e 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -257,6 +257,11 @@ RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) } } +bool RE_HasSingleLayer(Render *re) +{ + return (re->r.scemode & R_SINGLE_LAYER); +} + RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty) { return render_result_new_from_exr(exrhandle, colorspace, predivide, rectx, recty); @@ -264,12 +269,19 @@ RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool RenderLayer *render_get_active_layer(Render *re, RenderResult *rr) { - RenderLayer *rl = BLI_findlink(&rr->layers, re->r.actlay); - - if (rl) - return rl; - else - return rr->layers.first; + SceneRenderLayer *srl = BLI_findlink(&re->r.layers, re->r.actlay); + + if (srl) { + RenderLayer *rl = BLI_findstring(&rr->layers, + srl->name, + offsetof(RenderLayer, name)); + + if (rl) { + return rl; + } + } + + return rr->layers.first; } static int render_scene_needs_vector(Render *re) From e5327afcb73f102db8a82ccefc29bbf9cc6fb60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 16 Mar 2018 04:06:18 +0100 Subject: [PATCH 4/4] Fix T54326: Import Alembic stuck in edit mode Switch to object mode before doing the import. --- source/blender/editors/io/io_alembic.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index ca4ab30a08d..08181af2ef3 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -59,6 +59,8 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "ED_object.h" + #include "UI_interface.h" #include "UI_resources.h" @@ -543,6 +545,22 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op) } } + /* Switch to object mode to avoid being stuck in other modes (T54326). */ + if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT) { + Object *obedit = CTX_data_edit_object(C); + + if (obedit != NULL) { + ED_object_mode_toggle(C, obedit->mode); + } + else { + Object *ob = CTX_data_active_object(C); + + if (ob) { + ED_object_mode_toggle(C, ob->mode); + } + } + } + bool ok = ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes, as_background_job);