feat: port style transfer implementation to C++#229
feat: port style transfer implementation to C++#229JakubGonera merged 13 commits into@jakubgonera/cppfrom
Conversation
304f24d to
08b71a8
Compare
b593b51 to
cfe8795
Compare
| std::filesystem::path filePath = tempDir / filename; | ||
|
|
||
| if (!cv::imwrite(filePath.string(), image)) { | ||
| throw std::runtime_error("Failed to save the image: " + filePath.string()); |
There was a problem hiding this comment.
Btw, how are those exceptions resolved on the JS side?
There was a problem hiding this comment.
All of these have to be caught and currently they are then used to reject a promise -- if they are not caught we will get a runtime error that might crash the app. If the code throwing an exception is not called via a promise, but we still want the error to be pushed to JS, a JSError needs to be created and registered with the JS runtime. I could add a helper function to throw JSError with a C++ exception, the question is whether to do this in this PR. Thoughts?
There was a problem hiding this comment.
sounds like a useful helper function to me
There was a problem hiding this comment.
It turns out that it's sufficient to throw a JSError with the runtime attached to make the exception readable in JS. The only place where we call the native code without a promise is RnExecutorchInstaller, so right now we catch there any exceptions and rethrow them as JSErorrs.
| modelSource | ||
| ); | ||
| return global.loadStyleTransfer(loadedPaths[0] || ''); | ||
| this.nativeModule = global.loadStyleTransfer(paths[0] || ''); |
There was a problem hiding this comment.
Make sure this actually works when loading fails
There was a problem hiding this comment.
isn't global.loadStyleTransfer possibly null?
There was a problem hiding this comment.
Indeed it could be. The question is whether we could do anything about this. Right now the user will have an exception thrown at startup with a message indicating this. If this is null then this means that all the native code went out the window.
| std::filesystem::path filePath = tempDir / filename; | ||
|
|
||
| if (!cv::imwrite(filePath.string(), image)) { | ||
| throw std::runtime_error("Failed to save the image: " + filePath.string()); |
There was a problem hiding this comment.
sounds like a useful helper function to me
| while (std::getline(uriStream, stringData, ',')) { | ||
| if (segmentIndex == 1) | ||
| break; | ||
| ++segmentIndex; | ||
| } | ||
| if (segmentIndex != 1) { |
There was a problem hiding this comment.
looking at this, am I right that if uriStream is malformed so that it contains multiple comas this breaks? Shouldn't we parse whole uriStream?
There was a problem hiding this comment.
right now segmentIndex is either 0 or 1
There was a problem hiding this comment.
std::getline will fail if there are two or more consecutive separators.
There was a problem hiding this comment.
So that's a good point, that we need to somehow check for some malformed uris.
There was a problem hiding this comment.
Right now if the user supplies a string that has two commas next to each other we will pass an empty string to OpenCV which will return an empty image which in turn will result in an exception "Read image error: invalid argument" being thrown. The same holds for other cases where the payload does not represent a valid image. The exception will then result in a rejected promise.
I don't think that we should do any more work here on parsing. As far as I understand URI specification everything after the comma should be a base64 payload, and if the user is not conforming to this standard it shouldn't make any difference whether we fail while parsing a part of the intended payload or while parsing the whole.
| modelSource | ||
| ); | ||
| return global.loadStyleTransfer(loadedPaths[0] || ''); | ||
| this.nativeModule = global.loadStyleTransfer(paths[0] || ''); |
There was a problem hiding this comment.
isn't global.loadStyleTransfer possibly null?
c8cbe4a to
a991245
Compare
Port native implementation of style transfer to C++ #227. This is a part of a larger effort to merge native code from Kotlin and Objective C to a single implementation in C++. Old style transfer modules have been replaced by new, stateful implementation. For this purpose non-static versions of useModule and BaseModule have been introduced. Old implementations of style transfer have been removed. Added methods for handling fetching data via https that are passed on as function objects to C++. - Ported image processing capabilities equivalent to the ObjC/Kotlin implementations. - `ModelHostObject` serves as an automatic interface between model implementations and JSI. This is done by template metaprogramming; defining methods in `JsiConversions.h` for types used by the model is necessary for it to work. - A factory method for loading a style transfer model is registered in `RnExecutorchInstaller`. - `common/rnexecutorch/jsi` originates from react-native-audio-api - `base64.*` is used for converting from base64 due to https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp/ - `ada` is a header-only library for parsing urls due to https://github.com/ada-url/ada - headers for Executorch 0.6 have been updated - OpenCV 4.11.0 dependency is introduced for Android/C++. For iOS the version is bumped via Cocoapods to 4.11.0. - C10 headers are the dependency of OpenCV. - Exceptions in native C++ do not result in promise getting rejected when forwarding yet. - Garbage collection can malfunction for host objects. C++ host objects need to notify JS runtime about their size via external memory pressure for the garbage collector to know to free them. This is not yet done.
Port native implementation of style transfer to C++ #227. This is a part of a larger effort to merge native code from Kotlin and Objective C to a single implementation in C++.
Changes by sections
Typescript
Old style transfer modules have been replaced by new, stateful implementation. For this purpose non-static versions of useModule and BaseModule have been introduced.
Objective C & Kotlin
Old implementations of style transfer have been removed. Added methods for handling fetching data via https that are passed on as function objects to C++.
C++
ModelHostObjectserves as an automatic interface between model implementations and JSI. This is done by template metaprogramming; defining methods inJsiConversions.hfor types used by the model is necessary for it to work.RnExecutorchInstaller.Code attribution
common/rnexecutorch/jsioriginates from react-native-audio-apibase64.*is used for converting from base64 due to https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp/adais a header-only library for parsing urls due to https://github.com/ada-url/adaDependencies introduced/updated
Known issues