NewAPI/Display

From Allegro Wiki

< NewAPI(Redirected from Display)
Jump to: navigation, search

Below is just an early proposal, see here for the current SVN version which originally was based on it: http://www.liballeg.org/naturaldocs/files/display_new-c.html

Contents

Display API proposal

This is just an early draft, edit/comment it.

Introduction

In Bob's A5 proposal [1] which is the base for what we want to implement for 4.3, no separation is made between ALLEGRO_BITMAP and ALLEGRO_DISPLAY and the actual meaning of a display is left unclear.

This proposal tries to clarify the difference, and also makes an adjustment to the API introducing a per-thread state defining the current target of drawing operations. It's based on my actual tries at implementing an improved API, ideas from some short mailing list threads of the last years and, to the most part, the last IRC meeting.

ALLEGRO_DISPLAY and drawing primitives

An ALLEGRO_DISPLAY basically is a window. Allegro 4.9 will support programs with more than one operating system window, so it makes sense to have an explicit struct (in 4.2 the internal GFX_DRIVER would represent a window).

The goal for drawing primitives is to have code like this:

al_draw_line(100, 100, 200, 200, red);
al_draw_image(300, 100, ball);

That is, there is no need for an explicit target surface for each call. In 4.9, the handling of graphics updates is fundamentally different from 4.2, where things like "double buffering" or "page flipping" had to be done by hand and often resulted in buggy or not platform independent code. With that old system, it was important to know to which buffer graphics would go, e.g.:

void my_draw(BITMAP *target)
{
        line(target, 100, 100, 200, 200, red);
}

Allegro 4.9 will take over the task of handling the update mechanism, and all the user will usually do is issue graphics primitives and call al_flip_display() for them to appear (which internally, speaking in Allegro 4.2 terms, may do something to the effect of show_video_bitmap(page) or blit(backbuffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H) or allegro_gl_flip() or something else, depending on the driver).

What if we are not drawing to the screen?

Of course, there are special cases where not all drawing commands will target the standard display. For example if drawing switches to a different window, or if we target a sub-bitmap of the screen, or an off-screen bitmap.

In fact, there are two different things to consider here - targeting another window or an off-screen bitmap.

When drawing to another window

The current display in this proposal is a global per-thread state. That is, it should work just like an OpenGL context does: At any given time and in any given thread, only one ALLEGRO_DISPLAY can be the current one.

Likely, for the user, this will be completely transparent, as in 99% of cases the Allegro 4.9 application will only have one window, so only the 1% of users who do want to use multiple windows will have the need to change the current display at all. For this there will should be a function like:

/* Change the current display for the calling thread. */
al_set_current_display(ALLEGRO_DISPLAY *display)

It also is possible that there is no current display, for example if the program is some bitmap manipulation tool which never opens a window. We could either allow a NULL display for that case, or have a default dummy display which is active if no other is.

My initial thought is that if the user doesn't create a display, it is NULL, and they can only user memory bitmaps. Trent Gamblin 23:40, June 25, 2007 (UTC)

When drawing to an off-screen targets

Now, what if we don't just want to draw to some window, but e.g. into a memory bitmap or a sub bitmap? With Allegro 4.2 all graphics operations targeted a specific bitmap, but in most games this is not needed. OpenGL does not even have an easy way for this at all, without using pbuffers or FBOs all you can do is draw to the screen, then read pixels back to the screen.

For Allegro 4.9, it would of course be nice if a driver could allow using FBOs to draw to some off-screen bitmap. And of course there should still be the possibility to draw directly to memory bitmaps using software rendering.

The idea of this proposal is, to give each ALLEGRO_DISPLAY an active ALLEGRO_BITMAP, which is the actual target for drawing operations. By default, this will be a special bitmap representing the current backbuffer of the display, so the earlier mentioned:

al_draw_line(0, 0, 100, 100, red)

will still do what you would expect. But in special cases (and depending on if the driver supports it), it will now be possible to for example draw to the front buffer of a display. The functions needed would be something like:

/* Return a special bitmap representing the back-buffer of the current display. */
ALLEGRO_BITMAP *al_get_backbuffer(void)

/* Return a special bitmap representing the front-buffer of the current display. This may not be supported by the driver. */
ALLEGRO_BITMAP *al_get_frontbuffer(void)

and

/* Select the bitmap to which all subsequent drawing operations will draw. */
al_set_target_bitmap(ALLEGRO_BITMAP *bitmap)

With that last function, also an arbitrary memory bitmap or video bitmap or sub bitmap of either could be selected, in addition to the special back and front buffers.

Complete API summary

Events

An ALLEGRO_DISPLAY will generate events if you call al_register_event_source on it. The events that it can generate are:

  • ALLEGRO_EVENT_DISPLAY_EXPOSE - The display (or a portion thereof) has become visible. event->display.x/event->display.y will be the top left of the exposed area, and event->display.width/event->display.height will contain the width and height of the exposed area.
  • ALLEGRO_EVENT_DISPLAY_RESIZE - The window has been resized. event->display.x/event->display.y will contain the top left position of the resized window, and event->display.width/event->display.height will contain the the new width and height of the window. In order for the window to actually be resized, you must call al_acknowledge_resize.
  • ALLEGRO_EVENT_DISPLAY_CLOSE - The close button of the window has been pressed.
  • ALLEGRO_EVENT_DISPLAY_LOST - Displays can be lost with some drivers (just Direct3D?). This means that rendering is impossible. The device will be restored as soon as it is possible. The program should be able to ignore this event and continue rendering however it will have no effect.
  • ALLEGRO_EVENT_DISPLAY_FOUND - Generated when a lost device is regained. Bitmaps created without the ALLEGRO_SYNC_MEMORY_COPY flag may lose their data when the device is lost, so they should be recreated when this event is received.

Structures

ALLEGRO_DISPLAY

/* Represents one window */
struct ALLEGRO_DISPLAY

ALLEGRO_DISPLAY_MODE

typedef struct ALLEGRO_DISPLAY_MODE {
        int width;          /* Screen width */
        int height;         /* Screen height */
        int format;         /* The pixel format of the mode */
        int refresh_rate;   /* The refresh rate of the mode */
} ALLEGRO_DISPLAY_MODE;

Configuration/Querying

al_set_new_display_format

void al_set_new_display_format(int format);

Sets the pixel format for all displays created after this call. Format can be one of:

  • ALLEGRO_PIXEL_FORMAT_ANY = 0,
  • ALLEGRO_PIXEL_FORMAT_ARGB_8888
  • ALLEGRO_PIXEL_FORMAT_RGBA_8888
  • ALLEGRO_PIXEL_FORMAT_ARGB_4444
  • ALLEGRO_PIXEL_FORMAT_RGB_888 /* 24 bit format */
  • ALLEGRO_PIXEL_FORMAT_RGB_565
  • ALLEGRO_PIXEL_FORMAT_RGB_555
  • ALLEGRO_PIXEL_FORMAT_PALETTE_8
  • ALLEGRO_PIXEL_FORMAT_RGBA_5551
  • ALLEGRO_PIXEL_FORMAT_ARGB_1555
  • ALLEGRO_PIXEL_FORMAT_ABGR_8888
  • ALLEGRO_PIXEL_FORMAT_XBGR_8888 /* 32 bit size, 24 bits used */
  • ALLEGRO_PIXEL_FORMAT_BGR_888 /* 24 bit format */
  • ALLEGRO_PIXEL_FORMAT_BGR_565
  • ALLEGRO_PIXEL_FORMAT_BGR_555
  • ALLEGRO_PIXEL_FORMAT_RGBX_8888 /* 32 bit size, 24 bits used */
  • ALLEGRO_PIXEL_FORMAT_XRGB_8888 /* 32 bit size, 24 bits used */

al_set_new_display_refresh_rate

Sets the refresh rate to use for newly created displays. If the refresh rate is not available, al_create_display will fail. A list of modes with refresh rates can be found with al_get_num_display_modes and al_get_display_mode, documented above.

void al_set_new_display_refresh_rate(int refresh_rate);

Sets the refresh rate for displays created after this call. This will only affect fullscreen displays. Specifying 0 will use a default value.

al_set_new_display_flags

void al_set_new_display_flags(int flags);

Sets various flags for display creation. flags is a bitfield containing any reasonable combination of the following:

  • ALLEGRO_WINDOWED - prefer a windowed mode
  • ALLEGRO_FULLSCREEN - prefer a fullscreen mode
  • ALLEGRO_RESIZABLE - The display is resizable (only applicable if combined with ALLEGRO_WINDOWED)
  • ALLEGRO_OPENGL - require the driver to provide an initialized opengl context after returning successfully
  • ALLEGRO_DIRECT3D - require the driver to do rendering with Direct3D and provide a Direct3D device
  • ALLEGRO_DOUBLEBUFFER - use double buffering
  • ALLEGRO_PAGEFLIP - use page flipping
  • ALLEGRO_SINGLEBUFFER - Use only 1 buffer (front and back buffer are the same)

0 can be used for default values.

al_get_num_display_modes

Get the number of available fullscreen display modes for the current set of display parameters. This will use the values set with al_set_new_display_format, al_set_new_display_refresh_rate, and al_set_new_display_flags to find the number of modes that match. Settings the new display parameters to zero will give a list of all modes for the default driver.

int al_get_num_display_modes(void);

al_get_display_mode

Retrieves a display mode. Display parameters should not be changed between a call of al_get_num_display_modes and al_get_display_mode. index must be between 0 and the number returned from al_get_num_display_modes-1. mode must be an allocated ALLEGRO_DISPLAY_MODE structure. This function will return NULL on failure, and the mode parameter that was passed in on success. See ALLEGRO_DISPLAY_MODE above.

ALLEGRO_DISPLAY_MODE *al_get_display_mode(int index, ALLEGRO_DISPLAY_MODE *mode);

al_get_new_display_format

Gets the current pixel format used for newly created displays.

int al_get_new_display_format(void);

al_get_new_display_refresh_rate

Gets the current refresh rate used for newly created displays.

int al_get_new_display_refresh_rate(void);

al_get_new_display_flags

Gets the current flags used for newly created displays.

int al_get_new_display_flags(void);

al_get_display_width

Gets the width of the current display. This is like SCREEN_W in Allegro 4.x.

int al_get_display_width(void);

al_get_display_height

Gets the height of the current display. This is like SCREEN_H in Allegro 4.x.

int al_get_display_height(void);

al_get_display_format

Gets the pixel format of the current display.

int al_get_display_format(void);

al_get_display_refresh_rate

Gets the refresh rate of the current display.

int al_get_display_refresh_rate(void);

al_get_display_flags

Gets the flags of the current display.

int al_get_display_flags(void);

Creation/Destruction

al_create_display

ALLEGRO_DISPLAY *al_create_display(int w, int h)

Create a display, or window, with the specified dimensions.

w: the width of the display

h: the height of the display

The parameters of the display are determined by the last calls to al_set_new_display_*. Default parameters are used if none are set explicitly.

Creating a new display will automatically make it the active one, with the backbuffer selected for drawing.

al_destroy_display

void al_destroy_display(ALLEGRO_DISPLAY *dpy);

Destroy a display.


TODO: what to do about bitmaps tied to the display? implicit destroy?

Targets

al_set_current_display

void al_set_current_display(ALLEGRO_DISPLAY *display)

Change the current display for the calling thread.

al_get_current_display

ALLEGRO_DISPLAY *al_get_current_display(void)

Query for the current display in the calling thread.

al_set_target_bitmap

void al_set_target_bitmap(ALLEGRO_BITMAP *bitmap)

Select the bitmap to which all subsequent drawing operations in the calling thread will draw.

al_get_target_bitmap

ALLEGRO_BITMAP *al_get_target_bitmap(void)

Return the target bitmap of the current display.

al_get_backbuffer

ALLEGRO_BITMAP *al_get_backbuffer(void)

Return a special bitmap representing the back-buffer of the current display.

al_get_frontbuffer

ALLEGRO_BITMAP *al_get_frontbuffer(void)

Return a special bitmap representing the front-buffer of the current display. This may not be supported by the driver; returns NULL in that case.

Flipping/Updating

al_flip_display

void al_flip_display(void)

Copies or updates the front and back buffers so that what has been drawn previously on the currently selected display becomes visible on screen. Pointers to the special back and front buffer bitmaps remain valid and retain their semantics as back and front buffers respectively, although their contents may have changed.

al_update_display_region

bool
al_update_display_region(int x, int y, int width, int height)

Update the the front buffer from the backbuffer in the specified region. This does not flip the whole buffer and preserves the contents of the front buffer outside of the given rectangle. This may not be supported by all drivers, in which case it returns false.

Resizing

al_acknowledge_resize

void al_acknowledge_resize(void)

When the user receives a resize event from a resizable display, if they wish the display to be resized they must call this function to let the graphics driver know that it can now resize the display.

al_resize_display

Resize the current display. Returns false on error, true on success. This works on both fullscreen and windowed displays, regardless of the ALLEGRO_RESIZABLE flag.

bool al_resize_display(int width, int height);

Miscellaneous

al_wait_for_vsync

Wait for the beginning of a vertical retrace. Some driver/card/monitor combinations may not be capable of this. Returns false if not possible, true if successful.

bool al_wait_for_vsync(void);


Clipping

al_set_clipping_rectangle

Set the region of the target bitmap or display that pixels get clipped to. The default is to clip pixels to the entire bitmap.

void al_set_clipping_rectangle(int x, int y, int width, int height);

al_get_clipping_rectangle

Gets the clipping rectangle of the target bitmap.

void al_get_clipping_rectangle(int *x, int *y, int *width, int *height);

References

[1] http://wiki.allegro.cc/NewAPI/Documents/gfx-api

Personal tools