mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-25 23:07:18 +00:00
[obs] implement dmabuf import support on OBS 27+
This commit is contained in:
parent
717b90366b
commit
dda927da18
156
obs/lg.c
156
obs/lg.c
@ -20,10 +20,13 @@
|
|||||||
|
|
||||||
#define _GNU_SOURCE //needed for pthread_setname_np
|
#define _GNU_SOURCE //needed for pthread_setname_np
|
||||||
|
|
||||||
|
#include <obs/obs-config.h>
|
||||||
#include <obs/obs-module.h>
|
#include <obs/obs-module.h>
|
||||||
#include <obs/util/threading.h>
|
#include <obs/util/threading.h>
|
||||||
|
#include <obs/graphics/graphics.h>
|
||||||
#include <obs/graphics/matrix4.h>
|
#include <obs/graphics/matrix4.h>
|
||||||
|
|
||||||
|
#include <common/array.h>
|
||||||
#include <common/ivshmem.h>
|
#include <common/ivshmem.h>
|
||||||
#include <common/KVMFR.h>
|
#include <common/KVMFR.h>
|
||||||
#include <common/framebuffer.h>
|
#include <common/framebuffer.h>
|
||||||
@ -34,6 +37,17 @@
|
|||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the following comes from drm_fourcc.h and is included here to avoid the
|
||||||
|
* external dependency for the few simple defines we need
|
||||||
|
*/
|
||||||
|
#define fourcc_code(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \
|
||||||
|
((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
|
||||||
|
#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4')
|
||||||
|
#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4')
|
||||||
|
#define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0')
|
||||||
|
#define DRM_FORMAT_ABGR16161616F fourcc_code('A', 'B', '4', 'H')
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
STATE_STOPPED,
|
STATE_STOPPED,
|
||||||
@ -44,6 +58,14 @@ typedef enum
|
|||||||
}
|
}
|
||||||
LGState;
|
LGState;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
KVMFRFrame * frame;
|
||||||
|
size_t dataSize;
|
||||||
|
int fd;
|
||||||
|
}
|
||||||
|
DMAFrameInfo;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
obs_source_t * context;
|
obs_source_t * context;
|
||||||
@ -60,6 +82,11 @@ typedef struct
|
|||||||
uint8_t * texData;
|
uint8_t * texData;
|
||||||
uint32_t linesize;
|
uint32_t linesize;
|
||||||
|
|
||||||
|
#if LIBOBS_API_MAJOR_VER >= 27
|
||||||
|
bool dmabuf;
|
||||||
|
DMAFrameInfo dmaInfo[LGMP_Q_FRAME_LEN];
|
||||||
|
#endif
|
||||||
|
|
||||||
pthread_t frameThread, pointerThread;
|
pthread_t frameThread, pointerThread;
|
||||||
os_sem_t * frameSem;
|
os_sem_t * frameSem;
|
||||||
|
|
||||||
@ -114,6 +141,15 @@ static void deinit(LGPlugin * this)
|
|||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
|
|
||||||
case STATE_OPEN:
|
case STATE_OPEN:
|
||||||
|
#if LIBOBS_API_MAJOR_VER >= 27
|
||||||
|
for (int i = 0 ; i < ARRAY_LENGTH(this->dmaInfo); ++i)
|
||||||
|
if (this->dmaInfo[i].fd >= 0)
|
||||||
|
{
|
||||||
|
close(this->dmaInfo[i].fd);
|
||||||
|
this->dmaInfo[i].fd = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
lgmpClientFree(&this->lgmp);
|
lgmpClientFree(&this->lgmp);
|
||||||
ivshmemClose(&this->shmDev);
|
ivshmemClose(&this->shmDev);
|
||||||
break;
|
break;
|
||||||
@ -168,6 +204,9 @@ static obs_properties_t * lgGetProperties(void * data)
|
|||||||
obs_properties_t * props = obs_properties_create();
|
obs_properties_t * props = obs_properties_create();
|
||||||
|
|
||||||
obs_properties_add_text(props, "shmFile", obs_module_text("SHM File"), OBS_TEXT_DEFAULT);
|
obs_properties_add_text(props, "shmFile", obs_module_text("SHM File"), OBS_TEXT_DEFAULT);
|
||||||
|
#if LIBOBS_API_MAJOR_VER >= 27
|
||||||
|
obs_properties_add_bool(props, "dmabuf", obs_module_text("Use DMABUF import (requires kvmfr device)"));
|
||||||
|
#endif
|
||||||
|
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
@ -341,6 +380,10 @@ static void lgUpdate(void * data, obs_data_t * settings)
|
|||||||
if (!ivshmemOpenDev(&this->shmDev, this->shmFile))
|
if (!ivshmemOpenDev(&this->shmDev, this->shmFile))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if LIBOBS_API_MAJOR_VER >= 27
|
||||||
|
this->dmabuf = obs_data_get_bool(settings, "dmabuf") && ivshmemHasDMA(&this->shmDev);
|
||||||
|
#endif
|
||||||
|
|
||||||
this->state = STATE_OPEN;
|
this->state = STATE_OPEN;
|
||||||
|
|
||||||
uint32_t udataSize;
|
uint32_t udataSize;
|
||||||
@ -373,6 +416,57 @@ static void lgUpdate(void * data, obs_data_t * settings)
|
|||||||
pthread_setname_np(this->pointerThread, "LGPointerThread");
|
pthread_setname_np(this->pointerThread, "LGPointerThread");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LIBOBS_API_MAJOR_VER >= 27
|
||||||
|
static int dmabufGetFd(LGPlugin * this, LGMPMessage * msg, KVMFRFrame * frame, size_t dataSize)
|
||||||
|
{
|
||||||
|
DMAFrameInfo * dma = NULL;
|
||||||
|
|
||||||
|
/* find the existing dma buffer if it exists */
|
||||||
|
for (int i = 0; i < ARRAY_LENGTH(this->dmaInfo); ++i)
|
||||||
|
if (this->dmaInfo[i].frame == frame)
|
||||||
|
{
|
||||||
|
dma = this->dmaInfo + i;
|
||||||
|
/* if it's too small close it */
|
||||||
|
if (dma->dataSize < dataSize)
|
||||||
|
{
|
||||||
|
close(dma->fd);
|
||||||
|
dma->fd = -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* otherwise find a free buffer for use */
|
||||||
|
if (!dma)
|
||||||
|
for (int i = 0; i < ARRAY_LENGTH(this->dmaInfo); ++i)
|
||||||
|
if (!this->dmaInfo[i].frame)
|
||||||
|
{
|
||||||
|
dma = this->dmaInfo + i;
|
||||||
|
dma->frame = frame;
|
||||||
|
dma->fd = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(dma);
|
||||||
|
|
||||||
|
/* open the buffer */
|
||||||
|
if (dma->fd == -1)
|
||||||
|
{
|
||||||
|
const uintptr_t pos = (uintptr_t) msg->mem - (uintptr_t) this->shmDev.mem;
|
||||||
|
const uintptr_t offset = (uintptr_t) frame->offset + FrameBufferStructSize;
|
||||||
|
|
||||||
|
dma->dataSize = dataSize;
|
||||||
|
dma->fd = ivshmemGetDMABuf(&this->shmDev, pos + offset, dataSize);
|
||||||
|
if (dma->fd < 0)
|
||||||
|
{
|
||||||
|
puts("Failed to get the DMA buffer for the frame");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dma->fd;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void lgVideoTick(void * data, float seconds)
|
static void lgVideoTick(void * data, float seconds)
|
||||||
{
|
{
|
||||||
LGPlugin * this = (LGPlugin *)data;
|
LGPlugin * this = (LGPlugin *)data;
|
||||||
@ -382,6 +476,7 @@ static void lgVideoTick(void * data, float seconds)
|
|||||||
|
|
||||||
LGMP_STATUS status;
|
LGMP_STATUS status;
|
||||||
LGMPMessage msg;
|
LGMPMessage msg;
|
||||||
|
bool framebuffer = true;
|
||||||
|
|
||||||
os_sem_wait(this->frameSem);
|
os_sem_wait(this->frameSem);
|
||||||
if (this->state != STATE_RUNNING)
|
if (this->state != STATE_RUNNING)
|
||||||
@ -448,7 +543,6 @@ static void lgVideoTick(void * data, float seconds)
|
|||||||
os_sem_post(this->cursorSem);
|
os_sem_post(this->cursorSem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ((status = lgmpClientAdvanceToLast(this->frameQueue)) != LGMP_OK)
|
if ((status = lgmpClientAdvanceToLast(this->frameQueue)) != LGMP_OK)
|
||||||
{
|
{
|
||||||
if (status != LGMP_ERR_QUEUE_EMPTY)
|
if (status != LGMP_ERR_QUEUE_EMPTY)
|
||||||
@ -490,16 +584,30 @@ static void lgVideoTick(void * data, float seconds)
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum gs_color_format format;
|
enum gs_color_format format;
|
||||||
|
uint32_t drm_format;
|
||||||
|
|
||||||
this->bpp = 4;
|
this->bpp = 4;
|
||||||
switch(this->type)
|
switch(this->type)
|
||||||
{
|
{
|
||||||
case FRAME_TYPE_BGRA : format = GS_BGRA ; break;
|
case FRAME_TYPE_BGRA:
|
||||||
case FRAME_TYPE_RGBA : format = GS_RGBA ; break;
|
format = GS_BGRA;
|
||||||
case FRAME_TYPE_RGBA10 : format = GS_R10G10B10A2; break;
|
drm_format = DRM_FORMAT_ARGB8888;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FRAME_TYPE_RGBA:
|
||||||
|
format = GS_RGBA;
|
||||||
|
drm_format = DRM_FORMAT_ARGB8888;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FRAME_TYPE_RGBA10:
|
||||||
|
format = GS_R10G10B10A2;
|
||||||
|
drm_format = DRM_FORMAT_BGRA1010102;
|
||||||
|
break;
|
||||||
|
|
||||||
case FRAME_TYPE_RGBA16F:
|
case FRAME_TYPE_RGBA16F:
|
||||||
this->bpp = 8;
|
this->bpp = 8;
|
||||||
format = GS_RGBA16F;
|
format = GS_RGBA16F;
|
||||||
|
drm_format = DRM_FORMAT_ABGR16161616F;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -509,8 +617,38 @@ static void lgVideoTick(void * data, float seconds)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->texture = gs_texture_create(
|
this->texture = NULL;
|
||||||
this->width, this->height, format, 1, NULL, GS_DYNAMIC);
|
|
||||||
|
#if LIBOBS_API_MAJOR_VER >= 27
|
||||||
|
if (this->dmabuf)
|
||||||
|
{
|
||||||
|
int fd = dmabufGetFd(this, &msg, frame, frame->height * frame->pitch);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
goto dmabuf_fail;
|
||||||
|
|
||||||
|
this->texture = gs_texture_create_from_dmabuf(frame->width, frame->height,
|
||||||
|
drm_format, format, 1, &fd, &(uint32_t) { frame->pitch },
|
||||||
|
&(uint32_t) { 0 }, &(uint64_t) { 0 });
|
||||||
|
|
||||||
|
if (!this->texture)
|
||||||
|
{
|
||||||
|
puts("Failed to create dmabuf texture");
|
||||||
|
this->dmabuf = false;
|
||||||
|
goto dmabuf_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
framebuffer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmabuf_fail:
|
||||||
|
#else
|
||||||
|
(void) drm_format;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!this->texture)
|
||||||
|
this->texture = gs_texture_create(
|
||||||
|
this->width, this->height, format, 1, NULL, GS_DYNAMIC);
|
||||||
|
|
||||||
if (!this->texture)
|
if (!this->texture)
|
||||||
{
|
{
|
||||||
@ -524,7 +662,7 @@ static void lgVideoTick(void * data, float seconds)
|
|||||||
obs_leave_graphics();
|
obs_leave_graphics();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->texture)
|
if (framebuffer && this->texture)
|
||||||
{
|
{
|
||||||
FrameBuffer * fb = (FrameBuffer *)(((uint8_t*)frame) + frame->offset);
|
FrameBuffer * fb = (FrameBuffer *)(((uint8_t*)frame) + frame->offset);
|
||||||
framebuffer_read(
|
framebuffer_read(
|
||||||
|
Loading…
Reference in New Issue
Block a user