Display Raster Data?

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Display Raster Data?

Gtk+ - General mailing list
Hello,

I have bitmaps being generated by a process and need to display them
at ~60Hz. What is the best way to get the data to the screen?

It looks like I will have to create and destroy GdkPixbufs constantly.
I am starting to think a multimedia library like SDL2 would be a
better fit.

Cheers,
    R0b0t1
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|

Re: Display Raster Data?

Paul Davis


On Wed, Aug 1, 2018 at 12:18 AM, R0b0t1 via gtk-list <[hidden email]> wrote:
Hello,

I have bitmaps being generated by a process and need to display them
at ~60Hz.

just a quick note: you don't get to control the refresh rate.

your screen update refresh rate is independent of GTK+. All modern GUI toolkits are driven by the screen refresh rate (aka "vblank"). if your screen refreshes at some other rate, there's nothing the GUI toolkit can do to speed it up.

60Hz is a reasonable common refresh rate, but it's not universal, and you probably should not rely on it being the context in which your program runs.


_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|

Re: Display Raster Data?

Gtk+ - General mailing list
On Wed, Aug 1, 2018 at 3:45 AM, Paul Davis <[hidden email]> wrote:
>
> 60Hz is a reasonable common refresh rate, but it's not universal, and you
> probably should not rely on it being the context in which your program runs.
>

... I'm not, the update is driven by frame decoding elsewhere. I
pointed it out because doing it at ~60Hz is going to be harder than
say 30Hz or 25Hz and can dictate what is most proper.
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|

Re: Display Raster Data?

Gtk+ - General mailing list
I suggest you use GStreamer, you can build a video by pushing bitmap frames and it does everything else for you.

Otherwise, you can animate a DrawingArea. Set up a 60hz timer on your own. The timer callback simply calls
gtk_widget_queue_draw_area(). Then, on the draw_func of your drawingarea you display the bitmaps, one after another.
That's the simplest solution but can have lower timing quality

Luca


2018-08-01 14:18 GMT+02:00 R0b0t1 via gtk-list <[hidden email]>:
On Wed, Aug 1, 2018 at 3:45 AM, Paul Davis <[hidden email]> wrote:
>
> 60Hz is a reasonable common refresh rate, but it's not universal, and you
> probably should not rely on it being the context in which your program runs.
>

... I'm not, the update is driven by frame decoding elsewhere. I
pointed it out because doing it at ~60Hz is going to be harder than
say 30Hz or 25Hz and can dictate what is most proper.
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list


_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|

Re: Display Raster Data?

Gtk+ - General mailing list
I should point out that the draw_func may be called by Gtk whenever it needs,
The best is to have the timer callback change the "current" bitmap and call gtk_widget_queue_draw_area().
Then on the drawing callback of the drawing area you just paint the "current" bitmap.




2018-08-01 15:44 GMT+02:00 Luca Bacci <[hidden email]>:
I suggest you use GStreamer, you can build a video by pushing bitmap frames and it does everything else for you.

Otherwise, you can animate a DrawingArea. Set up a 60hz timer on your own. The timer callback simply calls
gtk_widget_queue_draw_area(). Then, on the draw_func of your drawingarea you display the bitmaps, one after another.
That's the simplest solution but can have lower timing quality

Luca


2018-08-01 14:18 GMT+02:00 R0b0t1 via gtk-list <[hidden email]>:
On Wed, Aug 1, 2018 at 3:45 AM, Paul Davis <[hidden email]> wrote:
>
> 60Hz is a reasonable common refresh rate, but it's not universal, and you
> probably should not rely on it being the context in which your program runs.
>

... I'm not, the update is driven by frame decoding elsewhere. I
pointed it out because doing it at ~60Hz is going to be harder than
say 30Hz or 25Hz and can dictate what is most proper.
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list



_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|

Re: Display Raster Data?

Paul Davis
In reply to this post by Gtk+ - General mailing list


On Wed, Aug 1, 2018 at 9:44 AM, Luca Bacci via gtk-list <[hidden email]> wrote:
I suggest you use GStreamer, you can build a video by pushing bitmap frames and it does everything else for you.

Otherwise, you can animate a DrawingArea. Set up a 60hz timer on your own. The timer callback simply calls
gtk_widget_queue_draw_area(). Then, on the draw_func of your drawingarea you display the bitmaps, one after another.
That's the simplest solution but can have lower timing quality

in GTK3, this is almost certainly not the best way to do this. You want to use a frame timer based on the refresh/vblank cycle of the monitor.
 

_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|

Re: Display Raster Data?

Gtk+ - General mailing list
On Wed, Aug 1, 2018 at 8:52 AM, Luca Bacci via gtk-list
<[hidden email]> wrote:
> I should point out that the draw_func may be called by Gtk whenever it
> needs,
> The best is to have the timer callback change the "current" bitmap and call
> gtk_widget_queue_draw_area().
> Then on the drawing callback of the drawing area you just paint the
> "current" bitmap.
>

This is what I first tried to do but could not find good information
on it. It seems I need to quickly create and destroy objects no matter
what I do which is why I sent this message.

I can set an image control's GdkPixbuf but there seems to be no way to
change the data that a GdkPixbuf points to. It may also be necessary
to create another GtkImage to perform double buffering inside the
window.


On Wed, Aug 1, 2018 at 10:06 AM, Paul Davis <[hidden email]> wrote:

>
> On Wed, Aug 1, 2018 at 9:44 AM, Luca Bacci via gtk-list <[hidden email]>
> wrote:
>>
>> I suggest you use GStreamer, you can build a video by pushing bitmap
>> frames and it does everything else for you.
>>
>> Otherwise, you can animate a DrawingArea. Set up a 60hz timer on your own.
>> The timer callback simply calls
>> gtk_widget_queue_draw_area(). Then, on the draw_func of your drawingarea
>> you display the bitmaps, one after another.
>> That's the simplest solution but can have lower timing quality
>
> in GTK3, this is almost certainly not the best way to do this. You want to
> use a frame timer based on the refresh/vblank cycle of the monitor.
>

I suspect he realized and that is why he recommended just changing the
current bitmap.


The only reason I can find to not use GStreamer is that decoding is
already done for me. Putting the frames into a video and having that
displayed may lead to pointless copying of the video data. Pointless
copying is usually the biggest time sink. However this would mean the
video would be double/triple buffered properly upon display and would
use video acceleration.

But doing properly double or triple buffered video isn't that hard.
The hard part is integrating the display and event loop with GTK+.
Considering my issues here and in the other post I made about command
line arguments my solution for now is to just not use GTK+ in
preference of SDL2. This has the benefit of getting me very easy video
acceleration and better cross platform support. (The application links
in about 1/5th the time.)

Any pointers are still appreciated, of course.

Cheers,
    R0b0t1


P.S. "GtkApplication is a class that handles many important aspects of
a GTK+ application in a convenient fashion, without enforcing a
one-size-fits-all application model."

/me squints
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|

Re: Display Raster Data?

Gtk+ - General mailing list

in GTK3, this is almost certainly not the best way to do this. You want to use a frame timer based on the refresh/vblank cycle of the monitor.

Yes you're right, I just meant to give the base idea.
..I think that gtk_widget_queue_draw_area() enqueues a redraw at the next frame clock tick, so draws are always done on frame-clock.
But I'm not sure, so it's best to base everything on the frame clock anyway.

This is what I first tried to do but could not find good information
on it. It seems I need to quickly create and destroy objects no matter
what I do which is why I sent this message.

I can set an image control's GdkPixbuf but there seems to be no way to
change the data that a GdkPixbuf points to.

Maybe you can try with gdk_pixbuf_new_from_data ()

It may also be necessary
to create another GtkImage to perform double buffering inside the
window.

No, you never experience flickering in Gtk. Gtk is completely double buffered by itself
If you want to know more, there is a nice overview:


But doing properly double or triple buffered video isn't that hard.
The hard part is integrating the display and event loop with GTK+.

That's not a problem, GStreamer integrates well with the Gtk main loop
and there are video sinks for Gtk, like GtkSink and GstVideoOverlay

Considering my issues here and in the other post I made about command
line arguments my solution for now is to just not use GTK+ in
preference of SDL2. This has the benefit of getting me very easy video
acceleration and better cross platform support. (The application links
in about 1/5th the time.)

Well SDL2 is a good library, sure. Choose what best suits your needs

Hope it helps.
Have a nice day!

Luca






2018-08-01 17:44 GMT+02:00 R0b0t1 <[hidden email]>:
On Wed, Aug 1, 2018 at 8:52 AM, Luca Bacci via gtk-list
<[hidden email]> wrote:
> I should point out that the draw_func may be called by Gtk whenever it
> needs,
> The best is to have the timer callback change the "current" bitmap and call
> gtk_widget_queue_draw_area().
> Then on the drawing callback of the drawing area you just paint the
> "current" bitmap.
>

This is what I first tried to do but could not find good information
on it. It seems I need to quickly create and destroy objects no matter
what I do which is why I sent this message.

I can set an image control's GdkPixbuf but there seems to be no way to
change the data that a GdkPixbuf points to. It may also be necessary
to create another GtkImage to perform double buffering inside the
window.


On Wed, Aug 1, 2018 at 10:06 AM, Paul Davis <[hidden email]> wrote:
>
> On Wed, Aug 1, 2018 at 9:44 AM, Luca Bacci via gtk-list <[hidden email]>
> wrote:
>>
>> I suggest you use GStreamer, you can build a video by pushing bitmap
>> frames and it does everything else for you.
>>
>> Otherwise, you can animate a DrawingArea. Set up a 60hz timer on your own.
>> The timer callback simply calls
>> gtk_widget_queue_draw_area(). Then, on the draw_func of your drawingarea
>> you display the bitmaps, one after another.
>> That's the simplest solution but can have lower timing quality
>
> in GTK3, this is almost certainly not the best way to do this. You want to
> use a frame timer based on the refresh/vblank cycle of the monitor.
>

I suspect he realized and that is why he recommended just changing the
current bitmap.


The only reason I can find to not use GStreamer is that decoding is
already done for me. Putting the frames into a video and having that
displayed may lead to pointless copying of the video data. Pointless
copying is usually the biggest time sink. However this would mean the
video would be double/triple buffered properly upon display and would
use video acceleration.

But doing properly double or triple buffered video isn't that hard.
The hard part is integrating the display and event loop with GTK+.
Considering my issues here and in the other post I made about command
line arguments my solution for now is to just not use GTK+ in
preference of SDL2. This has the benefit of getting me very easy video
acceleration and better cross platform support. (The application links
in about 1/5th the time.)

Any pointers are still appreciated, of course.

Cheers,
    R0b0t1


P.S. "GtkApplication is a class that handles many important aspects of
a GTK+ application in a convenient fashion, without enforcing a
one-size-fits-all application model."

/me squints


_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|

Re: Display Raster Data?

Gtk+ - General mailing list
In reply to this post by Gtk+ - General mailing list

I don't know the format, size, etc. of the images that you are working with. There are a few things that can affect the time it takes to move image data around. GTK should be able to handle the problem well though.

Try setting up a test environment with a frame counter and a timer on your image transfer function and see how long it takes. Work from there to optimize the situation. You can use a Pixbuf or a cairo image surface if you need to deal with byte copies or pixel by pixel copies. It's worth a try.

https://developer.gnome.org/gdk-pixbuf/stable/gdk-pixbuf-The-GdkPixbuf-Structure.html
https://cairographics.org/manual/cairo-Image-Surfaces.html

Eric


/*
    gcc -Wall cairo_image1.c -o cairo_image1 `pkg-config gtk+-3.0 --cflags --libs`

    Tested on Ubuntu16.04 32-bit with GTK3.18.
*/

#include<gtk/gtk.h>
#include<stdint.h>

cairo_surface_t *surface=NULL;

static gboolean animate_drawing(GtkWidget *drawing, GdkFrameClock *frame_clock, gpointer data);
static gboolean da_drawing(GtkWidget *da, cairo_t *cr, gpointer data);
static void draw_image(cairo_t *cr);

int main(int argc, char *argv[])
  {
    gtk_init(&argc, &argv);

    GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Cairo Image");
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    surface=cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 400, 400);

    GtkWidget *da=gtk_drawing_area_new();
    gtk_widget_set_hexpand(da, TRUE);
    gtk_widget_set_vexpand(da, TRUE);
    g_signal_connect(da, "draw", G_CALLBACK(da_drawing), NULL);
 
    GtkWidget *grid=gtk_grid_new();
    gtk_grid_attach(GTK_GRID(grid), da, 0, 0, 1, 1);
 
    gtk_container_add(GTK_CONTAINER(window), grid);
    gtk_widget_show_all(window);

    gtk_widget_add_tick_callback(GTK_WIDGET(da), (GtkTickCallback)animate_drawing, NULL, NULL);

    gtk_main();

    cairo_surface_destroy(surface);

    return 0;
  }
static gboolean animate_drawing(GtkWidget *da, GdkFrameClock *frame_clock, gpointer data)
  {
    //Check frame rate.
    gint64 frame=gdk_frame_clock_get_frame_counter(frame_clock);
    gint64 current_time=gdk_frame_clock_get_frame_time(frame_clock);
    gint64 start = gdk_frame_clock_get_history_start(frame_clock);
    gint64 history_len=frame-start;
    GdkFrameTimings *previous_timings=gdk_frame_clock_get_timings(frame_clock, frame-history_len);
    gint64 previous_frame_time=gdk_frame_timings_get_frame_time(previous_timings);
    g_print("Frame %i, %f fps\n", (gint)frame, (gdouble)(history_len)*G_USEC_PER_SEC/(gdouble)(current_time-previous_frame_time));

    gtk_widget_queue_draw(da);
    return G_SOURCE_CONTINUE;
  }
static gboolean da_drawing(GtkWidget *da, cairo_t *cr, gpointer data)
  {
    //Get the draw time.
    GTimer *timer=g_timer_new();
    draw_image(cr);
    g_print("Time %f\n", g_timer_elapsed(timer, NULL));
    g_timer_destroy(timer);
    return FALSE;
  }
static void draw_image(cairo_t *cr)
  {
    static gint counter=0;
    gint i=0;
    gint j=0;
    gint width=cairo_image_surface_get_width(surface);
    gint height=cairo_image_surface_get_height(surface);
    uint32_t *p1=(uint32_t*)cairo_image_surface_get_data(surface);
      
    for(i=0;i<height;i++)
      {
        for(j=0;j<width;j++)
          { 
            if(counter==i||counter==i+1) *p1=0xffff00ff;
            else *p1=0xffffffff;
            p1++;
          }                     
       }
  
    cairo_surface_mark_dirty(surface);
    cairo_set_source_surface(cr, surface, 0.0, 0.0);
    cairo_paint(cr);

    if(counter>height) counter=0;
    else counter++;
  }




_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list