Week 24: Photoshop brush support in Krita

Thanks to the pledge we did long time ago and thanks to the community member, Silvio Grosso, who made major donation, I’m working on Krita for next ~12 weeks full-time.  The Krita community and me prepared Action Plan II. It’s something like Google Summer Of Code proposal but with much more targets. I have tasks per week, not one big target like Summer Of Code projects.

First two weeks of the plan are devoted to the support of the Photoshop brushes. I worked on it already in Action Plan I, I added support of the brush masks (bitmaps) from the file format, but there are still presets saved in the ABR format and we want to support them. The presets are for defining the brush rotation, roundness,  it’s dynamics like spreading in some area or some color stuff like HSV changes. I’m working on it right now.

First I thought that let’s create new brush engine that mimics the Photoshop one and then load the presets into this one. But that would be waste of time. We already have brush engines that have features like the Photoshop one, but they are scattered in our brushes engines – especially in Pixel Brush and in Spray brush. Cyrille pointed me to this fact.And other problem is that we need to unify the brush engines. Those I created are little divergent to the other brush engines, so I’m unifying.

First thing I had to do was to add support of our standard brush dialog to the spray. That way you can spray abr bitmaps because of preddefined brush dialog shows them and you can spray Auto Brush masks and even Text. Great, isn’t it? I spent few days with that. I fixed some bugs and now the standard dialog brushes are sprayed in the same way as the old limited shapes which were there before (pixel, anti-aliased pixel, ellipse, rectangle, brush bitmap – texture). This step is needed to support the abr presets.

New clouds with Krita are even better then the real things (U2)!

Made with Krita now: More realistic clouds

We also started to work on backward compatibility with our presets so I just could  not dropped old shapes and pixels because your presets would be broken.Working on backward compatibility is not very funny – but it’s important. It builds character as Boudewijn said.The backward compatibility works for spray presets, if you find bugs, contact me on IRC or fill a bug report.

Old clouds with sprayMade with Krita before: Comic clouds before

The old shapes are useful so you can still spray old not-softness-aware circles, ellipses etc. I wanted to merge those stuff into our standard brush dialog, but it turned out to be complicated. We have KisBrush class that units all the brush masks under one class. I was trying to turn my shapes into that one, but I would need more time to design it and implement it wisely. The outcome of this is some interesting discussion in the Krita mailing list about my idea of random shapes based on QPainterPath.

At the end of the week I spent some hours on something different than ABR brush for a while to rest from ABR. It’s basically UI thing for airbrushing.
We had Airbrush brush engine in Krita, but it was basically only copy of Pixel Brush with hardcoded option for incremental deliver. We dropped it due to spray brush which simulates the Airbrush much more better and then we want to have less brush engines with overlapping features, so it was wise decision to drop the Airbrush brush engine.

Airbrush as optionTurn your brush engine into airbrush mode

Every brush engine can act like “airbrush”, by delivering the brush mask when you do not move with your input device in the actual position. It’s done on the tool level – the free hand tool incrementally call paintAt at the same position in time interval specified by rate. So I moved the rate option from the tool to the brush engines GUI and now it is part of the UI and you can turn on/off airbrush option in the UI for brush engines which want to support “airbrush” mode. And even it can be part of the brush engine settings you can save, that was not possible before.

On the different topic, I spent nice weekend shortly before my final state exam in Brussels at the Libre Graphics Meeting. Thanks to the KDE e.V. for the sponsorship! You can watch my talk in some funny language slovakish-english about some brush engines I wrote for Krita . It was great event.  I met some cool guys like GIMP developers for the first time. I also teamed up with Martin maxy Reynolds, mypaint maintainer and core developer. Great event, nice place to talk about Krita and meet people in real-life.

What I realized at LGM:
1. Krita does not have many users. Most probably due to not releasing stable release for a long time. Distributions ships the stable ugly Krita 1.6.x. Let’s hope in change with Krita 2.3 which should be the first user-ready,  stable, awesome, great, unbelieveable release.
2. I don’t like the vegetarian food at all. Brussels chips fries FTW!

In my real life I graduated two weeks ago! I’m Ing. Lukáš Tvrdý now. I finished 5 years of university, it can be translated to Master Of Science. Weeeee. I’m now going to job interviews and writing cover letters. So far it’s fun.

I'm going to Akademy

I’m giving a talk at Akademy 2010 about Krita: what it was like to be GSoC student, community sponsored developer, talk about how we are doing in Krita community and I will show some results of my work in Krita. Be there 😉

Posted in KDE, Krita | 4 Comments

Week 10: Default button

I hopped to the second part of the action plan already in week 9 and I’m working on features now. I also fix bugs these days. Performance part is pretty much done. But when we discover some regression or some other performance issue, I solve it. We also discovered that now the parts of the Action Plan are actually obsoleted. I also need time to focus on my thesis text and prepare for the state exam to become Master Of Science so we moved my last 3 weeks of work to June. I will continue to work on June til 1st week in September. It was already announced in Last Week In Krita. Thanks to the sponsors who allowed me to work more on Krita full-time.

The 10th week was devoted to concept of default button for presets. When you paint, you change the curve of the brush engine, then you tweek this value and maybe now you want to have default settings of the brush engine back. I added button for it to the brush engine configuration dialog so that you can access it fast.

How it works? That was quite complicated path, I did not know exactly what it should do in the beginning and unclear or weak requirements are bed thing. So I discussed with Boud about it and also with Sven Langkamp to come up with solution or better said how we want to implement this feature.

We have default settings for brush engines which are saved in the UI. When you code the brush engine, you setup default values in the GUI. Then when Krita starts, it loads those defaults. We decided that we don’t want to load the default preset out of the GUI but we will use saved preset. You can setup the GUI of the brush engine – that is the brush preset – and save it for later reuse.

Default button

Now we install default preset per brush engine into …/share/apps/krita/defaultpresets. We still load the defaults out of the GUI but when you click on default button, the saved default preset is loaded. The benefit is that if you don’t like our default preset, you can put your default preset to ~/.kde/share/apps/krita/defaultpresets and when you click the default button, the preset is loaded. You just have to name it according /install-path/share/apps/krita/defaultpresets. We still load the default preset from the GUI. This way we take the burden of maintaining the default presets according the state of the GUI of the brush engine. When I add new feature to the brush engine, I have to update the default preset.

Besides this I worked on performance regression, I checked the flood fill. It’s cool to have benchmarks around. No regression found! I also put some time to be in connection with potential GSoC students. So far it looks like Krita will have really great student proposals.

It was nice week, let’s hope the default button will be useful for you. I hope you had nice Easter!

Posted in Krita | 7 Comments

Hairy brush improvements

I renamed my very first brush engine, sumi-e, I wrote a long time ago. It was Google Summer Of Code 2008, the year I joined the Krita team. This brush engine started my joy over  the brush engines. I have improved it lately.

In hairy brush you don’t define the brush mask, but you define the bristles. Every bristle has a position and lenght. For setting up the bristles I used to use Guassian. I like this function for it’s naturalness, that’s why I used it. The value of the function defined the lenght of the bristle. But in turned out that it is not very effective. It produces masks you never had enough control over its dimension. You had to understand the sigma in Gaussian and not every artists care about math.

So I decided to reuse the brush dialog that is shared among the other paintops and use pixel masks to define the bristles. Every pixel define the bristle. The intensity and alpha of the pixel define the lenght of the bristle. The position is computed according the center of the brush. What it gives? Many new possibilities for shapes of the hairy brush. You could have only round shapes before, now you can have any shape. If the pixel is transparent, the bristle is not in the brush – that is the trick to have any shape. Other bonus is that you can have colourful shape also, that was not possible before.

Confeti brush defines the shapeConfeti brush can define position and the length of the bristle

You can control the hairs spacing in the brush shape by parameter scale. This parameter scales the position of the bristle from the center of the brush. Next parameter is random offset. The path of the bristle is randomly deformed according this parameter. You can setup the limit of the offset of the bristle from the initial position. So far the scale has been always controlled by the pressure. I made this optionally now by adding the size sensor and implement that support in hairy brush.  So you can turn off the change of the size according pressure or you can control the size by different sensor like time or distance or tablet’s tilt. And now you can paint also grass more easily as enkithan reported to me.

GrassLukáš Tvrdý – Developer tries to paint grass

There were some performance problems also with sumi-e, now hairy brush. I benchmarked and fixed the related bug and I introduced also some feature that helps with performance. Usually the more bristles, the more slowdown. I added possibility to control the amount of the bristles. You can specify the percentage of the density of the brush. Quite useful when you need big brush.

Related feature is also threshold according the pressure. Now when you paint, only the bristles which are able to touch the canvas, will be painted. Before I used opacity to control the used/unused bristles. Now it is more fun. You can turn off the size sensor and use threshold to control the size of the brush stroke. Or you can combine as these features complement.

Threshold

Next feature is called soak ink in Ink options. Bristles can be colorified according the first contact with the canvas. So you can use photo as the source of the color. Or you can process some photo like I did to demonstrate the feature

Hairy brush used for post-processingHairy brush used for post-processing image to give hairy look

I have some other ideas how to improve Hairy brush. Rotation has to be also controllable according the sensors.Ink depletion has to be reconsidered, more color effects has to be added. The bristles should be more anti-aliased. We will see.  Feel free to contact me if you have anything related to hairy brush features.

Here is the crop of the sketch that Boud, the Krita maintainer, did with hairy brush lately.I like especially the hairs and the eyes.

Wounded girl

Boudewijn Rempt – Wounded Girl

Posted in Krita | 3 Comments

Week 9: Mirroring feature

Last week we finished the part of the action plan regarding the performance. I started to work on usability improvements. The first usability improvement is canvas mirroring.

Canvas mirroring is useful in your painting work flow and Boudewijn explained that it is useful for artists to check errors in their paintings. In the classical painting you need some hardware for that — you need to find a real mirror and see if your painting looks creepy or not. In Krita you don’t have to buy a new mirror, you can use the canvas mirroring feature.

It is also useful when you paint something that supposed to be “almost” symmetrical. You paint ears of your hero or you paint head outlines. You can paint the first half, mirror the canvas and paint the second half and check back quickly. Other possibility is to use symmetrical feature I wrote for Softbrush lately.

In Krita you could already do this by transforming the image and it’s data but that can be slow if you are painting on big canvases. Krita aims to be professional tool, we want to support big canvases. So we need this also as projection feature. We will not transform the image data, we transform the projection of the image data.

I started to work on this and I had a feeling that this is not going to be about a lot of code but this task is going to be about orientate yourself in some complex part of the Krita called projection and about orientate in coordinate systems we have. You also have to find out and understand how the scrolling and zooming works.

I contacted mypaint maintainer maxy with some short mail asking how mirroring is done within mypaint. The answer was what I basically expected and it proved me that I might go in right direction.So first I started with mirroring the coordinates of the tools. We have few coordinate systems in canvas. First coordinate you get is the widget coordinate. That one is transformed according the scrolling offset. Then document origin, the top left coordinate of the image in canvas, also has to be taken into account. Next the zooming transformation follows.After this you are on document level coordinate system. On this level I mirror the coordinate. That means that the document is changed in mirrored manner. This works so far very nicely. For vertical mirroring you need to do transformation like scale(-1,1) and then translate(width,0) where width is the width of the document in my case. We mirror just vertically.

The next step is to mirror the projection of the image. I started to work in QPainter canvas as that one is the more complicated one. First I mirrored extra buffer QImage we have in canvas to be able to use RasterOp operations with Arthur. QImage::mirror()  was just quick&dirty hack to see what will be broken. So tools outlines were broken as they don’t know about the mirroring and some features worked in mirrored way. I removed the dirty hack and I used QTransform for transforming the QPainter. I left the QPainter transformed this time also for tools so the outlines were fixed.

The OpenGL canvas was similar to QPainter canvas, I needed to do just the transformation and again setup the QPainter which is used even in OpenGL based canvas for painting the tool outlines.

Then I started to work on fixing some related, quite complicated, bugs. I spent a lot of time with them without solution. The issue does not seem to be complicated. You just need to mirror some coordinates. But it is hard to know which ones, if you did not write that projection code. The issues are that when you scroll and zoom-in  in the part of the image, it became transparent. I suppose that projection thinks that part of the image is not visible so it does not update it or something like that. But I don’t know really if that is true and I can’t fix it either. Similar problem occurs in OpenGL canvas. I was not able to fix it either. I was trying but without lack. Try&error method did not bring any good results.

Then I spent time integrate the feature into Krita. You can mirror the canvas by View->Mirror Image (CTRL+I).To sum it up, the feature is in koffice-ko feature branch as trunk is frozen. It works with bugs we know about. We just need to fix them. The week I spent on it was nice start for this feature. Let’s hope the feature will be bug-free for Krita 2.3.

Posted in Krita | 5 Comments

New brush in Krita: Softbrush

I’m quite busy right these days. I don’t have much time to blog about some nice stuff I have done in Krita in my “spare-thesis time”. I’m writing the thesis about brush engines I implemented for Krita and I wanted to have a brush that is very common among digital painters. I noticed that they heavily uses the basic Pixel brush. I decided I want to have some special pixel brush.

I stared to change the function that produce the brush mask and affects it’s softness. I selected Gaussian as it is nice function and I experiment with this function, but I found it complicated to control it (you setup sigma, uh what is sigma, you artist ask?). So let’s add some different function to the brush mask code. Oh, let’s put this decision to the artists hands, let’s give him some curve he can model as he want. We already has nice widget for that in Krita, so use it. So you can setup the brush mask by curve!

Default CurveSetup brush softness with the curve

On the picture you can see Curve and Gaussian. The top red point represents the value of the brush mask in the center of the brush mask and the red point down in the right bottom corner represents the value of the edge of the brush mask. So far the brush mask supports only elliptical shape but I have also plans for rectangular shape of the brush mask but I need to find a way how to extend the 24-hours limit of the day so that I can code it :) You can add as many control points as you wish and tweak the softness between the center and edges.

You noticed the Gaussian also there, the mode and it’s code works but it will need some more love in the future. It gives some nice results also sometimes. I will see how it will end up.

So let’s make crazy setting of the curve and you can end up with the brush mask like this one with interesting edges:

Funny maskStroke with custom curve to change brush mask

As you can see, the brush supports pressure with no problems. Thanks to the Cyrille’s sensors you can change size by various attributes of your tablet or you can use some silk ones like a time or a distance. The brush supports also a rotation so you can setup some ellipse shape of the brush with a diameter and an aspect ratio and do some funny stuff like this one:

Rotation Dynamics of the soft brush in action

You setup an angle for your shape and you can allow Krita to manage the rotation for you. As you noticed, the opacity has been changing also, yes, you can control opacity with pressure. Those attributes are present in Pixel brush in Krita also. Let’s go for some new one.

I added parameter density to brush so that you can simulate in some non-photorealistic way brushes like charcoal, chalk and crayon. Basically you setup how many pixels from the brush mask will be used in a single dab.  Very nice attribute, I managed to simulate a little charcoal drawing, here is my “developer” painting:

Softbrush, charcoal attemptSoftbrush density demo: Lukáš Tvrdý – House with charcoal

When you paint, your hand can shake. Maybe your hand is very stiff, and you don’t shake with your hand when you paint :D. So I added a parameter for you. It is called Jitter movement. You can setup how much the brush will be jittered when you paint. Maybe want to draw straight lines with shaky feeling. This is example of some mild jittering:

JitteringSoftbrush mild jittering

If you exaggerate the parameter, you can end up with the result that spray brush, my other brush,  do for you

Spraying with jitterSoftbrush crazy jittering

Last feature, that is a little experimental, is called a HSV dynamics. I suppose you know what is HSV, it is physical color model, which model the color in terms of tint – hue, saturation and intensity – value. It was invented for artists so that they can more powerfully control the color they want to choose. I decided to change the parameters of the color dynamically in a stroke. This is still WIP (work-in-process) but so far you are able to grow the parameter, shrink and control it by pressure. Here is some demo, the feature with pressure can produce images with more gradients easily and you can avoid pick-that-color-and-put-it-here problem a little bit:

HSV DemoSoftbrush: Hue growing, saturation shrinking and value growing

You can control the progression by a curve again and more control over the HSV can be done by using pressure option and using the tablet. These features are for 2.2. For 2.3 I already have some new feature and it is called mirroring and it was inspired by David Revoy video tutorial. He is using something very similar in video (link to 4:40).

You define the vertical axis with the softbrush with CTRL+LEFT click and then you paint in mirror mode. If you setup the axis outside the canvas, it is turned off.

As you paint, your brush mask is mirrored and then painted in the mirror mode. It is WIP also, we plan to make it more general so that every brush engine can use it. I get the idea as I was working on canvas mirroring.

I produced video, watch it here in action.

I plan to blog about other new achievements but again time is issue. Beside I work on Krita full-time, I write thesis so I don’t have time these days. If you want to help me, you can produce some art with my brush engines and then I can include your work in my thesis! I’m interested in pictures created with spray, softbrush, sumi-e (will be renamed to hairy brush), deform brush and particle brush and its combination. Some of the pictures you see here are already part of my thesis. You need to compile trunk for it but it is easy!

So far enkithan and n-pigeon provided a lot of nice paintings for me. I pick up the picture that n-pigeon did lately with just soft brush and spray brush.

Softbrush and spray brush: n-pigeon - Watercolor Softbrush & spraybrush: n-pigeon – Watercolor

Posted in Computer graphics, Krita | 6 Comments

Week 8: Vectorization cancelled

In week 8 I started working on a part of the Krita I had never touched before. It is actually a library inside KOffice called Pigment. Pigment is responsible for the color management. It contains some colorspaces we actually don’t use in Krita because they are too simple for Krita’s needs. They are intended for use by other applications in KOffice. So far the applicationss do not have color management, but they can if the developers want it. Pigment contains many useful classes which operates on the color in some colorspace in many ways like doing the math, compute the histogram. It also contains the implementation of the composite operations. And here was my interest as we wanted to try to vectorize the composite operations by using SSE instructions and the vectorization feature in GCC4.x.

So first I started to write benchmarks for the various composite operations. And then I started to work with GCC feature. Vectorization of the composite operation is already implemented in GEGL by Øyvind Kolås. Also GIMP 2.6.x is using MMX, SSE, SSE2 so I had inspiration and I was trying to map it to our implementation of composite operations. GEGL is using nice code, but GIMP is using assembler directly. I don’t have much experience with assembler. I wish I had write assembler lessons previous year at the university. It is not hard
to code something, but it is hard to do it correctly. I read somewhere in Inkscape mailing list that they had some assembler code to speedup some work but it ended up to be slower then code optimized by compiler.

I had quite a hard time and I did not manage to implement the vectorization even with help I get regularly from Cyrille and boud and other Krita hackers and
GEGL hacker. We stopped it on Wednesday because we discovered that the issue is more complicated then we thought and it would require much more than two days to finish. Maybe another week or even weeks. And the result could be not faster. One of the problems we discovered was that the RGBA 8-bit colorspace uses the unsigned char datatype (quint8 in Qt) for the memory storage but when you do a composite operation, you have to retype it to the bigger data type like a int32. Why? If you have a pixel in quint8 with value 255 and other pixel with value 200 and you add or multiply them, you overflow the data type. And the result is bad. If you retype, you have solved that issue. I studied the GIMP code and how it is
implemented there. It is solved using MMX instuctions for this case. The MMX technology supports both saturating and wraparound modes. You can read about that more in details here. Another issue was that GIMP does not compute every composite operation with vectorization but only some composite operations are implemented this way.

So we decided to start to work on the other item in the action plan which is mirroring of the canvas and possibly rotation. On Thursday and Friday I was back in the canvas code. So far I have working code of the mirroring of the events from input devices. Now the hardest part will be to implement  mirroring in the projection. Projection is the code responsible for correct displaying of the zoomed image and it computes the image you see in the canvas when you scroll or move or some tool paint it’s outline or some part of the
image is changed by some tool. The task will continue also for OpenGL canvas as we have two canvases in Krita.

You see, the vectorization week does not bring any speedup, but I don’t want you to be sad so I decided to write a blog post about other Krita work I do in my spare time. Read it here.

Posted in Krita | 13 Comments

Week 7: 12 times faster smudge

This week of the sponsored Krita developer was a little shorter. On Monday I traveled back from Holland to Slovakia. I was at the Krita Hackfest 2010. We worked there quite hard so we decided to take a break for me for 2 days. So I started to work on Thursday and finished on Friday.

As I wrote in my previous blog post, I started to work on the smudge brush, because according the bug report it was horribly slow. Although I wrote many brush engines, this one is not mine. But I have many experiences with brush engines so I hoped to use them.

Thanks to the consultations with Cyrille Berger,author of this brush engine, I managed to speed up the smudge. I removed some unnecessary memory device and then I had to write famous custom bitBlt function which takes selections saved in different memory class into account. The performance bottleneck was transformation of our paint device into selection.

We introduced fixed paint device longer time ago which should speed up the composition of the brush masks because it is lightweight memory device, but in the smudge it introduced some workarounds which slowed down the performance. I removed that workarounds but it was complicated, that’s why nobody did it before. I ported some of my paintops to use the fixed paint device because according our benchmarks it is really faster.

Here is the table with the performance times of smudge in our KisStrokeBenchmark, where the brush engine draws the big stroke:

1. 7,519 msec per iteration (total: 7519, iterations: 1)
2. 5,275 msec per iteration (total: 5275, iterations: 1)
3. 1,202 msec per iteration (total: 1202, iterations: 1)
4. 653 msec per iteration (total: 653, iterations: 1)

You can see, that the speedup factor is almost twelve. The table consists of the iterations when optimizing. From initial time to the final optimization.

On Friday I was done so I started to work on a vectorization of the compositing operations. Sounds cool, nah? First I wrote benchmarks for our composite operations and now I will continue to write example code which will use the vectorization in gcc4.x. Here is what I’m going to study and use. The point is to speedup the composition of course.

Posted in Krita | 2 Comments

Week 5&6: Krita hackfest

I’m writing this blogpost from Boud’s kitchen. After 10 days of the Krita hackfest I feel quite dizzy. What I was doing?

According the action plan, this two weeks could be spent on some unfinished business. So we decided to work futher on the Adobe Photoshop brush integration. I fixed the type of the brush internally. Photoshop brushes for Krita consist of the alpha-map and the presets of the Photoshop’s brush engine. I ported the GIMP plug-in which loads the bitmaps in the abr brush. But the presets were not parsed.

Krita team: Where is the vision?

Frob wrote the python script which I mentioned previously in my blogpost. Frob and Alexandre Prokoudine are working on reverse engineering of the Photoshop’s resources like brushes and gradients. And their work includes also parsing of the brush engines presets. So I ported the script from python to Qt/C++ for Krita. The last step is to integrate the script. That was not done yet.

Then I arrived to Deventer, the Netherlands. Dmitry Kazakov was waiting for me at the airport and we went together to Deventer from Amsterdam. The weekend was gone so fast. We discussed a lot of issues together with Peter Sikking, interaction designer. That was very very interesting for me. I also met other Krita hackers I haven’t met yet like Adam or Vera. It is nice to be together, because you can be very productive.Together with Dmitry we fixed a bug in few minutes. It would take much more time if we would do it like a Report Bug -> Assign -> Fix.

Week 6 was the hackfest for me, Sven, Cyrille and Boud here in Deventer. We decided to give a try to 1/4 computation of the brush mask to have faster painting. This time it was implemented correctly. Before I tried to copy the 1/4 of the mask to the other parts of the mask. This time I decided to compute the brush mask with bi-linear interpolation. I spent 2 days on it fixing some artefacts that started to occur. Final measurements showed that the 1/4 computation is more expensive then the function itself as this time the arctan2 was not involved. Also other benchmark with arctan2 involved showed that the code is equally fast as the version without the interpolation. Maybe some bigger brushes will be faster but I need to investigate. The code is in trunk, we just need to find it’s usage.

Another optimization was for flood fill tool. Write benchmark, valgrind, identify the bottlenecks, try to fix them, do it few times and I was done. Cyrille helped me a lot, he is very good developer and he had always some good advices how to get the speedup. Finally I managed to make flood fill run 3.5 times faster.
Here is table and you can see how time dropped:

Start of the optimization
1. 5,921 msec
2. 5,752 msec
3. 5,574 msec
4. 3,581 msec
5. 1,711 msec
End of the optimization

The flood fill is still quite slow in the Krita. I tested on 4096×4096 pixel image. The performance problem now is that there is difference function used in the flood fill algorithm and the function convert the pixels to LAB. I suppose that in GIMP it is probably done on RGB 8-bit colorspace. But in Krita there are many colorspaces and the best way to do the difference is on L channel in LAB as Cyrille told me.

Then we were in Amsterdam in the Blender studios. We met Ton Roosendaal and the Durian project team. It was exciting for us. I managed to talk with Angela, the Durian artist from Canada. I had nice chat with her, lovely person. I also managed to talk with Ben, the artist who tried Krita and he also produced some art with it. I was in Amsterdam for the first time. I managed to see arrogant Amsterdam bikers, nice architecture and the cannal. We had long but nice walk around the town.

At the hackfest we discovered more performance issues. So I spent some time on smudge brush. I started with simple fixes and I started to work on some complicated issues. I’m writing bitBlt function for our fixed device. Fixed device is used for brush masks and it is faster then using paint device with tiles as the brush masks are usually small and they does not require tiles and undo. We need more function for bitBlt when the selection is stored in fixed device. So far I  the smudge is 1.42x faster.

Krita headquarter

Krita guys also started to work on various stuff that Peter Sikking proposed, e.g. we have a new widget and scratch box so I had to fix paintops also. Also I rewrote the deform brush. I’m trying to unify the brush engines in Krita and I wanted to add some new features to old brush engines, so rewrite was needed. The code was almost one and a half year old. I did a lot of work on brush engines also. Usually many fixes etc, but that is for other blogpost maybe later.

I would like to thank Boudewijn and Irina for taking care of us. The home-made food was “best thing ever” as Vera would say. I had nice time with the Krita team at Rempt’s house. Thank you for inviting me!

Busy week, I’m really tired and I’m looking forward for some rest and my home.

Posted in Krita | 2 Comments

Wacom tablet does not work in Qt

I’m at Deventer, we are having Krita sprint. I’m trying to implement some new stuff in Krita and I can’t :'( Tablet stopped to work for me in Krita and basically in Qt. I don’t see tablet events (qt example in widgets/tablet does not show anything), so no pressure, no tilt, just mouse events.

I have Fedora 12, Qt 4.6.2. linuxwacom was replaced by xorg-x11-drv-wacom, so there are no utilities like wacdump or xidump now.I removed old configuration lines in xorg.conf. They were needed long time ago, I used to setup my tablet according wacom tablet. I depend on the evdev now. The tablet work in mypaint and in Gimp. I have pressure support there.

I don’t have tablet pressure in Qt example in qt4/examples/widgets/tablet nor in Krita.

Cyrille proposed to check this command:

xlsatoms | grep -i wacom
303     Wacom Tablet Area
304     Wacom Rotation
305     Wacom Pressurecurve
306     Wacom Serial IDs
307     Wacom Strip Buttons
308     Wacom Wheel Buttons
309     Wacom TwinView Resolution
310     Wacom Display Options
311     Wacom Screen Area
312     Wacom Proximity Threshold
313     Wacom Capacity
314     Wacom Pressure Threshold
315     Wacom Sample and Suppress
316     Wacom Enable Touch
317     Wacom Hover Click
318     Wacom Tool Type
319     Wacom Button Actions
430     Wacom Stylus
431     Wacom Cursor
432     Wacom Eraser

So it looks ok. Have you got idea how to fix it? It seems that it is Fedora issue, other Krita developers
have working tablet support out of the box in the OpenSuse. I checked if the tablet support is compiled in Fedora, it is.

Krita hackers are offering me CD of OpenSuse. I like my Fedora, I don’t give up so far…Please, help if you can 😉

Sven Langkamp has also this same problem as I do, he is also on Fedora 12 these days.

Update 28.2.2010:
I filled bugreport for Fedora https://bugzilla.redhat.com/show_bug.cgi?id=569132

Also for Qt http://bugreports.qt.nokia.com/browse/QTBUG-8599

UPDATE: It works now with some patch. Fedora will ship some update soon. Thanks to Thomas Zander for the patch and Fedora guys for providing me test build!

Posted in Fedora, Qt | 15 Comments

Week 4: Optimizing iterators

So what happened last week? Except that Slovakia upset Russia in Hockey at Vancouver, Slovakia is also fixing Krita performance thanks to the donors, from all around the world, who made that possible. Enough about nationality, let’s talk about what happened.

The plan for the last week was to optimize iterators. We use tiled buffers for our memory management. You usually need undo function in the image processing application and storing the whole image is not a good idea. You rather break the image into tiled parts, rectangles and you store and restore them. But affects the whole application, you have to iterate pixels in filter, you have paint with the brush and that means to composite one image over another image. So basically iterators are very important for Krita. Its speed is priority of course.

We knew, from the measures  I did first week, that fetching those tiles is a slow process. That’s why we have a rectangle iterator which iterates the image tile by tile. But sometimes you need to iterate the image in lines. E.g. in the filters or under some special conditions when you need the access to the pixel before and after in the same line.

That’s why we have a line iterators, we have a vertical and a horizontal iterator. I was optimizing the line iterators. Instead of fetching the tiles every width/height of the tile, we now pre-fetch the tiles to some buffer, lock them and work with them, til we can skip to the next row of tiles. The tiles are 64×64 big by the way. Another important thing is that Krita is threaded and one thread is doing a projection updates (the final image you see in Krita) and other can work on some other stuff like painting or filtering. So we have to lock&unlock the tiles. I patched the vertical and the horizontal iterator.

Ben Dansie: Monkey

We managed to get speedup like 1.28x til 6.21x faster iterating. Cyrille Berger then suggested that we have quite complicated structure for iterators with many function calls, so let’s try a new API for iterator with less function calls. So my task was to code or better said port the horizontal iterator to the new API. The iterator is ready for testing. According the benchmarks, the new iterator is 1.5x faster then old API. Also Cyrille added a lot of custom magic to it so that it is faster. We are closer to the data manager speed, which limits the speed of iterators.

On Monday I also fixed the abr brush so that we can paint with abr brushes, but the work is not finished yet. This week I will work on it and also I will try to use the new iterator in KisPainter for compositing and explore the time results. Then at the end of the week I fly to Netherlands, where we are having our Krita sprint in Deventer, in Boudewijn’s home. I will spent 11 days there with other Krita hackers. So a lot of coding in front of us. We will be visiting the Blender team also. I’m looking forward to it!

So far we make progress, Sven Langkamp made me happy saying that the speedup for painting even with some filters is amazing now compared to what it was before. Also the artist, Ben Dansie,  from the project Durian, the Blender project of the open movie, used Krita for making some art. Cool, isn’t it? Now back to rediscover your Krita code ™.

Posted in Krita | 3 Comments