Supporting multiple pixel formats
I need to write some code which will operate on a number of pixel formats (eg A8R8G8B8, R8G8B8, R5G6B6, and even potentially floating point formats).
Ideally I would like to not have to write each function for each format since that is a massive amount of near identical code.
The only thing I could think of is some kind of interface letting it deal with pixel format conversions eg:
class IBitmap
{
public:
virtual unsigned getPixel(unsigned x, unsigned y)const=0;
virtual void setPixel(unsigned x, unsigned y, unsigned argb)=0;
virtual unsigned getWidth()const=0;
virtual unsigned getHeight()const=0;
};
However calling a virtual function for every get or set pixel operation is hardly fast, since not only is there the extra overhead of a virtual call, but it also far more importan开发者_如何学Ctly prevents inlining for something which is just a few instructions long.
Are there any other options which would allow for me to support all these formats efficiently? Generally speaking my code is likely to only operate on a small portion of the bitmap, and needs read/write access in many cases (blending).
Consider using templates. This will allow you to write generically where possible and take the hit for specialising the code at compile time
Sometimes known as static polymorphism. http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern
On modern processors virtual functions are pretty darn fast, so I'm not sure I'd reject them out of hand. Run a timing test or two to be sure. Virtual functions give you runtime polymorphism, which allows you to conceivably write (or generate at compile time) less code. The static polymorphism represented by templates will probably cause the compiler to generate that massive amount of code that you're trying to avoid.
To avoid having to write loads of formats, write a Color class or similar that always stores a particular format (eg. A8R8G8B8 or A32R32G32B32F) then have methods on that class to retrieve in different formats, eg. get(FORMAT_R5G6B6)
or similar. All your methods can then deal with that class. Whenever possible, convert the color only once (eg. when drawing a rect, convert the rect color to the destination format then write that to all the pixels - don't convert it for every pixel!).
Avoid having a SetPixel/GetPixel method at all. It cannot be done efficiently, especially if you're doing colour conversions on the fly, and especially not if the optimizer decides not to inline the calls. You'd do better to expose memory buffers directly, and trust that the caller will correctly use the memory. That's how every other API I've used before does it.
(This is my new answer because after extensive research, I concluded that Adobe GIL is not suitable for this purpose.)
I would highly recommend the architecture and interface design of the Windows Imaging Component.
What I mean is:
- Their interface is what I recommend. Not the implementation.
- Everyone can implement something similar. In fact, the Mono Project (Wine) contains a partial implementation of the WIC.
- Instead of the producer-consumer model, WIC uses a pipeline-storage model.
- A read-only bitmap implements IWICBitmapSource interface
- There are only 5 member methods.
- A writable bitmap implements IWICBitmap interface and provides direct memory read/write access to the pixel data.
- There are only 3 additional member methods, on top of IWICBitmapSource.
- Being a "storage" class means that this class does not depend on any other bitmap instances when producing pixel values.
- A read-only bitmap implements IWICBitmapSource interface
The overhead of converting everything to a single common format, then converting back after the operation, may be less than you think. If you can limit the number of pixels that are converted at a time, say to a single row, the intermediate results may remain in cache for the entire operation. I've actually seen a case where the end-to-end times were faster using this approach, although it involved one-bit pixels that are inherently difficult to work with when still packed.
You are right to be wary of a pixel-level function call. I've never seen a case where a pixel function didn't make the processing unacceptably slow.
精彩评论