rendering ideas

A few weeks ago I travelled to the Netherlands to be part of the Krita October Sprint. During this Sprint we decided to focus on bug fixing, my tasks included some simple bugs and a couple of more convoluted bugs. I started fixing the simple ones in order to gain speed: one about modifiers not working on OSX, the bug was simple enough but puzzling as the missing logic shouldn’t make the code work on Linux, but it did. The second bug was related to events logic in the preferences dialog command: My first approach was good but not simple, so talking with the team made me change the solution to something much more simple.

Hard working Krita Sprinters

The next days showed me how deep the rabbit hole goes in Krita’s code, my bug was in the invert color code, some color spaces didn’t show the correct/expected result. A quick dive showed that there was a different codebase for every colorspace invert operation, and the wrong results showed for the missing implementations. However this made the solution not very portable as the combination of colorspaces and color depths suggested I needed to implement 18 color inverters. A short consultation showed me that there was a space invert operation already implemented for the pixel depth, so refactoring to use this convertors in one class to invert the input colors made the invert filter work as expected, except for CMYK and Lab spaces in 16bit float spaces. After a couple of days of digging into the code and testing, we found that there is a a bug in the way CMYK and Lab is values are processed as normalized values are not returned in places they should be.

As my first Krita Sprint I was very nervous, however I was even more exited to meet the team. In a way it was also the first time to work in a code only environment which made it very fruitful as it showed me that code is not made by super coding super geniuses, but by a little changes made by a coordinated team of normal people.

A new vectorized code implemented using Vc library to allow SIMD operations for the generation of the Circular Soft Mask. Implementation was straightforward using internal methods declared in Vc however the gains were not as dramatic as with Gaussian Masks because one of the biggest bottlenecks is fetching from memory the predefined values rendered from the curve set by the user.

Making a plan

Phabricator task:Implement Circular Soft Mask Optim AVX
The code templates work the same as the Circular Gaussian Mask generator implementation, which I explained in my [previous post](blog, URL). Taking that into account the plan consisted in three simple steps.

Understand how the scalar vector is generating the values for the Mask

Previous implementation was based on a slow scalar model, calculating each mask value per coordinate. I implement a new vectorized code using Vc library to allow a robust SIMD usage, calculating the mask values in parallel. Not all operations are implemented on Vc data types, especially erf had to be implemented for Vc data types. The new implementation shows to be up to 10 times faster (on my system) on mask generation. Given that the mask generation requires the most computing on brush stroke generation, this speed improvement holds up even in the full brush stroke benchmarks. Given the way it is implemented the code can become faster as future SIMD registers grows on future CPUs.

Circular Gauss Optimization results.

Code study and implementation of Gauss Mask Mask generator.

Phabricator task:Implement Circular Gauss Mask Optim AVXVc creates code from templates tailored for each processor instruction set: AVX, AVX2, SSSE2, SSSE3, SSE2, and scalar. so first a template must be declared to manage the creation of each instructions set code. Using the vectorized Default Mask implementation as a guideline, studying how the code generates is constructed to provide the functionality allowed to extend it for the other MaskGeneratorsRead More »

Hi! GSoC student here :]. This first weeks coding for Krita have been so busy I forgot to write about them. So I’ll start to sum everything up in short posts about each step of the project implementation process.

First Steps, setting up a dev environment

I followed the steps in the 3rdparty to compile the base krita system on OSX. This easy to follow instructions helped me get a basic Krita installation in a short time. However not everything worked for me quite easily and most tests did not work or run at all on OSX with the message.

After some digging I found out that no program that uses a GUI can run outside of an app bundle. So while not a future proof, to start working on the code I made a quick script to install the tests I’m interested inside Krita.app folder. To allow tests to run. By default all tests are linked to libraries in the build dir, but because this wont work on OSX one approach would be to install also the tests in the bundle and link to the install libraries or, another approach could be to generate an app bundle for each test.

In any case the tests could run so It was time to start working on the unit test.

Implementing Mask Similarity Test

Phabricator task:Base unit test kis_mask_similarity_test
This unit test intention is to compare the correctness of the new vectorized mask rendering by comparing it to the same settings Mask produced by the previous engine. The new versions have to be as identical as possible to ensure the painting effects the user is expecting does not change between engines (The user can’t change how the mask is produced, but we use the scalar version for smaller brush dab sizes).

I can’t believe I was selected for the Google Summer of Code program for working on Krita. The proyect I’ll be working this summer is on optimizing Krita’s brush mask to work with AVX instructions. These instructions will be coded using the Vc library, a “zero overhead C++ types for parallel computing” that enables to efficiently transform the mask’s generator code to SIMD instructions for vectorization.

Brush masks is a core process in the painting task as it creates the shape it will be imprinted in the canvas. This, depending on brush settings, can be done as much as thousends of times per second. Having this optimized will greatly improve painting enjoyment keeping the brush stroke responsive on bigger sizes.

[FIXED] Release artscript v2.2.1 Now with one more customization option, better performance, softness control and yes: KRA convert now works with Krita 2.9 (now for real ;]). See 2.2.1 release information

Creating Images

No rules for this work in particular, no expectations, just had the idea to draw some figures that ended up having some relation. Get the source file! Update: Krita working with index coloring, working towards solving the color output mistery!

Working with index color filter, described here https://krita.org/item/236-last-week-in-krita-week-21, can be confusing. The filter works so slow (in my pc) that getting results just by moving sliders is a waste of time. Some things are good with the tool and some others are hideous. I wanted to work with index colors to get the messy pixely effect and also using live filters to edit anything later (if it’s needed). here are some notes on the tools to avoid future headaches.Above: my result. Used the same layer setup as in the video here https://www.youtube.com/watch?v=v1Z__mSfo8s (whoppix was very kind to share the file). To control a little better the output. I worked in gray scale all the way and used 4 main groups. Background, Clothes, Skin, Hair. The idea at first was to use a different colour on each section and a slightly different dithering effect on each.

Layer Stack description (As in source file)

Set a group for each dithered object you need. each group act as an isolation environment so its possible to get different colors and dithering patterns on different elements in canvas.

On Dither patterns and textures

Layer must have opacity lower than 20 to add the effect without interfering with the painting itself. If it is too high the pattern will become the painting instead of just dithering the gradients. You can use any data as dithering patterns. I only tested grayscale layers and different types of layer content. From what I can observe:

Sharp pixel shape patterns with different gray values work best

Its possible to use krita painting brush patterns to add dither, results are more or less nice. (Used on the background)

Add any image texture and tweak values to make nice dither. This came come from a photo or a painting. Krita grayscale patterns enter this category

Use a brush engine to generate Texture. this is trickier since you need to generate an organic pattern for it to look good. (Ramon miranda’s hairy brush set works extremely well for this.)

Brush engines tested and settings

Painting with Brush patterns Grayscale textures: Set Cut Off Policy to “Brush” and set arrows. black on middle, white closer to edge.

Speed problems?

Live filtering is very slow at the moment, to avoid the trouble of working at snail speeds get used to work in Grayscale (values only) and turn on index colors filtering for fine adjustments.

Controlling color output

This is a tricky business. I tried many different variations and I could obtain the same color combinations from different color mixtures in the dark, base, light, bright color swatches.

The colors provided by default work well as long as you don’t alter the value. In other words they will affect the gradient at the same bright tones as long as you don’t alter the value setting.

In the end I made the following process

Removing all swatches and leaving base will create a cut out shape with the color selected.

Add then a light tone for getting gradient variations. The colors are not exactly the ones you picked, but very close

You can use second and third rows, jumping wrows will make a strong gradient effect. however use with care as activating them might cause unwanted color shifting.

Color value is everything. Add a Bright tone with very dark value and you will affect the dark tones. Add light value to Dark column and highlight will get colored, despite being in the dark column. Not sure if this is a bug but, use this to your advantage to fine tune dark tones a little bit in the end.

Because of the former point, have some order, using values from light to dark, top to bottom.

Activate diagonal gradients to use any column and get mostly the same effect as if you were using only one column. I have to investigate this further as the option might imply some other things.

Adding screenshots showing color mixing variations.

Some color swatches variations

Conclusions

The results from this technique are strongly dependant on your value mastering and for more aesthetically appealing picture you have to prepare a nice set of patters and use them with care. Failing to do so will result in a muddy picture with no volume and zero flow on forms. Very difficult indeed to get. My pictures ire nowhere near that level. Finally, while the results are satisfactory I still need to master the coloring mistery for selecting the exact colors I want. I could help to set a gradient inside the affected area to help selecting the color ramps. In the end I had to use level and color balance to get a brighter look on the first image.

Second image was better controlled in respect to color setting in the filter. I started working on it with the experimental brush to focus only on hard shapes. Abusing Krita layers ystem I worked as with the red marker and light yellow for the background, cloned the resulting group layers. Added those clones to the indexed layer and toyed with the index filtering colors.