Buffers
A buffer is an area of memory that stores pixel data. Multiple buffers can be associated with a window or stream, but only one buffer can be associated with a pixmap.
Creating buffers
The buffers that you can create are:
- internal buffers
- Internal buffers are those that were created by calling one of the following Screen API functions:
- external buffers
- External buffers are those that were created by calling screen_create_buffer() and whose memory was allocated by applications. You can use (e.g. render into) an external buffer only after you've attached it to one of a pixmap, window, or stream.
Internal buffers
You can create buffers for pixmaps, streams, and windows by calling one of the following Screen API functions.
You may set the SCREEN_PROPERTY_USAGE on the Screen API object before you create its buffer if SCREEN_USAGE_READ or SCREEN_USAGE_WRITE is insufficient for your intended usage of the buffer. Otherwise, simply create the buffer for the Screen API object by calling the appropriate function. For example, to create buffers for a window:
...
screen_context_t ctx;
screen_window_t win;
int num_bufs = 2;
...
screen_create_window(&win, ctx);
screen_create_window_buffers(win, num_bufs);
...
You can now proceed to use the buffer. See Using buffers
.
External buffers
Applications such as drivers may have a requirement to allocate their own buffers because of memory location, or a buffer size requirement. These applications must ensure that all usage constraints are met when allocating the buffers to enable Screen to successfully attach the buffers. Failure to meet the usage constraints may also result in artifacts and system instability.
Applications that create their own buffers and allocate their memory must:
-
Create the the buffer of type screen_buffer_t
by calling screen_create_buffer().
For example:
... screen_buffer_t created_buf = NULL; ... screen_create_buffer(&created_buf); ...
-
Set the buffer properties.
At a minimum, you must set the following properties for the buffer that your application allocates:
- SCREEN_PROPERTY_FORMAT
- SCREEN_PROPERTY_BUFFER_SIZE
- SCREEN_PROPERTY_SIZE
- SCREEN_PROPERTY_STRIDE
If you're using one of the planar YUV formats, then you should also set the SCREEN_PROPERTY_PLANAR_OFFSETS property.
For example for a buffer of format SCREEN_FORMAT_NV12:
... const int width=1024, height=64, stride=4096; const int nbytes = stride*height + stride*(height/2); ... screen_set_buffer_property_iv(created_buf,SCREEN_PROPERTY_FORMAT,(const int[]){SCREEN_FORMAT_NV12}); screen_set_buffer_property_iv(created_buf,SCREEN_PROPERTY_BUFFER_SIZE,(const int[]){width, height}); screen_set_buffer_property_iv(created_buf,SCREEN_PROPERTY_SIZE,(const int[]){nbytes}); screen_set_buffer_property_iv(created_buf,SCREEN_PROPERTY_STRIDE,(const int[]){stride}); screen_set_buffer_property_iv(created_buf,SCREEN_PROPERTY_PLANAR_OFFSETS,(const int[]){0,(height*stride),-1}); ...
-
Allocate the memory for the buffer and assign access to it.
You can use either the SCREEN_PROPERTY_POINTER property or the SCREEN_PROPERTY_FD property to assign memory. However, note that you may need to set different attributes on the memory depending on which property you use:
- SCREEN_PROPERTY_POINTER
-
-
Allocate the memory for the buffer.
Allocate some memory for the buffer. How and from where the memory is allocated is up to the application; it can be statically allocated (mapped from a fixed address) or allocated from a shared memory object. For example:
... int fd; uint32_t *mmap_ptr; ... fd = shm_open(SHM_ANON, O_CREAT|O_EXCL|O_RDWR, 0400); shm_ctl(fd, SHMCTL_ANON, 0, nbytes); mmap_ptr = mmap(NULL, nbytes , PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); ...
-
Assign the pointer to the buffer.
You must set the SCREEN_PROPERTY_POINTER property to point to the memory that's been allocated for this buffer. For example:
... screen_set_buffer_property_pv(created_buf, SCREEN_PROPERTY_POINTER, (void**)&mmap_ptr); ...
-
Allocate the memory for the buffer.
- SCREEN_PROPERTY_FD
-
-
Allocate the memory for the buffer.
How and from where the memory is allocated is up to the application; it can be statically allocated (mapped from a fixed address) or allocated from a shared memory object. For example:
... int fd; ... fd = shm_open(SHM_ANON, O_CREAT|O_EXCL|O_RDWR, 0400); ... /* Seal the memory so it can't be modified */ if (0 != shm_ctl(shm_fd, SHMCTL_SEAL, 0, 0)){ /* error */ ... } ...
Note:When you're using the SCREEN_PROPERTY_FD property to indicate memory, you must ensure that you:- call shm_ctl() to set the SHMCTL_SEAL flag to prevent the shared memory object from being modified.
- ensure that the SHMCTL_REVOCABLE flag is NOT set on your shared memory object. You can call shm_ctl() with the SHMCTL_GET_FLAGS flag to verify which flags have been set on the object that you're using. If the SHMCTL_REVOCABLE flag has been set, you can't associate this object with your buffer.
-
Assign the file descriptor to the buffer.
You must set the SCREEN_PROPERTY_FD property to point to the memory that's been allocated for this buffer. For example:
... screen_set_buffer_property_iv(created_buf, SCREEN_PROPERTY_FD, &fd); ...
-
Allocate the memory for the buffer.
-
Attach the external buffer to a pixmap, window, or stream before you can use it.
See
Attaching buffers
.Note:You must be using a privileged Screen context that includes SCREEN_BUFFER_PROVIDER_CONTEXT in its type to attach the buffer. For example:
... screen_context_t screen_ctx; ... screen_create_context(&screen_ctx, (SCREEN_APPLICATION_CONTEXT | SCREEN_BUFFER_PROVIDER_CONTEXT)); ...
Attaching buffers
You can attach a buffer (of type screen_buffer_t) to associate it with a pixmap, stream, or window by calling the following functions respectively:
To attach buffers:
-
Get a screen_buffer_t.
To get access to a buffer, you can retrieve any of the following:
- an external buffer (i.e., one that was created by calling screen_create_buffer() and has memory allocated to it)
-
a buffer from a stream by calling the
screen_acquire_buffer()
function. For example:
screen_stream_t astream = NULL; screen_buffer_t buffer = NULL; ... screen_acquire_buffer(&buffer, astream, NULL, NULL, NULL, SCREEN_ACQUIRE_DONT_BLOCK); ...
-
a buffer from a pixmap, stream or window by calling
the screen_get_*_property_pv() function with one of its valid properties
that returns a buffer
- pixmap
-
Call screen_get_pixmap_property_pv()
with one of the following properties:
- SCREEN_PROPERTY_BUFFERS
- SCREEN_PROPERTY_RENDER_BUFFERS
- stream
-
Call screen_get_stream_property_pv()
with one of the following properties:
- SCREEN_PROPERTY_BUFFERS
- SCREEN_PROPERTY_FRONT_BUFFERS
- SCREEN_PROPERTY_RENDER_BUFFERS
- window
-
Call screen_get_window_property_pv()
with one of the following properties:
- SCREEN_PROPERTY_BUFFERS
- SCREEN_PROPERTY_FRONT_BUFFER
- SCREEN_PROPERTY_RENDER_BUFFERS
... screen_buffer_t *win_buf; win_buf = calloc((size_t)num_bufs, sizeof(screen_buffer_t)); ... screen_get_window_property_pv(win, SCREEN_PROPERTY_RENDER_BUFFERS, (void**)win_buf)); ...
-
Set the SCREEN_PROPERTY_USAGE on the Screen API object
(i.e., pixmap, stream, or window) that you're attaching the buffer to.
From the pixmap, stream, or window, you should indicate the intended usage of the buffer before you attach it because if the usage isn't set appropriately, Screen may prevent access to the buffer.
... screen_window_t a_win; ... int usage = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE; screen_set_window_property_iv(a_win, SCREEN_PROPERTY_USAGE, &usage); ...
Note:If the intended usage that you set on the Screen API object that you're attaching the buffer to isn't compatible with the buffer's usage that is was originally created with, then Screen may fail to attach the buffer or the buffer may not be usable for your intended purpose. -
Attach the buffer to a valid Screen API object by calling the appropriate
Screen API function.
For example:
... screen_attach_window_buffers(a_win, num_bufs, win_buf); ...
Note:Unlike pixmaps and windows, you can't attach buffers to streams that already have buffers associated with them without first calling screen_destroy_stream_buffers().
Using buffers
To use a buffer that's associated with a Screen API object, you must retrieve it from the object. The following are ways that you can retrieve a buffer that's valid for use (e.g., for blitting or rendering purposes):
- pixmap
-
Call screen_get_pixmap_property_pv()
with one of the following properties:
- SCREEN_PROPERTY_BUFFERS
- SCREEN_PROPERTY_RENDER_BUFFERS
... screen_context context; screen_pixmap_t screen_pix = NULL; screen_buffer_t pix_buf; uint32_t *pix_ptr; ... screen_get_pixmap_property_pv(pixmap, SCREEN_PROPERTY_RENDER_BUFFERS, (void**)&pix_buf); screen_get_buffer_property_pv(pix_buf, SCREEN_PROPERTY_POINTER, (void**)&pix_ptr); ... screen_fill(context, pix_buf, (const int[]){SCREEN_BLIT_COLOR, 0xabcd, SCREEN_BLIT_END}); ...
- stream
-
-
Call screen_get_stream_property_pv()
with one of the following properties:
- SCREEN_PROPERTY_BUFFERS
- SCREEN_PROPERTY_FRONT_BUFFERS
- SCREEN_PROPERTY_RENDER_BUFFERS
... int num_bufs = 0; screen_buffer_t *stream_buf = NULL; screen_get_stream_property_iv(stream, SCREEN_PROPERTY_RENDER_BUFFER_COUNT, &num_bufs); a_stream_buf = calloc((size_t)num_bufs, sizeof(screen_buffer_t)); ... screen_get_stream_property_pv(stream, SCREEN_PROPERTY_RENDER_BUFFERS, (void**)stream_buf); ... screen_post_stream(stream, stream_buf[0], 0, NULL, 0); ...
-
Call screen_acquire_buffer()
function. For example:
... screen_context ctx; screen_stream_t a_stream; screen_buffer_t buffer, dest_buffer; ... screen_acquire_buffer(&buffer, a_stream, NULL, NULL, NULL, SCREEN_ACQUIRE_DONT_BLOCK); ... screen_blit(ctx, buffer, dest_buffer, (const int[]){SCREEN_BLIT_COLOR, 0xabcd, SCREEN_BLIT_END}); ...
-
Call screen_get_stream_property_pv()
with one of the following properties:
- window
-
Call screen_get_window_property_pv()
with one of the following properties:
- SCREEN_PROPERTY_BUFFERS
- SCREEN_PROPERTY_FRONT_BUFFER
- SCREEN_PROPERTY_RENDER_BUFFERS
... int num_bufs = 0; screen_buffer_t *win_buf = NULL; screen_get_window_property_iv(win, SCREEN_PROPERTY_RENDER_BUFFER_COUNT, &num_bufs); other_win_buf = calloc((size_t)num_bufs, sizeof(screen_buffer_t)); ... screen_get_window_property_pv(win, SCREEN_PROPERTY_RENDER_BUFFERS, (void**)win_buf); ... screen_post_window(win, win_buf[0], 0, NULL, 0); ...