dwl-bar/src/shm.c

149 lines
3.7 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wayland-client-protocol.h>
#include "common.h"
#include "shm.h"
/* For unmapping the mapped memory when we're finished with the shared memory. */
typedef struct MemoryMapping {
void* ptr;
int size;
} MemoryMapping;
/* To help us keep track of our wayland buffers and their data. */
typedef struct Buffer {
wl_buffer* buffer;
uint8_t* buffer_ptr;
} Buffer;
struct ShmPriv {
MemoryMapping* memory;
Buffer buffers[2];
int current; // Since we hold multiple buffers we need to know which we're currently using.
};
static MemoryMapping* memory_mapping_create(int fd, int pool_size);
void memory_mapping_destroy(MemoryMapping* map);
static Buffer buffer_create(MemoryMapping* memmap, wl_shm_pool* shm, int fd, int width, int height, int offset, wl_shm_format format);
static void buffer_destroy(Buffer* buf);
static int allocate_shm(int size);
static const int buffer_amnt = 2;
int allocate_shm(int size) {
char name[] = "wl_shm";
int fd;
if ((fd = shm_open(name, O_CREAT | O_RDWR | O_EXCL, 0600)) < 0) {
die("shm_open when allocating shm");
}
shm_unlink(name);
if (ftruncate(fd, size) < 0) {
die("ftruncate when allocating shm");
}
return fd;
}
MemoryMapping* memory_mapping_create(int fd, int pool_size) {
MemoryMapping* map = ecalloc(1, sizeof(MemoryMapping));
void* ptr = mmap(NULL, pool_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED || !ptr) {
close(fd);
die("MAP_FAILED");
}
map->ptr = ptr;
map->size = pool_size;
return map;
}
void memory_mapping_destroy(MemoryMapping* map) {
munmap(map->ptr, map->size);
free(map);
}
Buffer buffer_create(MemoryMapping* memmap, wl_shm_pool* pool, int fd, int width, int height, int offset, wl_shm_format format) {
int stride = width * 4,
pool_size = height * stride;
Buffer buffer;
if (!memmap)
die("memmap is null");
wl_buffer* wl_buf = wl_shm_pool_create_buffer(pool, offset, width, height, stride, format);
buffer.buffer = wl_buf;
buffer.buffer_ptr = memmap->ptr+offset;
return buffer;
}
void buffer_destroy(Buffer* buffer) {
wl_buffer_destroy(buffer->buffer);
}
Shm* shm_create(int w, int h, wl_shm_format format) {
Shm* _shm = calloc(1, sizeof(Shm));
ShmPriv* priv = calloc(1, sizeof(ShmPriv));
MemoryMapping* memory;
int i, offset,
stride = w * 4,
size = stride * h,
total = size * buffer_amnt;
int fd = allocate_shm(total);
memory = memory_mapping_create(fd, total);
wl_shm_pool* pool = wl_shm_create_pool(shm, fd, total);
for (i = 0; i < buffer_amnt; i++) {
offset = size*i;
priv->buffers[i] = buffer_create(memory, pool, fd, w, h, offset, format);
}
close(fd);
wl_shm_pool_destroy(pool);
priv->memory = memory;
priv->current = 0;
_shm->priv = priv;
_shm->height = h;
_shm->width = w;
_shm->stride = stride;
return _shm;
}
void shm_destroy(Shm* shm) {
uint i;
if (shm->priv->memory) {
memory_mapping_destroy(shm->priv->memory);
}
for (i = 0; i < buffer_amnt; i++) { // REVIEW this may cause problems
if (&shm->priv->buffers[i]) {
buffer_destroy(&shm->priv->buffers[i]);
}
}
}
uint8_t* shm_data(Shm *shm) {
return shm->priv->buffers[shm->priv->current].buffer_ptr;
}
wl_buffer* shm_buffer(Shm *shm) {
return shm->priv->buffers[shm->priv->current].buffer;
}
void shm_flip(Shm *shm) {
shm->priv->current = 1-shm->priv->current;
}