Examples
Description:
Using graphics memory in a hardware driver
#include <WF/wfd.h>
#include <errno.h>
#include <fcntl.h>
#include <memobj/handles.h>
#include <memobj/physmem.h>
#include <screen/iomsg.h> // win_image_t
#include <screen/private/scrmem.h>
#include <screen/private/scrmem_open.h>
#include <stdbool.h>
#include <stdlib.h>
struct wfd_source {
struct scrmem *scrmem;
const struct memobj_phys_segment *locked_memory;
WFDSource wfd_handle;
};
WFD_API_CALL WFDSource WFD_APIENTRY
wfdCreateSourceFromImage(WFDDevice device, WFDPipeline pipeline,
WFDEGLImage egl_image, const WFDint *attribList) WFD_APIEXIT
{
// egl_image is always a win_image_t pointer
win_image_t *winimg = egl_image;
struct memobj *memobj;
struct wfd_source *src;
//TODO: handle device, pipeline, attribList parameters
src = malloc(sizeof *src);
if (!src) {
goto fail;
}
(*src) = (struct wfd_source){ .scrmem = NULL };
if (EOK != scrmem_open_from_win_image(&src->scrmem, winimg, O_RDONLY, NULL)) {
goto fail;
}
memobj = scrmem_get_memobj(src->scrmem);
if (!memobj) {
// Screen is not aware of any memory associated with the image.
goto fail;
}
if (EOK != memobj_lock_phys(memobj)) {
goto fail;
}
src->locked_memory = memobj_get_phys_layout(memobj);
if (src->locked_memory->next) {
// The memory isn't physically contiguous.
goto fail;
}
src->wfd_handle = 1; // TODO: store src and assign a proper handle
return src->wfd_handle;
fail:
if (src) {
if (src->locked_memory) {
memobj_unlock_phys(memobj);
}
scrmem_close(src->scrmem);
free(src);
}
//TODO: store error in WFDDevice
return WFD_INVALID_HANDLE;
}
Use scrmem_close() when scrmem and its associated data are no longer needed. Note that WFDDestroySource() might be the wrong place to do this; if the display controller is still accessing the memory, don't call scrmem_close() until it's done. A good time to do so is after wfdDeviceCommit() has waited for the source to be unbound.
Getting a buffer identifier in client code
#include <EGL/egl.h>
#include <screen/screen.h>
EGLint
get_buffer_id(int *id, screen_buffer_t screen_buf)
{
if (0 != screen_get_buffer_property_iv(screen_buf,
SCREEN_PROPERTY_ID, id)) {
return EGL_BAD_SURFACE;
}
return EGL_SUCCESS;
}
The EGL driver can then send the ID to the GPU's resource manager to indicate it wants to use the buffer as a render source or target. (While this driver would be running in the same process as Screen, it would have its own resource manager with a custom protocol.)
Wrapping graphics memory in a GPU driver
#include <errno.h>
#include <fcntl.h>
#include <memobj/handles.h>
#include <memobj/physmem.h>
#include <screen/private/scrmem.h>
#include <screen/private/scrmem_open.h>
#include <screen/screen.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/neutrino.h>
struct gpu_buffer {
struct scrmem *scrmem;
struct memobj *memobj;
// ...
};
struct gpu_buffer*
wrap_client_buffer(int id, bool writable, const struct _client_info *cinfo)
{
int err = 0;
struct gpu_buffer *gpubuf = malloc(sizeof *gpubuf);
if (!gpubuf) {
err = ENOMEM;
goto fail;
}
(*gpubuf) = (struct gpu_buffer){ .scrmem = NULL };
err = scrmem_open(&gpubuf->scrmem, id,
writable ? O_RDWR : O_RDONLY, cinfo);
if (err) {
goto fail;
}
gpubuf->memobj = scrmem_get_memobj(gpubuf->scrmem);
err = memobj_lock_phys(gpubuf->memobj);
if (err) {
goto fail;
}
//TODO: call memobj_get_phys_layout(), and store addresses
// in GPU-specific structures
return gpubuf;
fail:
if (gpubuf) {
scrmem_close(gpubuf->scrmem);
free(gpubuf);
}
errno = err;
return NULL;
}
Call scrmem_close() when the gpu_buffer structure is no longer needed, so the GPU no longer accesses the memory.
Note that this code needs to run within the Screen process. If the GPU driver is external, it's necessary to create a proxy within Screen (referenced by gpu-dlls in graphics.conf) to handle libscrmem calls.
Allocating graphics memory
scrmem handles: #include <errno.h>
#include <fcntl.h>
#include <memobj/alloc.h>
#include <memobj/handles.h>
#include <memobj/physmem.h>
#include <screen/private/scrmem.h>
#include <screen/private/scrmem_create.h>
#include <screen/iomsg.h> // win_image_t
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <sys/mman.h>
static void destructor(struct scrmem*, void*);
errno_t
create_scrmem(int width, int height, int format, int usage,
size_t count, struct scrmem **scrmem_out)
{
errno_t err = 0;
size_t alloced = 0;
size_t nbytes;
int prot = 0;
struct memobj_attr *memobj_attr = NULL;
struct scrmem_attr *scrmem_attr = NULL;
win_image_t *tmp_img = NULL;
struct memobj *tmp_memobj = NULL;
nbytes = 0x100000; //FIXME: calculate the size
if (usage & SCREEN_USAGE_READ) {
prot |= PROT_READ;
}
if (usage & SCREEN_USAGE_WRITE) {
prot |= PROT_WRITE;
}
err = memobj_attr_create(&memobj_attr);
if (err) {
goto out;
}
memobj_attr_set_size(memobj_attr, nbytes);
memobj_attr_set_phys_contig(attr, MEMOBJ_CONTIG_PREFER);
err = scrmem_attr_create(&scrmem_attr);
if (err) {
goto out;
}
scrmem_attr_set_destructor(scrmem_attr, destructor, NULL);
while (alloced < count) {
tmp_img = malloc(sizeof *tmp_img);
if (!tmp_img) {
err = ENOMEM;
goto out;
}
*tmp_img = (win_image_t){ .fd = -1 };
err = memobj_create(&tmp_memobj, memobj_attr);
if (err) {
goto out;
}
tmp_img->size = (int)nbytes;
tmp_img->width = width;
tmp_img->height = height;
tmp_img->format = format;
tmp_img->usage = usage;
// TODO: set tmp_img->strides
// TODO: set tmp_img->planar_offsets (if more than one plane)
if (memobj_is_always_contiguous(tmp_memobj)
&& EOK == memobj_lock_phys(tmp_memobj)) {
tmp_img->flags |= WIN_IMAGE_FLAG_PHYS_CONTIG;
tmp_img->paddr = (off64_t)memobj_get_phys_layout(tmp_memobj)->paddr;
}
if (prot) {
err = memobj_map(&tmp_img->vaddr, tmp_memobj,
(pid_t)0, prot, (off64_t)0, (size_t)0);
if (err) {
goto out;
}
}
scrmem_attr_set_win_image(scrmem_attr, tmp_img);
scrmem_attr_set_memobj(scrmem_attr, tmp_memobj);
err = scrmem_create(&scrmem_out[alloced], scrmem_attr);
if (err) {
goto out;
} else {
++alloced;
// the 'struct scrmem' owns tmp_* now
tmp_img = NULL;
tmp_memobj = NULL;
}
}
out:
memobj_attr_destroy(memobj_attr);
scrmem_attr_destroy(scrmem_attr);
if (err) {
free(tmp_img);
memobj_close(tmp_memobj);
while (alloced > 0) {
scrmem_close(scrmem_out[--alloced]);
}
}
return err;
}
static void
destructor(struct scrmem *scrmem, void *arg)
{
const win_image_t *img = scrmem_get_win_image(scrmem);
struct memobj *memobj = scrmem_get_memobj(scrmem);
(void)arg;
memobj_close(memobj);
free((win_image_t*)img);
}
