Qt DevDays 2010 - Qt GraphicsView in Depth: Alexis Menard
Transcription Whisper (large-v3), avec identification des locuteurs. À recouper avec la source d'origine.
Analyse automatique
Générée par IA — peut contenir des erreurs. Méthodologie
Chapitres
Répartition du ton (temps de parole politique)
Propositif 100 %
Affirmations vérifiables (citations exactes)
- 19:18PrésentateurFait
« Graphics view has a cache mode built-in inside. »
- 36:09PrésentateurFait
« when you call set pose many times then it's actually fluid because we don't need to update the BSP so it's only when the items become static that we re-add it into the BSP »
- 36:24PrésentateurFait
« the problem with that of course is if you call set pose or you animate thousands of items at the same time because then we got all those timers going on and then a big list of temporary items that are moving »
- 37:07PrésentateurFait
« it's basically it depends of the scene but you can try it as well it's a one line code change but BSP is usually more for static contents right »
- 40:15PrésentateurFait
« the only difference with that diagram is basically that when we asked the index the items for a given area it was returning everything not necessarily top levels »
- 40:36PrésentateurFait
« when you run out from the parents and then you do the subtree right as I was explaining let's say the parent has a transformation let's say 45 degree rotation »
- 41:56PrésentateurFait
« if you have an opacity of 0.5 on the parents and then the children will also have the opacity of 0.5 right »
- 42:18PrésentateurFait
« we tried to cache everything so cache the opacity cache the transformation and so on but that was a bad idea »
- 43:22PrésentateurFait
« versus now the recursive approach the fact that it is recursive and then each time we paint a child we actually give the painter like it is we actually save those calculations so rendering by sub trees make it very efficient »
- 46:09PrésentateurFait
« graphics item has two cache modes it's a bit like the background I was explaining before »
- 46:22PrésentateurFait
« it's basically like if you have a camera and then you take a picture of the item like it is on the screen and then you save that picture for the next time you are under a frame for instance »
- 47:03PrésentateurFait
« to make it clear I did a small diagram here on the left item coordinate cache take a screenshot like it is if the item was rotated then I take the screenshot and rotate the screenshot »
- 47:30PrésentateurFait
« when there is a cache set on the item we don't use the painter that we had from graphics view and then graphics scene we actually open a new one on the pixel map »
- 48:00PrésentateurFait
« since 4.6 there is a new API for qpxmap cache that I've implemented is because qpxmap cache the way it works is like you say here is a key here is a pixel map »
- 48:46PrésentateurFait
« what I did instead is like I've implemented an extension to the pixel cache that I recommend to use and to port your old cube pixel cache with string base key to the new API »
- 52:53PrésentateurFait
« item set coordinate set cache mode right and then queue graphics item »
- 56:25PrésentateurFait
« let's say I activate the item coordinate cache on it so if you remember correctly what I said we take a screenshot untransformed and then we apply the transformations on the pixel map »
Temps de parole
- Présentateur88 %
- ?9 %
≈ 62,1 interruptions / 10 min (chevauchements et interjections détectés).
Modèle mistral-small-latest · prompt v1 · les citations sont vérifiées mot pour mot dans le transcript ; le taux de réponse directe est calculé à partir des verdicts question par question. Aucun label idéologique n'est produit.
So,
the doors are closed, so I guess we can start. Welcome, everyone. I'm a bit impressed. A lot of people, big stage. I feel like a superstar, but I'm not. But at the end, I do give for free business cards. So, today's talk is about QGraphicsView in-depth. So, I assume people here have already used a bit of graphics view, because I use a bit of technical words, and I assume people already somehow played with the framework.
The
agenda for today, a bit of an introduction. History, and I will introduce graphics view architecture, basic, and then goes inside details for the view, and details for the scene, for the items.
Also,
the lessons we learn while developing this framework and the future of it, and I will conclude.
About
me, I'm French. You'll probably notice to my accent. I'm sorry. There's nothing I can do. I'm a Qt developer since 2008. I'm based in Oslo. Since the very first days I joined the company, I was interested by working on QGraphicsView, mainly because of my past.
I
was involved recently, beginning of the year, in QML development, mainly the graphical part of it, like making it work in QGraphicsView.
and
now I moved on a bit to change what I was doing, and I'm working on Qt WebKit and WebKit in general, and recently I was working on the HTML5 video and audio elements.
On
the side note, I'm a KDE developer, even though today I'm using macOS. Since 2006, I joined the KDE development when I was
a
student. I work on Keplato. It's a project management application. and then I joined Plasma, the desktop thing, in 2007 when they were trying to find people to help. And nowadays I'm actually working on the mobile version of Plasma, which works on my A900, as my spare time.
On
my spare time. Working in Qt development framework is actually quite cool, because I left the French fast food
for
the Norwegian gastronomy,
which
is based on sausages and hot dogs. So it's very nice. And also the weather is really cold up there. But it's fun to work there. Do you think how many we are for working on Qgraphics view? Let's say 10, 20, something like that? How many you think we are? Give numbers. Run them. Ah, he knows. We are two on a knife. There is Bjorn-Erik, my colleague. There is me, and there is a new guy that joined at the beginning of the year, the company. And there is also some guys working around, but not on the core Graphics view. We used to have Andreas, but he left. It was the main, like the guy behind Graphics view, the guy that created the framework.
So
a bit of the history of the framework. So Qgraphics view was born in Qt 4.2.
At
that time, it was born to replace the old Qt 3 Qcanvas.
So the
goal of that project was to make it better and easy to use API because Qcanvas, while I was doing the presentation, I was looking at the API of Qcanvas, and I was like, wow. And so, yeah, basically,
when
Qgraphics view arrived, it was a replacement of Qcanvas, the same, trying to solve the same issues and on a better API and based on Qt 4, basically.
Then
in Qt 4.3, we basically added features like convenience for, let's say, the reverberant selection for items, Qtransform support, and some later APIs addition like convenience like
for
mapping coordinates in between the scene and the item and so on. Qt 4.4, huge projects called Widgets and Canvas. The idea was to create
widgets
or at least the base, like the building blocks for bringing widgets inside Graphics view. By that, I mean creation of Qgraphics widgets and also creation of layouts
and
also the, like the, we wanted also to be able to support Qwidgets inside Qgraphics view and that's why Qgraphics proxy widget arrived.
Qt
4.5,
a
lot of feedback. Qgraphics widget, buggy. Layouts, not very nice. I know because I was using them in Plasma, so I was fixing them while I was using them in Plasma.
Basically,
it was like incorporating the feedback from the people, the customers, the community, and fixing everything. And we met also, met some performance improvements, but not that much. Basically,
faster
indexing lookup, I'll explain what it is. Better caching and stuff like that. But what we discovered back in time is like making layouts is really hard. So, we learned it the hard way. Qt 4.6, it's basically the biggest refactoring of the framework. We took our painting code, we threw it away, and we revoid it from scratch.
We
moved the indexing logic out of the scene, put it into a separate class so we could optimize it separately.
And
we also introduced Qgraphics objects.
It
was mainly for QML. So, Qgraphics object is like a subclass of Qgraphics item, but also inherits from Qobject. And then you can get the property support and all the convenience that you have with Qobject.
And
Qt 4.7, mainly stability, after the biggest refactoring that we did in 4.6, like bug fixing, little API additions there on there for QML, and some little tweaks for the performance, trying to do our best, basically.
And
since Qgraphics view is widely used in Nokia, at least for Amigo and Symbian 4, we got a lot of feedback from them as well, so I was working hardly to actually fix what they were asking for.
So,
the architecture. I'll just give a basic overview. You guys can figure out while using the framework, and I won't repeat the documentation anyway. So,
you
start with Graphics view, Qgraphics view. You can have multiple views. It's like a built-in feature of the framework. It's like
the
viewers can see the entire scene, or
they
can see part of the scene.
So,
they basically see a graphic scene. The graphic scene is responsible for managing the items, adding items, removing items. The graphic scene is responsible for paintings, and everything related to events. Internally, the graphic scene,
that
you won't find in the documentation, has a graphic scene index. So, why we have an index is basically to find the items. Like, we can't have just one list of items. We just need an index for finding them.
And
currently, on the framework, we've got
two
indexes. One is the BSP tree. I will explain what it is. And one is a linear scene index, which is basically a whole list of items.
So,
the three last boxes are internals. You want access to it. It's not public API. And, of course, the index is responsible for managing the items. So, the QGraphics items. It's only one of the index. It's like not two, right? Like, either you have a linear index, either you have the BSP. The view. So, it's Graphics view, right? So, as I said, it visualizes a part of the complete scene. It's a QAbstract scroll area because it supports scrolling. So, you can navigate in the scene with the view, with the mouse, for instance. And, if it's a QAbstract scroll area, then it's a QWidget, which means that it can be top-level, it can be put into a layout, and so on.
Everything that you get from QWidget, you have it on the Graphics view.
So,
as I said, scrolling support. It has a selection support. You can grab the mouse and select items inside with a rubber band, for instance.
And
the Graphics view is responsible. Like, I mean, the Graphics view receives all the events from QT, right? From the windowing system, for the event queue, for everything. Resale the paint events, resale the keyboard events, resale everything. And then, basically, except for the rubber band, is forward everything to the Graphics scene. There is not that much logic for the painting code, not that much logic for the events inside Graphics view. It's basically send everything to the Graphics scene.
The
view supports transformation, so you can actually rotate. You can do everything that QTransform support, basically. So rotation, scaling, and so on. So you apply on the view and not on the scene, right?
So
I won't go more in detail for Graphics view. Let's go for tips and tricks, because that's what matters. How you can use Graphics view and all the framework the best you can, right? That's the purpose of my talk.
First,
so Graphics view has an optimization flag. One is called don't save painter state.
So
what that means. Basically, when we render the items, like
we
get the painter from the paint event of QGraphics view, then it goes to the scene, and then the scene says, okay, I need to render items. It's a bit more complex, but let's put it simple for now.
So
let's say you have to render two items, right?
The
rendering of the item is actually made by calling paint on the item, right? You get a QPainter, and then you do stuff with it, and then you return, and then we paint the second item, right? That's how it works. Let's say the simplified version.
So
what happens is like when we call paint, we give the same painter that we have at the beginning, which means that in your paint function, you can do whatever, right? Changing the paint, changing the brush, doing crazy stuff, right?
Which
means that when we call paint on the second item,
the
painter has to be clean. Otherwise, you will narrate everything that you got from the previous paint event, the brush modified, the pen modified, and everything, right? So
what
happened today is like if you use GraphicView by default without setting this optimization flag, it's like before calling the paint on an item, we save the painter, call paint on your item. You can do whatever you want there, and then we restore the painter.
And
then we call the next one, save, paint, and restore.
So
when you arrive and your paint function on your item, you always have a clean painter.
So
when you trigger this, when you set this optimization flag to true, what happens is like we don't save and restore the painter anymore in between items.
It's
not like a huge performance improvement, like don't expect two times faster, right? Because saving and restoring has been optimized quite a lot on Qpainter, but
it's
still beneficial. So I actually show it in the demo.
So
I've ordered a small demo. By the way, there will be no super nice effect and so on. It's basic demos with boxes and rectangles, like all the fashion needs was basically on Guilnard's talk this morning, or I mean beginning of afternoon.
So
on this demo, it's basically a simple main window, right? I have a graphic scene here. I set the scene on my graphics view. It happens to be on the UI file. I don't need to go in detail, right? There is a graphics view.
I
got a top-level parent item, which is a top-level graphics widget.
I
add it into the scene, and then I have got a double loop, which basically adds graphics proxy widgets with the red widget inside. And then, let's see, it's a bit better to read, exactly.
So
I got a, yeah, graphics proxy widgets, and then set widgets, which is actually a red widget, and then set pose. I basically put them as a, like a grid, right?
And
then I got my small utility class, which basically gives me the FPS. And then I have an animation on the position on the parent item, so the top-level one, and I actually ask him to move, right? That's not a very advanced example, right? So, and then if you look at the red item, which is a key widget. Sorry. Let me see if I was right here.
Up. Yeah.
So, sorry, it was like I was editing the wrong one. So the yellow item, so it's just a graphics widget. I can show the implementation here, which in the paint event, does draw text, so it actually draws B. That's really basic. It's set the brush to yellow, so the background will be yellow, and the pen blue, so like the border of the rectangle will be basically blue,
and
an opacity of 0.5,
and
then just I draw a rect. Basic code, right?
So
when you run this example,
it
looks like this.
probably
showing my screen here. Yeah.
I
need to move it here. Up.
Exactly.
So as you can see here, on the button, my FPS tracker actually debugged the average millisecond I spent per frame,
and
as you can see here, 66, 67, 55, so around 60, let's put it like this, right? Now,
go
back to my main window,
and
then here,
on
the graphics view, I set the flag, optimization flag, don't save, pair or set, true. Let's see what it looks like when I run the app. The macro is really annoying. I can't remember the position of the window.
So
you see, it's like the frames are slightly faster, 50 is not like, it's not awesome, as I said, but it's still like some milliseconds per frame that we save by not saving and restoring the painter's save at each time I paint the item. This is the ideal use case, for sure.
The
problem, as I said on the slide, is we don't save the painter's save, right? Now, let's say I have a red item, like this, that I put on top of all of them, this one, right? It's basically the same item as the yellow one, but in red.
It's
just slightly different.
If
you look at
the
code here, so it's quite a pen, set the color, red, right? So I got the border of the rectangle being red,
and no
brush, and set the width to four, so it's like a huge line, and then a bonding, right? Right? So what do you expect?
You
expect a translucent rectangle?
When
you see this painting code, you expect a translucent rectangle with like a big blue border, a red border, sorry, right? Because, and let's see what's happened when you actually run the code. Ah,
here. You
see, funny enough, like the content is actually yellow.
Why?
Because when we run down the previous item, the smaller yellow ones, like we set the brush to be yellow on the yellow ones,
and
then since we don't save the painter state and restore the painter state anymore, like when we arrive on the paint function of the red one, then the brush is set to yellow,
which
means that you inherit a dirty state of the painter, right? That means that that's why it's actually yellow in the middle.
So I
recommend to use that flag, and when you have like broken behaviors like this, then you fix your painting code.
And
it's easy in that case.
Here,
on my red item,
what
I can do is painter, set brush, and then cut, no brush. That's what I want, right?
Then
you ensure that
what
you want will be on the screen regardless of the previous state of the painter, right? Otherwise, what you could have done is painter, restore, and save at the end, right? Sorry, save, sorry, save here,
and
then restore at the end of your paint function, right? But I recommend to set the brush because it's cleaner at least for me, I think. So when I run the example,
it
looks like this, translucent. That's what I wanted since the beginning.
And
of course, now if I remove,
if
I remove my fix, like this, right? Up. And then I come back to my main window and then unset the flag
and
then run it.
That's
the same result, right? So, use the flag.
If
you have regressions in your code, fix the painting code. That's the best you can do. Up. Let's go back to the presentation
because
I did the demo. Other tips and tricks. Graphics view has a cache mode built-in inside. So you get two modes. You can either cache the background or
do
not cache the background.
So
why? Because Graphics view has a draw background function that is virtual so you can reimplement it. It gives you a painter and a rectangle which is the size of the view,
right?
Oops. And so you can actually draw your custom background instead of the default one which is white. When you activate the cache, what happens is that
when
we call draw background, instead of giving the painter open like the normal painter that comes from Graphics view, we actually open one on a PixMap.
Then
we call draw background and then everything you do will go to a PixMap that will save
and
then the next paint event instead of calling again your draw background function will actually just draw the PixMap.
It's
nice
because
if you have a complex background let's say with gradients and really complex background gradients like dotted lines and stuff like that, then it will actually be faster.
The
drawback is
the
memory consumption because let's say your view is huge like you get at least a PixMap let's say 640 by 480, then at least the PixMap will be that size.
So
if you're running on a very low-end hardware and with not that much memory, well, you have to compromise with either you have more memory usage or you simplify the painting of your background. The other flag that is on it since 4.6 it's the indirect painting
it's
actually not tips and tricks it's just to remember what it is. Before 4.6 graphics view had a virtual method called draw items where you can actually subclass and override that method and interfere
on
the painting of the items. I don't know, setting something different from the painter or doing pre-processing or whatever.
The
problem with this public API is that it was giving a list of items to draw and
the
style options for them when you paint. And the list of style options was
not
very optimal. Allocating all of them and giving them to the public function to the function and in most cases was doing nothing because not that much people actually override draw items. So
since
4.6 we basically deactivate the call of that function so we change the behavior. It's bad, I know. But at least it doesn't call the public function anymore so it doesn't allocate all those graphic style options the q style option graphics item
and then
goes directly to the scene via private functions. But if you do want the old behavior you can set that flag indirect painting and then it will call the old function like before same behavior as before.
But
it's slow. It's slower.
So
sometimes you better think about what you were actually doing in your draw items code and think about okay can we do it a
different
way
because
there's not the optimal path. Just like just remember one thing on the cache mode don't activate the cache if on the draw background of your graphics view you just draw a pixmap
because
what's the point caching a pixmap
which
is a I mean caching into a pixmap a pixmap right so it has to be a very expensive draw background code
so
that the cache mode will be a beneficiary. Other tips and tricks I recommend the usage of set viewport new QTL widget so basically setting the viewport of graphics view as a GL widget so you can actually also do GL code in your painting code of the items
because
then the rendering will go through the GL widgets and then you get some GL acceleration or boost in some cases. For instance on the Nokia 900 the best couple I could find at least for KDE was using the GL widget as the viewport and graphic system raster. If someone comes with a better combination then I'll be happy. Also for instance let's say you're doing a full screen app which let's say you're doing a mobile application which is full screen
you
want to set set from style to zero. All those tips and tricks are no big deal right? I'm not talking about getting like I don't know 10% performance improvement
but
for instance getting away the frame style doesn't query the styles doesn't draw useless stuff doesn't allocate borders and stuff like that so when you do a full screen app like a game on a mobile phone you better want to set that.
For
instance on QML we do it. Same if you do a full screen app
you
want to set you
want to set the
attribute WA translucent background to false. This attribute means that the background of the graphics view will be translucent
so
you can actually do translucency right? And
it
depends the operating system you're only on let's say on X11 you need to have like a window compositor like let's say compes kwin or on Windows it has to be at least from Windows Vista and macOS it always works pretty much
so but
why you want to deactivate it sometimes because
on
the Android again
if
you set it to true
even
if you let's say draw a background which is completely opaque
the
compositor like the window compositing will try to compose it like crazy
to
actually try to do translucency even though you draw an opaque surface on top of it right? And then your FPS drops like crazy
so
once I discovered in Plasma like one of our issues at the beginning was that the fact that we didn't set to false the translucent background because on the desktop version we do require it
but
on the mobile phone since it's a full screen app we didn't care
and
it was set to true and the framework was very bad so be careful of your old code that went on the desktop and then you tried to port it on the mobile world and it's true
also
I recommend the usage of graphics system raster because it's any way faster than the native I think I have a small demo
so
on that demo so you remember I got like 58 54 FPS right let's say now I go to the project and then on run settings macOS or kit creator
should
be okay ah
so
you see like 20 milliseconds average per frame less just by using raster on this simple demo right which just draw rectangles and have a bit of opacity and draw some text right
what
a fight to just show that so yeah use graphics system raster go for it
back
in graphics view graphics view has some viewport update mode what is the viewport update mode is like the way we actually send updates I mean the way we actually update the scene
full
viewport update is recommended for viewports like GL widgets why because QGL widget for now at least doesn't support partial updates right so you can say oh the top left corner has been updated and as well as the right or the bottom right for instance it's always a full update
and
actually in some cases it's faster in GL to redo everything than trying to figure out what to redo
so
full viewport update when you have a GL widget is also what I found out to be the best combination for the I900 and Plasma
by
default it's bonding rect viewport update and to be honest I think it's the best compromise you can find it's the best case for many many use cases
you
can try the others there are two more it's well explained in the documentation to be honest it's like it's a one line change in your code right so try it and then you see if it's beneficial or not but at least it's nice to remember that they exist and use full viewport update for GL widgets it really depends the scene so try it by yourself other tips and tricks if you know the area the view should see so let's say you know that your graphics view will see the entire scene
or
you know exactly the part you'll see always call set scene right on the graphics view why
because
graphics view has a built-in feature to actually trying to
fit
the content and to see like the optimal part of the scene and also adjust the scroll bars and so on
and this
is expensive calculation when you add an item you know we have to figure out what we should see and so on and update the scroll bar and stuff like that so
when
you know the array you will see on the scene always set scene rect because then you don't need to we don't need to do those computations the framework won't do them for you right
so
when you got a full screen app that see the entire scene
then
set code sets in right it's the best code path you can get
also
there is a fit in view I just remember it's basically scaled the view matrix and update the scroll bar accordingly to ensure that the scene rectangle fits inside the graphics view port right
so
that you can see basically the entire scene
so
how it works it basically scaled right if it doesn't fit in your scene rect on the view then it will scale everything down so that you can see the entire scene right
I've
seen code people were calling fit in view because they didn't know exactly what it was doing and what happened is the scaling factor that was applied was close to 1 0.9 or something like that so on the screen with your eyes you can't see it
like
if you look like with a magnifier and stuff like that you see it but
it
looks the same right with 0.91 it transformation applied on every item right so the cost of convenience is basically that you slow down everything for sometimes nothing
so
be careful of this fit in view feature
sometimes
you better do it by yourself scaling the items you really need to see and so on the scene
so
the graphic scene
it
manages the item
it's
easy so by managing it means like if you delete the scene then it will delete all the items the scene is responsible for hiding items inside removing items inside
the
scene is also responsible for delivering the events
by
delivering the events it's like let's say you get a keyboard event the scene is responsible to find which item will get the keyboard event
the
graphic scene under the focus same where I should input and we will get the focus when the scene will get the focus back
and
the graphic scene handles the painting
so
what should be redrawed
how
we redrawed and stuff like that
so
the core feature of the I mean the graphic scene need an index so why basically the index is needed for item lookup so when you need to let's say you have a redraw on let's say on top right corner and you need to figure out
what
is in this area what are those items there so you need to find them fast right you cannot just go through one list and then one by one say okay are you there no are you there no are you there no right it will be slow so
and
also for collision detection let's say you want to know the items that collides with the one you are actually working on then you need to know the one around you right same you can't go through all of them to figure out if they are next to you and they collide to you they collide actually with you
so
we got two implementations today linear
just
plain list of items
so
linear time lookup it's actually partially false but let's put it like this BSP so it's binary space partitioning it's actually the default I'll explain the next slide what is BSP
so
BSP it's like
it's
a tree and how it works is like in the scene so when you add items and so on we modify that BSP tree
we
basically divide the scene into small parts to create a tree of areas right like I saw in the small diagrams look so let's say the shape like the black shape is like the scene we divide in two parts so we got the tree let's say A B and C
and
then we divide it to actually have like to basically decomplexify the scene that we have so that and then on the leaf of our tree we actually add the items
so
whenever you want
to
find an item you just look the area you're looking for so let's say I don't know a rectangle and then you look the x and y and then or C is like minus or like bigger or less and then you basically divide by two at each time the areas you're looking for items right
so
it's a well-known implementation mainly used in 3D they actually use they don't use that much VSP anymore they use like something like octree and stuff like like the 3D open source 3D lookup is fast as I was explaining we just divide like we just divide the areas and then go deep into the tree and then we have a smaller list of items than the global list of all items in the scene right
but
as you can imagine moving is slow because let's say the item move because of an animation
well
we need to first find it in the tree fast
but
then we need to move it in the tree so that it will have the right position afterwards because let's say it moves from the area C to B it has to move in the tree right
so
keeping up to date the BSP tree is something that is slow
so
let's say you have an animation where the item is called set pose set pose set pose set pose like it kills the frame rate so
we
come up with a work around
so
the first time you call set pose
we
put into temporary so we remove the item from the tree of the BSP right
we
put into a temporary list
and
then we start the timer
and
then at each time you call set pose the timer is reset
reset
reset reset reset reset and then when the timer expires like timeouts then we re-add the item into the BSP
so
that's why when you call set pose many times then it's actually fluid because we don't need to update the BSP so it's only when the items become static that we re-add it into the BSP
the
problem with that of course is if you call set pose or you animate thousands of items at the same time because then we got all those timers going on and then a big list of temporary items that are moving which means that when you need to remove them from this list because the timer expired and stuff like that then it's linear lookup and stuff like that so it has drawbacks
so
the index you can change it with the set item index method
and
then of course you might ask which one I should use BSP it's basically it depends of the scene but you can try it as well it's a one line code change but BSP is usually more for static contents right the one that you don't move typically the demo we have which is like the ship demo you know with like four views thousands of items that don't move
this
is the best use case no index
is
nice for animated scene that doesn't contain that much items for instance in QML we deactivate the BSP
because
there is no damaged items like in the ship demo for instance so no index is faster on Plasma I also put no index it was faster
okay
now let's move on a bit talking about how the wandering works
in
graphic scene it's hard to explain so I try to do my best to actually show it on slides
so
first what happened is like we get our suspects graphics view graphic scene and the index I put the index as a generic because it doesn't matter if we use the BSP or the linear in that case
so
we get a paint event that arrives from the window system or anything like you calling updates for instance or the window system saying oh you need this region is dirty you need to repaint
then
graphics view basically does nothing
I
mean yes it actually draw the background and then
call
draw items
not
the public function the private one since 4.6
on
the graphic scene and say okay here is the region you need to repaint
and
here is my transformation my view transformation and riddle
so
then the graphic scene need to find out for those regions the items that it needs to repaint for for that it it will say okay I go to the index and
I
like all
the
top levels
for
a given area so let's say if it's on the top right corner then give me all the top level items that are in that area
and
return me a list of that
right just
the parents
and
then what happened is like
we
start from the parent
and
then we render the subtree so all the children recursively
so
starting from the parent then one child and then recursively all the children of this child and then to the next child and so on and then we do it for all the top levels that is returning that the graphics in this return
so
it's recursive algorithm for painting it's actually almost the same in q widgets this paint algorithm is the one since 4-6 before it was not like that
before
it was iterative so the only difference with that diagram is basically that when we asked the index the items for a given area it was returning everything not necessarily top levels
so the
main problem with this approach was
when
you run out from the parents and then you do the subtree right as I was explaining let's say the parent has a transformation let's say 45 degree rotation
so
you need to apply the transformation on the painter right to paint 45 degree right so which means that all the children except if they ignore the transformation they will be rotated by 45 degree as well right
so
the painter
the
transformation set it on the like that you set on the painter it stay the same while we render recursively the whole subtree right
versus
the problem with the iterative approach is like since we got random items from different sub trees and just a list which was non ordered
we
start from one item say okay what is your transformation your top level fine I just use your transformation next one
next
one it can be a children deep inside the subtree and then we need to figure out okay what is the transformation and then you need to go to the parent to see if it has a transformation and so on until you reach the top level to actually find
the
transformation for the complete tree right
and
this was
a
bottleneck of the previous implementation is actually to find out also the opacity right if you have an opacity of 0.5 on the parents and then
the
children will also have the opacity of 0.5 right
but
if you can set different opacity on all the children right and then you combine this opacity and then that's the same you need to figure out up until the parents
the
real opacity that you will apply on the painter
so
what did first is we tried to cache everything so cache the opacity cache the transformation and so on but that was a bad idea because
when
you cache data it's fine if nothing changes like if you have to redo
after
and after the same content then that's fine because you calculate the cache the first time let's say for the transformation you calculate the cache for every item like their cached transform
but
let's say
you
call set transform then you need to update all the caches right so the worst part is like if you update the set transform on the parent then you need to invalidate all the cache on all the children and then recalculate everything back and forth
so
painting was faster but calling functions like set transform or set opacity became slower
so
at the end there was no benefits cache up to date was insanely hard
so
versus now the recursive approach
the
fact that it is recursive and then each time we paint a child we actually give the painter like it is we actually save those calculations so rendering by sub trees make it very efficient and also
the
fact that we are caching stuff like make the code really like it was looking bad and we were not proud in that case tentacular code like ugly really bad so we said nah let's clean it and rewrite everything the items so graphics item basically friends it has friends so the base class is graphics item it's subtract you need to implement paint and bonding write
it
has the qobject variant it's exactly the same
which
just like the property declaration and then of course you can have signal slot on it
and
I think if I recall correctly that's also some stuff for the gesture API because the gesture API need to get qobject
so use
qgraphics item if you don't care of the qobject facilities and you don't mind of the memory usage because you know if you multiply inherit qgraphics object from qobject and qgraphics item
so
the memory usage is qobject plus qgraphics item so if you have a lot of items in your scene be careful of the memory usage that's why the qgraphics item was designed to be not a qobject just for the memory usage we also have qgraphics subject I was explaining it's a qgraphics object also and it inherits from qgraphics layout items so that you can put into a layout it has a geometry concept so you can have a width height and x and y also it has font support palette support size policy support and stuff like so it's basically a bit like a qwidget
and
for instance if you have ever looked the Migo touch API for Migo
and
also the Orbit or also known as UI extension for Symbian they narrow it from Q-Graphics widgets because they put that into their layouts and so on so they use Q-Graphics widgets some tips and tricks about graphics item
the
cache mode graphics item has two cache modes it's a bit like the background I was explaining before so what happened the cache mode works is like
it's
basically like if you have a camera and then you take a picture of the item like it is on the screen and then you save that picture for the next time you are under a frame for instance so that you don't call again the paint function on the item
so
the item coordinate cache is a screenshot or a picture of the item untransformed
so if
you have a rotation on it doesn't work it will just take the picture of the item untransformed and then rotate the pixel map
for
instance device coordinate cache on the other hand take a screenshot of the item transformed right so to make it clear I did a small diagram here
on
the left item coordinate cache take a screenshot like it is
if
the item was rotated then I take the screenshot and rotate the screenshot device coordinate cache
as
you can see on the diagram like the dotted lines are actually
so
a bit how it works the cache mode so
when
there is a cache set on the item we don't use the painter that we had from graphics view and then graphics scene we actually open a new one on the pixel map
we
call your paint function
that
will render everything into the pixel map
and
then when we get that pixel map we store it into the pixel map cache
and
then I make a bit of advertisement since 4.6 there is a new API for qpxmap cache that I've implemented is because qpxmap cache the way it works is like
you
say here is a key
here
is a pixel map
it
store it for you
and
then the next time you want like so you can throw away your pixel that you store locally and then the next time you need to get this pixel from the cache you say hey I have the key I want to get it back and then the cache can view the pixel that it saved
so
the problem with the key before cat 4.6 it was that
it
was qstring
and
everybody knows that
if
you want to make something fast at least when it's in a painting code you should avoid string operation
so
what I did instead is like I've implemented an extension to the pixel cache that I recommend to use and to port your old cube pixel cache with string base key to the new API so that
you
give the pixel to the cache and then the cache gives you a key back which is an int it's encapsulated into a class but it's actually an int behind the scene
and
then you store that key
and
then the next time we run the item for instance we have the key we ask the pixel cache to get the pixel back and then we render everything we just draw the pixel that we get from the cache
so
when for instance you move
the
item
if
you don't call update on it then it's just reading from the cache and then bleating the pixel on the screen so super fast
if
a redraw is needed like for instance you call update on it then we need to figure out the exposed area
that
are dirty basically and then we call again paint on your item with a new pixel and then we replace the one in the cache by the new version
so
I got a demo for it so you'll see
the
cache modes beware
it's
nice it's fast let's say you got an item that is really complex
with
a drawing code
quite
complex
then
you save like I mean it's fast right you just run down the first frame and then after it's fast it's just like bleating a pixel on the screen but be careful because same problem as the backgrounds on the graphics view
is
like
it
allocates a pixel map but that is the size of the item right so if the item is huge then you get a huge pixel in memory
I'm
just saying device coordinate cache
always
uses more memory because as you can see here
the
actual pixel that we put on the cache the dotted lines are bigger right
so when
the item is un-transformed you better want to use item coordinate cache otherwise
like
the pixel map at the end will be the same but the code actually goes there is a bit different and more complex so if the item is un-transformed item coordinate cache
and
the drawback of item coordinate cache is like it might look bad
when
the item is transformed because we operate on the pixel map right and then the pixel map we all know that if you scale the pixel map it looks bad so I'll show exactly what's going on when it's formed
so
here I got another demo which is the cache mode
start
a project so it's basically the same demo as I had before so main window you know graphics scene graphics view apparent item same and then I got again a grid of items and in that case there are proxy
with
the red widget inside
I
show the code of the red widgets and then I position them as a grid and same my FPS tracker and same I have a property animation that moves them down
the
red widget is actually a q widget here which has a paint event and then the paint event just draw rectangle basic
so if
I run the thing right now I need to move the window
it
looks like this right moving down
and this
basic example right up and if you look the average is like
42
39 36 right
now
let's say on the item I said item set coordinate set cache mode right and then queue graphics item item code item coordinate cache
right
so I set the cache let's put it like this so you can see better I set the cache on the item right which means that the first time we run the item it runs into a pixel map then we put it into the cache and if we just move it which doesn't require to like I mean there is no dirty area while moving it unless if it's and just drawing a pixel map right so let's see the frame rates like on that guy
so
it builds and I move it back
here
so as
you
can see the frame is like 20 16 as half right
in
that case I can close when it's down here up so half just by using the cache in that particular case right
of
course and I use a lot of memory here because like I got 10 by 10 items right and I activate the cache for all of them so the memory usage increase quite a lot
so
be careful when you use it use it on the right items right on the one that you know it's a painting code complex and it's worth the memory usage
now
as I was explaining
let's
have another example to see the differences between
between
the device coordinate cache and actually the item coordinate cache so I got a small example simpler here you know graphics view graphics scene again then top level item parent and then I have children which is the yellow item I'll show what it does and then you'll see I will activate and show you the differences between the two cache modes so if you look the yellow item which is not yellow it actually
I
like white I'm French and the pen is white and actually writes stuff on it which is I'm
a
cached item right so if you run the example right now how it looks like
here
just moving around right now
if
I come back to my main window
what
happens is like if I actually
rotate
by 45 and scale the item by three on x and y right so I run it
here
no cache mode still involved right oops need to
put
it here it looks like that right so as you can see the pixel like the pixel map is not high resolution so it looks a bit crap but the font is perfect right
so
now let's say
I
activate the item coordinate cache on it
so
if you remember correctly what I said we take a screenshot untransformed and then we apply the transformations on the pixel map so the first time we render the item put it into the cache untransformed
and
then and then we apply transformation on it on the pixel map right so what do you expect to see you expect to see like the pixel map looking as bad as it was here
but
the text the text is not using like it's not using the painter API it's basically scaling the pixel map right so it will looks it should look bad actually and it will put it back
so
I don't know if you see it but it's actually really pixelized right because why we actually just scale a pixel map
right
instead of drawing
a
text on a scanned painter that's the difference
so
now you said well but in that case I just used the device coordinate cache well but that's exactly for what it is made
so
if I replace here
by
the way at each time I move the position there is no call to paint event no call to the paint function on your item right because it's cached
it's
only if you call update or it needs to be updated then it actually recall paint
so
now if you look here
I
change it to device coordinate cache
and
then you see
it's
nice
because
why
I
render the item into a pixel map after it has been transformed so the font was properly rendered and then I store that pixel map but of course
here
the memory usage is way bigger because
I
scale it by three right so on the item coordinate cache since I do a screenshot and transform the scaling is not taken into a code and the pixel is really tiny
versus
here I store this huge pixel in the memory
so
because I stored the transformed version
so
and then you have to basically
like
by yourself find out what is the best solution caching no device coordinate cache no or item coordinate cache it's up to you up to the memory that you have on your operating system
now
you know how it works
now
there is a tips and tricks
that
only if you have looked at the code you know how you can use it it's a third cache mode you know like for instance on the two other cache modes if you get an update on the right top corner then we actually clip the painter so that you only render that part
so
you get partial update of the cache right
now if
you use the graphics effect in a nasty way you can actually have subtree caching because all the cache mode that I was explaining apply per item right it's only for an item not for item plus children right so it's only for a given item
now
there are many people that say oh it would be nice to have subtree caching you know
because
you are under the complete subtree and then when you move the complete subtree then it's actually just bleating a pixmap right
so
now let's just explain how works the graphics effect so the graphics effect it's basically
we
render the items and the item itself so you can set an effect on the graphics item and then we render the item and all the children
into
a pixmap
so
why we do that
because
let's say you want to apply a blur effect
you
apply the effect on the complete subtree right you not apply the blur effect on the parent and then another blur effect on the child on one child and another child it's not right
so
you should get the complete subtree and then you apply the blur on everything
so
now you say hey but it actually render the complete thing on the pixmap the complete subtree on the pixmap so why I couldn't use that pixmap for myself so that I have a subtree caching
well
then so
and
because the API works that
you
get a draw code on the graphics effect class which gives you a painter and then you can actually ask for the pixmap of your subtree
and
then you can apply your transformation on it I mean your effects sorry so
on
the blur typically on the blur effect what we do on the draw is like we get this pixmap from the graphics blur effect on the pixmap so it's fast
now
let's say on your custom draw effects you just get the pixmap
from
the graphics view so contain all the subtree but you don't apply any effects you just draw it
well
then you just have basically a subtree caching implemented and
it
just works I have a demo to actually show
now
the only drawback of that as I was explaining is let's say one of the children get an update so either you call update on it or
for
some reason it has to be redraw because of capacity and stuff like that then all the pixmap is thrown away
and
then we have to rewonder the whole subtree on it we have to rewonder the subtree so you get the pixmap back and you can draw it
so
every update that happens inside the subtree is costly
so
that's the only drawback
so
now I have a small demo up here
close
that one graphics effect
source usual
suspect graphics view graphics scene asset the scene rex as I said parent item
nothing
and then just
20
by 20 yellow items and I put them as a grid same as before and if you look the yellow items they are the same as before just the B and opacity
and
yellow basically so same demo
so
then now
I
got here this caching effect
so if
you look the implementation of it
so
it subclass qgraphics effect
as
the draw function I was explaining ask the source pixmap so
I
can actually close that so you see better up
so
I ask the source pixmap and this pixmap that you get is actually the complete subtree so let's say the parent has many children then you get the parent plus all the children into a big pixmap right
and
then
here I
just draw the pixmap
but
in theory the way you should use the API is when you get this pixmap here
you
should do I don't know
do
an effect right blurring changing the colors on the pixmap whatever right but in that case we just use it and draw it right so
the
first time we render the guy on the item that has the effect then it will actually
say
oh there is an effect so we should call first draw all the subtree and then get the pixmap and then draw it and the pixmap is cached as well
so
source pixmap the first time render the complete subtree but the next time if nothing has changed on the subtree it reused a pixmap
that
is on the cache
so now
you said on which item I should set the effects
on
my demo so I got a lot of rectangles right
moving
around actually in that case the animation is different is actually I move actually animate the scale so all the items in the grid will actually scale right
so
then
it's
a bit stupid to actually set caching effect on all items it will bring me anything comparing to the normal cache mode right
but
what I want is like on this logical parent that is here
that
one
that
because all the yellow items are actually children of the parents right I want to set an effect on it
on
the parents so that
the
first time you will run all the children and then I get a pixmap and then whenever I need to redraw I scale the pixmap instead of scaling and redrawing everything so here
let's
say if I run without the effects you see
what
it looks like and the performance of it
I
move it you see it scales right
and
then it will stop at some point
so
of course the milliseconds per frame is not the same at each time because like on the very first paint we got many items then we scale we scale we scale and then some of them goes out of the viewport right so then we don't see them anymore so then we just discard the painting anyway so that's why the frame rate is getting
I
mean the time we spent per frame is getting lower and lower after the animation is getting before the end actually
so
now if I set the
the
effects
on
the parents so on my top level that contains all the children and then I run the animation
so
what do you expect for the frame rate same as the beginning here
and
then it should be constant right because I just scale a pixel map so the operation is always the same and then I come here
it
was
so
it's slightly faster as you can see 41
and
it's constant as I was explaining because
we
run off first and then it's just doing a pixel map but
in
that particular case it's faster it's nice
the
problem is as you can see if I rerun the demo
when
we scale
look
at the text since we scale a pixel map
text
will look crap it looks bad at the end right so
that's
the same drawback after item coordinate cache because we operate on a pixel map
so
when you should use these caching effects
actually
on my plasma here you don't see it that much but
the
way the panels move is basically we got like a normal screen
and
then one that will come so when you switch the screen like we scale down the current one slide it away then move the next one and scale up
and
those panels contain many items contain applets contain everything right and of course you know scaling
when
I do the scaling animation to like moving the panels around it was slow
and
then in that case I use the scale the effects I activate the effects only when I start the animation of changing the panel why because then when I do the scaling animation I only do it on the pix map and not on all items inside so that's one of the use cases I use the graphics effect like this
by
the way if you want to see how I use it it's on the KDE repository so I can point you the link for it
Q
graphics proxy widgets
haha it's
really tempting right because you can use any Q widget that you already have and put into the graphics view
it's
not fast
why
it's not fast because the way Q widget works is that you get a paint event right and then the paint event
you
don't get a painter you have to open the painter on the paint event right so since graphics view share the painter at each time you paint items
it's
different it's different comparing to Q widget
we
get a painter from Q graphics view which is a Q widget create I mean create a paint event from graphics view that create a painter and we reuse the same painter for
all
the items we render
even
for the background
so
now there is no way for us to actually give that painter to Q widgets
like
we can't create a paint event for the widget we embed right so the only way we can actually render the widget inside the canvas is give a painter you give a painter and render the widgets in the painter
but
render it's always a full update
so
whenever we paint a QGraphics proxy widget in Graphics view it will always be a full update on the widget
so
let's say the widget is like 200 by 200 it will be always 200 by 200 like you always paint the 200 by 200 widgets regardless the clipping regardless it's a partial update at some point
so
use it if you have no other alternatives really if you can't write your QGraphics widget subclasses
or
if you can't write Qt component for instance for QML or stuff like that
and
please don't embed complex hierarchy the way we thought people will use QGraphics proxy widgets it was like convenience for a push button and stuff like that and I've had bug reports on people embedding QMain window complete apps inside QGraphics proxy widget and expect everything to work
like
I can't debug all my life they won't work it's just too complex so it's basically making two different frameworks working together and so keep with simple widgets simplify them and try to use as simple as you can widgets like patch pattern line even combo box have to be sometimes problematics but
stuff
like that because otherwise you get focus issues painting artifacts because you know the way QGraphics proxy widget work is like we map all the events from graphic scene to QWidget and then send them through the event loop but many widgets
they
don't have code for actually handling the fat like for instance
the
X and Y is like 2000 2000 right
because
they're supposed to run on the desktop
which
is maximum resolution and 1600 by 1200 right and the scene can be huge right so for instance I remember I had a bug for the combo box and the pop-up that was showing
trying
to be smart and you know so if the combo box is on that it's not cut right
this
for instance if you were putting the combo box more in the scene on the X and Y more than your screen resolution then everything was completely broken so I actually fix it right but there's a lot of problems like this you will run into
just
because your code and our code is not very graphics view friendly so don't use it
I
have a small demo to show how slow it is and why you shouldn't use it
so
if I come back to my cache mode demo because it's defined
so
remember the demo right I create a proxy widget and then I set a widget which is just drawing a red rectangle right it was just like this basically if you remember correctly up right so let's see the frames it's unfair it has a cache mode
of
course I don't see the problem
I
put it back on the screen
so
you see it's like yeah 34 41 39 around like 30 something
now
let's say I replace my proxy
by
this yellow graphics widget which basically exactly I mean if you look this is the red widget so it's a q widget that was just a rectangle rectangle and here
it's
my yellow widget inherits from q graphics widget and does exactly the same thing but yellow right during a rectangle that's the size of the item and yellow right
and
you see the difference so I just replace it instead of
being
the proxy and with the red widget it's just the yellow item
and
then so you get exact same results but yellow right
and
then you wait up 1618 right so it's basically more than at least two times slower to use graphics proxy widgets in just the basic example I was showing so think about like you are doing text in the widget you are doing stuff like that right it will be even slower so please please please don't use qgraphics proxy widget if you don't have a good reason for it a very good reason actually
some
ninja tips and tricks use set flags with s
with
like and using flags and the or and the binary operator right for let's say flag one or flag two or flag three and or whatever
rather
than many set flag like set flag flag one true set flag flag two true
why
you why because first
whenever
you change a flag it it will go to the notification system of graphics item which will call the item change virtual function right so that you can react to the flag changes
so
you get many times call to item change so you don't want to do that actually sometimes like really what's the point you better have one call with all the flag changes and then you can do your stuff anyway also some flags
need
to update states internally for the graphics item let's say you change the way items clip children to shape which means that if you set it to a parent then all the children will be clipped to the shape of the parent
what
we do is on the children we say okay if you are out of the geometry of the item then we set an internal flag to say well then you don't need to be paint right pretty much I simplify the problem
so
we need to go sometimes through the hierarchy of items from the children to the parent and sometimes to the children from the parent to the children and so we need to go through the trees of parent and children and
you
want to do it one time right and so if you set flags with multiple flags we we could have done it one shot
so
use it want set flags with everything in one
if
you have like on my demo you remember I got this top level parent that was doing nothing right it was a QGraphics widget with no contents no paints nothing
I
should have set the flag item has no contents
I
didn't do because I wanted to keep it for the for this slide
so what
it means
if
you set that item has no contents it means that
in
the painting of graphic scene we won't set up the painter and call paint on the item because we know it has no contents it has nothing to draw
and
set up the painter with the opacity with the transformation and stuff like that
takes
a bit of time and calling a function also even though it's not if you know that you won't do anything on your paint event
so
if you just get a logical parent set item has no content to true it's a flag and then the painting will paint function won't be called
and
then you save some painter initializations item change so it's the notification thing I was explaining just before
calling
it is slow why it's because so you call item change with the changes that you have made on the item and qvariant is actually what you change on the item
so
for instance if you move the item you will get a notification saying oh the position has changed and here is the new position
and
we use qvariant so the appearing looks nice right you just have one function but it gives a qvariant as parameters you can pass everything it can be qpoints
if
the position has changed it can be real if it's the opacity that has changed and stuff like that right it's a nice API the problem is qvariant qvariant is not fast and we tried everything there is nothing we can do in q4 to make it faster
so
if we want to make it faster then we have to break the binary compatibility
at
least
so try
there is nothing I can change in q4 anyway so avoid to call it too much
try
to avoid to call it so
that's
why for set flags I recommend set flags because then you don't need to call it two times right you call it one time only so
be
careful of for instance there are some flags in graphics item that send the geometry changes
the
position changes and stuff like that
really be
careful when you set those flags
because
it will be slower really slow so sometimes it's better than you actually do a kind of listener you know and you basically react to I don't know let's say call to set pause or whatever and then by yourself actually listen to the changes that you want instead of calling item change
so
kind of action listener or a bit like on Java you know you listen to item and then you actually trigger by yourself the changes instead of going through the item change it's a bit unfortunate but that's how it is and there is nothing you can do for now I think that's all for the tips and tricks and presentation of Graphics View so now the lessons learned that
what
we learned when we actually did Graphics View because Graphics View has a canvas like it is now it's almost done like the core feature of Graphics View is pretty much done right you get an item you get a scene a view you can do transforms and so on features wise it's almost done
perhaps
we can use the subtree caching but I don't think it's like a proper subtree caching but I don't think it's worth the price to implement it actually
so
it's a good framework it can run fast on the devices right I mean Migo
Migo
Touch
Orbit
or the UI extension for CIMEN4 they are using it right and they will ship devices with it so you can do really nice things with Graphics View
but
it's not perfect and
what
we notice is like what people do in the pane functions influence a lot the performance what you do inside it's like matters a lot
it's
not very graphic card friendly because most of the work that we do is software sites clip pass calculation
and
like part of the transformation has to be done in CPU but some of them could be done in the graphic cards the effects
they
work fine on the device some of them work fine on the desktop but it's really fast slow effects we failed delivering fast graphics effects
making
QWidgets works in the canvas
it
helps many people but it opened a Pandora box and with a lot of bug reports and people trying to embed widgets inside the graphics view and expect it to work perfectly well in theory you could but the way the two frameworks works is too hard to make them communicate properly
also
what we learned is
the
expensive calculations for instance when you get the paint function then you can ask the exposed rate of the item like the dirty areas pretty much right
so that
was a bad idea to actually always trying to compute this exposed right because in many cases what you see in users code they don't use it some some
of
them do only sometimes some items in the scene actually use this exposed right for instance
but
all the others don't
and
what we learn actually is always calculating those things for instance always even though people don't use it is stupid we should make the expensive calculations like for instance the exposed right on demand so if you really need it then we calculate it it's slow but you ask for slowness kind of right
so we
change the behavior when we could it's a bit bad but that's that sometimes you have to do compromise and but it's one of the examples and there is I can't think of more but but yeah expensive calculation only on demand graphics item it's a pure virtual class right you need to implement at least bonding right and paint I think that was a bad idea to put it pure virtual we got a lot of problems that I mean it's mostly because of C++ right like when we actually catch the deletion of an item it's when it actually enter in the graphics item destructor right
because
you you have a subclass of graphics item it's your destructor that will be cool but the framework don't know yet that the item is about to die right
at
least when it's not a Q object and
so
when we know that the item is about to like it's being deleted is when we enter in the graphics item destructor but then it's too late to get the bonding right
because
like because of C++ you can't call the virtual method right
on
the graphics item level so
stuff
like that we have to add work counts in the index and so on because we don't know the geometry anymore and stuff like that so
I
think at the end it should have been pure virtual just normal geometry 0 0 0 like graphics widget and a paint that does nothing also multiple views
I've
seen some people using it you know but it makes the code really complex and optimization hard
but
at the end I think it's a nice feature and so
the
way it's implemented now I think it could have been better now it's like we can still improve it a bit but not that much actually I think we're pretty much done about optimization in graphic view it's not the common use case the multiple views so now it's like
how
we could have it easier to add another of it and support the default one view and somehow allows people to have different views I don't know by letting access easily I mean perhaps to let people access to the actual rendered content of the scene so they can actually grab a part of the scene and see it I don't know like exposing the surface of the scene or something like that but to improve the way it's implemented today
now
how we can make a better usage of the graphic card
well
I won't answer to that because now we'll do it I think it's tomorrow you better want to attend it's basically how you can write efficient paint method
could
we improve graphics view without breaking the API
I
don't think we can at least in the binary and source compatibility way nah
it
has to be like that for now
could
we have a high performance canvas in Q4 I think we can and I think the answer we given in the scene graph that was before this afternoon but for people that didn't go to that talk you can still download the videos when they will be available
I
would like to thanks everyone for coming and now you can throw questions to me and I try to do my best to answer
thank
you
any
questions
when you were explaining about the cache modes
and
especially about the trick you did to simulate the sub tree cache how do you define
when
the sub tree will be repainted or not is this something that is inside the
I
mean the plumbing of the effect thing
yeah
it's like the invalidating the big sub tree pixmap that you get from using the caching effect trick
you
don't need to care about invalidating it graphics does it for you
ok
so neither can you for instance move it to device coordinate cache or something similar to that
yeah
I mean it's like
it's a trick right
yeah it's a trick I actually it would be nice to have a support for a third cache now is it worth to spend the price to actually develop it and make it works really nice I don't know that's some people it's not perfect but it will help many people like in my case yeah I've seen some people using as well this trick so
any
other questions
wow
come on you have questions I had like I thought I would have a lot of questions so
hi
I was wondering
I
may not have understood this properly but when you draw the canvas I mean the graphics view and there's a lot of children items there's a first research of
all
the sub graphs or the sub trees
yeah top
levels
okay the top levels so what if you have
a
view in which you have for example one top level opacity for everything that's under it does this mean that
everything
will always be redrawn or is
like
you mean let's say you have
any number but
no no no it's like no no because like we we discard like on the subtree if we don't need to read because let's say for instance you get a parent and then clips the children and then there is a far away right it's it's possible in graphics view
this
one
will
never paint it
will
never paint it right it will be discarded so what we get from the index is only a list of top level not the complete subtree right it's then after that we recursively go to that subtree
and
then we discard the one that we don't need
thank
you
and
also opacity for instance if you have an opacity zero what we discard the guy right don't need to paint it
hi with
the Q graphics effect classes
for
example I've noticed the drop shadow effect is sometimes slow if you apply a drop shadow to a complete hierarchy of items is it possible to
get
the source image only for the top level item which may for example bound all of the entire subtree
or
does always get the source no
you always
get the sub trees complete complete subtree there's
no way
you can ask the the no there is no way you can actually ask for
optimization to have an extra boolean in there yeah
that's
actually a good idea and yeah I've already done actually could you please remind where we can find the copy of this presentation the what copy of this presentation I think the marketing people will send the presentation as well as the demos and everything I can't answer to be honest you can ask one of them when you see them
I
don't know there will be they will be available
you
will get them so
hi
we've heard a lot of tips for animated scenes
in
our projects we mostly have
static
scenes but there's a lot of activity in the views like zooming
moving
around do you have any tips for that
actually zooming is the worst case of graphics views as soon as you scale is not very friendly to be honest it's one of the weak point of graphics view
actually when
you actually scale the view I don't see really good trick like this
except
rendering into Pixmap the scene and then scale it by yourself but then you will get bad quality otherwise I would recommend to you the cache mode but that's one of the flows we have like the transformations is not fast
but
perhaps like if we sit down together we can probably try to find something
yeah
hi I'm really looking for comparison with
just
using QWidget as a framework and QGraphics view I mean
you
spoke about using QWidget within Graphics view
but
is there some kind of comparison like you use QWidget lonely does it perform worse or better with the same use case
it
depends actually Graphics view has its own use cases right I mean if you throw like a thousand widgets into a UI it would be slow Graphics view will work a bit better
so
stuff like that and I mean Graphics view you have to see it as a canvas where you yeah as a canvas right QWidget is yeah it's mostly like I mean UI right UI bits like buttons and so on so
I
would say Graphics view will perform sometimes better than widgets but I've been shown that sometimes it's not true actually yesterday someone actually showed me an app on the mobile phone and they told me that QWidget was faster than Graphics view for their use cases
so
really it depends
but
I agree that it's not easy to
when
you have to a new app you have to choose right you cannot afford to develop both versions right so
me
to be honest I I would go always for Graphics view but that's my own advice I mean I develop mobile apps in my spare time and I do it on Graphics view and if it's slow I fix Graphics view because I can do it so
I
do my best to fix it actually because
I
when I was doing that I fixed a lot of bugs and a lot of performance issues but Graphics view is not perfect I think we can come up with something better
no
one
yeah
I was
at
the scene graph presentation earlier and that was quite interesting but
I'm
wondering in the future say you have an app that's based on Graphics view
and
you want to have the optimizations from scene graph how can you migrate that to
scene graph
without I mean will you have to write the whole app again in
for
now I don't have an answer but I agree with you that's a migration path that we need to solve that's something that we should provide a proper migration path and the less painful with less pain as possible right
so
either by providing some kind of I don't want to say but like a kind of proxy widget but for the thing graph right but but yeah something we need to find a migration path for now I don't have the answer but I agree with you that it would be a problem and this is using my hat and say well we have lot of code as well on top of Q graphics view and we need to find a solution for that so yes I'll fight for migration that's that's it thanks everyone
one more question
I have
a question about the maximum number of items in a graphics scene
I
can't answer actually like ship demos has thousands and thousands items and it works fine
I
can't keep a number it depends what you do in the items depends the complexity of the items depends many parameters
in
theory it should be unlimited right but we know that it is not but I don't know it depends really what you do in the scene if you animate the scene if it's a static scene if the items are complex to draw or if it's just rectangles that you move around if it's just drawing pixel you can do a lot of them but if it's like drawing text then it will be slower right so it really depends the content it's a generalist framework we don't say oh it can handle like two millions items and it will be fine no we can't it's too complex and actually none of the canvas out there can actually say a number of items they can know depends what you do in the items
everybody enjoyed the