tag:blogger.com,1999:blog-279016622024-03-28T07:30:33.365+00:00Zack Rusinbattles of the true graphics ninjaZackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.comBlogger17125tag:blogger.com,1999:blog-27901662.post-38606417229876950552011-09-18T01:27:00.000+01:002011-09-18T01:27:50.708+01:00NV path renderingA while ago NVIDIA released drivers with their <a href="http://developer.download.nvidia.com/assets/gamedev/files/GL_NV_path_rendering.txt">NV_path_rendering</a> extension. GL_NV_path_rendering is a relatively new OpenGL extension which allows rendering of stroked and filled paths on the GPU.<br />
<br />
I've heard about it before but lately I've been too busy with other stuff to look at, well, anything.<br />
<br />
I've decided to spend a few seconds looking at the <a href="http://developer.nvidia.com/nv-path-rendering-videos">videos NVIDIA posted on their site</a>. They were comparing the NV_path_rendering, Skia, Cairo and Qt. Pretty neat. Some of the demos were using huge paths, clipped by another weird path and using perspective transforms. Qt was very slow. It was time for me to abandon my dream of teaching my imaginary hamster how to drive a stick shift and once again look at path rendering.<br />
<br />
You see, I wrote the path rendering code so many times that one of my favorite pastimes was creating ridicules paths that no one would ever think about rendering and seeing how fast I could render them. Qt's OpenGL code was always unbelievably good at rendering paths no one would ever render. Clearly these people were trying to outcrazy me.<br />
<br />
Fortunately there's an <a href="http://developer.nvidia.com/nv-path-rendering">SDK posted on the NVIDIA site</a> and it's really well done. It even compiles and works on GNU/Linux. Probably the best demo code for a new extension that I've ever seen. The extension itself is very well done as well. It's very robust, ultimately though it's the implementation that I care about. I have just one workstation with an NVIDIA card in it, a measly Quadro 600, running on a dual processor xeon e5405, but it was enough to play with it.<br />
<br />
The parts using Qt were using the raster engine though. I've looked at the code and decided to write something that would render the same thing but using just Qt. The results were a little surprising. Qt OpenGL could render tiger.svg scaling and rotating it at about 270fps, while the NV_path_rendering was running at about 72fps. Here's both of them running side by side:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpf9u7Lj07dGZCPiPOnunDlvX6UQ51jX0gvSr2BYTBjc9Gubvfr8Al6vorRB4PyNtvHGeMqusvW1TIZ47LtlCkI8PMBGYEW9b8FstbA5ZH_5JlGdYNDveX0Vk7hhQwF3865YLcNQ/s1600/nv_path_renderer_samples.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpf9u7Lj07dGZCPiPOnunDlvX6UQ51jX0gvSr2BYTBjc9Gubvfr8Al6vorRB4PyNtvHGeMqusvW1TIZ47LtlCkI8PMBGYEW9b8FstbA5ZH_5JlGdYNDveX0Vk7hhQwF3865YLcNQ/s400/nv_path_renderer_samples.png" width="400" /></a></div>
<br />
(numbers lower for both on account of them running at the same time of course). As you can see Qt is almost 4x faster. I've figured it might be related to the different SVG implementations and rendering techniques used, so I quickly hacked the demo NVIDIA posted to open a brand new window (you need to click on it to start rendering) and render to QGLPixelBuffer but using the same SVG and rendering code as their NV_path_rendering demo code. The results were basically the same.<br />
<br />
I posted the code for the Qt demo and the patch to nvpr_svg on github: <a href="https://github.com/zackr/qt_svg">https://github.com/zackr/qt_svg</a><br />
<br />
The patch is larger than it should be because it also changed the file encoding on the saved
files from DOS to Unix but you shouldn't have any issues applying it.<br />
<br />
So from a quick glance it doesn't seem like there are any performance benefits to using NV_path_rendering, in fact Qt would likely be quite a bit slower with it. Having said that NVIDIA's implementation looks very robust and a lot more numerically stable. I've spent a little bit of time looking at the individual pixels and came away very impressed.<br />
<br />
In general the extension is in a little bit of a weird situation. On one hand, unlike OpenVG which creates a whole new API, it's the proper way of introducing GPU path rendering, on the other hand pretty much every vector graphics toolkit out there already implements GPU based path rendering. Obviously the implementations differ and some might profit from the extension but for Qt the question is whether that quality matters more than the performance. Specifically whether the quality improves enough to justify the performance hit.<br />
<br />
I think the extension's success will largely depend on whether it's promoted to, at least an EXT or, ideally an ARB, meaning all the drivers support it. Using it would make the implementations of path rendering in toolkits/vector graphics libs a lot simpler and give driver developer a central place to optimize a pretty crucial part of the modern graphics stack. Unfortunately if you still need to maintain the non NV_path_rendering paths then it doesn't make a whole lot of sense.
Mesa3D implementation would be trivial simply because I've already implemented path rendering for OpenVG using the Gallium3D interface, so it'd be a matter of moving that code but I'm just not sure if anyone will be actually using this extension. All in all, it's a very well done extension but it might be a little too late.
Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com14tag:blogger.com,1999:blog-27901662.post-87876860329001676122011-04-25T21:21:00.015+01:002011-04-27T07:20:20.045+01:00ApiTrace<div style="text-align: left;">During the last three weeks I've spent most of my spare time writing a GUI for <a href="http://jrfonseca.blogspot.com/">Jose's</a> amazing <a href="https://github.com/apitrace/apitrace">ApiTrace</a> project. <a href="https://github.com/apitrace/apitrace">ApiTrace</a> is a project to trace, analyze and debug graphics api's. Both OpenGL and Direct3D. To some extend inspired by gDEBugger and Windows PIX. We wanted a tool that would let us slice through huge games and CAD apps to the exact call which causes problems and be able to inspect the entire graphics state, including the shaders, textures and all the buffers. We ended up doing that, plus a lot more and we're just getting started. In other words it's the best thing since "Human/Robot Emancipation Act of 3015". </div><div><br /></div><div>You begin by tracing your target application. You can do that either from the console or from the GUI. A trace file is created and we can do some amazing things with it. You can open it in a GUI and</div><div><ul><li>Inspect the state frame by frame, draw call by draw call:<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMqCXABiAhlefW_siwSHSJN0sL158dq7MXv-O7ncpwpQv0MFQjGJr-Vt_sX5FqRjd5KrR7WR2AeChiownIxU1pPTcfRMitSf-ggRMLp_b_6K6dXf2uxGdxQvtB6q3HnsIxK7sgIA/s1600/qapitrace10.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 202px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMqCXABiAhlefW_siwSHSJN0sL158dq7MXv-O7ncpwpQv0MFQjGJr-Vt_sX5FqRjd5KrR7WR2AeChiownIxU1pPTcfRMitSf-ggRMLp_b_6K6dXf2uxGdxQvtB6q3HnsIxK7sgIA/s320/qapitrace10.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5599729351059797586" /></a></li><li>Replay the trace file:<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWHj_tv2W5Mat-Fu_xOgDbhyCrJM2zMpjviJmLkYiOivHTIfFHDzEL9VmLPPW512MsvVg-wFfVGx7YdoNQav1eMubI3jjsYT5aFip5mIATviB9TYt6AuaUhWGzJpGgeifyq7cHkA/s1600/qapitrace2.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 262px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWHj_tv2W5Mat-Fu_xOgDbhyCrJM2zMpjviJmLkYiOivHTIfFHDzEL9VmLPPW512MsvVg-wFfVGx7YdoNQav1eMubI3jjsYT5aFip5mIATviB9TYt6AuaUhWGzJpGgeifyq7cHkA/s320/qapitrace2.png" alt="" id="BLOGGER_PHOTO_ID_5599620181177807442" border="0" /></a></li><li>Check every texture:<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc5xWqAE86LkfHxqPiEoI3mOE_yJ_lWXt9w5_LPMdPD-Qyyh2ydORT1jmcQsSkHrrikMX42JgfOIxfJZHIWXnRkWlk0LYblMZVEno4AohZ4KT9OHe2oQFh-iEiOUCRNzsFWTC7fA/s1600/qapitrace3.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 214px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc5xWqAE86LkfHxqPiEoI3mOE_yJ_lWXt9w5_LPMdPD-Qyyh2ydORT1jmcQsSkHrrikMX42JgfOIxfJZHIWXnRkWlk0LYblMZVEno4AohZ4KT9OHe2oQFh-iEiOUCRNzsFWTC7fA/s320/qapitrace3.png" alt="" id="BLOGGER_PHOTO_ID_5599620365123668386" border="0" /></a></li><li>Every bound framebuffer:<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgODK5Ug8vBWOrg5PPuUcsIWTyErvn2OsjNbnRlR1sKlsvRabgc0CZCnNFdG43KsEyVTYP1AnqbHgokNRjkK95BNb0jwCm3Fubs-zPImTK5JWS43OFhb2mdFKfE9vJCIOv4bD-tw/s1600/qapitrace4.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 219px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgODK5Ug8vBWOrg5PPuUcsIWTyErvn2OsjNbnRlR1sKlsvRabgc0CZCnNFdG43KsEyVTYP1AnqbHgokNRjkK95BNb0jwCm3Fubs-zPImTK5JWS43OFhb2mdFKfE9vJCIOv4bD-tw/s320/qapitrace4.png" alt="" id="BLOGGER_PHOTO_ID_5599620366605497970" border="0" /></a></li><li>Every shader:<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZyjJt7_w0jLVUJwCgzGHm9TnsckBOE-VUJQJ_HXNGlW4sq4zGhiljrCBGo-rm19bQfWUmDM9P49ZnABL9pORhNki81m0Ez0DZpV13re3G8mwHJI-R2F-qJaxZEZdPADFsNZqV6w/s1600/qapitrace5.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 219px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZyjJt7_w0jLVUJwCgzGHm9TnsckBOE-VUJQJ_HXNGlW4sq4zGhiljrCBGo-rm19bQfWUmDM9P49ZnABL9pORhNki81m0Ez0DZpV13re3G8mwHJI-R2F-qJaxZEZdPADFsNZqV6w/s320/qapitrace5.png" alt="" id="BLOGGER_PHOTO_ID_5599620370634122050" border="0" /></a></li><li>Every vertex buffer:<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBKKyXjLpDNqE_op4PvBqHvyRe__rghavcPFPtdJo6n-Q764yQW42moBv9pBGOQxA2IH2XM7ZLU1jgRQREGilDuRyVoPAmkHwuW9hGrSrPg21jXhpXnZGJIRKBGJlc7kOjRjlK4Q/s1600/qapitrace6.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 219px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBKKyXjLpDNqE_op4PvBqHvyRe__rghavcPFPtdJo6n-Q764yQW42moBv9pBGOQxA2IH2XM7ZLU1jgRQREGilDuRyVoPAmkHwuW9hGrSrPg21jXhpXnZGJIRKBGJlc7kOjRjlK4Q/s320/qapitrace6.png" alt="" id="BLOGGER_PHOTO_ID_5599620372969210626" border="0" /></a></li><li>You can see if OpenGL threw an error at any point during the replay and if so what was it:<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhbEQzeM3Ew-7wHsVBauMIk0iqlIT2bOWo7Re3mshp7IKBWH-FSdvz7ibo7xHAtDFRCimzp7WjwFNh0hlFcy1Jp1Bzf6RvI3idDJwkge9WDOL_vdi1W73ohyDbvb675Pq_jdLGmA/s1600/qapitrace9.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 216px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhbEQzeM3Ew-7wHsVBauMIk0iqlIT2bOWo7Re3mshp7IKBWH-FSdvz7ibo7xHAtDFRCimzp7WjwFNh0hlFcy1Jp1Bzf6RvI3idDJwkge9WDOL_vdi1W73ohyDbvb675Pq_jdLGmA/s320/qapitrace9.png" alt="" id="BLOGGER_PHOTO_ID_5599620553845343490" border="0" /></a></li><li>And to go completely nuts, as graphics developers like to do, you get to edit any shader, any uniform and large chunks of the state to immediately see the effects it would have on the rendering:<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhN-F8y34T64H8BpuDo9q45-uygiso-dAIxjuzekolB6mFBzEK29-nw7xz3-qRbCTwFFwC71qCzwRNAT82pWEbe-wJm-R5c-JWTEaxeJ7iJC_1r4obFXQf45c27VUzdx6TzYfRDQ/s1600/qapitrace8.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 219px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhN-F8y34T64H8BpuDo9q45-uygiso-dAIxjuzekolB6mFBzEK29-nw7xz3-qRbCTwFFwC71qCzwRNAT82pWEbe-wJm-R5c-JWTEaxeJ7iJC_1r4obFXQf45c27VUzdx6TzYfRDQ/s320/qapitrace8.png" alt="" id="BLOGGER_PHOTO_ID_5599620549990618882" border="0" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnXbIQhZJJOLlgHwC78LBum3zGKQ-IakC3uIgJRLwXx0q_O18iHG3sX8HOuyZBGsKlqogdnLJITD3KzCZbmIRCDott1_mEn63ZsYZ-Tq3IEnLKE8Ynvi1fbjR1AakWXU7LNZCc9Q/s1600/qapitrace7.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 219px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnXbIQhZJJOLlgHwC78LBum3zGKQ-IakC3uIgJRLwXx0q_O18iHG3sX8HOuyZBGsKlqogdnLJITD3KzCZbmIRCDott1_mEn63ZsYZ-Tq3IEnLKE8Ynvi1fbjR1AakWXU7LNZCc9Q/s320/qapitrace7.png" alt="" id="BLOGGER_PHOTO_ID_5599620376525539442" border="0" /></a></li></ul></div><div><br /></div><div>As a driver developer you no longer have to install all the games just to debug a problem, the report can simply include a short trace which you can use to immediately figure out what's wrong. As an application developer you can inspect every graphics call your app makes, you can analyze your api usage and you could automatically produce standalone testcases which you can send to driver developers.</div><div><br /></div><div><a href="https://github.com/apitrace/apitrace">ApiTrace</a> is hosted on <a href="https://github.com/apitrace/apitrace">github</a> and it's BSD licensed. It works on Linux and Windows (we're planning to add OSX support as well). Gui is written using Qt and requires the QJson library.</div><div><br /></div><div>Jose <a href="http://lists.freedesktop.org/archives/mesa-dev/2011-April/007090.html">just announced the first release</a> so let us know if there's anything that would make your life a lot easier. Next is support for multiple GL contexts, ability to export just a single frame from a trace (either as a trace file or a standalone C application), ability to start and stop tracing on a hot key and lots of other features soon. So whether you're a driver developer, working on games, CAD apps or 2D scene-graphs this is a tool that should make your life significantly easier and better.</div>Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com40tag:blogger.com,1999:blog-27901662.post-74396184570068233262010-11-02T14:56:00.002+00:002010-11-02T15:13:05.557+00:002D musings<div>If you've been following graphics developments in the 2D world over the last few years you've probably seen a number of blogs and articles complaining about performance. In particular about how slow 2D is on GPUs. Have you ever wondered why it's possible to make <a href="http://pc.ign.com/dor/objects/926419/id-tech-5-project/images/rage-20100503114108734.html">this</a> completely smooth but your desktop still sometimes feels sluggish?</div><div><br /></div><div><span class="Apple-style-span" ><b>Bad model</b></span></div><div><br /></div><div>For some weird reason ("neglect" being one of them) 2D rendering model hasn't evolved at all in the last few years. That is if it has evolved at all since the very first "draw line" became a function call. Draw line, draw rectangle, draw image, blit this, were simply joined by fill path, stroke path, few extra composition modes and such. At its very core the model remained the same though, meaning lots of calls to draw an equally large number of small primitives.</div><div><br /></div><div>This worked well because technically zero, or almost zero, setup code was necessary to start rendering. Then GPUs became prevalent and they could do amazing things but to get them to do anything you had to upload the data and the commands that would tell them what to do. With time more and more data had to be sent to the GPU to describe the increasingly complex and larger scenes. It made sense to optimize the process of uploads (I keep calling them "uploads" but "GPU downloads" is closer to the true meaning) by allowing to upload an entire resource once and then refer to it via a handle. Buffers, shaders, addition of new shading stages (tessellation, geometry) all meant to reduce the size of data that had to be uploaded to the GPU before every rendering.</div><div><br /></div><div>At least for games and well designed 3D software. 2D stuck to its old model of "make GPU download everything on every draw request". It worked ok because most of the user interface was static and rather boring so the performance was never much of an issue. Plus in many cases the huge setup costs are offset by the fact that the Graphics Processing Units are really good at processing graphics.</div><div><br /></div><div>Each application is composed of multiple widgets each widget draws itself using multiple primitives (pixmaps, rectangles, lines, paths) and each primitive needs to first upload the data needed by the GPU to render it. It's like that because from the 2D api perspective there's no object persistence. The api has no idea that you keep re-rendering the same button over and over again. All the api sees is another "draw rectangle" or "draw path" call which it will complete.</div><div><br /></div><div>On each frame the same data is being copied to the GPU over and over again. It's not very efficient, is it? There's a limited number of optimizations you can do in this model. Some of the more obvious ones include:<ul></ul></div><div><li>adding unique identifiers to the pixmaps/surfaces and using those as identifiers as keys in a texture cache which allows you to create a texture for every pixmap/surface only once,</li></div><div><li>collecting data from each draw call in a temporary buffer and copying it all at once (e.g. in SkOSWindow::afterChildren, QWindowSurface::endPaint or such),</li></div><div><li>creating a shader cache for different types of fills and composition modes</li></div><div></div><div><br /></div><div>But the real problem is that you keep making the GPU download the same data every frame and unfortunately that is really hard to fix in this model.</div><div><br /></div><div><span class="Apple-style-span" ><b>Fixing the model</b></span></div><div><br /></div><div>It all boils down to creating some kind of a store where lifetime of an object/model is known. This way the scene knows exactly what objects are being rendered and before rendering begins it can initialize and upload all the data the items need to be renderer. Then rendering is just that - rendering. Data transfers are limited to object addition/removal or significant changes to their properties and then further limited by the fact that a lot of the state can always be reused. Note that trivial things like changing the texture (e.g. on hover/push) don't require any additional transfers and things like translations can be limited to just two floats (translation in x and y) and they're usually shared for multiple primitives (e.g. in a pushbutton it would be used by the background texture and the label texture/glyphs)</div><div><br /></div><div>It would seem like the addition of QGraphicsView was a good time to change the 2D model, but that wasn't really possible because people like their QPainter. No one likes when a tool they have been using for a while and are fairly familiar with is suddenly taken away. Completely changing a model required a more drastic move.</div><div><br /></div><div><span class="Apple-style-span" ><b>QML and scene-graph</b></span></div><div><br /></div><div>QML fundamentally changes the way we create interfaces and it's very neat. From the api perspective it's not much different from JavaFX and one could argue which one is neater/better but QML allows us to almost completely get rid of the old 2D rendering model and that's why I love it! A side-effect of moving to QML is likely the most significant change we've done to accelerated 2D in a long time. The new <a href="http://labs.qt.nokia.com/2010/10/08/qt-scene-graph-round-2/">Qt scene graph</a> is a very important project that can make a huge difference to the performance, look and feel of 2D interfaces.</div><div>Give it a try. If you don't have OpenGL working, no worries it will work fine with Mesa3D on top of llvmpipe.</div><div><br /></div><div>A nice project would be doing the same in web engines. We have all the info there but we decompose it into the draw line, draw path, draw rectangle, draw image calls. Short of the canvas object which needs the old style painters, everything is there to make accelerated web engines a lot better at rendering the content.</div><div><br /></div>Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com36tag:blogger.com,1999:blog-27901662.post-65498330576628140942009-08-14T19:04:00.003+01:002009-08-14T19:23:53.937+01:00More 2D in KDEAn interesting question is: if the raster engine is faster at gross majority of graphics and Qt X11 engine falls back on quite a few features anyway why shouldn't we make raster the default until OpenGL implementations/engine are stable enough.<div><br /></div><div>There are two technical reasons for that. Actually that's not quite true, there's more but these two are the ones that will bother a lot of people.</div><div><br /></div><div>The first is that we'd kill KDE performance over network. So everyone who uses X/KDE over network would suddenly realize that their setup became unusable. Their sessions would suddenly send images for absolutely everything all the time... As you can imagine institutions/schools/companies who use KDE exactly in this way wouldn't be particularly impressed if suddenly updating their installations would render them unusable.</div><div><br /></div><div>The second reason is that I kinda like being able to read and sometimes even write text. Text tends to be pretty helpful during the process of reading. Especially things like emails and web browsing get a lot easier with text. I think a lot of people shares that opinion with me. To render text we need fonts, in turn those are composed of glyphs. To make text rendering efficient, we need to cache the glyphs. When running with the X11 engine we render the text using Xrender, which means that there's a central process that can technically manage all the glyphs used by applications running on a desktop. That process is the Xserver. With the raster engine we take Xserver out of the equation and suddenly every single application on the desktop needs to cache the glyphs for all the fonts they're using. This implies that every application suddenly uses megs and megs of extra memory. They all need to individually cache all the glyphs even if all of them use the same font. It tends to work ok for languages with a few glyphs e.g. 40+ for english (26 letters + 10 digits + a few punctuation marks). It doesn't work at all for languages with more. So unless it will be decided that KDE can only be used by people with languages whose alphabets contain about 30 letters or less, then I'd hold off with making raster engine the default.</div><div><br /></div><div>While the latter problem could be solved with some clever shared memory usage or forcing Xrender on top of raster engine (actually I shouldn't state that as a fact, I haven't looked at font rendering in raster engine in a while and maybe that was implemented lately), it's worth noting that X11 engine is simply fast enough to not bother over a few frames in this way or another. Those few frames that you'd gain would mean unusable KDE for others.</div><div><br /></div><div>And if you think that neither of the above two points bothers you and you'd still want to use raster engine by default you'll have to understand that I just won't post instructions on how to do that here. If you're a developer, you already know how to do it and if not there are trivial ways of finding that out from the Qt sources. If you're not a developer then you really should stick globally to the defaults and can simply test the applications with the -graphicssystem switches. </div>Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com27tag:blogger.com,1999:blog-27901662.post-46598083676445469292009-08-14T01:21:00.007+01:002009-08-14T05:31:18.564+01:002D in KDESo it seems a lot of people is wondering about this. By this I mean why dwarfs always have beards. Underground big ears would be probably a better evolutionary trait, but elfs got dibs on those.<br /><br />Qt, and therefore KDE, deals with 3 predominant ways of rendering graphics. I don't feel like bothering with transitions today, so find your own way from beards and dwarfs to Qt/KDE graphics. Those three ways are:<br /><ul><li>On the CPU with<span style="font-weight: bold;"> no </span>help from the GPU using the raster engine</li> <li>Using X11/Xrender with the X11 engine</li> <li>Using OpenGL with the OpenGL engine</li></ul>There's a couple of ways in which the decision about which one of those engines is being used is made.<br /><br />First there's the default global engine. This is what you get when you open a QPainter on a QWidget and its derivatives. So whenever you have code like<br /><code><br />void MyWidget::paintEvent(QPaintEvent *)<br />{<br /> QPainter p(this);<br /> ...<br />}<br /></code><br />you know the default engine is being used. The rules for that are as follows:<br /><ul><li>GNU/Linux : X11 engine is being used</li><li>Windows : Raster engine is being used</li><li>Application has been started with -graphicssystem= option :<br /><ul><li>-graphicssystem=native the rules above apply</li> <li>-graphicssystem=raster the raster engine is being used by default</li> <li>-graphicssystem=opengl the OpenGL engine is being used by default</li> </ul></li></ul>Furthermore depending on which QPaintDevice is being used, different engines will be selected. The rules for that are as follows:<br /><ul><li>QWidget the default engine is being used (picked as described above)</li><li>QPixmap the default engine is being used (picked as described above)</li><li>QImage the raster engine is being used (always, it doesn't matter what engine has been selected as the default)</li><li>QGLWidget, QGLFramebufferObject, QGLPixelBuffer the OpenGL engine is being used (always, it doesn't matter what engine has been selected as the default)</li></ul>Now here's where things get tricky: if the engine doesn't support certain features it will have to fallback to one engine that is sure to work on all platforms and have all the features required by the QPainter api - that is the raster engine. This was done to assure that all engines have the same feature set.<br /><br />While OpenGL engine should in general never fallback, that is not the case for X11 and there are fallbacks. One of the biggest immediate optimizations you can do to make your application run faster is to assure that you don't have fallbacks. A good way to check for that is to export QT_PAINT_FALLBACK_OVERLAY and run your application against a debug build of Qt, this way the region which caused a fallback will be highlighted (the other method is to gdb break in QPainter::draw_helper). Unfortunately this will only detect fallbacks in Qt.<br /><br />All of those engines also use drastically different methods of rendering primitives.<br />The raster engine rasterizes primitives directly.<br />The X11 engine tessellates primitives into trapezoids, that's because Xrender composites trapezoids.<br />The GL engine either uses the stencil method (described in this blog a long time ago) or shaders to decompose the primitives and the rest is handled by the normal GL rasterization rules.<br /><br />Tessellation is a fairly complicated process (also described a long ago in this blog). To handle degenerate cases the first step of this algorithm is to find intersections of the primitive. In the simplest form think about rendering figure 8. There's no way of testing whether the given primitive is self-intersecting without actually running the algorithm.<br />To render with anti-aliasing on the X11 engine we have to tessellate. We have to tessellate because Xrender requires trapezoids to render anti-aliased primitives. So if the X11 engine is being used and the rendering is anti-aliased whether you're rendering a line, heart or a moose we have to tessellate.<br /><br />Someone was worried that it's a O(n^2) process which is of course completely incorrect. We're not using a brute force algorithm here. The process is obviously O(nlogn). O(nlogn) complexity on the cpu side is something that both the raster and X11 engines need to deal with. The question is what happens next and what happens in the subsequent calls.<br /><br />While the raster engine can deal with all of it while rasterizing, the X11 engine can't. It has to tessellate, send the results to the server and hope for the best. If the X11 driver doesn't implement composition of trapezoids (which realistically speaking most of them doesn't) this operation is done by Pixman. In the raster engine the sheer spatial locality almost forces better cache utilization than what could be realistically achieved by the "application tessellate->server rasterization" process that the X11 engine has to deal with. So without all out acceleration in this case X11 engine can't compete with the raster engine. While simplifying a lot it's worth remembering that in terms of cycles register access is most likely smaller or equal to 1 cycle, access to L1 data cache is likely about 3 cycles, L2 is probably about 14 cycles, while the main memory is about 240 cycles. So for CPU based graphics efficient memory utilization is one of the most crucial undertakings.<br /><br />With that in mind, this is also the reason why a heavily optimized purely software based OpenGL implementation would be a lot faster than raster engine is at 2D graphics. In terms of memory usage OpenGL pipeline is simply a lot better at handling memory than the API QPainter provides.<br /><br />So what you should take away from this is that if you're living in the perfect world, the GL engine is so much better than absolutely anything else Qt/KDE have it's not even funny, X11 follows it and the raster engine trails far behind.<br /><br />The reality with which you're dealing with is that when using the X11 engine, due to the fallback you will be also using the raster engine (either on the application side with Qt raster engine or the server side with Pixman) and unfortunately in this case "the more the better" doesn't apply and you will suffer tremendously. Our X11 drivers don't accelerate chunks of Xrender, the applications don't have good means of testing what is accelerated, so what Qt does is simply doesn't use many of its features. So even if the driver would accelerate for example gradient fills and source picture transformations it wouldn't help you because Qt simply doesn't use them and always falls back to the raster engine. It's a bit of a chicken and an egg problem - Qt doesn't use it because it's slow, it's slow because no one uses it.<br /><br />The best solution to that conundrum is to try running your applications with -graphicssystem=opengl and report any problems you see to both Qt software and the Mesa3D/DRI bugzillas because the only way out is to make sure that both our OpenGL implementations and OpenGL usage in the rendering code on the applications side are working efficiently and correctly. The quicker we get the rendering stack to work on top of OpenGL the better off we'll be.Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com28tag:blogger.com,1999:blog-27901662.post-16730551943528485032009-03-12T14:14:00.002+00:002009-03-12T14:21:54.510+00:00KDE graphics benchmarksThis is really a public service announcement. KDE folks please stop writing "graphics benchmarks". It's especially pointless if you quantify your blog/article with "I'm not a graphics person but...".<br /><br />What you're doing is:<br /><pre><br /> timer start<br /> issue some draw calls<br /> timer stop<br /></pre><br />This is completely and utterly wrong.<br />I'll give you an analogy that should make it a lot easier to understand. Lets say you have a 1MB and a 100MB lan and you want to write a benchmark to compare how fast you can download a 1GB file on both of those, so you do:<br /><pre><br /> timer start<br /> start download of a huge file<br /> timer stop<br /></pre><br />Do you see the problem? Obviously the file hasn't been downloaded by the time you stopped the timer. What you effectively measured is the speed at which you can execute function calls.<br />And yes, while your original suspicion that the 100MB line is a lot faster is still likely true, your test in no way proves that. In fact it does nothing short of making some poor individuals very sad due to the state of computer science. Also "So what that the test is wrong, it still feels faster" is not a valid excuse, because the whole point is that the test is wrong.<br /><br />To give your tests some substance always make your applications run for at least a few seconds reporting the frames per second.<br /><br />Or even better don't write them. Somewhere out there, some people, who actually know what's going on, have those tests written. And those people, who just happen to be "graphics people" have reasons for making certain things default. So while you may think you've made this incredible discovery, you really haven't. There's a kde-graphics mailing list where you can pose graphics question. <br />So to the next person who wants to write a KDE graphics related blog/article please, please go through kde-graphics mailing list first.Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com12tag:blogger.com,1999:blog-27901662.post-2711474417303713512008-08-28T18:28:00.002+01:002008-08-28T18:32:10.843+01:00SVG in KDE"Commitment" is one of the words that have never been used in this blog. Which is pretty impressive given that I've managed to use such words as sheep, llamas, raspberries, ninjas, donkeys, crack or woodchuck quite extensively (especially impressive in a technology centric blog).<br /><br />That's because commitment implies that whatever it is one is committed to plays an important role in their life. It's a word that goes beyond the paper or the medium on which it was written. It enters the cold reality that surrounds us.<br /><br />But today is all about commitment. It's about commitment that KDE made to a technology broadly refereed to as Scalable Vector Graphics. I took some time off this week and came to Germany where I talked about usage of SVG in KDE.<br /><br />The paper about, what I like to call, the Freedom of Beauty, is available here:<br /><br /><a href="https://www.svgopen.org/2008/papers/104-SVG_in_KDE/">https://www.svgopen.org/2008/papers/104-SVG_in_KDE/</a><br /><br />It talks about the history of SVG in KDE, the rendering model used by KDE, it lists ways in which we use SVG and finally shows some problems which have been exposed by such diverse usage of SVG in a desktop environment. Please read it if you're interested in KDE or SVG.<br /><br />Hopefully this paper marks a start of a more proactive role KDE is going to be playing in shaping of the SVG standard.Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com7tag:blogger.com,1999:blog-27901662.post-3244323892432763252008-08-20T16:39:00.007+01:002008-08-20T17:05:06.542+01:00Fast graphicsInstead of highly popular pictures of llamas today I'll post a few numbers. Not related to llamas at all. Zero llamas. These will be Qt/KDE related numbers. And there's no llamas in KDE. There's a dragon, but he doesn't hang around with llamas at all. I know what you're thinking: KDE is a multi-coltural project surely someone must be chilling with llamas. I said it before and I'll say it again, what an avarage KDE developer, two llamas, one hamster and five chickens do in a privacy of their own home is none of your business.<br /><br />Lets take a simple application, called <a href="http://ktown.kde.org/%7Ezrusin/examples/qgears2.tar.bz2">qgears2</a>, based on David Reveman cairogears and see how it performs with different rendering backends. Pay attention to zero relation to llamas or any other animals. The application takes a few options, -image: to render using a CPU based raster engine, -render: to render using X11's Xrender and -gl to render using OpenGL (-llama option is not accepted). It has three basic tests, "GEARSFANCY" which renders a few basic paths with a linear gradient alpha blended on top, TEXT that tests some very simple text rendering and COMPO which is just compostion and scaling of images.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://ktown.kde.org/%7Ezrusin/gears.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px;" src="http://ktown.kde.org/%7Ezrusin/gears.png" alt="" border="0" /></a><br /><br />The numbers come from two different machines. One is my laptop which is running Xorg server version 1.4.2. Exa is 2.2.0. Intel driver 2.3.2. GPU is 965GM, CPU is T8300 at 2.4GHz running on Debian Unstable's kernel 2.6.26-1.<br />The second machine is running GeForce 6600 (NV43 rev a2), NVIDIA proprietary driver version G01-173.14.09, Xorg version 7.3, kernel 2.6.25.11, CPU is Q6600 @ 2.40GHz (thanks to Kevin Ottens for those numbers, as I don't have NVIDIA machine at the moment).<br /><br />The results for each test are as follows:<br /><table border="1"><caption>GEARSFANCY</caption><br /><tbody><tr><br /><th><br /></th><br /><th>I965</th><br /><th>NVIDIA</th><br /></tr><br /><tr><br /><th>Xrender</th><br /><td>35.37<br /></td><br /><td>44.743<br /></td><br /></tr><br /><tr><br /><th>Raster</th><br /><td>63.41<br /></td><br /><td>41.999<br /></td><br /></tr><br /><tr><br /><th>OpenGL</th><br /><td>131.41<br /></td><br /><td>156.250<br /></td><br /></tr><br /></tbody></table><br /><br /><table border="1"><br /><caption>TEXT<br /></caption><br /><tbody><tr><br /><th><br /></th><br /><th>I965</th><br /><th>NVIDIA</th><br /></tr><br /><tr><br /><th>Xrender</th><br /><td>13.389<br /></td><br /><td>40.683<br /></td><br /></tr><br /><tr><br /><th>Raster</th><br /><td>(incorrect results)<br /></td><br /><td>(incorrect results)<br /></td><br /></tr><br /><tr><br /><th>OpenGL</th><br /><td>36.496<br /></td><br /><td>202.840<br /></td><br /></tr><br /></tbody></table><br /><br /><table border="1"><br /><caption>COMPO<br /></caption><br /><tbody><tr><br /><th><br /></th><br /><th>I965</th><br /><th>NVIDIA</th><br /></tr><br /><tr><br /><th>Xrender</th><br /><td>67.751<br /></td><br /><td>66.313<br /></td><br /></tr><br /><tr><br /><th>Raster</th><br /><td>81.833<br /></td><br /><td>70.472<br /></td><br /></tr><br /><tr><br /><th>OpenGL</th><br /><td>411.523<br /></td><br /><td>436.681<br /></td><br /></tr><br /></tbody></table><br /><br />COMPO test isn't really fair because as I mentioned Qt doesn't use server side picture transformations with Xrender but it shows that OpenGL is certainly not slow at it.<br /><br />So what these results show is that GL backend, which hasn't been optimized at all, is between 2 to 6 times faster than anything out there and that pure CPU based Raster engine is faster than the Xrender engine.<br /><br />So if you're on an Intel GPU, or NVIDIA GPU rendering using GL will immediately make your application a number times faster. If you're running on a system with no capable GPU then using raster engine will make your application faster as well.<br />Switching Qt to use GL backend by default would result in all applications running a magnitude times faster. The quality would suffer though (unless HighQualityAntialiasing mode would be used in Qt in which case it would be the same). This certainly would fix our graphics performance woes and as a side-effect allow using GL shaders right on the widgets for some nifty effects.<br />On systems with no GPU raster engine is a great choice, on everything else GL is clearly the best option.Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com23tag:blogger.com,1999:blog-27901662.post-90498458371314015972008-06-27T17:44:00.002+01:002008-06-27T17:52:22.797+01:00Accelerating desktopsIn general I'm extremely good at ignoring emails and blog posts. Next to head-butting it is one of the primary skills I've developed while working on Free Software. Today I will respond to a few recent posts (all at once, I'm a mass-market responder) about accelerating graphics.<br /><br />Some kernel developers released a statement saying that binary blobs are simply not a good idea. I don't think anyone can argue that. But this statement prompted a discussion about graphics acceleration, or more specifically a certain vendor who is, allegedly, doing a terrible job at it.<br /><br />First of all the whole discussion is based on a fallacy rendering even the most elaborate conclusions void. It's assumed that in our graphics stack there's a straight forward way between accelerating an api and fast graphics. That's simply not the case.<br /><br />I don't think it's a secret that I'm not a fan of XRender. Actually "not a fan" is an understatement I flat out don't like it. You'd think that the fact that 8 years after its introduction we still don't have any driver that is actually real good at accelerating that "simple API" would be a sign of something... anything. When we were making Qt use more of the XRender api the only way we could do that is by having Lars and I go and rewrite the parts of XRender that we were using. So what happened was that instead of depending on XRender being reasonably fast we rewrote the parts that we really needed (which is realistically just the SourceOver blending) and did everything else client side (meaning not using XRender)<br /><br />Now going back to benchmarking XRender. Some people pointed out an application I wrote a while back to benchmark XRender: please do not use it to test a performance of anything. It will not respond to any real workloads. (also if you're taking something I wrote to prove some arbitrary point, it'd be likely a good idea to ping me and ask about it. You know on account of writing it, I just might have some insight into it). The thing about XRender is that there's a large amount of permutations for every operation. Each graphics framework which uses XRender uses specific, defined paths. For example Qt doesn't use server-side transformations (they were just pathetically slow and we didn't feel it would be in the best interest of our users to make Qt a lot slower), Cairo does. Accelerating server side transformations would make Cairo a lot faster, and would have absolutely no effect on Qt. So whether those tests pass with 20ms or 20hours has 0 (zero) effect on Qt performance.<br /><br />What I wanted to do with the XRender performance benchmarking application is basically have a list of operations that need to be implemented in driver to make Qt, Cairo or anything else using XRender fast. "To make KDE fast look at the following results:" type of thing. So the bottom line is that if one driver has for example result of 20ms for Source and SourceOver and 26 hours for everything else and there's second driver that has 100ms for all operations, it doesn't mean that on average driver two is a lot better for running KDE, in fact it likely means that running KDE will be five times faster on driver one.<br /><br />Closed sourced drivers are a terrible thing and there's a lot of reasons why vendors would profit immensely from having open drivers (which is possibly a topic for another post). Unfortunately I don't think that blaming driver writers for not accelerating graphics stack which we went out of our way to make as difficult to accelerate as possible is just a good way of bringing that point forward.Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com29tag:blogger.com,1999:blog-27901662.post-60550061510279798292007-10-23T23:57:00.000+01:002007-10-24T00:11:10.793+01:00KHTML futureI've read <a href="http://blog.froglogic.com/2007/10/the-khtml-future-faq/">Harri's</a> blog about WebKit and I figured it makes sense for someone to respond. First of all I liked the blog, It was full of drama, action, despair, marketing and bad and good characters. Which is really what I'm looking for when reading fiction.<br /><br />Especially the part that mentioned QtWebKit as an irrelevant fork of KHTML sources. That was awesome. It's the kind of imagination we need more of in the blogosphere. For the purposes of the point Harri was trying to make, which I think was "no matter what's the reality, our ego is bigger than yours", it was a well suited argument.<br /><br />Describing the WebKit project as a fork of KHTML sources is like calling GCC a fork of EGCS, or to use a more popular analogy it's like calling chicken a fork of an egg. If you want to talk about forks then technically nowadays KHTML is a fork of WebKit. Not a terribly good one at that. It's real easy to back that statement up by comparing the number of submits to KHTML to the number of submits to WebKit. In fact that comparison is just embarrassing for KHTML.<br /><br />I also found it funny that people like Lars Knoll, Simon Hausmann, George Staikos or myself are not part of the KHTML team. "We are the 'KHTML team' (except KHTML's author and ex-main developer Lars who's one of the biggest supporters of WebKit now and other people who used to work on KHTML but now work on WebKit as well... but they were all ugly... honestly!)" you can go make shirts with that.<br />We're working on WebKit now hence we're not KHTML team members. Any KDE developer who works on WebKit (hey, Niko, Rob, Adam, Enrico...) is automatically dissociated from the KHTML team.<br /><br />The fact is that there is more KDE developers contributing to WebKit than there is KDE developers contributing to KHTML.<br /><br />So since there's more of us, I think technically that means that we are the official KDE web engine team. KHTML team, we would love to work with you, the fork, but you're kind of a pain in the butt to deal with.<br /><br />Which is ok, because like I mentioned a number of times KDE community lives of the "who does the work decides" dogma. And ultimately the Apple guys, the Trolltech guys, people from George's company who work on this stuff full-time and tons of Free Software contributors working on WebKit do much, much more work than people do on KHTML.<br /><br />On a more serious note, let me explain a very important point: bug for bug compatibility with the latest Safari would be worth much, much more to KDE than any patches that are in KHTML and haven't been yet merged to WebKit could ever be worth.<br />Web works on the principle of percentages - web-designers test their sites with engines that have X% of market reach. Konqueror with stock KHTML isn't even on their radar. WebKit is. Having web designers cater towards their engine is worth more than gold to KDE users.<br /><br />And if you care more about some personal grudges than the good of KDE, that's also OK, because we, the official KDE web rendering team will do what's right for KDE and use WebKit.Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com37tag:blogger.com,1999:blog-27901662.post-84838195084147975282007-08-20T10:20:00.000+01:002007-08-20T10:27:42.744+01:00Small stepsI was on vacations last week but I'm being all jealous of my luggage. It got a free trip around the world. During my last 8 flights my luggage has been lost 5 times. Is that a record? Confetti anyone? It's a celebration. If you're going to meet me during any of the upcoming conferences I'll be the outgoing and highly sarcastic naked guy with a sign on my chest saying "for my face look this way" and an arrow pointing up.<br /><br />I neglected to mention that, <a href="http://labs.trolltech.com/blogs/2007/07/31/qtwebkit-on-windows/">as Simon said</a>, QtWebKit is working on Windows. Simon did an amazing job of porting all the quirks of the build system but "amazing" is the default state for all of his code so it's not a surprise at all. While he was doing that I've sat down and ported XML tokenizer to QXmlStream from LibXML. If you never wrote a web rendering tokenizer (and unless you're crazy, the chances of that are pretty high, and if you did you're crazy and won't remember doing it anyway) you know that "fragile" is a term that nicely describes it. After it was ported Lars and I sat down to fix the regressions and they didn't even know what hit them (ha! ninja reference).<br /><br />In other news I've merged in FreeType2 rasterization algorithm patches in Qt. Our raster engine, uses the beauty that is FreeType's rasterizer, with a few patches on top. Because they break BC in FreeType's public interfaces we can't merge them back at the moment. In any case the patches improve rendering speed in general antialiased paths of the raster engine (meaning on Windows, Qtopia Core and in general whenever rendering to a QImage) by about 10% which is gangsta awesome ("gangsta awesome" is a very high level of awesomeness, at least judging from MTV).<br /><br />I've also optimized the path clipping code. Andreas uses the path clipping code in GraphicsView for collision detection, so when I say "path clipping code" you should read "path clipping and GraphicsView collision detection". A lot of the time in that algorithm has been spent on vertex allocation for tested paths. I've used a few tricks to speed it up by about 15%. The code for that algorithm is the number two reason why baby seals die (<a href="http://www.hsus.org/protect_seals.html">the first is still undisputed</a>). It's not even the algorithm itself but the inherent complexity of the problem. I'm a big fan of computational geometry in computer graphics because it makes grown man cry, except me and I like feeling like the lean, mean, killing machine that I am. My favorite part of the path clipping problem is that there are two ways of solving the precision problems and neither of them really works. The trick is that paths operate in double coordinate system, efficient snap-rounding implementations that I've seen operate in fixed-point coordinate system which falls apart in this case because of absolutely random distribution of vertices across the full double spectrum. Tessellation and clipping itself can be done in a screen coordinate system, which makes it possible to consistently represent your coordinates with fixed-point representation. That doesn't work for paths because, e.g. boolean operations on paths need to be done in native path coordinates not screen coordinates. So the algorithm forces an absolutely crazy mix of dynamic fixed-point size, reduced-predicates, magic and good-will to work. Aren't you happy that I'm doing it for you? You better be.<br /><br />Yours(1) Latino(2) Lover(3)<br /><br />1) Not really "yours", more "community". I love "you" but "you" need to realize that I need to be seeing other people.<br />2) Not really "Latino". Unless of course my <a href="http://conference2005.kde.org/">Spanish</a> or <a href="http://www.bossaconference.org/">Brazilian</a> friends would like to name me an "honorary Latino" or "Latino by association". I'd be definitely down with that. The only food I can make that is eatable and doesn't force the fire department to evacuate the building before are nachos. I'm a definition of grace in the kitchen. "Whatever you have in the kitchen I will make it burn" is my motto. Plus I'm sporting quite an attitude to boot. "Make Zack a Latino" campaign. We can make it work!<br />3) Not really "lover". More "no feelings haver". Though technically I've worked on software for so long that hate is, next to sarcasm, my primary export.Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com3tag:blogger.com,1999:blog-27901662.post-56955110017475281572007-07-22T14:35:00.001+01:002007-07-22T14:51:55.636+01:00Web on canvas and Dashboard widgetsThere are days when I do something quite interesting and in my mind I can almost see myself on a stage in tight, tight spandex pants, long hair, perm, cowboy boots yelling angrily "are you ready to roock?!". People cheering, babies laughing, women throwing their bra's on the stage. It's poetic. Then I remember that I'm a computer scientist and I snap right out of it. I go back to the life filled with math equations on napkins, sleepless nights in front of buzzing computers, stacks of books in corners and no spandex pants (although I can deal with the last one just fine). The fact that I hate rock lessens the blow, but it doesn't make it any less disappointing. So in those moments of sadness I blog, yearning attention and approval, so readily available on the internet. Cough, cough...<br /><br />I was wondering how hard would it be to create a QGraphicsItem that uses QtWebKit to render pages on a canvas. The idea being that combining full blown canvas like QGraphicsView framework with web rendering engine would give us quite a killer combination. So I've sat down today and done it. At first I had to redo some of the rendering code in QtWebKit and once I was finished I had a QWebGraphicsItem that beautifully renders pages. It being a QGraphicsItem all the effects available to graphics items in Qt are available for free to it. So you can animate, scale, rotate, perspective-transform and do a whole bunch of neat effects on it for free. Once I've done that I figured that it's obvious that this is the best way of getting Apple's Dashboard widgets to work. So I've done that too. I quickly hacked up a class that reads-in Apple Dashboard widget bundles and can render them on a QWebGraphicsItem. The compatibility is not 1:1 quite yet, because some of the Dashboard widgets use JavaScript objects that I haven't implemented yet, like AddressBook object. To be honest I'm not 100% sure whether I want to implement them, I think we can get those things done a lot nicer, it's just a question of whether 1:1 compatibility with Apple Dashboard is worth the extra effort needed to make all those JavaScript objects work on KDE.<br />First a screenshot of one Apple Dashboard widget rendered and on top a scaled to half its size KDE homepage:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://chaos.troll.no/%7Ezrusin/qwebgraphicsitem5.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px;" src="http://chaos.troll.no/%7Ezrusin/qwebgraphicsitem5.png" alt="" border="0" /></a><br />Now a Dashboard widget with a perspective-transformed dot.kde.org page. Since this is QGraphicsView I can interact with the item while it's transformed so I've selected some text on it.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://chaos.troll.no/%7Ezrusin/qwebgraphicsitem3.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px;" src="http://chaos.troll.no/%7Ezrusin/qwebgraphicsitem3.png" alt="" border="0" /></a><br />Crackalicious. (no drugs were used while hacking on this, but I did touch myself a little after getting it to work). Furthermore (yes, there's more... what can I say, I'm a giver...) in QtWebKit we have this neat interface that allows you to inject QObject's into the framework as JavaScript objects at run-time, so adding new JavaScript objects is trivial and getting Opera widgets to work would be very, very simple. No spandex pants included though.Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com26tag:blogger.com,1999:blog-27901662.post-53119064571279450072007-07-14T15:59:00.000+01:002007-07-15T12:31:57.459+01:00ScripterBefore boarding a flight I'm eagerly awaiting the security presentation that is about to ensue. I figure that these people spent their valuable time learning how to point to the ground, back, forward and to the side and someone needs to appreciate that effort. During my last flight I even went ahead and tried to inspect my life jacket. "Tried" because as it turned out my seat was missing it. As the security announcement advised, I "calmly" informed the fellow sitting next to me that "in the unlikely event of a water landing" he's screwed because as a stronger man I'm taking his life jacket. This also prompted me to think about tools that make our life easier (just to clarify, when I say "our" I mean "my"). I've spent a little time yesterday creating a tool that will make my (when I say "my" I mean "our") life a lot easier. So today I wanted to tell him (when I say "him" I mean "you") about us (when I say "us" I mean "it").<br /><br />I've spent a lot of time writing simple C++ applications to test out some kind of rendering algorithm. Internally we had a tool that automated a lot of it. The tool uses a very simplistic, reg-exp based language to specify commands. I wanted something more powerful. This is how scripter came to be. Scripter is a very simple application that uses QtScript's bindings to Arthur to do its rendering. It allows for rapid prototyping of algorithms and most importantly for me, quick testing of Qt's rendering framework. At first it was a whole IDE with its own code editor, very quickly though I decided to remove the editor and just make it a content widget that monitors the file it was opened with for changes. The reason for that is that I wanted to keep working in my own editor and just have a dynamic, visual preview of everything I was doing. So with Scripter one can be writing rendering code while the visuals effects of the editing are immediately visible. Here are two screenshots of examples included with it:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://chaos.troll.no/%7Ezrusin/scripter1.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px;" src="http://chaos.troll.no/%7Ezrusin/scripter1.png" alt="" border="0" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://chaos.troll.no/%7Ezrusin/scripter2.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px;" src="http://chaos.troll.no/%7Ezrusin/scripter2.png" alt="" border="0" /></a><br />But the whole beauty of this application is ability to create animations, while seeing the changes done in real-time. I recorded two demos:<br /><ul><li><a href="http://chaos.troll.no/%7Ezrusin/scripter.ogg">The first one shows me just playing around with an example.</a> In this case it's a freedesktop.org clock.</li><li><a href="http://chaos.troll.no/%7Ezrusin/scripter_demo.ogg">The second shows me writing a simple animation from scratch.</a> This one has an added benefit of seeing me hack in real-time, no copy&pasting, a little bit of chaos (next time I should probably figure out what kind of animation I want to do before start recording, but oh, well, live and learn). Fun. This one is 12mb though.</li></ul>Scripter requires Qt 4.4. If you don't have Qt 4.4's snapshot it won't work. Get it from the SVN at labs.trolltech.com with :<br /><pre> svn co svn://labs.trolltech.com/svn/graphics/scripter<br /><br /></pre>Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com9tag:blogger.com,1999:blog-27901662.post-17561602107606529352007-06-04T11:43:00.001+01:002007-06-04T11:58:46.779+01:00Mirroring widgets"The life of man is divided between waking, dreaming and dreamless sleep." or so it's written in "The Upanishads"... I wouldn't know because the cartoon version still hasn't been released and I refuse to spend even a second of my life pumping a stream of information into my brain that hasn't been properly sprinkled with commercials and product placement. Which reminds me: use Qt...<br /><br />I can almost see you sitting at your desk with the same expression the great Plato had when he said: "What?" (not one of his greatest quotes, but I'm sure he said it at one point or the other). In my last blog I described how the engineering department at Trolltech spent the last few months fixing bugs in, what could be described as, a constant "waking" state. By natural progression the next Qt release is putting us in the "dreaming" state.<br /><br />It's been a while since the last time that I've posted an example on how to do something funky so today I'll partially make up for it. I get a lot of questions asking me how to do something windowing system specific. People at the office can approximate the exact time of delivery of each one of the emails relating to that topic as the seismographic vibrations, originating in the vicinity of the area where the table meets with my head (in a repeated and aggressive fashion), cause ripples to appear in coffee mugs around the office. Hopefully today's example will satisfy the most vicious desires for X11 wackiness.<br /><br />6'2" (height by association - as measured by the height of the author), weighting at about 139 lines of code (while wearing the license header), the undisputed (mainly because the only one) champion (questionably) of... well, nothing: QX11Mirror. QX11Mirror is a class that can monitor and return the contents of any X11 window in real time. So you could start your favorite media player, pass its window id to QX11Mirror and then render the contents half-the-size with perspective transformation. It would look like this:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://labs.trolltech.com/images/3/3a/Qx11mirror.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px;" src="http://labs.trolltech.com/images/3/3a/Qx11mirror.png" alt="" border="0" /></a>One thing that you can't see is that the contents of the movie is updated while the movie is playing and the perspective transformation is animating. All of which is done in real-time. It's really cool.<br /><br />The original reason for writing this, seemingly, silly example was not "making something pretty". Even though the inability to make applications look gorgeous is the number one cause of hair loss (as shown in a study by doctor "me". Note: "me" is not really a doctor. In fact "me" doesn't even fulfill grammatical requirements of the previous sentences.), which is number one reason for you not looking gorgeous and I'm a big proponent of having KDE developers look beautiful. "KDE - we got hair... In all the right places...". (I know... I'm as shocked as you are that I'm not being paid a zillion dollars to do marketing.) No, the original reason for all of this was to make web plugins behave a lot nicer. Currently the problem is that they don't compose correctly within the web rendering tree. So what I wanted to do is correctly fetch the offscreen contents of those windows, render them in correct stacking order and propagate the events back to them. This goes along the "make stuff work" ideology which I consider myself to be a big fan off. Oh, and here's Flash plugin rendering inside of a Qt applications (as always in my example, things are animating inside):<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://chaos.troll.no/%7Ezrusin/webplugins.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px;" src="http://chaos.troll.no/%7Ezrusin/webplugins.png" alt="" border="0" /></a>Oh, and the code is available at <a href="http://labs.trolltech.com/page/Graphics/Examples/Examples2">Graphics Dojo</a>.Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com14tag:blogger.com,1999:blog-27901662.post-4485330256089226732007-05-30T18:05:00.000+01:002007-05-30T18:17:40.752+01:00KeyholeToday's blog might sound a little muffled, that's because it's coming straight from the heart. Which is in direct opposition to all of the "What's Open Source community missing" blogs/articles, which are coming straight from a vastly less prominent body part. To not dwell to much on human anatomy, I'm going to move on to the main topic today which is peace, love and Qt 4.3. The first two are overrated and got their fair share of treatment in all kinds of literary works, therefore the only reasonable conclusion is that my perky-self focuses on Qt today.<br /><br />A number of people surely have already pointed out in their blogs that Qt 4.3.0 has been released. The first thing you'll notice about this release is the version number. Rightfully so because 4.3.0 is the highest Qt version we've ever released. 4.2.0 was already taken and we felt very strongly about reusing a ".0". Although "13.13.0" was available we really came together as a team/body/unit/crew (pick one) to release 4.3.0.<br /><br />Now, I'm not going to be doing marketing for 4.3.0 (mainly because others are being paid better to do that) or listing the "like totally awesome new features", what I wanted to do is present the perspective of people who actually spent days and nights working to make this piece of software the best they could. Whether from the loins of those geeks came something exceptional is a judgement call that I leave to you. This is your keyhole into our world.<br /><br />The main focus of this release was for us the general increase in quality of Qt. In the darkness of our meeting rooms we were moving tons of paper, while from time to time lonely tears danced on our cheeks (due the fact that the light smoke coming from our pens and pencils was irritating our eyes). Immersed in this mysterious darkness, we sat and watched. The cracking of the projector, seemed to be the only noise that dared to challenge the insanable silence. We knew that we wanted to make people smile a little more with this new release. Very early in the release process we also agreed that shipping drugs with Qt was not an option. We turned for help to the happiness champions - <a href="http://en.wikipedia.org/wiki/Care_Bears">Care Bears</a> and <a href="http://en.wikipedia.org/wiki/Popples">Popples</a>. We watched and analyzed. In the very end we decided that while we agree that Gi-Joe's are like totally cooler (the engineering department is unfortunately male dominated) we know what we have to do. We came to the conclusion that people seem to be a lot happier if things work the way they planned and there's no unpleasant surprises. That's what we focused on. Fixing bugs, making sure that things work the way they are expected to, all in all improving the quality of Qt. If you have ever spent extended periods of time just staring at the code and rerunning tests in order to fix bugs, you know it's a mundane process that takes a lot of concentration. This is what we've been doing for the last few months. Fixing bugs and running around screaming (a lot of screaming, not a whole lot of running) if someone broke one of the tests. Have you ever seen engineers play ping-pong after fixing bugs for weeks? Oh, it's quite a sight. A lot of raw energy (very raw, one could say that energy hardly touched by any kind of skill). Flying balls, paddles and often engineers were a common sight late in the evening (low flying engineers bring bad luck - especially if the flight schedule predicts a landing at "you").<br /><br />No one is more critical of us than we are but we work together to improve all the things we don't like. While I was thinking about this today I couldn't stop thinking about Pythagoreans who despite achieving many great things, were often described as a group who cherished authority beyond anything else. That approach is completely different from any discussion we have here. Every argument is judged solely based on its soundness no matter who's making it. I think that what I'm trying to say in this, severely not hysterical, paragraph is that one thing you can be sure off is that every decision we have reached and every change we have made in Qt was not due to any kind of hidden agenda, religious beliefs or beauty of people pushing for it. It was done because 20+ engineers decided that the arguments for it are stronger than against it. I realize that due to the fact that we have those discussions at the office and in person, a lot of the transparency of them remains hidden behinds clouds for people outside Trolltech. We're working to improve the flow of the information from the heart of Qt's home to the outside and while we do that please remain assured that behind the clouds there's a world adhering to the strictest physical and logical rules and not an ocean of strings with muppets drowning underneath.<br /><br />Having said that, we're very happy with Qt 4.3.0 so hopefully you'll enjoy it too.<br /><br />If you want pure Qt release goodness with pictures of the chosen few who get to stare at Qt code until their eyes bleed make sure you read <a href="http://labs.trolltech.com/blogs/2007/05/30/qt-430-released/">Girish's blog</a>.Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com4tag:blogger.com,1999:blog-27901662.post-9505640379990965702007-03-09T10:13:00.000+00:002007-03-09T10:25:56.664+00:00ReflectionsIn the spirit of my never ending "pimp your Qt application" series comes another example. This time, "how to make iTunes-like album selector". It's funny how much attention this widget got. I looked at it yesterday on one of the Macs at the office and just implemented it. I probably should make it a view for a list model but for now it's just a simple widget. It runs at perfectly smooth 60 frames per second while utilizing ~7% cpu on my 3GHz Pentium4 with NVIDIA GeForce 6600, so by no means a monster of a machine. Oh, and of course this is all done with pure Qt. Reflections are actually a vector effect, so they would work equally well for any vector based graphics (by using the same code as this example, you can reflect your svg's or even whole widgets with no problem). Mandatory screenshot:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://chaos.troll.no/%7Ezrusin/reflections.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px;" src="http://chaos.troll.no/%7Ezrusin/reflections.png" alt="" border="0" /></a>And as with every animated example a movie (again, framerate of the screencapture does not come close to the real world performance) is available <a href="http://chaos.troll.no/%7Ezrusin/reflections.ogg">here</a> . Finally the code is available <a href="http://ktown.kde.org/~zrusin/examples/browser.tar.bz2">here</a>.Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com12tag:blogger.com,1999:blog-27901662.post-85160215192530450502007-03-07T12:02:00.000+00:002007-03-07T12:15:09.295+00:00Gradient boundsThe most unfriendly thing about rendering gradients with Qt has been the fact that you had to specify gradients in coordinates of the shape they were to be rendered on. It wasn't ideal especially for all applications which included any kind of animations or were rendering large number of items because it meant that the gradient had to be individually created for each and every one of items/frames. I've fixed that two days ago by adding a coordinate-mode property to QGradient, which now accepts ObjectBoundingMode. Object bounding mode, just like in SVG, means that the gradient coordinates are percentages of bounding box of the shape that the gradient is about to fill. So all the coordinates are between 0 and 1 and Qt automatically adjusts the bounds for gradient when it's being rendered. This makes it possible to easily use QGradient's with QPalette. An example where I'm drawing a bunch of rectangles and animate them along while the gradient is set only once with (0,0, 1, 1) coordinate box (meaning starting at the topleft and ending at the bottom right corner of each rectangle).<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://chaos.troll.no/%7Ezrusin/gradientbounds.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px;" src="http://chaos.troll.no/%7Ezrusin/gradientbounds.png" alt="" border="0" /></a>And since it's an animation (including a widget show/hide effect) here's a <a href="http://chaos.troll.no/%7Ezrusin/gradientbounds.ogg">movie showing it in action</a>.Zackhttp://www.blogger.com/profile/16222054590923441165noreply@blogger.com8