1
0
mirror of https://github.com/jojo61/vdr-plugin-softhdcuvid.git synced 2023-10-10 13:37:41 +02:00

More changes for HDR support with kernel 5.12

Support for LUTs
Removed default PIP witch cuvid
This commit is contained in:
jojo61 2021-03-16 09:40:08 +01:00
parent c09bad125d
commit 891d432536
7 changed files with 386 additions and 200 deletions

View File

@ -36,7 +36,7 @@ LIBPLACEBO_GL ?= 0
CONFIG := #-DDEBUG # remove # to enable debug output
CONFIG := -DDEBUG # remove # to enable debug output
@ -214,7 +214,7 @@ endif
ifeq ($(CUVID),1)
CONFIG += -DUSE_PIP # PIP support
#CONFIG += -DUSE_PIP # PIP support
CONFIG += -DCUVID # enable CUVID decoder
LIBS += -lEGL -lGL
ifeq ($(YADIF),1)
@ -321,7 +321,7 @@ DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -D_GNU_SOURCE $(CONFIG) \
override CXXFLAGS += $(_CFLAGS) $(DEFINES) $(INCLUDES) \
-g -W -Wextra -Winit-self -Werror=overloaded-virtual -Wno-unused-parameter
override CFLAGS += $(_CFLAGS) $(DEFINES) $(INCLUDES) \
-g -W -Wextra -Winit-self -Wdeclaration-after-statement
-g -W -Wextra -Winit-self -std=gnu99
### The object files (add further files here):

195
drm.c
View File

@ -23,7 +23,7 @@ struct _Drm_Render_
uint32_t connector_id, crtc_id, video_plane;
uint32_t hdr_metadata;
uint32_t mmWidth,mmHeight; // Size in mm
uint32_t hdr_blob_id;
uint32_t hdr_blob_id;
};
typedef struct _Drm_Render_ VideoRender;
@ -186,33 +186,33 @@ static int SetPropertyRequest(drmModeAtomicReqPtr ModeReq, int fd_drm,
static void CuvidSetVideoMode(void);
void set_video_mode(int width, int height)
{
drmModeConnector *connector;
drmModeModeInfo *mode;
int ii;
if (height != 1080 && height != 2160)
return;
connector = drmModeGetConnector(render->fd_drm, render->connector_id);
for (ii = 0; ii < connector->count_modes; ii++) {
mode = &connector->modes[ii];
printf("Mode %d %dx%d Rate %d\n",ii,mode->hdisplay,mode->vdisplay,mode->vrefresh);
if (width == mode->hdisplay &&
height == mode->vdisplay &&
mode->vrefresh == DRMRefresh &&
render->mode.hdisplay != width &&
render->mode.vdisplay != height &&
!(mode->flags & DRM_MODE_FLAG_INTERLACE)) {
memcpy(&render->mode, mode, sizeof(drmModeModeInfo));
VideoWindowWidth = mode->hdisplay;
drmModeConnector *connector;
drmModeModeInfo *mode;
int ii;
if (height != 1080 && height != 2160)
return;
connector = drmModeGetConnector(render->fd_drm, render->connector_id);
for (ii = 0; ii < connector->count_modes; ii++) {
mode = &connector->modes[ii];
printf("Mode %d %dx%d Rate %d\n",ii,mode->hdisplay,mode->vdisplay,mode->vrefresh);
if (width == mode->hdisplay &&
height == mode->vdisplay &&
mode->vrefresh == DRMRefresh &&
render->mode.hdisplay != width &&
render->mode.vdisplay != height &&
!(mode->flags & DRM_MODE_FLAG_INTERLACE)) {
memcpy(&render->mode, mode, sizeof(drmModeModeInfo));
VideoWindowWidth = mode->hdisplay;
VideoWindowHeight = mode->vdisplay;
eglDestroySurface (eglDisplay, eglSurface);
EglCheck();
gbm_surface_destroy (gbm.surface);
InitBo(render->bpp);
CuvidSetVideoMode();
Debug(3,"Set new mode %d:%d\n",mode->hdisplay,mode->vdisplay);
break;
}
}
eglDestroySurface (eglDisplay, eglSurface);
EglCheck();
gbm_surface_destroy (gbm.surface);
InitBo(render->bpp);
CuvidSetVideoMode();
Debug(3,"Set new mode %d:%d\n",mode->hdisplay,mode->vdisplay);
break;
}
}
}
static int FindDevice(VideoRender * render)
@ -234,33 +234,33 @@ static int FindDevice(VideoRender * render)
#ifdef RASPI
render->fd_drm = open("/dev/dri/card1", O_RDWR);
#else
render->fd_drm = open("/dev/dri/card0", O_RDWR);
render->fd_drm = open("/dev/dri/card0", O_RDWR);
#endif
if (render->fd_drm < 0) {
fprintf(stderr, "FindDevice: cannot open /dev/dri/card0: %m\n");
return -errno;
}
int ret = drmSetMaster(render->fd_drm);
int ret = drmSetMaster(render->fd_drm);
if (ret < 0)
{
drm_magic_t magic;
if (ret < 0)
{
drm_magic_t magic;
ret = drmGetMagic(render->fd_drm, &magic);
if (ret < 0)
{
Debug(3, "drm:%s - failed to get drm magic: %s\n", __FUNCTION__, strerror(errno));
return -1;
}
ret = drmGetMagic(render->fd_drm, &magic);
if (ret < 0)
{
Debug(3, "drm:%s - failed to get drm magic: %s\n", __FUNCTION__, strerror(errno));
return -1;
}
ret = drmAuthMagic(render->fd_drm, magic);
if (ret < 0)
{
Debug(3, "drm:%s - failed to authorize drm magic: %s\n", __FUNCTION__, strerror(errno));
return -1;
}
}
ret = drmAuthMagic(render->fd_drm, magic);
if (ret < 0)
{
Debug(3, "drm:%s - failed to authorize drm magic: %s\n", __FUNCTION__, strerror(errno));
return -1;
}
}
version = drmGetVersion(render->fd_drm);
fprintf(stderr, "FindDevice: open /dev/dri/card0: %s\n", version->name);
@ -309,15 +309,15 @@ static int FindDevice(VideoRender * render)
continue;
if (connector->connection == DRM_MODE_CONNECTED && connector->count_modes > 0) {
float aspect = (float)connector->mmWidth / (float)connector->mmHeight;
if ((aspect > 1.70) && (aspect < 1.85)) {
render->mmHeight = 90;
render->mmWidth = 160;
} else {
render->mmHeight = connector->mmHeight;
render->mmWidth = connector->mmWidth;
}
render->connector_id = connector->connector_id;
float aspect = (float)connector->mmWidth / (float)connector->mmHeight;
if ((aspect > 1.70) && (aspect < 1.85)) {
render->mmHeight = 90;
render->mmWidth = 160;
} else {
render->mmHeight = connector->mmHeight;
render->mmWidth = connector->mmWidth;
}
render->connector_id = connector->connector_id;
// FIXME: use default encoder/crtc pair
if ((encoder = drmModeGetEncoder(render->fd_drm, connector->encoder_id)) == NULL){
fprintf(stderr, "FindDevice: cannot retrieve encoder (%d): %m\n", errno);
@ -403,7 +403,7 @@ static int FindDevice(VideoRender * render)
#ifdef RASPI
case DRM_FORMAT_ARGB8888:
#else
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_XRGB2101010:
#endif
if (!render->video_plane) {
render->video_plane = plane->plane_id;
@ -440,7 +440,6 @@ void VideoInitDrm()
{
int i;
if (!(render = calloc(1, sizeof(*render)))) {
Fatal(_("video/DRM: out of memory\n"));
return;
@ -454,12 +453,15 @@ void VideoInitDrm()
assert (gbm.dev != NULL);
PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
get_platform_display =
(void *) eglGetProcAddress("eglGetPlatformDisplay");
(void *) eglGetProcAddress("eglGetPlatformDisplayEXT");
assert(get_platform_display != NULL);
eglDisplay = get_platform_display(EGL_PLATFORM_GBM_KHR, gbm.dev, NULL);
EglCheck();
assert (eglDisplay != NULL);
// return;
@ -475,7 +477,7 @@ void VideoInitDrm()
fprintf(stderr, "cannot allocate atomic request (%d): %m\n", errno);
return;
}
printf("set CRTC %d of Connector %d aktiv\n",render->crtc_id,render->connector_id);
printf("set CRTC %d of Connector %d aktiv\n",render->crtc_id,render->connector_id);
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
DRM_MODE_OBJECT_CRTC, "MODE_ID", modeID);
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id,
@ -506,6 +508,7 @@ static int old_color=-1,old_trc=-1;
void InitBo(int bpp) {
// create the GBM and EGL surface
render->bpp = bpp;
gbm.surface = gbm_surface_create (gbm.dev, VideoWindowWidth,VideoWindowHeight,
bpp==10?GBM_FORMAT_XRGB2101010:GBM_FORMAT_ARGB8888,
@ -518,6 +521,7 @@ void InitBo(int bpp) {
static struct gbm_bo *previous_bo = NULL;
static uint32_t previous_fb;
static int has_modeset = 0;
static void drm_swap_buffers () {
@ -556,10 +560,13 @@ static void drm_swap_buffers () {
DRM_MODE_OBJECT_CRTC, "ACTIVE", 0);
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
sleep(2);
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id,
DRM_MODE_OBJECT_CONNECTOR, "Colorspace",old_color==AVCOL_PRI_BT2020?9:2 );
SetPropertyRequest(ModeReq, render->fd_drm, render->video_plane,
DRM_MODE_OBJECT_PLANE, "COLOR_ENCODING",old_color==AVCOL_PRI_BT2020?2:1 );
SetPropertyRequest(ModeReq, render->fd_drm, render->video_plane,
DRM_MODE_OBJECT_PLANE, "COLOR_RANGE",0 );
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
DRM_MODE_OBJECT_CRTC, "MODE_ID", modeID);
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id,
@ -568,13 +575,14 @@ static void drm_swap_buffers () {
DRM_MODE_OBJECT_CRTC, "ACTIVE", 1);
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
fprintf(stderr, "cannot set atomic mode modeset 2 (%d): %m\n", errno);
if (drmModeDestroyPropertyBlob(render->fd_drm, modeID) != 0)
fprintf(stderr, "cannot destroy prperty blob (%d): %m\n", errno);
drmModeAtomicFree(ModeReq);
m_need_modeset = 0;
has_modeset = 1;
}
drmModeSetCrtc (render->fd_drm, render->crtc_id, fb, 0, 0, &render->connector_id, 1, &render->mode);
@ -594,7 +602,7 @@ static void drm_clean_up () {
return;
Debug(3,"drm clean up\n");
if (previous_bo) {
if (previous_bo) {
drmModeRmFB (render->fd_drm, previous_fb);
gbm_surface_release_buffer (gbm.surface, previous_bo);
}
@ -603,26 +611,71 @@ static void drm_clean_up () {
render->saved_crtc->x, render->saved_crtc->y, &render->connector_id, 1, &render->saved_crtc->mode);
drmModeFreeCrtc (render->saved_crtc);
if (has_modeset) {
drmModeAtomicReqPtr ModeReq;
const uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
uint32_t modeID = 0;
if (drmModeCreatePropertyBlob(render->fd_drm, &render->mode, sizeof(render->mode), &modeID) != 0) {
fprintf(stderr, "Failed to create mode property.\n");
return;
}
if (!(ModeReq = drmModeAtomicAlloc())) {
fprintf(stderr, "cannot allocate atomic request (%d): %m\n", errno);
return;
}
// Need to disable the CRTC in order to submit the HDR data....
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
DRM_MODE_OBJECT_CRTC, "ACTIVE", 0);
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id,
DRM_MODE_OBJECT_CONNECTOR, "HDR_OUTPUT_METADATA", 0);
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id,
DRM_MODE_OBJECT_CONNECTOR, "Colorspace",2 );
SetPropertyRequest(ModeReq, render->fd_drm, render->video_plane,
DRM_MODE_OBJECT_PLANE, "COLOR_ENCODING",1 );
SetPropertyRequest(ModeReq, render->fd_drm, render->video_plane,
DRM_MODE_OBJECT_PLANE, "COLOR_RANGE",1 );
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
DRM_MODE_OBJECT_CRTC, "MODE_ID", modeID);
SetPropertyRequest(ModeReq, render->fd_drm, render->connector_id,
DRM_MODE_OBJECT_CONNECTOR, "CRTC_ID", render->crtc_id);
SetPropertyRequest(ModeReq, render->fd_drm, render->crtc_id,
DRM_MODE_OBJECT_CRTC, "ACTIVE", 1);
if (drmModeAtomicCommit(render->fd_drm, ModeReq, flags, NULL) != 0)
fprintf(stderr, "cannot set atomic mode (%d): %m\n", errno);
if (drmModeDestroyPropertyBlob(render->fd_drm, modeID) != 0)
fprintf(stderr, "cannot destroy prperty blob (%d): %m\n", errno);
drmModeAtomicFree(ModeReq);
has_modeset = 0;
}
if (render->hdr_blob_id)
drmModeDestroyPropertyBlob(render->fd_drm, render->hdr_blob_id);
render->hdr_blob_id = 0;
render->hdr_blob_id = 0;
eglDestroySurface (eglDisplay, eglSurface);
EglCheck();
EglCheck();
gbm_surface_destroy (gbm.surface);
eglDestroyContext (eglDisplay, eglContext);
EglCheck();
eglDestroyContext (eglDisplay, eglSharedContext);
EglCheck();
eglSharedContext = NULL;
EglCheck();
eglDestroyContext (eglDisplay, eglSharedContext);
EglCheck();
eglSharedContext = NULL;
eglTerminate (eglDisplay);
EglCheck();
EglCheck();
gbm_device_destroy (gbm.dev);
drmDropMaster(render->fd_drm);
drmDropMaster(render->fd_drm);
close (render->fd_drm);
eglDisplay = NULL;
free(render);
eglDisplay = NULL;
free(render);
}

15
hdr.c
View File

@ -1,5 +1,5 @@
#include <libavutil/mastering_display_metadata.h>
#if 0
/**
* struct hdr_metadata_infoframe - HDR Metadata Infoframe Data.
*
@ -85,7 +85,7 @@ struct hdr_output_metadata {
struct hdr_metadata_infoframe hdmi_metadata_type1;
};
};
#endif
enum hdr_metadata_eotf {
@ -336,8 +336,8 @@ static void set_hdr_metadata(int color,int trc, AVFrameSideData *sd1, AVFrameSid
struct AVContentLightMetadata *ld = NULL;
if (render->hdr_metadata == -1) { // Metadata not supported
return;
}
return;
}
// clean up FFMEPG stuff
if (trc == AVCOL_TRC_BT2020_10)
@ -392,7 +392,7 @@ static void set_hdr_metadata(int color,int trc, AVFrameSideData *sd1, AVFrameSid
break;
case AVCOL_TRC_SMPTE2084: // 16
eotf = EOTF_ST2084;
break;
break;
default:
eotf = EOTF_TRADITIONAL_GAMMA_SDR;
break;
@ -471,7 +471,7 @@ static void set_hdr_metadata(int color,int trc, AVFrameSideData *sd1, AVFrameSid
ret = drmModeCreatePropertyBlob(render->fd_drm, &data, sizeof(data), &render->hdr_blob_id);
if (ret) {
printf("DRM: HDR metadata: failed blob create \n");
render->hdr_blob_id = 0;
render->hdr_blob_id = 0;
return;
}
@ -482,9 +482,10 @@ static void set_hdr_metadata(int color,int trc, AVFrameSideData *sd1, AVFrameSid
if (render->hdr_blob_id)
drmModeDestroyPropertyBlob(render->fd_drm, render->hdr_blob_id);
render->hdr_blob_id = 0;
render->hdr_blob_id = 0;
return;
}
m_need_modeset = 1;
Debug(3,"DRM: HDR metadata: prop set\n");

View File

@ -123,17 +123,17 @@ static const struct gl_vao_entry vertex_vao[] = {
char sh[SHADER_LENGTH];
char shv[SHADER_LENGTH];
GL_init()
void GL_init()
{
sh[0] = 0;
}
GLV_init()
void GLV_init()
{
shv[0] = 0;
}
pl_shader_append(const char *fmt, ...)
void pl_shader_append(const char *fmt, ...)
{
char temp[1000];
va_list ap;
@ -148,7 +148,7 @@ pl_shader_append(const char *fmt, ...)
}
pl_shader_append_v(const char *fmt, ...)
void pl_shader_append_v(const char *fmt, ...)
{
char temp[1000];
va_list ap;

View File

@ -53,7 +53,9 @@ extern "C"
#endif
#if PLACEBO
#include <libplacebo/filters.h>
extern void ToggleLUT();
#endif
}
//////////////////////////////////////////////////////////////////////////////
@ -61,7 +63,7 @@ extern "C"
/// vdr-plugin version number.
/// Makefile extracts the version number for generating the file name
/// for the distribution archive.
static const char *const VERSION = "3.3.2"
static const char *const VERSION = "3.4"
#ifdef GIT_REV
"-GIT" GIT_REV
#endif
@ -2143,13 +2145,15 @@ void cSoftHdMenu::Create(void)
} else {
Add(new cOsdItem(hk(tr("Suspend SoftHdDevice")), osUser1));
}
#ifdef PLACEBO
Add(new cOsdItem(hk(tr("Toggle LUT on/off")), osUser2));
#endif
#ifdef USE_PIP
if (PipReceiver) {
Add(new cOsdItem(hk(tr("PIP toggle on/off: off")), osUser2));
Add(new cOsdItem(hk(tr("PIP toggle on/off: off")), osUser3));
} else {
Add(new cOsdItem(hk(tr("PIP toggle on/off: on")), osUser2));
Add(new cOsdItem(hk(tr("PIP toggle on/off: on")), osUser3));
}
Add(new cOsdItem(hk(tr("PIP zapmode (not working)")), osUser3));
Add(new cOsdItem(hk(tr("PIP channel +")), osUser4));
Add(new cOsdItem(hk(tr("PIP channel -")), osUser5));
if (PipReceiver) {
@ -2163,6 +2167,7 @@ void cSoftHdMenu::Create(void)
Add(new cOsdItem(hk(tr("PIP swap position: alternative")), osUser7));
}
Add(new cOsdItem(hk(tr("PIP close")), osUser8));
#endif
Add(new cOsdItem(NULL, osUnknown, false));
Add(new cOsdItem(NULL, osUnknown, false));
@ -2402,8 +2407,13 @@ eOSState cSoftHdMenu::ProcessKey(eKeys key)
}
}
return osEnd;
#ifdef PLACEBO
case osUser2:
ToggleLUT();
return osEnd;
#endif
#ifdef USE_PIP
case osUser2:
case osUser3:
TogglePip();
return osEnd;
case osUser4:

View File

@ -1793,7 +1793,7 @@ static void VideoStreamClose(VideoStream * stream, int delhw)
*/
int VideoPollInput(VideoStream * stream)
{
if (!stream->Decoder) { // closing
if (!stream->Decoder || !stream->HwDecoder) { // closing
#ifdef DEBUG
fprintf(stderr, "no decoder\n");
#endif
@ -1810,9 +1810,9 @@ int VideoPollInput(VideoStream * stream)
stream->PacketRead = stream->PacketWrite;
// FIXME: ->Decoder already checked
Debug(3, "Clear buffer request in Poll\n");
if (stream->Decoder) {
if (stream->Decoder && stream->HwDecoder) {
CodecVideoFlushBuffers(stream->Decoder);
VideoResetStart(stream->HwDecoder);
// VideoResetStart(stream->HwDecoder);
}
stream->ClearBuffers = 0;
return 1;
@ -3391,8 +3391,8 @@ void GetStats(int *missed, int *duped, int *dropped, int *counter, float *framet
*frametime = 0.0f;
*width = 0;
*height = 0;
*color = NULL;
*eotf = NULL;
*color = 0;
*eotf = 0;
if (MyVideoStream->HwDecoder) {
VideoGetStats(MyVideoStream->HwDecoder, missed, duped, dropped, counter, frametime, width, height, color,
eotf);

318
video.c
View File

@ -140,6 +140,7 @@ typedef enum
#endif
#include <libavutil/hwcontext.h>
#include <libavutil/mastering_display_metadata.h>
#include <libavutil/pixdesc.h>
#ifdef CUVID
@ -186,6 +187,9 @@ typedef void *EGLImageKHR;
#define VK_USE_PLATFORM_XCB_KHR
#include <libplacebo/vulkan.h>
#endif
#if PL_API_VER >= 113
#include <libplacebo/shaders/lut.h>
#endif
#include <libplacebo/renderer.h>
#endif
@ -455,6 +459,7 @@ static float VideoColorBlindnessFaktor = 1.0f;
static char* shadersp[NUM_SHADERS];
char MyConfigDir[200];
static int num_shaders = 0;
static int LUTon = -1;
static xcb_atom_t WmDeleteWindowAtom; ///< WM delete message atom
static xcb_atom_t NetWmState; ///< wm-state message atom
@ -1391,7 +1396,7 @@ typedef struct _cuvid_decoder_
int fds[(CODEC_SURFACES_MAX + 1) * 2];
#endif
#ifdef PLACEBO
struct pl_image pl_images[CODEC_SURFACES_MAX + 1]; // images for Placebo chain
struct pl_frame pl_frames[CODEC_SURFACES_MAX + 1]; // images for Placebo chain
struct ext_buf ebuf[CODEC_SURFACES_MAX + 1]; // for managing vk buffer
#endif
@ -1430,17 +1435,27 @@ static CudaFunctions *cu;
#endif
#ifdef PLACEBO
struct file
{
void *data;
size_t size;
};
typedef struct priv
{
const struct pl_gpu *gpu;
const struct pl_vulkan *vk;
const struct pl_vk_inst *vk_inst;
struct pl_context *ctx;
#if PL_API_VER >= 113
struct pl_custom_lut *lut;
#endif
struct pl_renderer *renderer;
struct pl_renderer *renderertest;
const struct pl_swapchain *swapchain;
struct pl_context_params context;
// struct pl_render_target r_target;
// struct pl_frame r_target;
// struct pl_render_params r_params;
// struct pl_tex final_fbo;
#ifndef PLACEBO_GL
@ -1451,10 +1466,9 @@ typedef struct priv
#ifdef PLACEBO_GL
struct pl_opengl *gl;
#endif
#if PL_API_VER >= 58
const struct pl_hook *hook[NUM_SHADERS];
int num_shaders;
#endif
} priv;
static priv *p;
@ -1606,15 +1620,15 @@ static void CuvidDestroySurfaces(CuvidDecoder * decoder)
}
for (j = 0; j < Planes; j++) {
#ifdef PLACEBO
if (decoder->pl_images[i].planes[j].texture) {
if (decoder->pl_frames[i].planes[j].texture) {
#ifdef VAAPI
if (p->has_dma_buf && decoder->pl_images[i].planes[j].texture->params.shared_mem.handle.fd) {
close(decoder->pl_images[i].planes[j].texture->params.shared_mem.handle.fd);
if (p->has_dma_buf && decoder->pl_frames[i].planes[j].texture->params.shared_mem.handle.fd) {
close(decoder->pl_frames[i].planes[j].texture->params.shared_mem.handle.fd);
}
#endif
SharedContext;
pl_tex_destroy(p->gpu, &decoder->pl_images[i].planes[j].texture);
pl_tex_destroy(p->gpu, &decoder->pl_frames[i].planes[j].texture);
NoContext;
}
#else
@ -1717,17 +1731,17 @@ static void CuvidReleaseSurface(CuvidDecoder * decoder, int surface)
#ifdef PLACEBO
SharedContext;
if (p->has_dma_buf) {
if (decoder->pl_images[surface].planes[0].texture) {
if (decoder->pl_images[surface].planes[0].texture->params.shared_mem.handle.fd) {
close(decoder->pl_images[surface].planes[0].texture->params.shared_mem.handle.fd);
if (decoder->pl_frames[surface].planes[0].texture) {
if (decoder->pl_frames[surface].planes[0].texture->params.shared_mem.handle.fd) {
close(decoder->pl_frames[surface].planes[0].texture->params.shared_mem.handle.fd);
}
pl_tex_destroy(p->gpu, &decoder->pl_images[surface].planes[0].texture);
pl_tex_destroy(p->gpu, &decoder->pl_frames[surface].planes[0].texture);
}
if (decoder->pl_images[surface].planes[1].texture) {
if (decoder->pl_images[surface].planes[1].texture->params.shared_mem.handle.fd) {
close(decoder->pl_images[surface].planes[1].texture->params.shared_mem.handle.fd);
if (decoder->pl_frames[surface].planes[1].texture) {
if (decoder->pl_frames[surface].planes[1].texture->params.shared_mem.handle.fd) {
close(decoder->pl_frames[surface].planes[1].texture->params.shared_mem.handle.fd);
}
pl_tex_destroy(p->gpu, &decoder->pl_images[surface].planes[1].texture);
pl_tex_destroy(p->gpu, &decoder->pl_frames[surface].planes[1].texture);
}
}
NoContext;
@ -1884,6 +1898,7 @@ static bool create_context_cb(EGLDisplay display, int es_version, EGLContext * o
attribs = attributes10;
*bpp = 10;
if (!eglChooseConfig(display, attributes10, NULL, 0, &num_configs)) { // try 10 Bit
EglCheck();
Debug(3, " 10 Bit egl Failed\n");
attribs = attributes8;
*bpp = 8;
@ -2266,7 +2281,7 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
int n, i, size = 1, fd;
const struct pl_fmt *fmt;
struct pl_tex *tex;
struct pl_image *img;
struct pl_frame *img;
struct pl_plane *pl;
SharedContext;
@ -2289,17 +2304,17 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
fmt = pl_find_named_fmt(p->gpu, n == 0 ? "r16" : "rg16"); // 10 Bit YUV
size = 2;
}
if (decoder->pl_images[i].planes[n].texture) {
if (decoder->pl_frames[i].planes[n].texture) {
// #ifdef VAAPI
if (decoder->pl_images[i].planes[n].texture->params.shared_mem.handle.fd) {
close(decoder->pl_images[i].planes[n].texture->params.shared_mem.handle.fd);
if (decoder->pl_frames[i].planes[n].texture->params.shared_mem.handle.fd) {
close(decoder->pl_frames[i].planes[n].texture->params.shared_mem.handle.fd);
}
// #endif
pl_tex_destroy(p->gpu, &decoder->pl_images[i].planes[n].texture); // delete old texture
pl_tex_destroy(p->gpu, &decoder->pl_frames[i].planes[n].texture); // delete old texture
}
if (p->has_dma_buf == 0) {
decoder->pl_images[i].planes[n].texture = pl_tex_create(p->gpu, &(struct pl_tex_params) {
decoder->pl_frames[i].planes[n].texture = pl_tex_create(p->gpu, &(struct pl_tex_params) {
.w = n == 0 ? size_x : size_x / 2,
.h = n == 0 ? size_y : size_y / 2,
.d = 0,
@ -2316,7 +2331,7 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
}
// make planes for image
pl = &decoder->pl_images[i].planes[n];
pl = &decoder->pl_frames[i].planes[n];
pl->components = n == 0 ? 1 : 2;
pl->shift_x = 0.0f;
pl->shift_y = 0.0f;
@ -2336,16 +2351,16 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
Fatal(_("Unable to create placebo textures"));
}
#ifdef CUVID
fd = dup(decoder->pl_images[i].planes[n].texture->shared_mem.handle.fd);
fd = dup(decoder->pl_frames[i].planes[n].texture->shared_mem.handle.fd);
CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = {
.type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD,
.handle.fd = fd,
.size = decoder->pl_images[i].planes[n].texture->shared_mem.size, // image_width * image_height * bytes,
.size = decoder->pl_frames[i].planes[n].texture->shared_mem.size, // image_width * image_height * bytes,
.flags = 0,
};
checkCudaErrors(cu->cuImportExternalMemory(&decoder->ebuf[i * 2 + n].mem, &ext_desc)); // Import Memory segment
CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC tex_desc = {
.offset = decoder->pl_images[i].planes[n].texture->shared_mem.offset,
.offset = decoder->pl_frames[i].planes[n].texture->shared_mem.offset,
.arrayDesc = {
.Width = n == 0 ? size_x : size_x / 2,
.Height = n == 0 ? size_y : size_y / 2,
@ -2362,7 +2377,7 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
#endif
}
// make image
img = &decoder->pl_images[i];
img = &decoder->pl_frames[i];
img->signature = i;
img->num_planes = 2;
img->repr.sys = PL_COLOR_SYSTEM_BT_709; // overwritten later
@ -2380,6 +2395,7 @@ void createTextureDst(CuvidDecoder * decoder, int anz, unsigned int size_x, unsi
NoContext;
}
#ifdef VAAPI
// copy image and process using CUDA
@ -2413,18 +2429,21 @@ void generateVAAPIImage(CuvidDecoder * decoder, int index, const AVFrame * frame
return;
}
// fmt = pl_find_fourcc(p->gpu,desc.layers[n].drm_format);
#if 1
if (decoder->PixFmt == AV_PIX_FMT_NV12) {
fmt = pl_find_named_fmt(p->gpu, n == 0 ? "r8" : "rg8"); // 8 Bit YUV
} else {
fmt = pl_find_named_fmt(p->gpu, n == 0 ? "r16" : "rg16"); // 10 Bit YUV
}
#endif
assert(fmt != NULL);
#ifdef PLACEBO_GL
fmt->fourcc = desc.layers[n].drm_format;
#endif
struct pl_tex_params tex_params = {
.w = n == 0 ? image_width : image_width / 2,
.w = n == 0 ? image_width : image_width / 2 ,
.h = n == 0 ? image_height : image_height / 2,
.d = 0,
.format = fmt,
@ -2441,23 +2460,20 @@ void generateVAAPIImage(CuvidDecoder * decoder, int index, const AVFrame * frame
},
.size = size,
.offset = offset,
#ifdef PLACEBO_GL
.stride_h = n == 0 ? image_height : image_height / 2,
.stride_w = desc.layers[n].pitch[0],
#endif
#if PL_API_VER > 87
.drm_format_mod = DRM_FORMAT_MOD_INVALID,
#endif
},
.drm_format_mod = desc.objects[id].drm_format_modifier,
},
};
// printf("vor create Object %d with fd %d import size %u offset %d %dx%d\n",id,fd,size,offset, tex_params.w,tex_params.h);
if (decoder->pl_images[index].planes[n].texture) {
pl_tex_destroy(p->gpu, &decoder->pl_images[index].planes[n].texture);
if (decoder->pl_frames[index].planes[n].texture) {
pl_tex_destroy(p->gpu, &decoder->pl_frames[index].planes[n].texture);
}
decoder->pl_images[index].planes[n].texture = pl_tex_create(p->gpu, &tex_params);
decoder->pl_frames[index].planes[n].texture = pl_tex_create(p->gpu, &tex_params);
}
Unlock_and_NoContext;
@ -3037,7 +3053,7 @@ int get_RGB(CuvidDecoder * decoder)
#ifdef PLACEBO
struct pl_render_params render_params = pl_render_default_params;
struct pl_render_target target = { 0 };
struct pl_frame target = { 0 };
const struct pl_fmt *fmt;
int offset, x1, y1, x0, y0;
@ -3223,7 +3239,7 @@ int get_RGB(CuvidDecoder * decoder)
target.num_overlays = 0;
}
if (!pl_render_image(p->renderer, &decoder->pl_images[current], &target, &render_params)) {
if (!pl_render_image(p->renderer, &decoder->pl_frames[current], &target, &render_params)) {
Fatal(_("Failed rendering frame!\n"));
}
pl_gpu_finish(p->gpu);
@ -3456,6 +3472,15 @@ static void CuvidRenderFrame(CuvidDecoder * decoder, const AVCodecContext * vide
color = frame->colorspace;
if (color == AVCOL_SPC_UNSPECIFIED) // if unknown
color = AVCOL_SPC_BT709;
if (color == AVCOL_SPC_RGB)
color = AVCOL_SPC_BT470BG; // fix ffmpeg libav failure
frame->colorspace = color;
// more libav fixes
if (frame->color_primaries == AVCOL_PRI_UNSPECIFIED)
frame->color_primaries = AVCOL_PRI_BT709;
if (frame->color_trc == AVCOL_TRC_UNSPECIFIED)
frame->color_trc = AVCOL_TRC_BT709;
#ifdef RASPI
//
// Check image, format, size
@ -3509,9 +3534,9 @@ static void CuvidRenderFrame(CuvidDecoder * decoder, const AVCodecContext * vide
output = av_frame_alloc();
av_hwframe_transfer_data(output, frame, 0);
av_frame_copy_props(output, frame);
// printf("Save Surface ID %d %p %p\n",surface,decoder->pl_images[surface].planes[0].texture,decoder->pl_images[surface].planes[1].texture);
// printf("Save Surface ID %d %p %p\n",surface,decoder->pl_frames[surface].planes[0].texture,decoder->pl_frames[surface].planes[1].texture);
bool ok = pl_tex_upload(p->gpu, &(struct pl_tex_transfer_params) {
.tex = decoder->pl_images[surface].planes[0].texture,
.tex = decoder->pl_frames[surface].planes[0].texture,
.stride_w = output->linesize[0],
.stride_h = h,
.ptr = output->data[0],
@ -3520,7 +3545,7 @@ static void CuvidRenderFrame(CuvidDecoder * decoder, const AVCodecContext * vide
.rc.z1 = 0,
});
ok &= pl_tex_upload(p->gpu, &(struct pl_tex_transfer_params) {
.tex = decoder->pl_images[surface].planes[1].texture,
.tex = decoder->pl_frames[surface].planes[1].texture,
.stride_w = output->linesize[0] / 2,
.stride_h = h / 2,
.ptr = output->data[1],
@ -3698,7 +3723,7 @@ error:
/// @param level video surface level 0 = bottom
///
#ifdef PLACEBO
static void CuvidMixVideo(CuvidDecoder * decoder, int level, struct pl_render_target *target, struct pl_overlay *ovl)
static void CuvidMixVideo(CuvidDecoder * decoder, int level, struct pl_frame *target, struct pl_overlay *ovl)
#else
static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
int level)
@ -3712,10 +3737,10 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
struct pl_tex_vk *vkp;
struct pl_plane *pl;
const struct pl_fmt *fmt;
struct pl_tex *tex0,*tex1;
struct pl_image *img;
struct pl_frame *img;
bool ok;
VdpRect video_src_rect;
VdpRect dst_rect;
VdpRect dst_video_rect;
@ -3726,7 +3751,7 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
float xcropf, ycropf;
GLint texLoc;
AVFrame *frame;
AVFrameSideData *FrameSideData = NULL;
AVFrameSideData *sd,*sd1,*sd2;
#ifdef PLACEBO
if (level) {
@ -3760,8 +3785,8 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
#ifdef USE_DRM
if (!decoder->Closing) {
frame = decoder->frames[current];
AVFrameSideData *sd1 = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
AVFrameSideData *sd2 = av_frame_get_side_data(frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
sd1 = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
sd2 = av_frame_get_side_data(frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
set_hdr_metadata(frame->color_primaries, frame->color_trc, sd1, sd2);
}
@ -3802,15 +3827,21 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
glActiveTexture(GL_TEXTURE0);
#else
img = &decoder->pl_images[current];
pl = &decoder->pl_images[current].planes[1];
img = &decoder->pl_frames[current];
pl = &decoder->pl_frames[current].planes[1];
memcpy(&deband, &pl_deband_default_params, sizeof(deband));
memcpy(&render_params, &pl_render_default_params, sizeof(render_params));
render_params.deband_params = &deband;
frame = decoder->frames[current];
// Fix Color Parameters
switch (decoder->ColorSpace) {
case AVCOL_SPC_RGB: // BT 601 is reportet as RGB
case AVCOL_SPC_BT470BG:
memcpy(&img->repr, &pl_color_repr_sdtv, sizeof(struct pl_color_repr));
img->color.primaries = PL_COLOR_PRIM_BT_601_625;
img->color.transfer = PL_COLOR_TRC_BT_1886;
@ -3830,6 +3861,37 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
deband.grain = 0.0f; // no grain in HDR
img->color.sig_scale = 1.0f;
pl->shift_x = -0.5f;
if ((sd = av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE))) {
img->profile = (struct pl_icc_profile) {
.data = sd->data,
.len = sd->size,
};
// Needed to ensure profile uniqueness
pl_icc_profile_compute_signature(&img->profile);
}
if ((sd1 = av_frame_get_side_data(frame, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL))) {
const AVContentLightMetadata *clm = (AVContentLightMetadata *) sd->data;
img->color.sig_peak = clm->MaxCLL / PL_COLOR_SDR_WHITE;
img->color.sig_avg = clm->MaxFALL / PL_COLOR_SDR_WHITE;
}
// This overrides the CLL values above, if both are present
if ((sd2 = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA))) {
const AVMasteringDisplayMetadata *mdm = (AVMasteringDisplayMetadata *) sd->data;
if (mdm->has_luminance)
img->color.sig_peak = av_q2d(mdm->max_luminance) / PL_COLOR_SDR_WHITE;
}
// Make sure this value is more or less legal
if (img->color.sig_peak < 1.0 || img->color.sig_peak > 50.0)
img->color.sig_peak = 0.0;
#ifdef USE_DRM
set_hdr_metadata(frame->color_primaries, frame->color_trc, sd1, sd2);
#endif
#if defined VAAPI || defined USE_DRM
render_params.peak_detect_params = NULL;
render_params.deband_params = NULL;
@ -3844,9 +3906,11 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
pl->shift_x = -0.5f;
break;
}
//printf("sys %d prim %d trc %d light %d\n",img->repr.sys,img->color.primaries,img->color.transfer,img->color.light);
// Source crop
if (VideoScalerTest) { // right side defined scaler
#if PL_API_VER >= 100
//Input crop
img->crop.x0 = video_src_rect.x1 / 2 + 1;
img->crop.y0 = video_src_rect.y0;
@ -3864,20 +3928,9 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
target->crop.x1 = dst_video_rect.x1;
target->crop.y1 = dst_video_rect.y1;
#endif
#else
// Input crop
img->src_rect.x0 = video_src_rect.x1 / 2 + 1;
img->src_rect.y0 = video_src_rect.y0;
img->src_rect.x1 = video_src_rect.x1;
img->src_rect.y1 = video_src_rect.y1;
// Output Scale
target->dst_rect.x0 = dst_video_rect.x1 / 2 + dst_video_rect.x0 / 2 + 1;
target->dst_rect.y0 = dst_video_rect.y0;
target->dst_rect.x1 = dst_video_rect.x1;
target->dst_rect.y1 = dst_video_rect.y1;
#endif
} else {
#if PL_API_VER >= 100
img->crop.x0 = video_src_rect.x0;
img->crop.y0 = video_src_rect.y0;
img->crop.x1 = video_src_rect.x1;
@ -3895,17 +3948,6 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
target->crop.y1 = dst_video_rect.y1;
#endif
#else
img->src_rect.x0 = video_src_rect.x0;
img->src_rect.y0 = video_src_rect.y0;
img->src_rect.x1 = video_src_rect.x1;
img->src_rect.y1 = video_src_rect.y1;
target->dst_rect.x0 = dst_video_rect.x0;
target->dst_rect.y0 = dst_video_rect.y0;
target->dst_rect.x1 = dst_video_rect.x1;
target->dst_rect.y1 = dst_video_rect.y1;
#endif
}
#if PL_API_VER < 100
@ -3943,6 +3985,7 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
render_params.upscaler = pl_named_filters[VideoScaling[decoder->Resolution]].filter;
render_params.downscaler = pl_named_filters[VideoScaling[decoder->Resolution]].filter;
render_params.color_adjustment = &colors;
colors.brightness = VideoBrightness;
@ -3980,18 +4023,25 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
}
}
render_params.hooks = &p->hook;
if (ovl || (video_src_rect.x1 > dst_video_rect.x1) || (video_src_rect.y1 > dst_video_rect.y1) ) {
render_params.num_hooks = 0; // no user shaders when OSD activ or downward scaling
if (level || ovl || (video_src_rect.x1 > dst_video_rect.x1) || (video_src_rect.y1 > dst_video_rect.y1) ) {
render_params.num_hooks = 0; // no user shaders when OSD activ or downward scaling or PIP
}
else {
render_params.num_hooks = p->num_shaders;
}
#endif
#if PL_API_VER >= 113
// provide LUT Table
if (LUTon)
render_params.lut = p->lut;
else
render_params.lut = NULL;
#endif
if (decoder->newchannel && current == 0) {
if (decoder->newchannel && current == 0) {
colors.brightness = -1.0f;
colors.contrast = 0.0f;
if (!pl_render_image(p->renderer, &decoder->pl_images[current], target, &render_params)) {
if (!pl_render_image(p->renderer, &decoder->pl_frames[current], target, &render_params)) {
Debug(3, "Failed rendering first frame!\n");
}
decoder->newchannel = 2;
@ -4000,14 +4050,14 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
decoder->newchannel = 0;
// uint64_t tt = GetusTicks();
if (!pl_render_image(p->renderer, &decoder->pl_images[current], target, &render_params)) {
if (!pl_render_image(p->renderer, &decoder->pl_frames[current], target, &render_params)) {
Debug(4, "Failed rendering frame!\n");
}
// pl_gpu_finish(p->gpu);
//printf("Rendertime %ld -- \n,",GetusTicks() - tt);
if (VideoScalerTest) { // left side test scaler
#if PL_API_VER >= 100
// Source crop
img->crop.x0 = video_src_rect.x0;
img->crop.y0 = video_src_rect.y0;
@ -4025,26 +4075,17 @@ static void CuvidMixVideo(CuvidDecoder * decoder, __attribute__((unused))
target->crop.x1 = dst_video_rect.x1 / 2 + dst_video_rect.x0 / 2;
target->crop.y1 = dst_video_rect.y1;
#endif
#else
// Source crop
img->src_rect.x0 = video_src_rect.x0;
img->src_rect.y0 = video_src_rect.y0;
img->src_rect.x1 = video_src_rect.x1 / 2;
img->src_rect.y1 = video_src_rect.y1;
// Video aspect ratio
target->dst_rect.x0 = dst_video_rect.x0;
target->dst_rect.y0 = dst_video_rect.y0;
target->dst_rect.x1 = dst_video_rect.x1 / 2 + dst_video_rect.x0 / 2;
target->dst_rect.y1 = dst_video_rect.y1;
#endif
render_params.upscaler = pl_named_filters[VideoScalerTest - 1].filter;
render_params.downscaler = pl_named_filters[VideoScalerTest - 1].filter;
// render_params.lut = NULL;
render_params.num_hooks = 0;
if (!p->renderertest)
p->renderertest = pl_renderer_create(p->ctx, p->gpu);
if (!pl_render_image(p->renderertest, &decoder->pl_images[current], target, &render_params)) {
if (!pl_render_image(p->renderertest, &decoder->pl_frames[current], target, &render_params)) {
Debug(4, "Failed rendering frame!\n");
}
} else if (p->renderertest) {
@ -4137,7 +4178,7 @@ static void CuvidDisplayFrame(void)
uint64_t diff;
static float fdiff = 23000.0;
struct pl_swapchain_frame frame;
struct pl_render_target target;
struct pl_frame target;
bool ok;
@ -5410,6 +5451,57 @@ void VideoSetVideoEventCallback(void (*videoEventCallback)(void))
#ifdef PLACEBO
static bool open_file(const char *path, struct file *out)
{
if (!path || !path[0]) {
*out = (struct file) {0};
return true;
}
FILE *fp = NULL;
bool success = false;
fp = fopen(path, "rb");
if (!fp)
goto done;
if (fseeko(fp, 0, SEEK_END))
goto done;
off_t size = ftello(fp);
if (size < 0)
goto done;
if (fseeko(fp, 0, SEEK_SET))
goto done;
void *data = malloc(size);
if (!fread(data, size, 1, fp))
goto done;
*out = (struct file) {
.data = data,
.size = size,
};
success = true;
done:
if (fp)
fclose(fp);
return success;
}
static void close_file(struct file *file)
{
if (!file->data)
return;
free(file->data);
*file = (struct file) {0};
}
void pl_log_intern(void *stream, enum pl_log_level level, const char *msg)
{
static const char *prefix[] = {
@ -5426,8 +5518,16 @@ void pl_log_intern(void *stream, enum pl_log_level level, const char *msg)
void InitPlacebo()
{
CuvidMessage(2,"Init Placebo mit API %d\n", PL_API_VER);
static const char *lut_file = "lut/lut.cube";
CuvidMessage(2,"Init Placebo mit API %d\n", PL_API_VER);
#ifdef PLACEBO_GL
CuvidMessage(2,"Placebo mit opengl\n");
#else
CuvidMessage(2,"Placebo mit vulkan\n");
#endif
p = calloc(1, sizeof(struct priv));
if (!p)
Fatal(_("Cant get memory for PLACEBO struct"));
@ -5512,6 +5612,7 @@ void InitPlacebo()
.surface = p->pSurface,
.present_mode = VK_PRESENT_MODE_FIFO_KHR,
.swapchain_depth = SWAP_BUFFER_SIZE,
.prefer_hdr = true,
});
#endif
@ -5533,7 +5634,20 @@ void InitPlacebo()
Fatal(_( "libplacebo: failed initializing swapchain\n"));
}
#endif
#if PL_API_VER >= 113
// load LUT File
struct file lutf;
char tmp[200];
sprintf(tmp,"%s/%s",MyConfigDir,lut_file);
if (open_file(tmp, &lutf) && lutf.size) {
if (!(p->lut = pl_lut_parse_cube(p->ctx, lutf.data, lutf.size)))
fprintf(stderr, "Failed parsing LUT.. continuing anyway\n");
close_file(&lutf);
}
else {
Debug(3, "Placebo: No LUT File used\n");
}
#endif
// create renderer
p->renderer = pl_renderer_create(p->ctx, p->gpu);
if (!p->renderer) {
@ -5606,6 +5720,9 @@ void exit_display()
#endif
pl_context_destroy(&p->ctx);
#if PL_API_VER >= 113
pl_lut_free(&p->lut);
#endif
free(p);
p = NULL;
#endif
@ -6946,6 +7063,11 @@ void VideoSetScalerTest(int onoff)
VideoSurfaceModesChanged = 1;
}
void ToggleLUT()
{
LUTon ^= -1;
}
///
/// Set Color Blindness.
///