
Originally Posted by
rombust
I cannot remember how it works (I wrote this example many years ago).
iirc, this is how it "should" work.
1. The thread renders the fractal
2. The main thread upload the pixelbuffer to a texture.
Ok, I see the beginning uploading at code:
Code:
pixelbuffer_write->unlock();
texture_write->set_subimage(canvas, 0, 0, *pixelbuffer_write, pixelbuffer_write->get_size());
Is really uploading `pixelbuffer` to the `texture_write` does not finished after returns from `set_subimage()` and is it still going on for some time? Or this code does only some initializing and does not start transfer data?

Originally Posted by
rombust
The texture is buffered to prevent pipeline stalls. I.E. the GPU driver would stall if trying to display and upload the texture at the same time.
And is at what point the data transmission begins from the texture to the GPU - at the call `clan::Image image(*texture...); image.draw()`?
If pixelbuf starts transfer to the GPU at call `texture_write->set_subimage()` and finished after returns from `image.draw()` I understand the logic of the example. But it is really hard for noob like me 
The part of code for your convenience with hope for further clarifications 
Code:
bool App::update()
{
... skip the code related to the fractal
// If the pixel buffer was uploaded on the last frame, double buffer it
if (texture_write_active)
{
texture_write_active = false;
if (texture_buffers_offset == 0)
{
texture_buffers_offset = 1;
texture_write = &texture_buffers[1];
texture_completed = &texture_buffers[0];
}
else
{
texture_buffers_offset = 0;
texture_write = &texture_buffers[0];
texture_completed = &texture_buffers[1];
}
}
// Wait for pixel buffer completion
std::unique_lock<std::mutex> lock(thread_mutex);
if (thread_complete_flag == true)
{
thread_complete_flag = false;
pixelbuffer_write->unlock();
texture_write->set_subimage(canvas, 0, 0, *pixelbuffer_write, pixelbuffer_write->get_size());
texture_write_active = true;
// Note the worker thread will start on the other pixelbuffer straight away, in the next "if" statement
}
// Start a new transfer when required
if ((thread_start_flag == false))
{
worker_thread_framerate_counter.frame_shown();
// Swap the pixelbuffer's
if (pixel_buffers_offset == 0)
{
pixel_buffers_offset = 1;
pixelbuffer_write = &pixel_buffers[1];
pixelbuffer_completed = &pixel_buffers[0];
}
else
{
pixel_buffers_offset = 0;
pixelbuffer_write = &pixel_buffers[0];
pixelbuffer_completed = &pixel_buffers[1];
}
pixelbuffer_write->lock(canvas, clan::access_write_only);
dest_pixels = (unsigned char *) pixelbuffer_write->get_data();
thread_start_flag = true;
thread_complete_flag = false;
// Adjust the mandelbrot scale
float mandelbrot_time_delta_ms = (float) (current_time - last_mandelbrot_time);
last_mandelbrot_time = current_time;
scale -= scale * mandelbrot_time_delta_ms / 1000.0f;
if (scale <= 0.001f)
scale = 4.0f;
thread_worker_event.notify_all();
}
pixelbuffer_write->unlock();
// Draw rotating mandelbrot
canvas.set_transform(clan::Mat4f::translate(canvas.get_width()/2, canvas.get_height()/2, 0.0f) * clan::Mat4f::rotate(clan::Angle(angle, clan::angle_degrees), 0.0f, 0.0f, 1.0f));
clan::Image image(*texture_completed, clan::Size(texture_size, texture_size));
image.draw( canvas, -texture_size/2, -texture_size/2 );
canvas.set_transform(clan::Mat4f::identity());
... skip the part related to the FPS and error handling
window.flip(0);
return !quit;
}
Bookmarks