Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVojtech Bubnik <bubnikv@gmail.com>2021-04-13 11:55:27 +0300
committerVojtech Bubnik <bubnikv@gmail.com>2021-04-13 11:55:27 +0300
commitdb324b22951c14d2d3d74b670b6bec4e411c781a (patch)
treef637605921f522f513d79e28e4a33a98d7044bac
parent89b942ffb7a3a2f5368a387b359909900934b0d9 (diff)
Ported ChromeOS support from master aka PrusaSlicer 2.4.0-alpha:
1) Detect platform 2) Disable OpenGL multi-sampling on ChromeOS 3) Disable eject on ChromeOS, different location of external devices mount point.
-rw-r--r--src/PrusaSlicer.cpp4
-rw-r--r--src/libslic3r/CMakeLists.txt2
-rw-r--r--src/libslic3r/Platform.cpp71
-rw-r--r--src/libslic3r/Platform.hpp41
-rw-r--r--src/libslic3r/utils.cpp141
-rw-r--r--src/slic3r/GUI/OpenGLManager.cpp10
-rw-r--r--src/slic3r/GUI/Plater.cpp5
-rw-r--r--src/slic3r/GUI/RemovableDriveManager.cpp51
8 files changed, 305 insertions, 20 deletions
diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp
index 60f3a1321..6a019271e 100644
--- a/src/PrusaSlicer.cpp
+++ b/src/PrusaSlicer.cpp
@@ -37,6 +37,7 @@
#include "libslic3r/GCode/PostProcessor.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/ModelArrange.hpp"
+#include "libslic3r/Platform.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/TriangleMesh.hpp"
@@ -594,6 +595,9 @@ bool CLI::setup(int argc, char **argv)
}
}
+ // Detect the operating system flavor after SLIC3R_LOGLEVEL is set.
+ detect_platform();
+
boost::filesystem::path path_to_binary = boost::filesystem::system_complete(argv[0]);
// Path from the Slic3r binary to its resources.
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index 11e37afc6..5e0808190 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -137,6 +137,8 @@ add_library(libslic3r STATIC
PerimeterGenerator.hpp
PlaceholderParser.cpp
PlaceholderParser.hpp
+ Platform.cpp
+ Platform.hpp
Point.cpp
Point.hpp
Polygon.cpp
diff --git a/src/libslic3r/Platform.cpp b/src/libslic3r/Platform.cpp
new file mode 100644
index 000000000..ae02c42b3
--- /dev/null
+++ b/src/libslic3r/Platform.cpp
@@ -0,0 +1,71 @@
+#include "Platform.hpp"
+
+#include <boost/log/trivial.hpp>
+#include <boost/filesystem/operations.hpp>
+
+namespace Slic3r {
+
+static auto s_platform = Platform::Uninitialized;
+static auto s_platform_flavor = PlatformFlavor::Uninitialized;
+
+void detect_platform()
+{
+#if defined(_WIN32)
+ BOOST_LOG_TRIVIAL(info) << "Platform: Windows";
+ s_platform = Platform::Windows;
+ s_platform_flavor = PlatformFlavor::Generic;
+#elif defined(__APPLE__)
+ BOOST_LOG_TRIVIAL(info) << "Platform: OSX";
+ s_platform = Platform::OSX;
+ s_platform_flavor = PlatformFlavor::Generic;
+#elif defined(__linux__)
+ BOOST_LOG_TRIVIAL(info) << "Platform: Linux";
+ s_platform = Platform::Linux;
+ s_platform_flavor = PlatformFlavor::GenericLinux;
+ // Test for Chromium.
+ {
+ FILE *f = ::fopen("/proc/version", "rt");
+ if (f) {
+ char buf[4096];
+ // Read the 1st line.
+ if (::fgets(buf, 4096, f)) {
+ if (strstr(buf, "Chromium OS") != nullptr) {
+ s_platform_flavor = PlatformFlavor::LinuxOnChromium;
+ BOOST_LOG_TRIVIAL(info) << "Platform flavor: LinuxOnChromium";
+ } else if (strstr(buf, "microsoft") != nullptr || strstr(buf, "Microsoft") != nullptr) {
+ if (boost::filesystem::exists("/run/WSL") && getenv("WSL_INTEROP") != nullptr) {
+ BOOST_LOG_TRIVIAL(info) << "Platform flavor: WSL2";
+ s_platform_flavor = PlatformFlavor::WSL2;
+ } else {
+ BOOST_LOG_TRIVIAL(info) << "Platform flavor: WSL";
+ s_platform_flavor = PlatformFlavor::WSL;
+ }
+ }
+ }
+ ::fclose(f);
+ }
+ }
+#elif defined(__OpenBSD__)
+ BOOST_LOG_TRIVIAL(info) << "Platform: OpenBSD";
+ s_platform = Platform::BSDUnix;
+ s_platform_flavor = PlatformFlavor::OpenBSD;
+#else
+ // This should not happen.
+ BOOST_LOG_TRIVIAL(info) << "Platform: Unknown";
+ static_assert(false, "Unknown platform detected");
+ s_platform = Platform::Unknown;
+ s_platform_flavor = PlatformFlavor::Unknown;
+#endif
+}
+
+Platform platform()
+{
+ return s_platform;
+}
+
+PlatformFlavor platform_flavor()
+{
+ return s_platform_flavor;
+}
+
+} // namespace Slic3r
diff --git a/src/libslic3r/Platform.hpp b/src/libslic3r/Platform.hpp
new file mode 100644
index 000000000..735728e89
--- /dev/null
+++ b/src/libslic3r/Platform.hpp
@@ -0,0 +1,41 @@
+#ifndef SLIC3R_Platform_HPP
+#define SLIC3R_Platform_HPP
+
+namespace Slic3r {
+
+enum class Platform
+{
+ Uninitialized,
+ Unknown,
+ Windows,
+ OSX,
+ Linux,
+ BSDUnix,
+};
+
+enum class PlatformFlavor
+{
+ Uninitialized,
+ Unknown,
+ // For Windows and OSX, until we need to be more specific.
+ Generic,
+ // For Platform::Linux
+ GenericLinux,
+ LinuxOnChromium,
+ // Microsoft's Windows on Linux (Linux kernel simulated on NTFS kernel)
+ WSL,
+ // Microsoft's Windows on Linux, version 2 (virtual machine)
+ WSL2,
+ // For Platform::BSDUnix
+ OpenBSD,
+};
+
+// To be called on program start-up.
+void detect_platform();
+
+Platform platform();
+PlatformFlavor platform_flavor();
+
+} // namespace Slic3r
+
+#endif // SLIC3R_Platform_HPP
diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp
index 0c26d42c8..9d0162980 100644
--- a/src/libslic3r/utils.cpp
+++ b/src/libslic3r/utils.cpp
@@ -6,6 +6,7 @@
#include <cstdarg>
#include <stdio.h>
+#include "Platform.hpp"
#include "Time.hpp"
#ifdef WIN32
@@ -417,6 +418,140 @@ std::error_code rename_file(const std::string &from, const std::string &to)
#endif
}
+#ifdef __linux__
+// Copied from boost::filesystem, to support copying a file to a weird filesystem, which does not support changing file attributes,
+// for example ChromeOS Linux integration or FlashAIR WebDAV.
+// Copied and simplified from boost::filesystem::detail::copy_file() with option = overwrite_if_exists and with just the Linux path kept,
+// and only features supported by Linux 3.10 (on our build server with CentOS 7) are kept, namely sendfile with ranges and statx() are not supported.
+bool copy_file_linux(const boost::filesystem::path &from, const boost::filesystem::path &to, boost::system::error_code &ec)
+{
+ using namespace boost::filesystem;
+
+ struct fd_wrapper
+ {
+ int fd { -1 };
+ fd_wrapper() = default;
+ explicit fd_wrapper(int fd) throw() : fd(fd) {}
+ ~fd_wrapper() throw() { if (fd >= 0) ::close(fd); }
+ };
+
+ ec.clear();
+ int err = 0;
+
+ // Note: Declare fd_wrappers here so that errno is not clobbered by close() that may be called in fd_wrapper destructors
+ fd_wrapper infile, outfile;
+
+ while (true) {
+ infile.fd = ::open(from.c_str(), O_RDONLY | O_CLOEXEC);
+ if (infile.fd < 0) {
+ err = errno;
+ if (err == EINTR)
+ continue;
+ fail:
+ ec.assign(err, boost::system::system_category());
+ return false;
+ }
+ break;
+ }
+
+ struct ::stat from_stat;
+ if (::fstat(infile.fd, &from_stat) != 0) {
+ fail_errno:
+ err = errno;
+ goto fail;
+ }
+
+ const mode_t from_mode = from_stat.st_mode;
+ if (!S_ISREG(from_mode)) {
+ err = ENOSYS;
+ goto fail;
+ }
+
+ // Enable writing for the newly created files. Having write permission set is important e.g. for NFS,
+ // which checks the file permission on the server, even if the client's file descriptor supports writing.
+ mode_t to_mode = from_mode | S_IWUSR;
+ int oflag = O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC;
+
+ while (true) {
+ outfile.fd = ::open(to.c_str(), oflag, to_mode);
+ if (outfile.fd < 0) {
+ err = errno;
+ if (err == EINTR)
+ continue;
+ goto fail;
+ }
+ break;
+ }
+
+ struct ::stat to_stat;
+ if (::fstat(outfile.fd, &to_stat) != 0)
+ goto fail_errno;
+
+ to_mode = to_stat.st_mode;
+ if (!S_ISREG(to_mode)) {
+ err = ENOSYS;
+ goto fail;
+ }
+
+ if (from_stat.st_dev == to_stat.st_dev && from_stat.st_ino == to_stat.st_ino) {
+ err = EEXIST;
+ goto fail;
+ }
+
+ //! copy_file implementation that uses sendfile loop. Requires sendfile to support file descriptors.
+ //FIXME Vojtech: This is a copy loop valid for Linux 2.6.33 and newer.
+ // copy_file_data_copy_file_range() supports cross-filesystem copying since 5.3, but Vojtech did not want to polute this
+ // function with that, we don't think the performance gain is worth it for the types of files we are copying,
+ // and our build server based on CentOS 7 with Linux 3.10 does not support that anyways.
+ {
+ // sendfile will not send more than this amount of data in one call
+ constexpr std::size_t max_send_size = 0x7ffff000u;
+ uintmax_t offset = 0u;
+ while (off_t(offset) < from_stat.st_size) {
+ uintmax_t size_left = from_stat.st_size - offset;
+ std::size_t size_to_copy = max_send_size;
+ if (size_left < static_cast<uintmax_t>(max_send_size))
+ size_to_copy = static_cast<std::size_t>(size_left);
+ ssize_t sz = ::sendfile(outfile.fd, infile.fd, nullptr, size_to_copy);
+ if (sz < 0) {
+ err = errno;
+ if (err == EINTR)
+ continue;
+ if (err == 0)
+ break;
+ goto fail; // err already contains the error code
+ }
+ offset += sz;
+ }
+ }
+
+ // If we created a new file with an explicitly added S_IWUSR permission,
+ // we may need to update its mode bits to match the source file.
+ if (to_mode != from_mode && ::fchmod(outfile.fd, from_mode) != 0) {
+ if (platform_flavor() == PlatformFlavor::LinuxOnChromium) {
+ // Ignore that. 9p filesystem does not allow fmod().
+ BOOST_LOG_TRIVIAL(info) << "copy_file_linux() failed to fchmod() the output file \"" << to.string() << "\" to " << from_mode << ": " << ec.message() <<
+ " This may be expected when writing to a 9p filesystem.";
+ } else {
+ // Generic linux. Write out an error to console. At least we may get some feedback.
+ BOOST_LOG_TRIVIAL(error) << "copy_file_linux() failed to fchmod() the output file \"" << to.string() << "\" to " << from_mode << ": " << ec.message();
+ }
+ }
+
+ // Note: Use fsync/fdatasync followed by close to avoid dealing with the possibility of close failing with EINTR.
+ // Even if close fails, including with EINTR, most operating systems (presumably, except HP-UX) will close the
+ // file descriptor upon its return. This means that if an error happens later, when the OS flushes data to the
+ // underlying media, this error will go unnoticed and we have no way to receive it from close. Calling fsync/fdatasync
+ // ensures that all data have been written, and even if close fails for some unfathomable reason, we don't really
+ // care at that point.
+ err = ::fdatasync(outfile.fd);
+ if (err != 0)
+ goto fail_errno;
+
+ return true;
+}
+#endif // __linux__
+
CopyFileResult copy_file_inner(const std::string& from, const std::string& to, std::string& error_message)
{
const boost::filesystem::path source(from);
@@ -434,7 +569,13 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to, s
if (ec)
BOOST_LOG_TRIVIAL(debug) << "boost::filesystem::permisions before copy error message (this could be irrelevant message based on file system): " << ec.message();
ec.clear();
+#ifdef __linux__
+ // We want to allow copying files on Linux to succeed even if changing the file attributes fails.
+ // That may happen when copying on some exotic file system, for example Linux on Chrome.
+ copy_file_linux(source, target, ec);
+#else // __linux__
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
+#endif // __linux__
if (ec) {
error_message = ec.message();
return FAIL_COPY_FILE;
diff --git a/src/slic3r/GUI/OpenGLManager.cpp b/src/slic3r/GUI/OpenGLManager.cpp
index 4f1e00793..1908c1d34 100644
--- a/src/slic3r/GUI/OpenGLManager.cpp
+++ b/src/slic3r/GUI/OpenGLManager.cpp
@@ -5,6 +5,8 @@
#include "I18N.hpp"
#include "3DScene.hpp"
+#include "libslic3r/Platform.hpp"
+
#include <GL/glew.h>
#include <boost/algorithm/string/split.hpp>
@@ -333,7 +335,13 @@ void OpenGLManager::detect_multisample(int* attribList)
{
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
bool enable_multisample = wxVersion >= 30003;
- s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? EMultisampleState::Enabled : EMultisampleState::Disabled;
+ s_multisample =
+ enable_multisample &&
+ // Disable multi-sampling on ChromeOS, as the OpenGL virtualization swaps Red/Blue channels with multi-sampling enabled,
+ // at least on some platforms.
+ platform_flavor() != PlatformFlavor::LinuxOnChromium &&
+ wxGLCanvas::IsDisplaySupported(attribList)
+ ? EMultisampleState::Enabled : EMultisampleState::Disabled;
// Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows
// s_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample");
}
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index e154c0567..a9e66333e 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -88,6 +88,7 @@
#include <wx/glcanvas.h> // Needs to be last because reasons :-/
#include "WipeTowerDialog.hpp"
#include "libslic3r/CustomGCode.hpp"
+#include "libslic3r/Platform.hpp"
using boost::optional;
namespace fs = boost::filesystem;
@@ -3769,7 +3770,9 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
// If writing to removable drive was scheduled, show notification with eject button
if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !has_error) {
show_action_buttons(false);
- notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, true);
+ notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path,
+ // Don't offer the "Eject" button on ChromeOS, the Linux side has no control over it.
+ platform_flavor() != PlatformFlavor::LinuxOnChromium);
wxGetApp().removable_drive_manager()->set_exporting_finished(true);
}else if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !has_error)
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, false);
diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp
index b11cc8dd5..59a202beb 100644
--- a/src/slic3r/GUI/RemovableDriveManager.cpp
+++ b/src/slic3r/GUI/RemovableDriveManager.cpp
@@ -1,4 +1,5 @@
#include "RemovableDriveManager.hpp"
+#include "libslic3r/Platform.hpp"
#include <libslic3r/libslic3r.h>
#include <boost/nowide/convert.hpp>
@@ -185,8 +186,13 @@ namespace search_for_drives_internal
{
//confirms if the file is removable drive and adds it to vector
- //if not same file system - could be removable drive
- if (! compare_filesystem_id(path, parent_path)) {
+ if (
+#ifdef __linux__
+ // Chromium mounts removable drives in a way that produces the same device ID.
+ platform_flavor() == PlatformFlavor::LinuxOnChromium ||
+#endif
+ // If not same file system - could be removable drive.
+ ! compare_filesystem_id(path, parent_path)) {
//free space
boost::system::error_code ec;
boost::filesystem::space_info si = boost::filesystem::space(path, ec);
@@ -229,22 +235,28 @@ std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() cons
#else
- //search /media/* folder
- search_for_drives_internal::search_path("/media/*", "/media", current_drives);
-
- //search_path("/Volumes/*", "/Volumes");
- std::string path(std::getenv("USER"));
- std::string pp(path);
-
- //search /media/USERNAME/* folder
- pp = "/media/"+pp;
- path = "/media/" + path + "/*";
- search_for_drives_internal::search_path(path, pp, current_drives);
+ if (platform_flavor() == PlatformFlavor::LinuxOnChromium) {
+ // ChromeOS specific: search /mnt/chromeos/removable/* folder
+ search_for_drives_internal::search_path("/mnt/chromeos/removable/*", "/mnt/chromeos/removable", current_drives);
+ } else {
+ //search /media/* folder
+ search_for_drives_internal::search_path("/media/*", "/media", current_drives);
+
+ //search_path("/Volumes/*", "/Volumes");
+ std::string path(std::getenv("USER"));
+ std::string pp(path);
+
+ //search /media/USERNAME/* folder
+ pp = "/media/"+pp;
+ path = "/media/" + path + "/*";
+ search_for_drives_internal::search_path(path, pp, current_drives);
+
+ //search /run/media/USERNAME/* folder
+ path = "/run" + path;
+ pp = "/run"+pp;
+ search_for_drives_internal::search_path(path, pp, current_drives);
+ }
- //search /run/media/USERNAME/* folder
- path = "/run" + path;
- pp = "/run"+pp;
- search_for_drives_internal::search_path(path, pp, current_drives);
#endif
return current_drives;
@@ -441,7 +453,10 @@ RemovableDriveManager::RemovableDrivesStatus RemovableDriveManager::status()
RemovableDriveManager::RemovableDrivesStatus out;
{
tbb::mutex::scoped_lock lock(m_drives_mutex);
- out.has_eject = this->find_last_save_path_drive_data() != m_current_drives.end();
+ out.has_eject =
+ // Cannot control eject on Chromium.
+ platform_flavor() != PlatformFlavor::LinuxOnChromium &&
+ this->find_last_save_path_drive_data() != m_current_drives.end();
out.has_removable_drives = ! m_current_drives.empty();
}
if (! out.has_eject)