6

We're developping an application for 2D data processing and display. At the moment data is displayed by converting each point to a color depending on intensity, so in rather low level code. This works well. A new feature is displaying a grid and a bunch of lines that can be moved with the mouse on that image.

As usual when new technologies are going to be picked, I made a little demo to test some things out: using the current data plot, a line is drawn on top that can be moved up/down with the mouse, and at the same time there is text displaying the cursor coordinates. I tried some different ways: using a Canvas, using a somehwat lower level DrawingContext and using the low level WriteableBitmapEx api.

To me, there was no real difference in ease of coding nor display speed. Yes the Canvas option had a couple of lines less code than the others, while I had the impression the lower level options were somewhat faster to display. But no huge differenes making me pick one immediately.

So the problem now is: I have no idea how to select the most suitable system for the job, but it is a very important decision to make since the graphical part of the app will likely continue to grow. Needless to say it would be a small disaster if we pick A now, and in one year we figure out B would have been way better. Normally I'd select the fastest or most convenient option, or look at future requirements and use the system that seems to fit best, but in this case there is simply not enough difference, and future requirements are not exactly known: for now we think it's sufficient if we can draw lines, circles and some text, and update speed is not that important. However the application is in it's early stage, so is the underlying hardware and there are less than 100 customers. That however, might change rapidly. And so can requirements.

Question is simple: what to do? Some options I've been thinkig about:

  • pick one that 'feels' best (WriteableBitmapEx but probably just because I have an affinity with lowlevel stuff)
  • pick the one with the least amount of code (Canvas, also seems very easy on the UI level with effects and mouse events and what not)
  • make a more extensive demo so differences become more clear pick one, but put everything behind an interface so the implementation can be swapped later (might be quite some work)
2
  • Is small disaster an overstatement? Software rewrites happen all the time.
    – rwong
    Commented Aug 20, 2012 at 4:13
  • yes but there's a difference between a planned refactory and having to rewrite a core lib while there is no time allocated to it
    – stijn
    Commented Aug 20, 2012 at 8:08

4 Answers 4

3

Either way, you are going to need higher-level code. The question is who is better qualified to write it? Someone with almost no experience in the area or someone who makes a living writing libraries used by thousands of people? I'm not trying to be mean here, but they've already solved dozens of problems you aren't even aware exist yet. Use the higher level APIs until you're qualified and have good reason to replace them.

Also, in my experience the worst bottlenecks tend to be in my own code rather than in what third party library I happened to choose. Focus on things like keeping the data cached instead of constantly recalculating it. Avoid disk accesses. Keep your GUI code as decoupled as possible from the rest of the system. Think about the bare minimum your drawing code needs to know to do its job, and use well-defined interfaces to provide it.

1
  • 2
    "they've already solved dozens of problems you aren't even aware exist yet" -> this. I just started thinking about the key aspects of the lib, and the further I get, the more features I discover that I will need but didn't even think of on beforehand. And they are not exactly the most easy to write properly.
    – stijn
    Commented Aug 20, 2012 at 8:13
5

With a decent decoupled design, realizing you need something more efficient down the road and implementing a new rendering mechanism shouldn't be as though a task as it would seem.

My advice would be to pick the component that you and your team is most comfortable with (whether it be the easiest or the one closest to what you have worked with in the past). Then, your biggest concern should be to decouple model/logic as much as possible from rendering to be able to reimplement a new rendering system on top of the same interface should the need arise.

You're not at a point in time where you can make optimization as requirements are not well known and you don't have the full-fledged system to work with so any optimization done right now is likely time wasted.

1
  • 1
    As pwny noted, I'd put an interface between the calling code and the underlying implementation. Abstract it out as much as you can. Then if you find your current preferred solution to be unworkable, you can switch to using another library or method for doing the actual 'drawing'.
    – Catharz
    Commented Aug 21, 2012 at 7:23
3
+50

make a more extensive demo so differences become more clear pick one, but put everything behind an interface so the implementation can be swapped later (might be quite some work)

This will be necessary.

This "graphical" UI control will have the following requirements:

  • Fast image composition of text and labels
  • Double-buffering (to avoid flicker)
  • Ability to map mouse click coordinates to graphical objects.
    • Pay special attention to the situations where multiple graphical objects overlap. Unsatisfactory handling of this situation will make an application unusable to most people.

while I had the impression the lower level options were somewhat faster to display.

Contrary to your belief, some high-level frameworks delegate the heavy-lifting of pixel rendering and composition to lower-level frameworks, (which then delegate to the hardware) thus the performance difference may not be significant.

The main question is, what composition algorithm is used underneath the framework you will be choosing, and whether it will be sufficiently fast enough.

I give two examples of such composition strategies:

  1. For each text and label to be drawn on top of the canvas, it is first rendered to an individual RGBA32 transparent layer. All these layers are then composited onto the final bitmap at a later time.
  2. For each text and label to be drawn, the "destination" bitmap is locked, and their pixels are modified directly. Only the "inked pixels" need to be modified.

These strategies have different trade-offs. (The first one can be parallelized, but require more memory (RGBA32) and more computation (composition). The second one is serial but require less memory and computation.) Also, some strategy is more portable to GPU rendering than the other.

Since we aren't computer graphics experts, we do not know enough to predict which strategy will win, therefore we rely on experimentation (extensive demo) to find out.

1
  • +bounty for providing detailed information
    – stijn
    Commented Aug 25, 2012 at 9:05
1

First, you need to come to terms with the fact that you can't choose the right framework now, because you don't have enough information. So you should choose the framework which minimizes regret if it turns out to be the wrong one. In other words, choose the one that's most flexible.

For example, one nightmare scenario is to choose the low level framework, then it turns out all your needs are pretty standard. You spend lots of time writing, debugging and maintaining methods that are verbose and tedious in the low level framework, but already exist in the high level framework. Well, does the high level one also allow you to write low level code when needed? It might be the better choice.

In other words, if you don't know whether you'll be writing high level or low level code, choose a framework that's ok for both, rather than one that's really optimized for one but a disaster for the other. A year from now, you'll know which framework you should have used, and it won't be this one. But the more flexible one will only be a little worse than the optimal. You need flexibility in performance as well: something that allows you to write fast code if it turns out you need to.

The other thing you can do is try to put your drawing code behind an internal interface, to allow you to swap it out later, in case you really need to. This is harder than it sounds. If you pick a low level framework, your interface will gravitate towards lower level concepts. And -- surprise! -- often just the concepts in the framework. But if you go this route, unit tests are a must. First of all, writing a test which exercises just a given feature will force you to write that feature in a way that isn't intertwined with the rest of the code. And second, if you later have to swap out the back end, you'll have an easy way to find out what you've broken.

Another thing to look at is, which framework has the most momentum? Look at the mailing list archives. Is much going on? Perhaps a sub optimal framework will grow into a better one. In any event, if you end up pushing a framework in ways it wasn't intended to be used, it's good to have a community of experts to ask.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.