Paste P322

Ugly WIP rust code
ActivePublic

Authored by alvinhochun on Feb 16 2019, 6:59 PM.
diff --git a/plugins/filters/pixelizefilter/CMakeLists.txt b/plugins/filters/pixelizefilter/CMakeLists.txt
index a75e23eeca..fdb85ab402 100644
--- a/plugins/filters/pixelizefilter/CMakeLists.txt
+++ b/plugins/filters/pixelizefilter/CMakeLists.txt
@@ -1,4 +1,34 @@
+set(RUST_CARGO_EXECUTABLE "D:\\dev\\toolchain\\rust\\cargo\\bin\\cargo.exe")
+
+# FIXME: Specify target only for Windows (mingw)
+# FIXME: Detect bitness
+set(RUST_TARGET "x86_64-pc-windows-gnu")
+# FIXME: ...
+list(APPEND RUST_NATIVE_STATIC_LIBS userenv)
+
+set(RUST_TARGET_DIR "${CMAKE_CURRENT_BINARY_DIR}/rust-target")
+# Note: `rustc` does *not* output libxxx.a on Windows even with the GNU target.
+# FIXME: look for proper file on *nix
+set(krita_filter_pixelize_rs_OUTLIB "${RUST_TARGET_DIR}/x86_64-pc-windows-gnu/debug/krita_filter_pixelize_rs.lib")
+
+# Dummy target to cause `cargo` to always run
+add_custom_command(OUTPUT always_build COMMAND ${CMAKE_COMMAND} -E echo_append)
+
+# FIXME: Add `--release` for release build
+add_custom_command(
+ OUTPUT "${krita_filter_pixelize_rs_OUTLIB}"
+ COMMAND "${RUST_CARGO_EXECUTABLE}" ARGS build --target x86_64-pc-windows-gnu --target-dir "${RUST_TARGET_DIR}"
+ DEPENDS always_build
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/rust"
+ USES_TERMINAL
+)
+
+add_custom_target(krita_filter_pixelize_rs DEPENDS "${krita_filter_pixelize_rs_OUTLIB}")
+
+
set(kritapixelizefilter_SOURCES kis_pixelize_filter_plugin.cpp kis_pixelize_filter.cpp )
add_library(kritapixelizefilter MODULE ${kritapixelizefilter_SOURCES})
-target_link_libraries(kritapixelizefilter kritaui)
+target_compile_definitions(kritapixelizefilter PRIVATE -DUSE_RUST)
+add_dependencies(kritapixelizefilter krita_filter_pixelize_rs)
+target_link_libraries(kritapixelizefilter PRIVATE kritaui "${krita_filter_pixelize_rs_OUTLIB}" ${RUST_NATIVE_STATIC_LIBS})
install(TARGETS kritapixelizefilter DESTINATION ${KRITA_PLUGIN_INSTALL_DIR})
diff --git a/plugins/filters/pixelizefilter/kis_pixelize_filter.cpp b/plugins/filters/pixelizefilter/kis_pixelize_filter.cpp
index 704fab4ef1..06291202bb 100644
--- a/plugins/filters/pixelizefilter/kis_pixelize_filter.cpp
+++ b/plugins/filters/pixelizefilter/kis_pixelize_filter.cpp
@@ -54,6 +54,37 @@
#include "kis_algebra_2d.h"
#include "kis_lod_transform.h"
+#ifdef USE_RUST
+#include "krita_filter_pixelize_rs.hpp"
+extern "C" {
+
+bool kisSequentialConstIteratorNextPixelCallback(KisSequentialConstIterator *it)
+{
+ return it->nextPixel();
+}
+
+const quint8 *kisSequentialConstIteratorOldRawDataCallback(const KisSequentialConstIterator *it)
+{
+ return it->oldRawData();
+}
+
+bool kisSequentialIteratorNextPixelCallback(KisSequentialIterator *it)
+{
+ return it->nextPixel();
+}
+
+quint8 *kisSequentialIteratorRawDataCallback(KisSequentialIterator *it)
+{
+ return it->rawData();
+}
+
+void koMixColorsOpMixColors(const KoMixColorsOp *mixOp, const quint8 *colors, quint32 nColors, quint8 *dst)
+{
+ mixOp->mixColors(colors, nColors, dst);
+}
+
+} // extern "C"
+#endif
KisPixelizeFilter::KisPixelizeFilter() : KisFilter(id(), FiltersCategoryArtisticId, i18n("&Pixelize..."))
{
@@ -105,10 +136,16 @@ void KisPixelizeFilter::processImpl(KisPaintDeviceSP device,
//read
KisSequentialConstIterator srcIt(device, pixelRect);
+ // write only colors in applyRect
+ const QRect writeRect = pixelRect & applyRect;
+ KisSequentialIterator dstIt(device, writeRect);
memset(buffer.data(), 0, bufferSize);
quint8 *bufferPtr = buffer.data();
+#ifdef USE_RUST
+ krita_filter_pixelize_rs_process_block(&srcIt, &dstIt, pixelSize, pixelWidth, pixelHeight, mixOp, bufferPtr, numColors, pixelColor.data());
+#else
while (srcIt.nextPixel()) {
memcpy(bufferPtr, srcIt.oldRawData(), pixelSize);
bufferPtr += pixelSize;
@@ -117,13 +154,10 @@ void KisPixelizeFilter::processImpl(KisPaintDeviceSP device,
// mix all the colors
mixOp->mixColors(buffer.data(), numColors, pixelColor.data());
- // write only colors in applyRect
- const QRect writeRect = pixelRect & applyRect;
-
- KisSequentialIterator dstIt(device, writeRect);
while (dstIt.nextPixel()) {
memcpy(dstIt.rawData(), pixelColor.data(), pixelSize);
}
+#endif
}
progressUpdater->setValue(i);
}
diff --git a/plugins/filters/pixelizefilter/krita_filter_pixelize_rs.hpp b/plugins/filters/pixelizefilter/krita_filter_pixelize_rs.hpp
new file mode 100644
index 0000000000..52972702ac
--- /dev/null
+++ b/plugins/filters/pixelizefilter/krita_filter_pixelize_rs.hpp
@@ -0,0 +1,18 @@
+#ifndef KRITA_FILTER_PIXELIZE_RS_HPP
+#define KRITA_FILTER_PIXELIZE_RS_HPP
+
+extern "C" {
+
+void krita_filter_pixelize_rs_process_block(KisSequentialConstIterator *src_it,
+ KisSequentialIterator *dst_it,
+ qint32 pixel_size,
+ qint32 pixelize_width,
+ qint32 pixelize_height,
+ const KoMixColorsOp *ko_mix_colors_op,
+ quint8 *working_buffer,
+ quint32 num_colors,
+ quint8 *pixel_color_data);
+
+} // extern "C"
+
+#endif
diff --git a/plugins/filters/pixelizefilter/rust/.gitignore b/plugins/filters/pixelizefilter/rust/.gitignore
new file mode 100644
index 0000000000..2f7896d1d1
--- /dev/null
+++ b/plugins/filters/pixelizefilter/rust/.gitignore
@@ -0,0 +1 @@
+target/
diff --git a/plugins/filters/pixelizefilter/rust/Cargo.lock b/plugins/filters/pixelizefilter/rust/Cargo.lock
new file mode 100644
index 0000000000..779a2ad1c3
--- /dev/null
+++ b/plugins/filters/pixelizefilter/rust/Cargo.lock
@@ -0,0 +1,4 @@
+[[package]]
+name = "krita-filter-pixelize-rs"
+version = "0.1.0"
+
diff --git a/plugins/filters/pixelizefilter/rust/Cargo.toml b/plugins/filters/pixelizefilter/rust/Cargo.toml
new file mode 100644
index 0000000000..7b541c3a1b
--- /dev/null
+++ b/plugins/filters/pixelizefilter/rust/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "krita-filter-pixelize-rs"
+version = "0.1.0"
+authors = ["Alvin Wong <alvinhochun@gmail.com>"]
+edition = "2018"
+publish = false
+
+[dependencies]
+
+[lib]
+crate-type = ["staticlib"]
diff --git a/plugins/filters/pixelizefilter/rust/src/krita_ffi.rs b/plugins/filters/pixelizefilter/rust/src/krita_ffi.rs
new file mode 100644
index 0000000000..40343a8121
--- /dev/null
+++ b/plugins/filters/pixelizefilter/rust/src/krita_ffi.rs
@@ -0,0 +1,63 @@
+extern "C" {
+ fn kisSequentialConstIteratorNextPixelCallback(it: *mut KisSequentialConstIterator) -> bool;
+ fn kisSequentialConstIteratorOldRawDataCallback(
+ it: *const KisSequentialConstIterator,
+ ) -> *const u8;
+ fn kisSequentialIteratorNextPixelCallback(it: *mut KisSequentialIterator) -> bool;
+ fn kisSequentialIteratorRawDataCallback(it: *mut KisSequentialIterator) -> *mut u8;
+ fn koMixColorsOpMixColors(
+ ko_mix_colors_op: *const KoMixColorsOp,
+ colors: *const u8,
+ n_colors: u32,
+ dst: *mut KoColorData,
+ );
+}
+
+#[repr(C)]
+pub struct KisSequentialConstIterator {
+ _private: [u8; 0],
+}
+
+impl KisSequentialConstIterator {
+ pub fn next_pixel(&mut self) -> bool {
+ unsafe { kisSequentialConstIteratorNextPixelCallback(self) }
+ }
+
+ pub unsafe fn old_raw_data_ptr(&self) -> *const u8 {
+ let pixel_ptr = kisSequentialConstIteratorOldRawDataCallback(self);
+ // slice::from_raw_parts(pixel_ptr, pixel_size as usize)
+ pixel_ptr
+ }
+}
+
+#[repr(C)]
+pub struct KisSequentialIterator {
+ _private: [u8; 0],
+}
+
+impl KisSequentialIterator {
+ pub fn next_pixel(&mut self) -> bool {
+ unsafe { kisSequentialIteratorNextPixelCallback(self) }
+ }
+
+ pub unsafe fn raw_data_ptr(&mut self) -> *mut u8 {
+ let pixel_ptr = kisSequentialIteratorRawDataCallback(self);
+ pixel_ptr
+ }
+}
+
+#[repr(C)]
+pub struct KoColorData {
+ _private: [u8; 0],
+}
+
+#[repr(C)]
+pub struct KoMixColorsOp {
+ _private: [u8; 0],
+}
+
+impl KoMixColorsOp {
+ pub unsafe fn mix_colors(&self, colors: *const u8, n_colors: u32, dst: *mut KoColorData) {
+ koMixColorsOpMixColors(self, colors, n_colors, dst);
+ }
+}
diff --git a/plugins/filters/pixelizefilter/rust/src/lib.rs b/plugins/filters/pixelizefilter/rust/src/lib.rs
new file mode 100644
index 0000000000..9949a81d11
--- /dev/null
+++ b/plugins/filters/pixelizefilter/rust/src/lib.rs
@@ -0,0 +1,80 @@
+mod krita_ffi;
+
+use crate::krita_ffi::KisSequentialConstIterator;
+use crate::krita_ffi::KisSequentialIterator;
+use crate::krita_ffi::KoColorData;
+use crate::krita_ffi::KoMixColorsOp;
+
+/// Invokes a closure and aborts if an unwinding panic occurs.
+///
+/// This must be used in any exported functions callable from C/C++ code, as
+/// unwinding from Rust code into external caller is undefined behaviour. One
+/// must not assume an panic will not happen in Rust code.
+///
+/// An exception is when the specific function provides an alternative
+/// mechanism to inform the caller of a panic and it can be certain that the
+/// program will be able to properly recover from a panic condition, which in
+/// such cases it is still an absolute requirement to wrap the code in
+/// `std::panic::catch_unwind` and manually handle the error.
+fn catch_unwind_abort<F: FnOnce() -> R + std::panic::UnwindSafe, R>(f: F) -> R {
+ std::panic::catch_unwind(f).unwrap_or_else(|_| {
+ std::process::abort();
+ })
+}
+
+#[no_mangle]
+pub extern "C" fn krita_filter_pixelize_rs_process_block(
+ src_it: *mut KisSequentialConstIterator,
+ dst_it: *mut KisSequentialIterator,
+ pixel_size: i32,
+ _pixelize_width: i32,
+ _pixelize_height: i32,
+ ko_mix_colors_op: *const KoMixColorsOp,
+ working_buffer: *mut u8,
+ num_colors: u32,
+ pixel_color_data: *mut KoColorData,
+) {
+ catch_unwind_abort(|| {
+ let src_it = unsafe { &mut *src_it };
+ let dst_it = unsafe { &mut *dst_it };
+ let mix_op = unsafe { &*ko_mix_colors_op };
+
+ let mut buffer_ptr = working_buffer;
+ while src_it.next_pixel() {
+ unsafe {
+ std::ptr::copy_nonoverlapping(
+ src_it.old_raw_data_ptr(),
+ buffer_ptr,
+ pixel_size as usize,
+ );
+ buffer_ptr = buffer_ptr.offset(pixel_size as isize);
+ }
+ }
+
+ // mix all the colors
+ unsafe {
+ mix_op.mix_colors(working_buffer, num_colors, pixel_color_data);
+ }
+
+ while dst_it.next_pixel() {
+ unsafe {
+ std::ptr::copy_nonoverlapping(
+ pixel_color_data as *const u8,
+ dst_it.raw_data_ptr(),
+ pixel_size as usize,
+ );
+ }
+ }
+ })
+}
+
+#[cfg(test)]
+mod tests {
+ // /// This test cannot be made to pass unless [rust-lang/rust#32512][1] is
+ // /// fixed.
+ // /// [1]: https://github.com/rust-lang/rust/issues/32512
+ // #[test]
+ // fn test_should_abort() {
+ // super::catch_unwind_abort(|| panic!("test panic"));
+ // }
+}
alvinhochun created this object in space S1 KDE Community.