PDA

View Full Version : PixelBuffer?



ArtHome
03-17-2014, 07:48 PM
Hi!

I need a fastest way to display visual state of some matrix. One cell from the matrix is the one point on the window.

Using PixelBuffer example I wrote a working prototype, but it so slow and I doubt that it is effective.

So:

int App::start(const std::vector<std::string> &args)
{
clan::DisplayWindowDescription win_desc;
pMainWindow = new clan::DisplayWindow(win_desc);
pCanvas = new clan::Canvas (*pMainWindow);

pPixelBuf = new clan::PixelBuffer(100, 100, clan::tf_rgba8);

...
while(true){

pMainWindow->flip();
pCanvas->clear();

clan::ubyte8 *pixels = (clan::ubyte8 *) pPixelBuf->get_data();

for (int i = 0; i < 10000; ++i) {

clan::Colorf color = ...

*(pixels++) = clan::ubyte8(color.get_red() * 255);
*(pixels++) = clan::ubyte8(color.get_green() * 255);
*(pixels++) = clan::ubyte8(color.get_blue() * 255);
*(pixels++) = illuminated ? 255 : clan::ubyte8(color.get_alpha() * 255);
}

clan::Image image(*pCanvas, *pPixelBuf, clan::Rect(0, 0, pPixelBuf->get_size()));
image.draw(*pCanvas, 0, 0);
...
}
}



As can be seen above:
1. Create PixelBuffer and get pointer to pixels from it. Modify pixels.
2. Create an Image for PixelBuffer.
3. Draw image on window's canvas.
4. Need to call window's flip().

It's ok or something wrong? I don't understand the purpose of lock()/unlock()...
Sorry for my poor English :)

rombust
03-18-2014, 07:21 AM
That will be slow.

If you think what is happening in these lines....
clan::Image image(*pCanvas, *pPixelBuf, clan::Rect(0, 0, pPixelBuf->get_size()));
image.draw(*pCanvas, 0, 0);

The image is being created from raw pixelbuffer pixels, then drawn in the same frame.
Between these 2 lines, the pixelbuffer is being uploaded to the GPU. This is a relatively slow process, and has to wait to complete before drawing starts.

It is faster to have 2 image buffers where the image to be uploaded to is drawn on the next frame. (known as double buffering)

However, if I remember correctly a "fix" was added to clanD3D target to always wait for upload to complete. So double buffering probably will only work fast for clanGL. That "fix" should not be there, so pixelbuffers can be uploaded in parallel, but we would require an alternative method to determine if upload is complete before attempting to draw with it. (OpenGL does this automatically)

The alternative is to use TransferTexture objects. This method "should" work on clanD3D and clanGL

"class CL_API_DISPLAY TransferTexture : public PixelBuffer"

You can think of this like creating memory on the graphics card (although not always strictly true)

Again, you need to double buffer the TransferTextures and Texture2D's.

"lock" is required to obtain permission to write to the memory (and internally it requests the memory address to write it)

See Examples/Display_Render/PixelBuffer. It uses both methods

One final thing, it may also be faster creating the pixelbuffer on a second thread. (See Examples/Display/Thread).

Warning: I might be wrong about a lot of this, it's been a couple of years since I used it :)

Judas
03-18-2014, 08:27 AM
Rombust: Both Direct3D and OpenGL blocks when uploading with a system memory pixel buffer unless a GPU buffer object is being used. The main difference between the two API's is that Direct3D requires that the usage of a buffer object is explicitly declared at creation time, while OpenGL uses hints that the application does not have to follow. The transfer buffer types exists as a way to declare which usage you intend for the buffer object.

ArtHome: If you want to maximize speed, make sure that the GPU objects are only created once. Then upload to those objects each frame. For maximum speed the best approach is to have two textures (Image objects) so one can be used for rendering while the application is uploading to the other one.

You only have to lock a pixel buffer object if it is placed on the GPU (which is only the case if you use the constructers taking a GC/Canvas argument). Otherwise the lock/unlock functions does nothing. Note that if you do place it on the GPU (best for performance), then you must call lock() to obtain a pointer to the buffer and unlock to release it. If the buffer object is still being used by the GPU when lock() is called, then it will block until the GPU finishes.

ArtHome
03-18-2014, 03:31 PM
I can not understand how double buffering will speedup program? To eliminate flicker there was a DisplayWindow->flip()
Or is it the case of a dual-core processor and diversity modification buffer and display it on two threads?

rombust
03-18-2014, 04:15 PM
Read "Double buffer" as meaning using "two buffers"

Wikipedia definition is not helpful :) "Description" is fine, however "Double buffering in computer graphics" refers to common usage in the 1990's not in 2014

The CPU and GPU cannot read/write to the same memory simultaneously.

So the 2 options are:

1) CPU Create Object ---> CPU Upload Object to GPU --> GPU Draw Object

2) CPU Create Object A --> CPU Upload Object A to GPU
GPU Draw Object B
Swap A and B

1 is single buffered, GPU waiting for CPU to complete
2 is double buffered, GPU and CPU running at the same time.

ArtHome
03-18-2014, 05:38 PM
refers to common usage in the 1990's not in 2014

The CPU and GPU cannot read/write to the same memory simultaneously.

I understand now thanks :)

ArtHome
03-19-2014, 08:56 AM
A drawing directly on the window canvas is slower than using double-buffering technique?