Re: Most efficient way of copying a wxBitmap?

346 views
Skip to first unread message

Dominique Lacerte

unread,
Jan 9, 2003, 7:44:53 PM1/9/03
to wx-u...@lists.wxwindows.org

Our application is primarily moving graphical images around in the client
area. The main concern is getting these objects to move very smoothly and
behave properly when they overlap (i.e. Z-order). We have a "main" bitmap
that is used as the drawing surface for these objects and then we BLT parts
of this main bitmap to the client area when changes are made to it. So most
of the CPU time is spent copying small bitmaps to the main bitmap and then
copying the main bitmap to the client area. With wxImagick BLTing the small
bitmap to the main bitmap was handled completely in the imagick code, using
floating point operations when merging pixels into the destination. This was
very slow! If we switch to using wxImage we get the speed increase of not
using floating point, but we still have this innefficiency that whenever a
wxImage is BLT to the temporary bitmap it is either converted to an HBITMAP
first (if the main bitmap is a wxBitmap) or the operation is done as a
memcopy of three bytes per pixel (if the main bitmap is also a wxImagick)
but in the latter case have simply moved the conversion step to when the
main bitmap is copied to the window. If we stick with wxBitmap we can have
all BLTs being used with no conversions.

I will look into upgrading to a more recent wxWindows when I get the chance,
but from looking over the notes on what's changed I don't see any mention of
improvements in this area. Any other suggestions are welcome!

Julian Smart

unread,
Jan 10, 2003, 3:42:56 AM1/10/03
to wx-u...@lists.wxwindows.org
At 17:05 09/01/2003 -0800, you wrote:
>I'm in a similar boat. All of my code does image manipulations to a
>wxImage object and then converts it to a wxBitmap. This is slow. I've
>started writing some optimization routines, but I would prefer a real
>solution. Admittedly, I haven't tried the 2.4 version, but somehow I doubt
>much has changed to help me. If anyone can point me to an OSS library for
>real-time image manipulation that plays well with wxWindows, I'd appreciate it.
>
>For reference, I am working with 12bit image data stored with unsigned
>chars. Something that could do real-time manipulations directly on this
>original data would be nice. My company used Sun's XIL in the past, but
>this library is no longer supported.

You might want to take a look at the wx-dev list, where this issue
is being discussed. There is work being done on a wxRawBitmap class
for faster blitting (however this may not necessarily help if you're
having to convert from wxImage).

Regards,

Julian
=========================================================================
Julian Smart mailto:julian...@btopenworld.com
3 Water Street, Stamford, http://www.anthemion.co.uk
Lincs, U.K., PE9 2NJ +44 (0)1780 765976
StoryLines: an intuitive writing tool http://www.storylinescentral.com
HelpBlocks: easy HTML help authoring http://www.helpblocks.com
========================================================================


David Elliott

unread,
Jan 10, 2003, 2:48:33 PM1/10/03
to wx-u...@lists.wxwindows.org

On Friday, January 10, 2003, at 03:42 AM, Julian Smart wrote:

> At 17:05 09/01/2003 -0800, you wrote:
>> I'm in a similar boat. All of my code does image manipulations to a
>> wxImage object and then converts it to a wxBitmap. This is slow. I've
>> started writing some optimization routines, but I would prefer a real
>> solution. Admittedly, I haven't tried the 2.4 version, but somehow I
>> doubt much has changed to help me. If anyone can point me to an OSS
>> library for real-time image manipulation that plays well with
>> wxWindows, I'd appreciate it.
>>
>> For reference, I am working with 12bit image data stored with
>> unsigned chars. Something that could do real-time manipulations
>> directly on this original data would be nice. My company used Sun's
>> XIL in the past, but this library is no longer supported.
>
> You might want to take a look at the wx-dev list, where this issue
> is being discussed. There is work being done on a wxRawBitmap class
> for faster blitting (however this may not necessarily help if you're
> having to convert from wxImage).
>

Well, keep in mind my comment on wx-dev about where the bottlenecks
occur.

On MSW blitting often takes a considerable amount of time if Windows
(or sometimes your specific video driver) decides that you haven't
given it graphics in the format it really wants.

From what I've seen, you really want to be drawing from DIBs on MSW.
Apparently Derry Bryson has been using the new wxDIB class and agrees
with me that if you want fast drawing on MSW you need to keep your
image around as a DIB.

I'm actually considering moving AWAY from wxImage and TO something
based on ImageMagick. Realize that it really doesn't matter what
format you use. unless it IS in an acceptable format for a DIB. you
will be required to convert from your format to DIB, keep the DIB
around, and draw off of that.

In my application I have an auto-zoom feature which scales the image to
fit the window. This is the default mode, so it was important that
resizing the window not be hindered by doing all the calculations to
re-scale the image. What I found was that if I keep the entire image
as a DIB in a file mapping (which wxDIB does) then I can use normal
Win32 bitmap drawing calls to scale it on the fly. In fact, scaling a
DIB is so quick on every win32 system I've encountered (this includes
old 200 Mhz machines) that doing it EVERY time a size event is received
is not even a problem.

Of course what really helped smoothness for me was double-buffering.
Right now I simply keep an offscreen bitmap exactly the size of the
client area of the window I'm painting in. On each size event I redraw
that. On paint I directly move it from there to the window.

Actually, I wouldn't really even need to double buffer as if you think
about it I'm only adding an extra copy step by doing so, but here's a
few things. First of all, doing a straight blit from the offscreen
buffer to the window on screen can actually complete AFTER the function
returns (according to MS docs). For another thing, it means that I can
destroy the DIB when the window becomes inactive because I'll at least
still be able to draw the existing contents of the window, and it is
highly unlikely that the user is going to scroll or do something which
would cause the contents to change while the window is not active-- if
they do I can create then destroy the DIB.

Yet another point. DC scaling w/ device dependent bitmaps (not DIBs)
and odd sized-images is a toss up. On some computers it works just
fine, in fact, much faster than drawing a DIB scaled onto a DC.
However, for some stupid reason, certain Windows 2000 machines take a
major performance hit when drawing a DDB scaled onto a DC. Not all
Win2000 machines, not always even on the same machine, but if it
happens you'll know it (at least with my program) because resizing the
window will get so choppy as to be entirely unusable!

Thus, the reason I use DIBs as source material for drawing rather than
DDBs. Please note (especially to the original poster of this thread)
that there is absolutely NO advantage to using wxImage over wxImagick.
In fact, there are a number of disadvantages for an app which process
images. That is, storing image data has little to do with drawing it.
wxImage is a class intended for storing 24-bit image data only.
wxBitmap (and now wxDIB) are classes for storing image data intended
for display. I think the best solution is to convert from wxImagick to
wxDIB and use the DIB for display. As I said above, you will probably
also want to throw the DIB out (because they eat RAM) whenever you get
a chance to do so.

-Dave


Derry Bryson

unread,
Jan 10, 2003, 3:43:40 PM1/10/03
to wx-u...@lists.wxwindows.org

To clarify, what I did was modify wxBitmap in wxMSW to use DIB's rather
than DDB's when the depth is >= 16 bits. It's all transparent,
except that you can now create wxBitmaps > 16MB on Win95/98/Me. The
performance hit for using DIB's is negligible or non-existant in
my testing.

To draw, I simply select the wxBitmap into a wxMemoryDC and blit
into the paint dc (or whatever, I actually double buffer). To zoom
I set the dest DC's user scale and let the Blit handle it. Works
very nicely and is portable across platforms.

Derry

Derry Bryson

unread,
Jan 10, 2003, 3:57:38 PM1/10/03
to wx-u...@lists.wxwindows.org
Robert Wohleb wrote:
>
> I'll take a look at the dev list.
>
> I'm using Linux. My raw images are very large 12bit x-ray images. The software I am developing is used to view these images along with data overlays generated by my company's software. The basic functionality required is pan, zoom, and window/level adjustment. Currently I am experimenting with quick rendering of window/level change from an 8bit copy of the viewable area of the img, then doing a full render from the viewable area of the 12bit img when the scrollbar is released. Unfortunately, I am not seeing a huge speedup. From what I can tell, the biggest waste of time is in converting the wxImage to a wxBitmap. I have to do this for every new render. If there was some way to manipulate the wxBitmap directly it would speed things up dramatically. Any ideas?

Actually if you look at the drawing code in wxGTK, you'll find some even bigger time wasters.
When scaling, for instance, it actually converts the wxBitmap to a wxImage, does the scaling, and
converts that back to a wxBitmap to be drawn. Drawing without scaling is quite fast, however.

What is needed, I think, is a method to quickly extract and scale a portion of a wxImage (or
whatever you want to use) directly into a wxBitmap for drawing.

Regards,

Derry

Eric Kidd

unread,
Jan 10, 2003, 5:11:50 PM1/10/03
to wx-users Mailing List
On Fri, 2003-01-10 at 14:48, David Elliott wrote:
> > You might want to take a look at the wx-dev list, where this issue
> > is being discussed. There is work being done on a wxRawBitmap class
> > for faster blitting (however this may not necessarily help if you're
> > having to convert from wxImage).
> >
> Well, keep in mind my comment on wx-dev about where the bottlenecks
> occur.
>
> On MSW blitting often takes a considerable amount of time if Windows
> (or sometimes your specific video driver) decides that you haven't
> given it graphics in the format it really wants.
>
> From what I've seen, you really want to be drawing from DIBs on MSW.
> Apparently Derry Bryson has been using the new wxDIB class and agrees
> with me that if you want fast drawing on MSW you need to keep your
> image around as a DIB.

I'm using DIBs in wxRawBitmap on Windows.

If you need *super-high* blitting performance, you want to use unclipped
DirectDraw surfaces, and store your most important image data on the
video card. This also lets you synchronize with the vertical refresh to
avoid tearing. But this is a bit outside the scope of wxWindows...

Cheers,
Eric


Dominique Lacerte

unread,
Jan 10, 2003, 5:33:36 PM1/10/03
to wx-u...@lists.wxwindows.org

Hi,

This is what I'm investigating now... we'll likely use DirectDraw when we
can and fall back to using wxBitmap when it's not available. It looks like
DirectDraw will give us exactly what we want. Judging from the numerous
messages resulting from my original post BLTing bitmaps seems to be an area
of interest!

Dominique (Doc Dom) Lacerte
Best free e-book about online dating...
http://www.DocDom.com/OnlineDating/

David Elliott

unread,
Jan 12, 2003, 1:07:34 PM1/12/03
to wx-u...@lists.wxwindows.org
On Friday, January 10, 2003, at 03:43 PM, Derry Bryson wrote:

> David Elliott wrote:
>>
>> From what I've seen, you really want to be drawing from DIBs on MSW.
>> Apparently Derry Bryson has been using the new wxDIB class and agrees
>> with me that if you want fast drawing on MSW you need to keep your
>> image around as a DIB.
>>
>
> To clarify, what I did was modify wxBitmap in wxMSW to use DIB's rather
> than DDB's when the depth is >= 16 bits. It's all transparent,
> except that you can now create wxBitmaps > 16MB on Win95/98/Me. The
> performance hit for using DIB's is negligible or non-existant in
> my testing.
>

Okay.. I actually like the idea of making wxBitmap just use DIBs for
certain bitmaps. In reality, DIB /IS/ the preferred format for large
bitmaps so wxBitmap should just use it and hide the complexity entirely
from the user of not being able to make a >16MB image (except in some
cases where the phase of the moon is correct).

> To draw, I simply select the wxBitmap into a wxMemoryDC and blit
> into the paint dc (or whatever, I actually double buffer). To zoom
> I set the dest DC's user scale and let the Blit handle it. Works
> very nicely and is portable across platforms.
>

Yes, I do the same. This is the proper way to do things and it seems
the only way which works quickly on Win32. Though IIRC, DC scaling on
GTK was rather slow.

-Dave


Derry Bryson

unread,
Jan 13, 2003, 4:13:25 PM1/13/03
to wx-u...@lists.wxwindows.org
Vadim Zeitlin wrote:
>
> On Mon, 13 Jan 2003 10:49:17 -0800 Derry Bryson <dbr...@techass.com> wrote:
>
> DB> I can tell you using BitBlt() does not work when scaling in many cases on
> DB> machines I have tested with Windows 98 when using DIB's. That is the only
> DB> reason I changed it (as I explained on SourceForge).
>
> Yes, but I didn't understand it then and must admit that I still don't.
> What do you mean by "scaling"? wxDC::Blit() never does any scaling, so what
> is the problem?
>

Scaling occurs when blitting from a DC with one scaling factor set to
a DC with a different scaling factor, as it should.

> DB> Although I have not actually measured it, I haven't noticed any difference
> DB> in blitting speed using BitBlt() vs. StretchBlt(). I can, however, easily
> DB> find machines that will not blit at all except with no scaling or certain
> DB> specific scaling values when using BitBlt().
>
> I'm still confused... There is never any scaling done in wxDC::Blit(), is
> there?
>
> BTW, I do think we should have a separate Blit() overload (or maybe a
> StretchBlit()) to do the scaling.
>

Might be nice, but not necessary.

Derry

Vadim Zeitlin

unread,
Jan 13, 2003, 5:06:04 PM1/13/03
to wx-u...@lists.wxwindows.org
On Mon, 13 Jan 2003 13:13:25 -0800 Derry Bryson <dbr...@techass.com> wrote:

DB> Scaling occurs when blitting from a DC with one scaling factor set to
DB> a DC with a different scaling factor, as it should.

Can we check for this situation efficiently and only use StretchBlt() if
really needed? Or is there really no penalty with using StretchBlt()
always? I find it hard to believe but then I don't have your experience
with the subject.

Thanks,
VZ


Derry Bryson

unread,
Jan 13, 2003, 7:28:22 PM1/13/03
to wx-u...@lists.wxwindows.org

We could just compare the UserScale values of the source and dest wxDC's or
the appropriate values in the windows DC.

I think in the end it comes down to the video driver and hardware and this is
why we can see such variance in experience with speed and support. As a driver
writer I would certainly be checking for trivial cases to optimize (like blits with
no scaling and horizontal/vertical lines, etc.), but that does mean all drivers
do this. I would also expect that both BitBlt() and StretchBlt() would
end up in the same blitting code, but you never know.

Derry

Vadim Zeitlin

unread,
Jan 13, 2003, 7:49:14 PM1/13/03
to wx-u...@lists.wxwindows.org
On Mon, 13 Jan 2003 16:28:22 -0800 Derry Bryson <dbr...@techass.com> wrote:

DB> I think in the end it comes down to the video driver and hardware and this is
DB> why we can see such variance in experience with speed and support. As a driver
DB> writer I would certainly be checking for trivial cases to optimize (like blits with
DB> no scaling and horizontal/vertical lines, etc.), but that does mean all drivers
DB> do this. I would also expect that both BitBlt() and StretchBlt() would
DB> end up in the same blitting code, but you never know.

Right... Well, I guess we're going to leave this as is and wait for the
first bug report about a broken video driver for which StretchBlt() is
horribly slow -- and then we'll try to do something about it.

For now I'm just going to add a comment explaining why StretchBlt() is
used. BTW, would you (or David) have an example of video cards/drivers for
which BitBlt() is much slower than StretchBlt() or is it something really
irreproducible?

Thanks,
VZ


David Elliott

unread,
Jan 13, 2003, 8:50:09 PM1/13/03
to wx-u...@lists.wxwindows.org
On Monday, January 13, 2003, at 08:02 PM, arkanes wrote:

> Consider this the first bug report of horribly slow performance on
> certain graphics cards - on my laptop (where I develop), with some
> worthless crap S3 embedded chipset, I have the nasty lag mentioned in
> my previous posts - I know for a fact that using a true BitBlt() api
> call
> from the MFC on this same hardware does NOT lag, so I assume it's the
> StretchBlt(), although I haven't tested it.
>
What type of bitmap was selected into the source DC and what version of
windows are you running?

I'm also noticing that in my drawing code (which I haven't revisited
for a while) I do a direct call to BitBlt when copying from my
offscreen DC to the window. On other platforms I do dc.Blit(). Though
realize all of this code was written primarily with wx 2.2.9 in mind,
so the reason for using BitBlt directly may not apply to 2.4.0.

In addition, when drawing to the memory DC I select the (compatible)
offscreen bitmap into a memory DC and use StretchDIBits rather than
selecting both the offscreen bitmap and the DIB into memdcs and using
StretchBlt.

Note that I actually do NOT use DC scaling.

There is a lot of black magic going on, and to be honest, I never did
come up with good reasons. I started out with a completely reasonable
design that should have worked and it did on my system. Eventually I
found this and that problem, and eventually after much trial and error
I arrived at what I have working now.

So I may need to actually retract my statement about StretchBlt being
exactly equivalent to BitBlt if no stretching is done. To be honest
with you I can really only vaguely remember having used StretchBlt
before winding up with StretchDIBits.

In fact.. if I really think long and hard I think the main speedup with
DIBs came by using StretchDIBits in lieu of StretchBlt (or even BitBlt
on a stretched DC).

-Dave

-----

So I was writing software for Win32 and it worked okay on my computer
but not on my boss's. I tried adjusting my code every which way but it
didn't help...

bummer.

Finally I figured it out and immediately switched development to Mac
before I went completely crazy.

I'm Dave Elliott and I'm a programmer.


Dominique Lacerte

unread,
Jan 13, 2003, 9:30:23 PM1/13/03
to wx-u...@lists.wxwindows.org

Hi,

What you say makes sense and follows the pattern of other objects such as
wxString but I did not see this behavior. When I changed bmp2 it also
changed bmp1.

Dominique

Derry Bryson

unread,
Jan 13, 2003, 9:26:05 PM1/13/03
to wx-u...@lists.wxwindows.org
David Elliott wrote:
>
>
> In fact.. if I really think long and hard I think the main speedup with
> DIBs came by using StretchDIBits in lieu of StretchBlt (or even BitBlt
> on a stretched DC).
>

Maybe that's a reason to add a StretchBlit() method to wxDC() as Vadim
suggested.

Derry

Derry Bryson

unread,
Jan 13, 2003, 10:49:50 PM1/13/03
to wx-u...@lists.wxwindows.org
Vaclav Slavik wrote:
>
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Dominique Lacerte wrote:
> > It is my understanding that with wxWindows 2.2.7 (and I doubt this
> > has changed) the result of this operation is that bmp1 and bmp2
> > point to the same bitmap.
>
> ...but as soon as you modify either bmp1 or bmp2, deep copy is made.
> If it does not, it's a bug.
>

Actually, I think there is a bug here. I don't see it copying
it if you select a bmp into memory DC and draw on it.

Derry

Vadim Zeitlin

unread,
Jan 14, 2003, 11:20:11 AM1/14/03
to wx-u...@lists.wxwindows.org
[please set your word wrap to 75 or less, thank you]

On Mon, 13 Jan 2003 17:18:48 -0800 Robert Wohleb <rwo...@r2tech.com> wrote:

RW> This discussion has been MFC related, but I was wondering if the
RW> associated calls on the GTK side are hardware accelerated. Are bitmaps
RW> kept in video memory when possible?

I don't think GTK+ (or rather GDK) does anything special to optimize the
bitmaps drawing but you'd expect the X11 server to do something about this.
So ultimately it should depend on the driver, but this is just pure
speculation at that point.

Regards,
VZ


David Elliott

unread,
Jan 14, 2003, 12:34:48 PM1/14/03
to wx-u...@lists.wxwindows.org
On Tuesday, January 14, 2003, at 07:11 AM, arkanes wrote:

> This is on WinXP - I'm just using a standard wxBitmap, drawing into
> that with a wxMemoryDC, and then blitting that into the wxPaintDC.
>
> Using wxWindows 2.4, I'll check it against 2.2.9 today (need to
> re-download and compile)
>
> I'm not doing any scaling or anything, so I have no need for
> StretchBlt() - I'll try making the direct call to BitBlt().
>
> I'm not especially worried about cross-platform stuff (I just prefer
> wxWindows to the MFC), so I can always drop this specific code back
> down the the API level, but I'd prefer something more elegant.
>
I think one major problem is there needs to be a way to create a bitmap
compatible with some DC other than 1) using win32 api functions (as I
do) or 2) making wxWindows convert it "on the fly" (and thus take up
precious extra time).

I think if you create a compatible bitmap (which you can even wrap in a
wxBitmap object) and do a blit directly from that to the window
performance should be great.

-Dave


Derry Bryson

unread,
Jan 14, 2003, 1:32:39 PM1/14/03
to wx-u...@lists.wxwindows.org
David Elliott wrote:
>
> On Tuesday, January 14, 2003, at 07:11 AM, arkanes wrote:
>
> > This is on WinXP - I'm just using a standard wxBitmap, drawing into
> > that with a wxMemoryDC, and then blitting that into the wxPaintDC.
> >
> > Using wxWindows 2.4, I'll check it against 2.2.9 today (need to
> > re-download and compile)
> >
> > I'm not doing any scaling or anything, so I have no need for
> > StretchBlt() - I'll try making the direct call to BitBlt().
> >
> > I'm not especially worried about cross-platform stuff (I just prefer
> > wxWindows to the MFC), so I can always drop this specific code back
> > down the the API level, but I'd prefer something more elegant.
> >
> I think one major problem is there needs to be a way to create a bitmap
> compatible with some DC other than 1) using win32 api functions (as I
> do) or 2) making wxWindows convert it "on the fly" (and thus take up
> precious extra time).
>

I confused Dave. Earlier you said you have seen blitting from compatible
bitmaps (DDB's) be very slow, whereas DIB's are always fast. But now you
are suggesting using compatible bitmaps instead of DIB's?

Besides, before my patch (and even now if wxUSE_DIB_FOR_BITMAP is turned
off) you will get a bitmap compatible with the screen (which is what you
want, right?).

Derry

Derry Bryson

unread,
Jan 14, 2003, 1:50:35 PM1/14/03
to wx-u...@lists.wxwindows.org
David Elliott wrote:
> Eh?
>
> I would say it's more a reason to properly implement DrawBitmap for
> drawing a DIB onto a DC. The patch would be rather simple actually.
> Basically, in the event that the wxBitmap is actually a DIB, then use
> StretchDIBits to draw it-- or in this case SetDIBitsToDevice would work
> since scaling is already applied to the DC.
>
> If that were done then drawing DIBs would be a hell of a lot quicker.
>

I'll take a look at doing that, however I notice that neither StretchDIBits()
nor SetDIBitsToDevice() say anything about handling dc scaling which may be
why it is implemented as it is.

Derry

David Elliott

unread,
Jan 14, 2003, 2:35:34 PM1/14/03
to wx-u...@lists.wxwindows.org

:-)

Yes, it IS indeed confusing. There are times when you want a DIB and
times when you want a compatible bitmap.

Unfortunately, wxWindows does NOT have an API for creating a truly
compatible bitmap (with CreateCompatibleBitmap). That is, you cannot
in ANY way get it to create a bitmap compatible with a given DC,
because there are no functions that even take a wxDC.

Trust me, when blitting (WITHOUT stretching) directly from one DC to
another, compatible is going to be fastest no matter what.

IF stretching is involved I have found speed to be consistent and
reasonable when drawing from a DIB. When drawing from a compatible
bitmap, speed can vary quite greatly.

So, essentially I can say that the wxWindows API for drawing images is
so poor that it's not even possible to draw an image in any reasonable
amount of time using it.

So, how to fix it:

Simple really, add a constructor for creating wxBitmap given a wxDC.
Why this hasn't been done yet is way beyond me. I am pretty certain I
proposed this a long time ago, and I'm definitely certain I sent the
code for my bitmap/drawing stuff which included a
CreateCompatibleBitmap function.

However, I am grateful that wxBitmap now does use DIBs by default, as
that is what you want to do UNLESS you have an actual DC which you can
use to create a compatible bitmap. Doesn't X11 work the same way?
I.e. you don't know what kind of bitmap is compatible with the screen
until you have a graphics context for the specific window you are
trying to draw upon? Especially because with X11 it is HIGHLY possible
that certain windows will have different capabilities. The best
example is menus and other temporary windows with some toolkits will
(on workstations that support it) use an alternate visual (typically
8-bit palette) to draw the menu overtop other windows without at all
disturbing them. SGIs typically can do this.

Anyway.. how about we get some of this stuff working in HEAD and if
possible we'll backport a new wxBitmap constructor to 2.4.1 since IMHO
wxBitmap is rather useless without it.

The idea is that whenever you are stretching you want to have the
source as a DIB. However, when you are NOT stretching and are simply
flipping the offscreen buffer onto the screen, not using a compatible
bitmap kind of defeats the whole purpose.

Do you understand now? Or am I still unable to explain this properly?
Maybe I should stop talking and show you some code. In fact, I think I
can squeeze a few changes into my program in time for the next release
so maybe I can rework my code to use normal wxWindows functions and
then release some sample code to illustrate how things should be done.

One more thing. On non-MSW platforms scaling is done by converting
wxBitmap to wxImage and back. I think we should have a "DIB
equivalent" for non-MSW platforms. The reason for this is that on MSW
you WANT to draw from a DIB (wxBitmap) and thus your code will be
written using wxBitmap as the source image. However, on other
platforms you'd be better off using wxImage and scaling it yourself!
Thus, in order to keep the current API it would make sense to allow
wxBitmap to encapsulate the wxImage data so that if scaling needs to be
applied it won't cost the conversion to wxImage. Of course before the
REAL drawing is done it would need to be converted to a real wxBitmap
(but it already has to do that anyway).

-Dave


Derry Bryson

unread,
Jan 14, 2003, 4:26:08 PM1/14/03
to wx-u...@lists.wxwindows.org
David Elliott wrote:
>
> On Tuesday, January 14, 2003, at 01:32 PM, Derry Bryson wrote:
>
> >
> > I confused Dave. Earlier you said you have seen blitting from
> > compatible
> > bitmaps (DDB's) be very slow, whereas DIB's are always fast. But now
> > you
> > are suggesting using compatible bitmaps instead of DIB's?
> >
> > Besides, before my patch (and even now if wxUSE_DIB_FOR_BITMAP is
> > turned
> > off) you will get a bitmap compatible with the screen (which is what
> > you
> > want, right?).
> >
> :-)
>
> Yes, it IS indeed confusing. There are times when you want a DIB and
> times when you want a compatible bitmap.
>
> Unfortunately, wxWindows does NOT have an API for creating a truly
> compatible bitmap (with CreateCompatibleBitmap). That is, you cannot
> in ANY way get it to create a bitmap compatible with a given DC,
> because there are no functions that even take a wxDC.
>

This is true to an extent, but really what you want is a bitmap
compatible with the screen. There are three ways currently to get
a bitmap compatible with the screen: 1) create a wxBitmap with
a depth of 0, 2) create a bitmap from a wxIcon, and 3) create a
bitmap from a wxImage.

> Trust me, when blitting (WITHOUT stretching) directly from one DC to
> another, compatible is going to be fastest no matter what.
>
> IF stretching is involved I have found speed to be consistent and
> reasonable when drawing from a DIB. When drawing from a compatible
> bitmap, speed can vary quite greatly.
>
> So, essentially I can say that the wxWindows API for drawing images is
> so poor that it's not even possible to draw an image in any reasonable
> amount of time using it.
>

I wouldn't go quite that far.

Okay, I got it now. If you need to scale, then you want DIB's otherwise
you want DDB's.

How about this: I'll do what I originally planned which was to modify wxBitmap
on wxMSW to allow one to select whether DDB's or DIB's should be created except
that it will always create a DIB if the bitmap would be >16MB on OS's < NT 4.0.
The default behavior will to create DDB's if possible. In addition, I will
fix DrawBitmap() to use SetDIBitsToDevice() or StretchDIBits() if drawing
from a DIB.

> One more thing. On non-MSW platforms scaling is done by converting
> wxBitmap to wxImage and back. I think we should have a "DIB
> equivalent" for non-MSW platforms. The reason for this is that on MSW
> you WANT to draw from a DIB (wxBitmap) and thus your code will be
> written using wxBitmap as the source image. However, on other
> platforms you'd be better off using wxImage and scaling it yourself!
> Thus, in order to keep the current API it would make sense to allow
> wxBitmap to encapsulate the wxImage data so that if scaling needs to be
> applied it won't cost the conversion to wxImage. Of course before the
> REAL drawing is done it would need to be converted to a real wxBitmap
> (but it already has to do that anyway).
>

I don't think I'm up for this one right now.

I am looking at going a different direction. I think the solution may
be to maintain a list of wxBitmap's (DDB's on wxMSW) each of
which is a small portion of the image that are updated as needed (i.e.
when the associated portion of the image changes or the image is zoomed,
etc.) rather than one large wxBitmap for the whole image. These bitmaps
would be prescaled so it's just a direct blit. I think this would
end up much faster and more memory efficient because you would only
need to have bitmaps for the visible portion of the image (maybe some
sort of cache to keep the number of bitmaps and memory use in check).
In addition, I think that something like this is the only way to achieve
reasonable speed if updating small portions of the image, like when
drawing lines or text. Looks to me like Photoshop and Gimp are doing
something like this. What I wouldn't give to get a look at the source
for Photoshop, it is so fast!

Derry

Derry Bryson

unread,
Jan 14, 2003, 10:34:23 PM1/14/03
to wx-u...@lists.wxwindows.org
David Elliott wrote:
>
> > How about this: I'll do what I originally planned which was to modify
> > wxBitmap
> > on wxMSW to allow one to select whether DDB's or DIB's should be
> > created except
> > that it will always create a DIB if the bitmap would be >16MB on OS's
> > < NT 4.0.
> > The default behavior will to create DDB's if possible. In addition, I
> > will
> > fix DrawBitmap() to use SetDIBitsToDevice() or StretchDIBits() if
> > drawing
> > from a DIB.
> >
> Allowing one to select DDB or DIB is going in the right direction.
> Honestly, I recommend adding a parameter taking a wxDC with a default
> value of wxScreenDC(). To create a DIB, one could use a null DC (i.e.
> not a real one). The reason for this is one of backward compatibility.
> Previously when a depth of 0 was asked for it meant Compatible. If
> the default is wxScreenDC() this will hold true. However, if a null DC
> is used, it would create a DIB.
>
> However, with that said I suggest we make the code that copies from an
> image by default use DIBs (i.e. the DC parameter would be a null DC)
> but of course allow any DC (including the screen) to be specified to
> allow a compatible bitmap to be created. The reasoning here is that
> I'll bet 99% of people want to convert a wxImage to a wxBitmap and use
> dc.DrawBitmap() to draw it. It is very likely scaling the image will
> be required (because the eventual DC can have a scaling factor).
>
> Note that this WILL change the default behavior from DDB to DIB, but 1)
> your dib patch is currently doing it anyway, and 2) it doesn't "break"
> code (even binary) to do it.
>
> What I am suggesting is that for HEAD we add the wxDC& parameter to the
> bitmap constructor (taking w,h,d) and to the constructor (well,
> conversion function) from wxImage, with the default parameters as I
> have specified above. In the 2.4 series we should be able to do the
> same thing but without specifying a default value for the new
> parameter. Then the old function turns into a simple call to the new
> function with the default paramter (duh). AFAIK that won't break
> binary compatiblity.
>
> In fact, the only thing that will be different is the implementation.
> Where before you got a DDB, you will now get a DIB. Like I said above,
> for 99% of cases that is probably desirable. For the cases where a
> compatible bitmap really was expected it really doesn't matter as there
> will only be a minor slowdown when drawing. And in any case I'll bet
> almost anyone trying to draw images with any reasonable speed already
> has hacks like you and I anyway and will probably not really be
> affected by this.
>
> Does all that sound good?
>

Sounds okay to me and I'm not against changing the API for 2.5, but even
the DIB stuff will break binary compatiblity for 2.4.

I have already implemented what I said above (and was about to submit a
patch), but could change it to automatically create DIB's for bitmaps
created from wxImages and submit a patch tomorrow. I don't understand
what other DC you might want to create compatible bitmaps besides the
screen, but we could do that after.

> >> One more thing. On non-MSW platforms scaling is done by converting
> >> wxBitmap to wxImage and back. I think we should have a "DIB
> >> equivalent" for non-MSW platforms. The reason for this is that on MSW
> >> you WANT to draw from a DIB (wxBitmap) and thus your code will be
> >> written using wxBitmap as the source image. However, on other
> >> platforms you'd be better off using wxImage and scaling it yourself!
> >> Thus, in order to keep the current API it would make sense to allow
> >> wxBitmap to encapsulate the wxImage data so that if scaling needs to
> >> be
> >> applied it won't cost the conversion to wxImage. Of course before the
> >> REAL drawing is done it would need to be converted to a real wxBitmap
> >> (but it already has to do that anyway).
> >>
> >
> > I don't think I'm up for this one right now.
> >

> Okay, it doesn't HAVE to be done.. it is an implementation detail. It
> could be done for the same reason that DIBs should be used on Win32--
> the DC probably has a scaling factor applied which is going to slow
> things down anyway.


>
> > I am looking at going a different direction. I think the solution may
> > be to maintain a list of wxBitmap's (DDB's on wxMSW) each of
> > which is a small portion of the image that are updated as needed (i.e.
> > when the associated portion of the image changes or the image is
> > zoomed,
> > etc.) rather than one large wxBitmap for the whole image. These
> > bitmaps
> > would be prescaled so it's just a direct blit. I think this would
> > end up much faster and more memory efficient because you would only
> > need to have bitmaps for the visible portion of the image (maybe some
> > sort of cache to keep the number of bitmaps and memory use in check).
> > In addition, I think that something like this is the only way to
> > achieve
> > reasonable speed if updating small portions of the image, like when
> > drawing lines or text. Looks to me like Photoshop and Gimp are doing
> > something like this. What I wouldn't give to get a look at the source
> > for Photoshop, it is so fast!
> >

> Okay, well, while taking frames out of the image is nice and all (and
> believe me, I certainly toyed with the idea) I don't think wxBitmap is
> the place for this. Maybe much later, but to be honest with you, I'm
> looking for solutions here which are not radical shifts in thinking,
> but are minor improvements to get behavior that most people already
> expect (as judging by personal experience and also reading the mailing
> lists).
>

I agree, wxBitmap is not the place for this and I never said it was. I am
not talking about anything to go into wxWindows. I am saying that I will
probably be going in that direction. All that will be required of
wxWindows is a fast unscaled blit of a wxBitmap.

> That is to say, I am looking for stuff that can be applied to 2.4,
> because to be honest with you I consider the current behavior to be
> completely broken and I'll bet most users will agree with me.
>

I don't think the current wxGTK behavior is broken, just slow. It was
a way to support the required behavior without writing a whole
new bitmap class and adding support for it into the various
DC classes. I think this is bigger than you think it is. You will
have to implement drawing and blitting, etc.

Regards,

Derry

David Elliott

unread,
Jan 14, 2003, 11:14:57 PM1/14/03
to wx-u...@lists.wxwindows.org

On Tuesday, January 14, 2003, at 05:42 PM, Vadim Zeitlin wrote:

> On Tue, 14 Jan 2003 13:26:08 -0800 Derry Bryson <dbr...@techass.com>
> wrote:
>
> DB> > Unfortunately, wxWindows does NOT have an API for creating a
> truly
> DB> > compatible bitmap (with CreateCompatibleBitmap). That is, you
> cannot
> DB> > in ANY way get it to create a bitmap compatible with a given DC,
>
> Does it really matter while we're talking about drawing the bitmaps on
> screen? I.e. aren't all wxWindow/Client/Screen/PaintDC compatible
> between
> each other anyhow? This could be a problem for the printing but the
> drawing
> speed hardly matters there (hmm, 30 fps per page?)
>
Where did you get printing from?

For printers you want (have?) to use DIBs I don't think you can
CreateCompatibleBitmap on a print DC.

I am suggesting being able to pass along a wxClientDC or something such
that it is actually possible to create a bitmap compatible for a window
(which COULD have a visual different from the screen). Yes, I realize
that in practice this is EXTREMELY unlikely on Win32 (though possible)
and usually unlike in X, but quite possible and there are (as I
mentioned in another mail) implementations of this.

My thoughts are that if we need a flag (at least a bool) to specify
whether a DIB or DDB should be created, then we ought to accept a
reference to some wxDC instead (which if invalid means to create a
DIB). This will also allow CreateCompatibleBitmap to be used as
intended, allowing different visuals for different windows.

> DB> This is true to an extent, but really what you want is a bitmap
> DB> compatible with the screen.
>
> At least this is what _I_ want -- unless you can tell me why I don't
> ;-)
>
See above, what you REALLY want os a bitmap compatible with the window.
Typically a bitmap compatible with the screen suffices, though not
always.

> DB> There are three ways currently to get a bitmap compatible with the
> DB> screen: 1) create a wxBitmap with a depth of 0
>
> The most natural and almost "default" method.
>
True.. for 99% of cases this is what you want. Indeed, I erred in my
other mail. even with the DIB patch a depth of 0 creates a bitmap
compatible with the screen (d'oh).

> DB> Okay, I got it now. If you need to scale, then you want DIB's
> otherwise
> DB> you want DDB's.
>
> Ok, it starts making sense to me as well. It is quite logical, too,
> as you
> can imagine that without scaling it's just a matter of a memmove()
> while
> with scaling you need to process the image and this should be faster
> with a
> DIB if this is what Windows uses internally anyhow.
>
EXACTLY! It's probably the same thing as how we convert back to
wxImage to do the scaling.

> DB> How about this: I'll do what I originally planned which was to
> modify
> DB> wxBitmap on wxMSW to allow one to select whether DDB's or DIB's
> should
> DB> be created except that it will always create a DIB if the bitmap
> would
> DB> be >16MB on OS's < NT 4.0. The default behavior will to create
> DDB's
> DB> if possible.
>
> Isn't this already done?
>
No, and I completely disagree with this. When converting from an image
DIB is the appropriate format for wxBitmap.

> DB> In addition, I will fix DrawBitmap() to use
> DB> SetDIBitsToDevice() or StretchDIBits() if drawing from a DIB.
>
> Yes, as I said in my comment to your patch, I believe (no time to test
> unfortunately) that this should be worth it.
>
Yes, there is absolutely no question that DrawBitmap needs to use the
appropriate functions for handling DIBS rather than selecting a DIB
into a DC as a source image (this is a quite broken idea for a DIB
really, even if MS allows it).

> DB> > One more thing. On non-MSW platforms scaling is done by
> converting
> DB> > wxBitmap to wxImage and back. I think we should have a "DIB
> DB> > equivalent" for non-MSW platforms. The reason for this is that
> on MSW
> DB> > you WANT to draw from a DIB (wxBitmap) and thus your code will be
> DB> > written using wxBitmap as the source image. However, on other
> DB> > platforms you'd be better off using wxImage and scaling it
> yourself!
> DB> > Thus, in order to keep the current API it would make sense to
> allow
> DB> > wxBitmap to encapsulate the wxImage data so that if scaling
> needs to be
> DB> > applied it won't cost the conversion to wxImage. Of course
> before the
> DB> > REAL drawing is done it would need to be converted to a real
> wxBitmap
> DB> > (but it already has to do that anyway).
> DB>
> DB> I don't think I'm up for this one right now.
>
> This is much closer to what Eric is doing. It's a bit confusing to
> have 2
> or 3 parallel threads discussing almost the same thing but not
> quite... But
> if we could unify (and implement :-) the ideas from all of them, it
> could
> be very interesting.
>
Believe me, I've been following most of it. This is kind of an
offshoot of that work. What I am trying to do here is make the
existing implementation work as one would expect.

> DB> What I wouldn't give to get a look at the source for Photoshop, it
> is
> DB> so fast!
>
> Exactly because of the latter I don't think you (or me or anyone else)
> would be able to make much out of its source :-/
>
>
Well, it's not necessarily true that the code for Photoshop is hard to
comprehend. Though I'm with you, it's highly likely.

Okay.. to sum this up.

Apparently the only real objection I have to what is in HEAD right now
is that IMHO there ought to be a way to convert a wxImage to a
compatible bitmap. However, I do NOT think wxWindows should try to
automatically decide this. I think it should just use a DIB unless
(through some parameter yet to be determined, I prefer the DC idea) the
user really wants a compatible bitmap.

However, I honestly think now that I think about it that what we have
in HEAD right now ought to be safe to move into 2.4. I'm gonna try
modifying my app to use this method, maybe tomorrow.

-Dave


Derry Bryson

unread,
Jan 15, 2003, 1:00:30 AM1/15/03
to wx-u...@lists.wxwindows.org
David Elliott wrote:

>
> On Tuesday, January 14, 2003, at 10:34 PM, Derry Bryson wrote:
> > David Elliott wrote:
> >>
> >> Note that this WILL change the default behavior from DDB to DIB, but
> >> 1)
> >> your dib patch is currently doing it anyway, and 2) it doesn't "break"
> >> code (even binary) to do it.
> >
> [...]

> > Sounds okay to me and I'm not against changing the API for 2.5, but
> > even
> > the DIB stuff will break binary compatiblity for 2.4.
> >
> Umm.. how? It doesn't define new or change existing virtual methods
> and it maintains the same class interface.
>
> .... SHIT... forgot about that new m_hFileMap. If that's the case
> though it WOULD be possible to use a wxHashMap to associate that with a
> particular wxBitmap rather than storing it as a class member (which
> breaks binary compatibility).
>
> Is there any other reason to think binary compatibility cannot be
> maintained?
>

Not that I can see.

> [...]


> > I have already implemented what I said above (and was about to submit a
> > patch), but could change it to automatically create DIB's for bitmaps
> > created from wxImages and submit a patch tomorrow. I don't understand
> > what other DC you might want to create compatible bitmaps besides the
> > screen, but we could do that after.
> >

> I'm cool with whatever you come up with so long as by default a DIB
> will ALWAYS be created when converting from a wxImage unless the user
> has specifically requested otherwise. If you want a bool, so be it,
> though I am trying to consider the (real) possibility that a GUI can
> have one or more screens with one or more visual types (perhaps even
> more than one visual type on only one screen).
>

I see your point.

I will have wxBitmap::CreateFromImage() default to DIB when
depth = -1 and add the following constructors:

wxBitmap::wxBitmap(int w, int h, const wxDC& dc)
wxBitmap::wxBitmap(const wxImage& image, const wxDC& dc)

which will create bitmaps compatible with the dc. You can create
DDB's from wxImage's using the new constructor using wxScreenDC.
These constructors can then be added to other ports as implemented.

How's this sound?

> [...]


> >
> > I don't think the current wxGTK behavior is broken, just slow. It was
> > a way to support the required behavior without writing a whole
> > new bitmap class and adding support for it into the various
> > DC classes. I think this is bigger than you think it is. You will
> > have to implement drawing and blitting, etc.
> >

> Not necessarily. What I can do is make the conversion from wxImage to
> wxBitmap "lazy" for wxGTK.
>
> That is, converting to a bitmap will not actually do the conversion
> until something (e.g. selecting it into a DC) causes the conversion to
> occur. If nothing occurs that causes a real bitmap to be required
> (i.e. the image is merely used in a call to DrawBitmap) then I think
> we'd see a BIG speed improvement on wxGTK.
>

Clever, it just might work.

Derry

Reply all
Reply to author
Forward
0 new messages