forked from enlightenment/efl
evas-engines: Port evas drm engines to use Ecore_Drm2 library
This patch ports the evas drm and gl_drm engines to use the new Ecore_Drm2 library Signed-off-by: Chris Michael <cpmichael@osg.samsung.com>
This commit is contained in:
parent
13337c2583
commit
ccb573ec7b
|
@ -597,16 +597,23 @@ AC_DEFUN([EVAS_CHECK_ENGINE_DEP_DRM],
|
|||
[
|
||||
|
||||
requirement=""
|
||||
have_dep="yes"
|
||||
have_dep="no"
|
||||
have_hw_dep="no"
|
||||
evas_engine_[]$1[]_cflags=""
|
||||
evas_engine_[]$1[]_libs=""
|
||||
|
||||
PKG_CHECK_EXISTS([libdrm],
|
||||
[
|
||||
have_dep="yes"
|
||||
requirement="libdrm"
|
||||
], [have_dep="no"])
|
||||
|
||||
if test "x${have_dep}" = "xyes" ; then
|
||||
if test "x$3" = "xstatic" ; then
|
||||
requirements_pc_evas="${requirement} ${requirements_pc_evas}"
|
||||
requirements_pc_deps_evas="${requirement} ${requirements_pc_deps_evas}"
|
||||
else
|
||||
PKG_CHECK_MODULES([DRM], [${requirement}])
|
||||
evas_engine_[]$1[]_cflags="${DRM_CFLAGS}"
|
||||
evas_engine_[]$1[]_libs="${DRM_LIBS}"
|
||||
fi
|
||||
|
@ -636,10 +643,10 @@ else
|
|||
AC_MSG_ERROR([We currently do not support GL DRM without OpenGL ES. Please consider OpenGL ES if you want to use it.])
|
||||
fi
|
||||
|
||||
PKG_CHECK_EXISTS([egl ${gl_library} gbm wayland-client >= REQUIRED_WAYLAND_VERSION],
|
||||
PKG_CHECK_EXISTS([egl ${gl_library} libdrm gbm wayland-client >= REQUIRED_WAYLAND_VERSION],
|
||||
[
|
||||
have_dep="yes"
|
||||
requirement="egl ${gl_library} gbm wayland-client >= REQUIRED_WAYLAND_VERSION"
|
||||
requirement="egl ${gl_library} libdrm gbm wayland-client >= REQUIRED_WAYLAND_VERSION"
|
||||
],
|
||||
[have_dep="no"])
|
||||
|
||||
|
|
|
@ -1276,7 +1276,6 @@ endif
|
|||
endif
|
||||
|
||||
if BUILD_ENGINE_DRM
|
||||
dist_installed_evasmainheaders_DATA += modules/evas/engines/drm/Evas_Engine_Drm.h
|
||||
DRM_SOURCES = \
|
||||
modules/evas/engines/drm/evas_outbuf.c \
|
||||
modules/evas/engines/drm/evas_engine.c \
|
||||
|
@ -1301,20 +1300,19 @@ modules_evas_engines_drm_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
|
|||
-I$(top_srcdir)/src/lib/evas/cserve2 \
|
||||
-I$(top_srcdir)/src/modules/evas/engines/drm \
|
||||
@EVAS_CFLAGS@ \
|
||||
@ECORE_DRM_CFLAGS@ \
|
||||
@ECORE_DRM2_CFLAGS@ \
|
||||
@evas_engine_drm_cflags@
|
||||
modules_evas_engines_drm_module_la_LIBADD = \
|
||||
@USE_EVAS_LIBS@ \
|
||||
@USE_ECORE_DRM_LIBS@ \
|
||||
@USE_ECORE_DRM2_LIBS@ \
|
||||
@evas_engine_drm_libs@
|
||||
modules_evas_engines_drm_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ @USE_ECORE_DRM_INTERNAL_LIBS@
|
||||
modules_evas_engines_drm_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ @USE_ECORE_DRM2_INTERNAL_LIBS@
|
||||
modules_evas_engines_drm_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
|
||||
modules_evas_engines_drm_module_la_LIBTOOLFLAGS = --tag=disable-static
|
||||
endif
|
||||
endif
|
||||
|
||||
if BUILD_ENGINE_GL_DRM
|
||||
dist_installed_evasmainheaders_DATA += modules/evas/engines/gl_drm/Evas_Engine_GL_Drm.h
|
||||
GL_DRM_SOURCES = \
|
||||
modules/evas/engines/gl_drm/evas_outbuf.c \
|
||||
modules/evas/engines/gl_drm/evas_engine.c \
|
||||
|
@ -1339,13 +1337,13 @@ modules_evas_engines_gl_drm_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
|
|||
-I$(top_srcdir)/src/lib/evas/cserve2 \
|
||||
-I$(top_srcdir)/src/modules/evas/engines/gl_drm \
|
||||
@EVAS_CFLAGS@ \
|
||||
@ECORE_DRM_CFLAGS@ \
|
||||
@ECORE_DRM2_CFLAGS@ \
|
||||
@evas_engine_gl_drm_cflags@
|
||||
modules_evas_engines_gl_drm_module_la_LIBADD = \
|
||||
@USE_EVAS_LIBS@ \
|
||||
@USE_ECORE_DRM_LIBS@ \
|
||||
@USE_ECORE_DRM2_LIBS@ \
|
||||
@evas_engine_gl_drm_libs@
|
||||
modules_evas_engines_gl_drm_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ @USE_ECORE_DRM_INTERNAL_LIBS@
|
||||
modules_evas_engines_gl_drm_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@ @USE_ECORE_DRM2_INTERNAL_LIBS@
|
||||
modules_evas_engines_gl_drm_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
|
||||
modules_evas_engines_gl_drm_module_la_LIBTOOLFLAGS = --tag=disable-static
|
||||
endif
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
#ifndef _EVAS_ENGINE_DRM_H
|
||||
# define _EVAS_ENGINE_DRM_H
|
||||
|
||||
# include <Ecore_Drm.h>
|
||||
|
||||
typedef struct _Evas_Engine_Info_Drm Evas_Engine_Info_Drm;
|
||||
|
||||
struct _Evas_Engine_Info_Drm
|
||||
typedef struct _Evas_Engine_Info_Drm
|
||||
{
|
||||
/* PRIVATE - don't mess with this baby or evas will poke its tongue out */
|
||||
/* at you and make nasty noises */
|
||||
|
@ -13,18 +9,17 @@ struct _Evas_Engine_Info_Drm
|
|||
|
||||
struct
|
||||
{
|
||||
unsigned int rotation, depth;
|
||||
Eina_Bool destination_alpha : 1;
|
||||
int fd;
|
||||
int depth, bpp;
|
||||
unsigned int format, rotation;
|
||||
|
||||
void *output;
|
||||
Eina_Bool alpha : 1;
|
||||
Eina_Bool vsync : 1;
|
||||
|
||||
unsigned int crtc_id, conn_id, buffer_id;
|
||||
|
||||
Eina_Bool use_hw_accel : 1;
|
||||
Ecore_Drm_Device *dev;
|
||||
} info;
|
||||
|
||||
/* non-blocking or blocking mode */
|
||||
Evas_Engine_Render_Mode render_mode;
|
||||
};
|
||||
} Evas_Engine_Info_Drm;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,65 +1,57 @@
|
|||
#include "evas_engine.h"
|
||||
|
||||
/* local structures */
|
||||
typedef struct _Render_Engine Render_Engine;
|
||||
|
||||
struct _Render_Engine
|
||||
typedef struct _Render_Engine
|
||||
{
|
||||
Render_Engine_Software_Generic generic;
|
||||
};
|
||||
} Render_Engine;
|
||||
|
||||
/* function tables - filled in later (func and parent func) */
|
||||
static Evas_Func func, pfunc;
|
||||
|
||||
/* external variables */
|
||||
int _evas_engine_drm_log_dom;
|
||||
|
||||
/* local functions */
|
||||
static void *
|
||||
_output_setup(Evas_Engine_Info_Drm *info, int w, int h)
|
||||
static Render_Engine *
|
||||
_render_engine_setup(Evas_Engine_Info_Drm *info, int w, int h)
|
||||
{
|
||||
Render_Engine *re = NULL;
|
||||
Render_Engine *re;
|
||||
Outbuf *ob;
|
||||
|
||||
/* try to allocate space for our render engine structure */
|
||||
if (!(re = calloc(1, sizeof(Render_Engine))))
|
||||
goto on_error;
|
||||
re = calloc(1, sizeof(Render_Engine));
|
||||
if (!re) return NULL;
|
||||
|
||||
/* try to create new outbuf */
|
||||
if (!(ob = evas_outbuf_setup(info, w, h)))
|
||||
goto on_error;
|
||||
ob = _outbuf_setup(info, w, h);
|
||||
if (!ob) goto err;
|
||||
|
||||
if (!evas_render_engine_software_generic_init(&re->generic, ob,
|
||||
evas_outbuf_buffer_state_get,
|
||||
evas_outbuf_rot_get,
|
||||
evas_outbuf_reconfigure, NULL,
|
||||
evas_outbuf_update_region_new,
|
||||
evas_outbuf_update_region_push,
|
||||
evas_outbuf_update_region_free,
|
||||
NULL, evas_outbuf_flush,
|
||||
evas_outbuf_free,
|
||||
_outbuf_state_get,
|
||||
_outbuf_rotation_get,
|
||||
_outbuf_reconfigure,
|
||||
NULL,
|
||||
_outbuf_update_region_new,
|
||||
_outbuf_update_region_push,
|
||||
_outbuf_update_region_free,
|
||||
NULL,
|
||||
_outbuf_flush,
|
||||
_outbuf_free,
|
||||
ob->w, ob->h))
|
||||
goto on_error;
|
||||
goto init_err;
|
||||
|
||||
/* return the allocated render_engine structure */
|
||||
return re;
|
||||
|
||||
on_error:
|
||||
if (re) evas_render_engine_software_generic_clean(&re->generic);
|
||||
|
||||
init_err:
|
||||
evas_render_engine_software_generic_clean(&re->generic);
|
||||
err:
|
||||
free(re);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* engine api functions */
|
||||
static void *
|
||||
eng_info(Evas *evas EINA_UNUSED)
|
||||
{
|
||||
Evas_Engine_Info_Drm *info;
|
||||
|
||||
/* try to allocate space for our engine info structure */
|
||||
if (!(info = calloc(1, sizeof(Evas_Engine_Info_Drm))))
|
||||
return NULL;
|
||||
info = calloc(1, sizeof(Evas_Engine_Info_Drm));
|
||||
if (!info) return NULL;
|
||||
|
||||
/* set some engine default properties */
|
||||
info->magic.magic = rand();
|
||||
|
@ -74,55 +66,47 @@ eng_info_free(Evas *evas EINA_UNUSED, void *einfo)
|
|||
Evas_Engine_Info_Drm *info;
|
||||
|
||||
/* free the engine info */
|
||||
if ((info = (Evas_Engine_Info_Drm *)einfo))
|
||||
free(info);
|
||||
info = (Evas_Engine_Info_Drm *)einfo;
|
||||
free(info);
|
||||
}
|
||||
|
||||
static int
|
||||
eng_setup(Evas *evas, void *einfo)
|
||||
{
|
||||
Evas_Engine_Info_Drm *info;
|
||||
Evas_Public_Data *epd;
|
||||
Render_Engine *re;
|
||||
Evas_Public_Data *epd;
|
||||
Evas_Engine_Info_Drm *info;
|
||||
|
||||
/* try to cast to our engine info structure */
|
||||
if (!(info = (Evas_Engine_Info_Drm *)einfo)) return 0;
|
||||
info = (Evas_Engine_Info_Drm *)einfo;
|
||||
if (!info) return 0;
|
||||
|
||||
/* try to get the evas public data */
|
||||
if (!(epd = eo_data_scope_get(evas, EVAS_CANVAS_CLASS))) return 0;
|
||||
epd = eo_data_scope_get(evas, EVAS_CANVAS_CLASS);
|
||||
if (!epd) return 0;
|
||||
|
||||
/* check for valid engine output */
|
||||
if (!(re = epd->engine.data.output))
|
||||
re = epd->engine.data.output;
|
||||
if (!re)
|
||||
{
|
||||
/* NB: If we have no valid output then assume we have not been
|
||||
* initialized yet and call any needed common init routines */
|
||||
evas_common_init();
|
||||
|
||||
/* try to create a new render_engine */
|
||||
if (!(re = _output_setup(info, epd->output.w, epd->output.h)))
|
||||
return 0;
|
||||
re = _render_engine_setup(info, epd->output.w, epd->output.h);
|
||||
if (!re) return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Outbuf *ob;
|
||||
|
||||
/* try to create a new outbuf */
|
||||
ob = evas_outbuf_setup(info, epd->output.w, epd->output.h);
|
||||
ob = _outbuf_setup(info, epd->output.w, epd->output.h);
|
||||
if (!ob) return 0;
|
||||
|
||||
/* if we have an existing outbuf, free it */
|
||||
evas_render_engine_software_generic_update(&re->generic, ob,
|
||||
ob->w, ob->h);
|
||||
}
|
||||
|
||||
/* reassign engine output */
|
||||
epd->engine.data.output = re;
|
||||
if (!epd->engine.data.output) return 0;
|
||||
|
||||
/* check for valid engine context */
|
||||
if (!epd->engine.data.context)
|
||||
{
|
||||
/* create a context if needed */
|
||||
epd->engine.data.context =
|
||||
epd->engine.func->context_new(epd->engine.data.output);
|
||||
}
|
||||
|
@ -135,7 +119,8 @@ eng_output_free(void *data)
|
|||
{
|
||||
Render_Engine *re;
|
||||
|
||||
if ((re = data))
|
||||
re = data;
|
||||
if (re)
|
||||
{
|
||||
evas_render_engine_software_generic_clean(&re->generic);
|
||||
free(re);
|
||||
|
@ -144,7 +129,6 @@ eng_output_free(void *data)
|
|||
evas_common_shutdown();
|
||||
}
|
||||
|
||||
/* module api functions */
|
||||
static int
|
||||
module_open(Evas_Module *em)
|
||||
{
|
||||
|
@ -165,6 +149,8 @@ module_open(Evas_Module *em)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ecore_init();
|
||||
|
||||
/* store parent functions */
|
||||
func = pfunc;
|
||||
|
||||
|
@ -185,6 +171,8 @@ module_close(Evas_Module *em EINA_UNUSED)
|
|||
{
|
||||
/* unregister the eina log domain for this engine */
|
||||
eina_log_domain_unregister(_evas_engine_drm_log_dom);
|
||||
|
||||
ecore_shutdown();
|
||||
}
|
||||
|
||||
static Evas_Module_Api evas_modapi =
|
||||
|
|
|
@ -6,8 +6,13 @@
|
|||
# include "evas_private.h"
|
||||
# include "Evas.h"
|
||||
# include "Evas_Engine_Drm.h"
|
||||
# include <Ecore.h>
|
||||
# include <Ecore_Drm2.h>
|
||||
# include <drm_fourcc.h>
|
||||
# include <xf86drm.h>
|
||||
# include <xf86drmMode.h>
|
||||
|
||||
#include "../software_generic/Evas_Engine_Software_Generic.h"
|
||||
# include "../software_generic/Evas_Engine_Software_Generic.h"
|
||||
|
||||
extern int _evas_engine_drm_log_dom;
|
||||
|
||||
|
@ -36,35 +41,44 @@ extern int _evas_engine_drm_log_dom;
|
|||
# endif
|
||||
# define CRI(...) EINA_LOG_DOM_CRIT(_evas_engine_drm_log_dom, __VA_ARGS__)
|
||||
|
||||
typedef struct _Outbuf_Fb
|
||||
{
|
||||
int age;
|
||||
Ecore_Drm2_Fb *fb;
|
||||
|
||||
Eina_Bool valid : 1;
|
||||
Eina_Bool drawn : 1;
|
||||
Eina_Bool busy : 1;
|
||||
} Outbuf_Fb;
|
||||
|
||||
struct _Outbuf
|
||||
{
|
||||
Evas_Engine_Info_Drm *info;
|
||||
|
||||
int w, h;
|
||||
int rotation;
|
||||
unsigned int depth;
|
||||
int fd, w, h, bpp, rotation;
|
||||
unsigned int depth, format;
|
||||
|
||||
struct
|
||||
{
|
||||
Ecore_Drm_Fb *buffer[4];
|
||||
|
||||
Eina_List *pending_writes;
|
||||
|
||||
int curr, last, num;
|
||||
int num;
|
||||
Outbuf_Fb ofb[4], *current;
|
||||
Ecore_Drm2_Output *output;
|
||||
Eina_List *pending;
|
||||
} priv;
|
||||
|
||||
Eina_Bool destination_alpha : 1;
|
||||
drmEventContext ctx;
|
||||
Ecore_Fd_Handler *hdlr;
|
||||
|
||||
Eina_Bool alpha : 1;
|
||||
Eina_Bool vsync : 1;
|
||||
};
|
||||
|
||||
Outbuf *evas_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h);
|
||||
void evas_outbuf_free(Outbuf *ob);
|
||||
void evas_outbuf_reconfigure(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth);
|
||||
Render_Engine_Swap_Mode evas_outbuf_buffer_state_get(Outbuf *ob);
|
||||
int evas_outbuf_rot_get(Outbuf *ob);
|
||||
void *evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch);
|
||||
void evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h);
|
||||
void evas_outbuf_update_region_free(Outbuf *ob, RGBA_Image *update);
|
||||
void evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode);
|
||||
Outbuf *_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h);
|
||||
void _outbuf_free(Outbuf *ob);
|
||||
int _outbuf_rotation_get(Outbuf *ob);
|
||||
void _outbuf_reconfigure(Outbuf *ob, int w, int h, int rotation, Outbuf_Depth depth);
|
||||
Render_Engine_Swap_Mode _outbuf_state_get(Outbuf *ob);
|
||||
void *_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch);
|
||||
void _outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h);
|
||||
void _outbuf_update_region_free(Outbuf *ob, RGBA_Image *update);
|
||||
void _outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,183 +8,430 @@
|
|||
#define GREEN_MASK 0x00ff00
|
||||
#define BLUE_MASK 0x0000ff
|
||||
|
||||
static void _outbuf_tick_schedule(int fd, void *data);
|
||||
|
||||
static Eina_Bool ticking = EINA_FALSE;
|
||||
|
||||
static void
|
||||
_evas_outbuf_buffer_swap(Outbuf *ob, Eina_Rectangle *rects, unsigned int count)
|
||||
_outbuf_tick_begin(void *data)
|
||||
{
|
||||
Ecore_Drm_Fb *buff;
|
||||
Outbuf *ob;
|
||||
|
||||
buff = ob->priv.buffer[ob->priv.curr];
|
||||
ob = data;
|
||||
ticking = EINA_TRUE;
|
||||
if (ob) _outbuf_tick_schedule(ob->fd, ob);
|
||||
}
|
||||
|
||||
/* mark the fb as dirty */
|
||||
ecore_drm_fb_dirty(buff, rects, count);
|
||||
static void
|
||||
_outbuf_tick_end(void *data EINA_UNUSED)
|
||||
{
|
||||
ticking = EINA_FALSE;
|
||||
}
|
||||
|
||||
/* send this buffer to the crtc */
|
||||
ecore_drm_fb_send(ob->info->info.dev, buff, NULL, NULL);
|
||||
static void
|
||||
_outbuf_tick_source_set(Outbuf *ob)
|
||||
{
|
||||
if (ob)
|
||||
{
|
||||
ecore_animator_custom_source_tick_begin_callback_set
|
||||
(_outbuf_tick_begin, ob);
|
||||
ecore_animator_custom_source_tick_end_callback_set
|
||||
(_outbuf_tick_end, ob);
|
||||
ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM);
|
||||
}
|
||||
else
|
||||
{
|
||||
ecore_animator_custom_source_tick_begin_callback_set(NULL, NULL);
|
||||
ecore_animator_custom_source_tick_end_callback_set(NULL, NULL);
|
||||
ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
|
||||
}
|
||||
}
|
||||
|
||||
ob->priv.last = ob->priv.curr;
|
||||
ob->priv.curr = (ob->priv.curr + 1) % ob->priv.num;
|
||||
static void
|
||||
_outbuf_tick_schedule(int fd EINA_UNUSED, void *data)
|
||||
{
|
||||
Outbuf *ob;
|
||||
Outbuf_Fb *ofb;
|
||||
|
||||
ob = data;
|
||||
if (!ticking) return;
|
||||
|
||||
ofb = ob->priv.current;
|
||||
if (!ofb) return;
|
||||
|
||||
drmVBlank vbl =
|
||||
{
|
||||
.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
|
||||
.request.sequence = 1,
|
||||
.request.signal = (unsigned long)data,
|
||||
};
|
||||
|
||||
if (drmWaitVBlank(fd, &vbl) < 0)
|
||||
_outbuf_tick_source_set(NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_vblank(int fd, unsigned int frame EINA_UNUSED, unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
|
||||
{
|
||||
ecore_animator_custom_tick();
|
||||
if (ticking) _outbuf_tick_schedule(fd, data);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_pageflip(int fd EINA_UNUSED, unsigned int frame EINA_UNUSED, unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
|
||||
{
|
||||
Outbuf *ob;
|
||||
Outbuf_Fb *ofb;
|
||||
Ecore_Drm2_Fb *next;
|
||||
|
||||
ob = data;
|
||||
|
||||
ofb = ob->priv.current;
|
||||
if (ofb) ofb->busy = EINA_FALSE;
|
||||
|
||||
next = ecore_drm2_output_next_fb_get(ob->priv.output);
|
||||
if (next)
|
||||
{
|
||||
ecore_drm2_output_next_fb_set(ob->priv.output, NULL);
|
||||
if (ecore_drm2_fb_flip(next, ob->priv.output, ob) < 0)
|
||||
_outbuf_tick_source_set(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_drm_event(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
|
||||
{
|
||||
Outbuf *ob;
|
||||
int ret;
|
||||
|
||||
ob = data;
|
||||
ret = drmHandleEvent(ob->fd, &ob->ctx);
|
||||
if (ret)
|
||||
{
|
||||
WRN("drmHandleEvent failed to read an event");
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_outbuf_buffer_swap(Outbuf *ob, Eina_Rectangle *rects, unsigned int count)
|
||||
{
|
||||
/* Ecore_Drm2_Plane *plane; */
|
||||
Outbuf_Fb *ofb;
|
||||
|
||||
ofb = ob->priv.current;
|
||||
if (!ofb) return;
|
||||
|
||||
ecore_drm2_fb_dirty(ofb->fb, rects, count);
|
||||
if (ecore_drm2_fb_flip(ofb->fb, ob->priv.output, ob) < 0)
|
||||
{
|
||||
_outbuf_tick_source_set(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
ofb->busy = EINA_TRUE;
|
||||
ofb->drawn = EINA_TRUE;
|
||||
ofb->age = 0;
|
||||
|
||||
/* plane = ecore_drm2_plane_find(ob->priv.output, ofb->fb, ob->format); */
|
||||
/* if (plane) */
|
||||
/* { */
|
||||
/* drmVBlank vbl = */
|
||||
/* { */
|
||||
/* .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT, */
|
||||
/* .request.sequence = 1, */
|
||||
/* }; */
|
||||
|
||||
/* vbl.request.type |= ecore_drm2_output_vblank_get(ob->priv.output); */
|
||||
/* vbl.request.signal = (unsigned long)ofb; */
|
||||
|
||||
/* ecore_drm2_fb_dirty(ofb->fb, rects, count); */
|
||||
|
||||
/* if (!ecore_drm2_plane_fb_set(plane, ofb->fb)) */
|
||||
/* { */
|
||||
/* ERR("Failed to set FB on Plane"); */
|
||||
/* return; */
|
||||
/* } */
|
||||
|
||||
/* if (drmWaitVBlank(ob->fd, &vbl) < 0) */
|
||||
/* { */
|
||||
/* _outbuf_tick_source_set(NULL); */
|
||||
/* return; */
|
||||
/* } */
|
||||
|
||||
/* ofb->busy = EINA_TRUE; */
|
||||
/* ofb->drawn = EINA_TRUE; */
|
||||
/* ofb->age = 0; */
|
||||
|
||||
/* ob->priv.current = NULL; */
|
||||
/* } */
|
||||
/* else */
|
||||
/* WRN("Could not find a plane for this framebuffer"); */
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_outbuf_fb_create(Outbuf *ob, Outbuf_Fb *ofb)
|
||||
{
|
||||
ofb->fb =
|
||||
ecore_drm2_fb_create(ob->fd, ob->w, ob->h,
|
||||
ob->depth, ob->bpp, ob->format);
|
||||
if (!ofb->fb) return EINA_FALSE;
|
||||
|
||||
ofb->age = 0;
|
||||
ofb->busy = EINA_FALSE;
|
||||
ofb->drawn = EINA_FALSE;
|
||||
ofb->valid = EINA_TRUE;
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_outbuf_fb_destroy(Outbuf_Fb *ofb)
|
||||
{
|
||||
ecore_drm2_fb_destroy(ofb->fb);
|
||||
|
||||
memset(ofb, 0, sizeof(*ofb));
|
||||
ofb->valid = EINA_FALSE;
|
||||
ofb->busy = EINA_FALSE;
|
||||
ofb->drawn = EINA_FALSE;
|
||||
ofb->age = 0;
|
||||
}
|
||||
|
||||
Outbuf *
|
||||
evas_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h)
|
||||
_outbuf_setup(Evas_Engine_Info_Drm *info, int w, int h)
|
||||
{
|
||||
Outbuf *ob;
|
||||
char *num;
|
||||
int i = 0;
|
||||
|
||||
/* try to allocate space for outbuf */
|
||||
if (!(ob = calloc(1, sizeof(Outbuf)))) return NULL;
|
||||
ob = calloc(1, sizeof(Outbuf));
|
||||
if (!ob) return NULL;
|
||||
|
||||
/* set properties of outbuf */
|
||||
ob->w = w;
|
||||
ob->h = h;
|
||||
|
||||
ob->info = info;
|
||||
ob->depth = info->info.depth;
|
||||
ob->fd = info->info.fd;
|
||||
ob->alpha = info->info.alpha;
|
||||
ob->rotation = info->info.rotation;
|
||||
ob->destination_alpha = info->info.destination_alpha;
|
||||
ob->vsync = info->info.vsync;
|
||||
|
||||
/* we must triple-buffer to prevent problems with the page flip handler */
|
||||
ob->bpp = info->info.bpp;
|
||||
ob->depth = info->info.depth;
|
||||
ob->format = info->info.format;
|
||||
|
||||
ob->priv.output = info->info.output;
|
||||
|
||||
ob->priv.num = 3;
|
||||
|
||||
/* check for buffer override */
|
||||
if ((num = getenv("EVAS_DRM_BUFFERS")))
|
||||
num = getenv("EVAS_DRM_BUFFERS");
|
||||
if (num)
|
||||
{
|
||||
ob->priv.num = atoi(num);
|
||||
if (ob->priv.num <= 0) ob->priv.num = 1;
|
||||
if (ob->priv.num <= 0) ob->priv.num = 3;
|
||||
else if (ob->priv.num > 4) ob->priv.num = 4;
|
||||
}
|
||||
|
||||
/* check for vsync override */
|
||||
if ((num = getenv("EVAS_DRM_VSYNC")))
|
||||
ob->vsync = atoi(num);
|
||||
|
||||
/* try to create buffers */
|
||||
for (; i < ob->priv.num; i++)
|
||||
for (i = 0; i < ob->priv.num; i++)
|
||||
{
|
||||
ob->priv.buffer[i] =
|
||||
ecore_drm_fb_create(ob->info->info.dev, ob->w, ob->h);
|
||||
if (!ob->priv.buffer[i])
|
||||
if (!_outbuf_fb_create(ob, &(ob->priv.ofb[i])))
|
||||
{
|
||||
ERR("Failed to create buffer %d", i);
|
||||
break;
|
||||
WRN("Failed to create framebuffer %d", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
DBG("Evas Engine Created Dumb Buffer");
|
||||
DBG("\tFb: %d", ob->priv.buffer[i]->id);
|
||||
DBG("\tHandle: %d", ob->priv.buffer[i]->hdl);
|
||||
DBG("\tStride: %d", ob->priv.buffer[i]->stride);
|
||||
DBG("\tSize: %d", ob->priv.buffer[i]->size);
|
||||
DBG("\tW: %d\tH: %d",
|
||||
ob->priv.buffer[i]->w, ob->priv.buffer[i]->h);
|
||||
}
|
||||
|
||||
/* set the front buffer to be the one on the crtc */
|
||||
ecore_drm_fb_send(info->info.dev, ob->priv.buffer[0], NULL, NULL);
|
||||
/* setup vblank handler */
|
||||
memset(&ob->ctx, 0, sizeof(ob->ctx));
|
||||
ob->ctx.version = DRM_EVENT_CONTEXT_VERSION;
|
||||
ob->ctx.vblank_handler = _cb_vblank;
|
||||
ob->ctx.page_flip_handler = _cb_pageflip;
|
||||
|
||||
ob->hdlr =
|
||||
ecore_main_fd_handler_add(ob->fd, ECORE_FD_READ, _cb_drm_event, ob,
|
||||
NULL, NULL);
|
||||
|
||||
_outbuf_tick_source_set(ob);
|
||||
|
||||
return ob;
|
||||
}
|
||||
|
||||
void
|
||||
evas_outbuf_free(Outbuf *ob)
|
||||
_outbuf_free(Outbuf *ob)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* destroy the old buffers */
|
||||
for (; i < ob->priv.num; i++)
|
||||
ecore_drm_fb_destroy(ob->priv.buffer[i]);
|
||||
for (i = 0; i < ob->priv.num; i++)
|
||||
_outbuf_fb_destroy(&ob->priv.ofb[i]);
|
||||
|
||||
ecore_main_fd_handler_del(ob->hdlr);
|
||||
|
||||
/* free allocate space for outbuf */
|
||||
free(ob);
|
||||
}
|
||||
|
||||
int
|
||||
_outbuf_rotation_get(Outbuf *ob)
|
||||
{
|
||||
return ob->rotation;
|
||||
}
|
||||
|
||||
void
|
||||
evas_outbuf_reconfigure(Outbuf *ob, int w, int h, int rot, Outbuf_Depth depth)
|
||||
_outbuf_reconfigure(Outbuf *ob, int w, int h, int rotation, Outbuf_Depth depth)
|
||||
{
|
||||
int i = 0;
|
||||
unsigned int format = DRM_FORMAT_ARGB8888;
|
||||
|
||||
/* check if we are inheriting the old buffer depth */
|
||||
if (depth == OUTBUF_DEPTH_INHERIT) depth = ob->depth;
|
||||
switch (depth)
|
||||
{
|
||||
case OUTBUF_DEPTH_RGB_16BPP_565_565_DITHERED:
|
||||
format = DRM_FORMAT_RGB565;
|
||||
break;
|
||||
case OUTBUF_DEPTH_RGB_16BPP_555_555_DITHERED:
|
||||
format = DRM_FORMAT_RGBX5551;
|
||||
break;
|
||||
case OUTBUF_DEPTH_RGB_16BPP_444_444_DITHERED:
|
||||
format = DRM_FORMAT_RGBX4444;
|
||||
break;
|
||||
case OUTBUF_DEPTH_RGB_16BPP_565_444_DITHERED:
|
||||
format = DRM_FORMAT_RGB565;
|
||||
break;
|
||||
case OUTBUF_DEPTH_RGB_32BPP_888_8888:
|
||||
format = DRM_FORMAT_RGBX8888;
|
||||
break;
|
||||
case OUTBUF_DEPTH_ARGB_32BPP_8888_8888:
|
||||
format = DRM_FORMAT_ARGB8888;
|
||||
break;
|
||||
case OUTBUF_DEPTH_BGRA_32BPP_8888_8888:
|
||||
format = DRM_FORMAT_BGRA8888;
|
||||
break;
|
||||
case OUTBUF_DEPTH_BGR_32BPP_888_8888:
|
||||
format = DRM_FORMAT_BGRX8888;
|
||||
break;
|
||||
case OUTBUF_DEPTH_RGB_24BPP_888_888:
|
||||
format = DRM_FORMAT_RGB888;
|
||||
break;
|
||||
case OUTBUF_DEPTH_BGR_24BPP_888_888:
|
||||
format = DRM_FORMAT_BGR888;
|
||||
break;
|
||||
case OUTBUF_DEPTH_INHERIT:
|
||||
default:
|
||||
depth = ob->depth;
|
||||
format = ob->format;
|
||||
break;
|
||||
}
|
||||
|
||||
/* check for changes */
|
||||
if ((ob->w == w) && (ob->h == h) &&
|
||||
(ob->destination_alpha == ob->info->info.destination_alpha) &&
|
||||
(ob->rotation == rot) &&
|
||||
(ob->depth == depth))
|
||||
if ((ob->w == w) && (ob->h == h) && (ob->rotation == rotation) &&
|
||||
(ob->depth == depth) && (ob->format == format))
|
||||
return;
|
||||
|
||||
/* set new outbuf properties */
|
||||
ob->rotation = rot;
|
||||
ob->depth = depth;
|
||||
ob->destination_alpha = ob->info->info.destination_alpha;
|
||||
ob->format = format;
|
||||
ob->rotation = rotation;
|
||||
|
||||
/* handle rotation */
|
||||
if ((ob->rotation == 0) || (ob->rotation == 180))
|
||||
{
|
||||
ob->w = w;
|
||||
ob->h = h;
|
||||
}
|
||||
else
|
||||
ob->w = w;
|
||||
ob->h = h;
|
||||
if ((ob->rotation == 90) || (ob->rotation == 270))
|
||||
{
|
||||
ob->w = h;
|
||||
ob->h = w;
|
||||
}
|
||||
|
||||
/* destroy the old buffers */
|
||||
for (; i < ob->priv.num; i++)
|
||||
ecore_drm_fb_destroy(ob->priv.buffer[i]);
|
||||
for (i = 0; i < ob->priv.num; i++)
|
||||
_outbuf_fb_destroy(&ob->priv.ofb[i]);
|
||||
|
||||
for (i = 0; i < ob->priv.num; i++)
|
||||
{
|
||||
ob->priv.buffer[i] =
|
||||
ecore_drm_fb_create(ob->info->info.dev, ob->w, ob->h);
|
||||
if (!ob->priv.buffer[i])
|
||||
if (!_outbuf_fb_create(ob, &(ob->priv.ofb[i])))
|
||||
{
|
||||
ERR("Failed to create buffer %d", i);
|
||||
break;
|
||||
WRN("Failed to create framebuffer %d", i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Render_Engine_Swap_Mode
|
||||
evas_outbuf_buffer_state_get(Outbuf *ob)
|
||||
static Outbuf_Fb *
|
||||
_outbuf_fb_wait(Outbuf *ob)
|
||||
{
|
||||
int delta;
|
||||
int iter = 0, i = 0;
|
||||
|
||||
/* check for valid output buffer */
|
||||
if (!ob) return MODE_FULL;
|
||||
|
||||
delta = (ob->priv.last - ob->priv.curr + ob->priv.num) % ob->priv.num;
|
||||
|
||||
/* This is the number of frame since last frame */
|
||||
switch (delta)
|
||||
while (iter++ < 10)
|
||||
{
|
||||
case 0:
|
||||
return MODE_COPY;
|
||||
case 1:
|
||||
return MODE_DOUBLE;
|
||||
case 2:
|
||||
return MODE_TRIPLE;
|
||||
case 3:
|
||||
return MODE_QUADRUPLE;
|
||||
default:
|
||||
return MODE_FULL;
|
||||
for (i = 0; i < ob->priv.num; i++)
|
||||
{
|
||||
if (ob->priv.ofb[i].busy) continue;
|
||||
if (ob->priv.ofb[i].valid) return &(ob->priv.ofb[i]);
|
||||
}
|
||||
|
||||
drmHandleEvent(ob->fd, &ob->ctx);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_outbuf_fb_assign(Outbuf *ob)
|
||||
{
|
||||
int i;
|
||||
|
||||
ob->priv.current = _outbuf_fb_wait(ob);
|
||||
|
||||
if (!ob->priv.current)
|
||||
{
|
||||
WRN("No Free Buffers. Dropping a frame");
|
||||
for (i = 0; i < ob->priv.num; i++)
|
||||
{
|
||||
if (ob->priv.ofb[i].valid)
|
||||
{
|
||||
ob->priv.ofb[i].age = 0;
|
||||
ob->priv.ofb[i].drawn = EINA_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < ob->priv.num; i++)
|
||||
{
|
||||
if ((ob->priv.ofb[i].valid) && (ob->priv.ofb[i].drawn))
|
||||
{
|
||||
ob->priv.ofb[i].age++;
|
||||
if (ob->priv.ofb[i].age > ob->priv.num)
|
||||
{
|
||||
ob->priv.ofb[i].age = 0;
|
||||
ob->priv.ofb[i].drawn = EINA_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
Render_Engine_Swap_Mode
|
||||
_outbuf_state_get(Outbuf *ob)
|
||||
{
|
||||
int age;
|
||||
|
||||
if (!_outbuf_fb_assign(ob)) return MODE_FULL;
|
||||
|
||||
age = ob->priv.current->age;
|
||||
if (age > ob->priv.num) return MODE_FULL;
|
||||
else if (age == 1) return MODE_COPY;
|
||||
else if (age == 2) return MODE_DOUBLE;
|
||||
else if (age == 3) return MODE_TRIPLE;
|
||||
else if (age == 4) return MODE_QUADRUPLE;
|
||||
|
||||
return MODE_FULL;
|
||||
}
|
||||
|
||||
void *
|
||||
evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch)
|
||||
_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, int *cy, int *cw, int *ch)
|
||||
{
|
||||
RGBA_Image *img = NULL;
|
||||
|
||||
if ((w <= 0) || (h <= 0)) return NULL;
|
||||
|
||||
/* DBG("Outbuf Region New: %d %d %d %d", x, y, w, h); */
|
||||
|
||||
RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, ob->w, ob->h);
|
||||
|
||||
if ((ob->rotation == 0) && (ob->depth == 32))
|
||||
if ((ob->rotation == 0))// && (ob->depth == 32))
|
||||
{
|
||||
Eina_Rectangle *rect;
|
||||
|
||||
|
@ -204,7 +451,7 @@ evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, i
|
|||
return NULL;
|
||||
}
|
||||
|
||||
img->cache_entry.flags.alpha = ob->destination_alpha;
|
||||
img->cache_entry.flags.alpha = ob->alpha;
|
||||
|
||||
#ifdef EVAS_CSERVE2
|
||||
if (evas_cserve2_use_get())
|
||||
|
@ -221,48 +468,52 @@ evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, i
|
|||
if (ch) *ch = h;
|
||||
|
||||
/* add this cached image data to pending writes */
|
||||
ob->priv.pending_writes =
|
||||
eina_list_append(ob->priv.pending_writes, img);
|
||||
ob->priv.pending =
|
||||
eina_list_append(ob->priv.pending, img);
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
void
|
||||
evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h)
|
||||
_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h)
|
||||
{
|
||||
Gfx_Func_Convert func = NULL;
|
||||
Eina_Rectangle rect = {0, 0, 0, 0}, pr;
|
||||
DATA32 *src;
|
||||
DATA8 *dst;
|
||||
Ecore_Drm_Fb *buff;
|
||||
Ecore_Drm2_Fb *buff;
|
||||
int bpp = 0, bpl = 0;
|
||||
int rx = 0, ry = 0;
|
||||
int bw = 0, bh = 0;
|
||||
|
||||
/* check for valid output buffer */
|
||||
if (!ob) return;
|
||||
|
||||
/* check for pending writes */
|
||||
if (!ob->priv.pending_writes) return;
|
||||
if (!ob->priv.pending) return;
|
||||
|
||||
/* check for valid source data */
|
||||
if (!(src = update->image.data)) return;
|
||||
|
||||
/* check for valid desination data */
|
||||
buff = ob->priv.buffer[ob->priv.curr];
|
||||
if (!(dst = buff->mmap)) return;
|
||||
if (!ob->priv.current) return;
|
||||
buff = ob->priv.current->fb;
|
||||
|
||||
dst = ecore_drm2_fb_data_get(buff);
|
||||
if (!dst) return;
|
||||
|
||||
if ((ob->rotation == 0) || (ob->rotation == 180))
|
||||
{
|
||||
func =
|
||||
evas_common_convert_func_get(0, w, h, ob->depth,
|
||||
evas_common_convert_func_get(0, w, h, ob->bpp,
|
||||
RED_MASK, GREEN_MASK, BLUE_MASK,
|
||||
PAL_MODE_NONE, ob->rotation);
|
||||
}
|
||||
else if ((ob->rotation == 90) || (ob->rotation == 270))
|
||||
{
|
||||
func =
|
||||
evas_common_convert_func_get(0, h, w, ob->depth,
|
||||
evas_common_convert_func_get(0, h, w, ob->bpp,
|
||||
RED_MASK, GREEN_MASK, BLUE_MASK,
|
||||
PAL_MODE_NONE, ob->rotation);
|
||||
}
|
||||
|
@ -304,15 +555,18 @@ evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int
|
|||
rect.h = w;
|
||||
}
|
||||
|
||||
bpp = (ob->depth / 8);
|
||||
if (bpp <= 0) return;
|
||||
bpp = ob->bpp / 8;
|
||||
bw = ob->w;
|
||||
bh = ob->h;
|
||||
/* bpp = (ob->depth / 8); */
|
||||
/* if (bpp <= 0) return; */
|
||||
|
||||
bpl = buff->stride;
|
||||
bpl = ecore_drm2_fb_stride_get(buff);
|
||||
|
||||
if (ob->rotation == 0)
|
||||
{
|
||||
RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h,
|
||||
0, 0, buff->w, buff->h);
|
||||
0, 0, bw, bh);
|
||||
dst += (bpl * rect.y) + (rect.x * bpp);
|
||||
w -= rx;
|
||||
}
|
||||
|
@ -320,7 +574,7 @@ evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int
|
|||
{
|
||||
pr = rect;
|
||||
RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h,
|
||||
0, 0, buff->w, buff->h);
|
||||
0, 0, bw, bh);
|
||||
rx = pr.w - rect.w;
|
||||
ry = pr.h - rect.h;
|
||||
src += (update->cache_entry.w * ry) + rx;
|
||||
|
@ -330,7 +584,7 @@ evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int
|
|||
{
|
||||
pr = rect;
|
||||
RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h,
|
||||
0, 0, buff->w, buff->h);
|
||||
0, 0, bw, bh);
|
||||
rx = pr.w - rect.w; ry = pr.h - rect.h;
|
||||
src += ry;
|
||||
w -= ry;
|
||||
|
@ -339,7 +593,7 @@ evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int
|
|||
{
|
||||
pr = rect;
|
||||
RECTS_CLIP_TO_RECT(rect.x, rect.y, rect.w, rect.h,
|
||||
0, 0, buff->w, buff->h);
|
||||
0, 0, bw, bh);
|
||||
rx = pr.w - rect.w; ry = pr.h - rect.h;
|
||||
src += (update->cache_entry.w * rx);
|
||||
w -= ry;
|
||||
|
@ -352,13 +606,13 @@ evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int
|
|||
}
|
||||
|
||||
void
|
||||
evas_outbuf_update_region_free(Outbuf *ob EINA_UNUSED, RGBA_Image *update EINA_UNUSED)
|
||||
_outbuf_update_region_free(Outbuf *ob EINA_UNUSED, RGBA_Image *update EINA_UNUSED)
|
||||
{
|
||||
/* evas_cache_image_drop(&update->cache_entry); */
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode render_mode)
|
||||
_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode render_mode)
|
||||
{
|
||||
Eina_Rectangle *r;
|
||||
RGBA_Image *img;
|
||||
|
@ -367,19 +621,21 @@ evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode
|
|||
if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return;
|
||||
|
||||
/* get number of pending writes */
|
||||
n = eina_list_count(ob->priv.pending_writes);
|
||||
n = eina_list_count(ob->priv.pending);
|
||||
if (n == 0) return;
|
||||
|
||||
/* allocate rectangles */
|
||||
if (!(r = alloca(n * sizeof(Eina_Rectangle)))) return;
|
||||
r = alloca(n * sizeof(Eina_Rectangle));
|
||||
if (!r) return;
|
||||
|
||||
/* loop the pending writes */
|
||||
EINA_LIST_FREE(ob->priv.pending_writes, img)
|
||||
EINA_LIST_FREE(ob->priv.pending, img)
|
||||
{
|
||||
Eina_Rectangle *rect;
|
||||
int x = 0, y = 0, w = 0, h = 0;
|
||||
|
||||
if (!(rect = img->extended_info)) continue;
|
||||
rect = img->extended_info;
|
||||
if (!rect) continue;
|
||||
|
||||
x = rect->x; y = rect->y; w = rect->w; h = rect->h;
|
||||
|
||||
|
@ -430,11 +686,5 @@ evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode
|
|||
}
|
||||
|
||||
/* force a buffer swap */
|
||||
_evas_outbuf_buffer_swap(ob, r, n);
|
||||
}
|
||||
|
||||
int
|
||||
evas_outbuf_rot_get(Outbuf *ob)
|
||||
{
|
||||
return ob->rotation;
|
||||
_outbuf_buffer_swap(ob, r, n);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef _EVAS_ENGINE_GL_DRM_H
|
||||
# define _EVAS_ENGINE_GL_DRM_H
|
||||
|
||||
# include <Ecore_Drm.h>
|
||||
# include <Ecore_Drm2.h>
|
||||
# include <gbm.h>
|
||||
|
||||
typedef enum _Evas_Engine_Info_GL_Drm_Swap_Mode
|
||||
|
@ -26,11 +26,11 @@ struct _Evas_Engine_Info_GL_Drm
|
|||
{
|
||||
struct gbm_device *gbm;
|
||||
|
||||
int fd, bpp;
|
||||
unsigned int rotation, depth;
|
||||
unsigned int crtc_id, conn_id, buffer_id;
|
||||
unsigned int format, flags;
|
||||
|
||||
Ecore_Drm_Device *dev;
|
||||
void *output;
|
||||
|
||||
Eina_Bool destination_alpha : 1;
|
||||
Eina_Bool vsync : 1;
|
||||
|
|
|
@ -118,12 +118,9 @@ static const EVGL_Interface evgl_funcs =
|
|||
Eina_Bool
|
||||
eng_gbm_init(Evas_Engine_Info_GL_Drm *info)
|
||||
{
|
||||
Ecore_Drm_Device *dev;
|
||||
|
||||
if (!info) return EINA_FALSE;
|
||||
if (!(dev = info->info.dev)) return EINA_FALSE;
|
||||
|
||||
if (!(info->info.gbm = gbm_create_device(dev->drm.fd)))
|
||||
if (!(info->info.gbm = gbm_create_device(info->info.fd)))
|
||||
{
|
||||
ERR("Coult not create gbm device");
|
||||
return EINA_FALSE;
|
||||
|
@ -146,13 +143,6 @@ eng_gbm_shutdown(Evas_Engine_Info_GL_Drm *info)
|
|||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
/* local inline functions */
|
||||
static inline Outbuf *
|
||||
eng_get_ob(Render_Engine *re)
|
||||
{
|
||||
return re->generic.software.ob;
|
||||
}
|
||||
|
||||
/* local functions */
|
||||
static void
|
||||
gl_symbols(void)
|
||||
|
@ -362,6 +352,8 @@ evgl_eng_native_window_create(void *data)
|
|||
Render_Engine *re;
|
||||
struct gbm_surface *surface;
|
||||
Evas_Engine_Info_GL_Drm *info;
|
||||
unsigned int format = GBM_FORMAT_XRGB8888;
|
||||
unsigned int flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
|
||||
|
||||
re = (Render_Engine *)data;
|
||||
if (!re)
|
||||
|
@ -377,9 +369,9 @@ evgl_eng_native_window_create(void *data)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
surface = gbm_surface_create(info->info.gbm,
|
||||
eng_get_ob(re)->w, eng_get_ob(re)->h,
|
||||
info->info.format, info->info.flags);
|
||||
surface =
|
||||
gbm_surface_create(info->info.gbm,
|
||||
eng_get_ob(re)->w, eng_get_ob(re)->h, format, flags);
|
||||
if (!surface)
|
||||
{
|
||||
ERR("Could not create gl drm window");
|
||||
|
@ -786,6 +778,37 @@ _native_cb_free(void *image)
|
|||
free(n);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_vblank(int fd, unsigned int frame EINA_UNUSED, unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
|
||||
{
|
||||
evas_outbuf_vblank(data, fd);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_page_flip(int fd, unsigned int frame EINA_UNUSED, unsigned int sec EINA_UNUSED, unsigned int usec EINA_UNUSED, void *data)
|
||||
{
|
||||
evas_outbuf_page_flip(data, fd);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_cb_drm_event(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
|
||||
{
|
||||
Render_Engine *re;
|
||||
int ret;
|
||||
|
||||
re = data;
|
||||
if (!re) return EINA_TRUE;
|
||||
|
||||
ret = drmHandleEvent(re->fd, &re->ctx);
|
||||
if (ret)
|
||||
{
|
||||
ERR("drmHandleEvent failed to read an event: %m");
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
/* engine specific override functions */
|
||||
static void *
|
||||
eng_info(Evas *eo_e EINA_UNUSED)
|
||||
|
@ -899,6 +922,17 @@ eng_setup(Evas *evas, void *in)
|
|||
return 0;
|
||||
}
|
||||
|
||||
re->fd = info->info.fd;
|
||||
|
||||
memset(&re->ctx, 0, sizeof(re->ctx));
|
||||
re->ctx.version = DRM_EVENT_CONTEXT_VERSION;
|
||||
re->ctx.vblank_handler = _cb_vblank;
|
||||
re->ctx.page_flip_handler = _cb_page_flip;
|
||||
|
||||
re->hdlr =
|
||||
ecore_main_fd_handler_add(info->info.fd, ECORE_FD_READ,
|
||||
_cb_drm_event, re, NULL, NULL);
|
||||
|
||||
/* try to create new outbuf */
|
||||
ob = evas_outbuf_new(info, epd->output.w, epd->output.h, swap_mode);
|
||||
if (!ob)
|
||||
|
@ -970,16 +1004,16 @@ eng_setup(Evas *evas, void *in)
|
|||
re->generic.software.ob = NULL;
|
||||
gl_wins--;
|
||||
|
||||
if (ob_old) evas_outbuf_free(ob_old);
|
||||
|
||||
ob = evas_outbuf_new(info, epd->output.w, epd->output.h, swap_mode);
|
||||
if (!ob)
|
||||
{
|
||||
if (ob_old) evas_outbuf_free(ob_old);
|
||||
free(re);
|
||||
return 0;
|
||||
}
|
||||
|
||||
evas_outbuf_use(ob);
|
||||
if (ob_old) evas_outbuf_free(ob_old);
|
||||
|
||||
ob->evas = evas;
|
||||
|
||||
|
@ -1439,6 +1473,8 @@ module_open(Evas_Module *em)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ecore_init();
|
||||
|
||||
/* store it for later use */
|
||||
func = pfunc;
|
||||
|
||||
|
@ -1471,6 +1507,8 @@ module_close(Evas_Module *em EINA_UNUSED)
|
|||
/* unregister the eina log domain for this engine */
|
||||
eina_log_domain_unregister(_evas_engine_gl_drm_log_dom);
|
||||
_evas_engine_gl_drm_log_dom = -1;
|
||||
|
||||
ecore_shutdown();
|
||||
}
|
||||
|
||||
static Evas_Module_Api evas_modapi =
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
# include "Evas.h"
|
||||
# include "Evas_Engine_GL_Drm.h"
|
||||
|
||||
# include <Ecore.h>
|
||||
# include <drm_fourcc.h>
|
||||
# include <xf86drm.h>
|
||||
# include <xf86drmMode.h>
|
||||
|
||||
# define EGL_EGLEXT_PROTOTYPES
|
||||
# define GL_GLEXT_PROTOTYPES
|
||||
|
||||
|
@ -64,6 +69,10 @@ typedef struct _Render_Engine Render_Engine;
|
|||
struct _Render_Engine
|
||||
{
|
||||
Render_Engine_GL_Generic generic;
|
||||
|
||||
int fd;
|
||||
drmEventContext ctx;
|
||||
Ecore_Fd_Handler *hdlr;
|
||||
};
|
||||
|
||||
struct _Context_3D
|
||||
|
@ -80,11 +89,10 @@ struct _Outbuf
|
|||
|
||||
Evas *evas; // used for pre_swap, post_swap
|
||||
|
||||
int w, h;
|
||||
unsigned int rotation, depth;
|
||||
int fd, w, h, bpp;
|
||||
unsigned int rotation, depth, format;
|
||||
Render_Engine_Swap_Mode swap_mode;
|
||||
|
||||
/* struct gbm_device *gbm; */
|
||||
struct gbm_surface *surface;
|
||||
|
||||
struct
|
||||
|
@ -98,6 +106,7 @@ struct _Outbuf
|
|||
struct
|
||||
{
|
||||
struct gbm_bo *bo[2];
|
||||
Ecore_Drm2_Output *output;
|
||||
} priv;
|
||||
|
||||
Eina_Bool destination_alpha : 1;
|
||||
|
@ -123,6 +132,9 @@ void *evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int
|
|||
void evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, int w, int h);
|
||||
void evas_outbuf_update_region_free(Outbuf *ob, RGBA_Image *update);
|
||||
void evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects, Evas_Render_Mode render_mode);
|
||||
void evas_outbuf_vblank(void *data, int fd);
|
||||
void evas_outbuf_page_flip(void *data, int fd);
|
||||
|
||||
Evas_Engine_GL_Context* evas_outbuf_gl_context_get(Outbuf *ob);
|
||||
void *evas_outbuf_egl_display_get(Outbuf *ob);
|
||||
Context_3D *evas_outbuf_gl_context_new(Outbuf *ob);
|
||||
|
@ -138,6 +150,12 @@ _re_wincheck(Outbuf *ob)
|
|||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static inline Outbuf *
|
||||
eng_get_ob(Render_Engine *re)
|
||||
{
|
||||
return re->generic.software.ob;
|
||||
}
|
||||
|
||||
extern unsigned int (*glsym_eglSwapBuffersWithDamage)(EGLDisplay a, void *b, const EGLint *d, EGLint c);
|
||||
extern unsigned int (*glsym_eglSetDamageRegionKHR)(EGLDisplay a, EGLSurface b, EGLint *c, EGLint d);
|
||||
|
||||
|
|
|
@ -5,12 +5,86 @@
|
|||
static Outbuf *_evas_gl_drm_window = NULL;
|
||||
static EGLContext context = EGL_NO_CONTEXT;
|
||||
static int win_count = 0;
|
||||
static Eina_Bool ticking = EINA_FALSE;
|
||||
|
||||
#ifdef EGL_MESA_platform_gbm
|
||||
static PFNEGLGETPLATFORMDISPLAYEXTPROC dlsym_eglGetPlatformDisplayEXT = NULL;
|
||||
static PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC dlsym_eglCreatePlatformWindowSurfaceEXT = NULL;
|
||||
#endif
|
||||
|
||||
static void
|
||||
_outbuf_tick_schedule(int fd, void *data)
|
||||
{
|
||||
if (!ticking) return;
|
||||
|
||||
drmVBlank vbl =
|
||||
{
|
||||
.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
|
||||
.request.sequence = 1,
|
||||
.request.signal = (unsigned long)data,
|
||||
};
|
||||
|
||||
drmWaitVBlank(fd, &vbl);
|
||||
}
|
||||
|
||||
static void
|
||||
_outbuf_tick_begin(void *data)
|
||||
{
|
||||
Outbuf *ob;
|
||||
|
||||
ob = data;
|
||||
ticking = EINA_TRUE;
|
||||
if (ob) _outbuf_tick_schedule(ob->fd, ob);
|
||||
}
|
||||
|
||||
static void
|
||||
_outbuf_tick_end(void *data EINA_UNUSED)
|
||||
{
|
||||
ticking = EINA_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_outbuf_tick_source_set(Outbuf *ob)
|
||||
{
|
||||
if (ob)
|
||||
{
|
||||
ecore_animator_custom_source_tick_begin_callback_set
|
||||
(_outbuf_tick_begin, ob);
|
||||
ecore_animator_custom_source_tick_end_callback_set
|
||||
(_outbuf_tick_end, ob);
|
||||
ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM);
|
||||
}
|
||||
else
|
||||
{
|
||||
ecore_animator_custom_source_tick_begin_callback_set(NULL, NULL);
|
||||
ecore_animator_custom_source_tick_end_callback_set(NULL, NULL);
|
||||
ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_TIMER);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
evas_outbuf_vblank(void *data, int fd)
|
||||
{
|
||||
ecore_animator_custom_tick();
|
||||
if (ticking) _outbuf_tick_schedule(fd, data);
|
||||
}
|
||||
|
||||
void
|
||||
evas_outbuf_page_flip(void *data, int fd EINA_UNUSED)
|
||||
{
|
||||
Outbuf *ob;
|
||||
Ecore_Drm2_Fb *next;
|
||||
|
||||
ob = data;
|
||||
next = ecore_drm2_output_next_fb_get(ob->priv.output);
|
||||
if (next)
|
||||
{
|
||||
ecore_drm2_output_next_fb_set(ob->priv.output, NULL);
|
||||
if (ecore_drm2_fb_flip(next, ob->priv.output, ob) < 0)
|
||||
_outbuf_tick_source_set(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_evas_outbuf_gbm_surface_destroy(Outbuf *ob)
|
||||
{
|
||||
|
@ -25,63 +99,51 @@ _evas_outbuf_gbm_surface_destroy(Outbuf *ob)
|
|||
static void
|
||||
_evas_outbuf_gbm_surface_create(Outbuf *ob, int w, int h)
|
||||
{
|
||||
unsigned int format = GBM_FORMAT_XRGB8888;
|
||||
unsigned int flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
|
||||
|
||||
if (!ob) return;
|
||||
|
||||
ob->surface =
|
||||
gbm_surface_create(ob->info->info.gbm, w, h,
|
||||
ob->info->info.format, ob->info->info.flags);
|
||||
gbm_surface_create(ob->info->info.gbm, w, h, format, flags);
|
||||
|
||||
if (!ob->surface) ERR("Failed to create gbm surface");
|
||||
}
|
||||
|
||||
static void
|
||||
_evas_outbuf_fb_cb_destroy(struct gbm_bo *bo, void *data)
|
||||
_evas_outbuf_fb_cb_destroy(struct gbm_bo *bo EINA_UNUSED, void *data)
|
||||
{
|
||||
Ecore_Drm_Fb *fb;
|
||||
Ecore_Drm2_Fb *fb;
|
||||
|
||||
fb = data;
|
||||
if (fb)
|
||||
{
|
||||
struct gbm_device *gbm;
|
||||
|
||||
gbm = gbm_bo_get_device(bo);
|
||||
drmModeRmFB(gbm_device_get_fd(gbm), fb->id);
|
||||
free(fb);
|
||||
}
|
||||
if (fb) ecore_drm2_fb_destroy(fb);
|
||||
}
|
||||
|
||||
static Ecore_Drm_Fb *
|
||||
_evas_outbuf_fb_get(Ecore_Drm_Device *dev, struct gbm_bo *bo)
|
||||
static Ecore_Drm2_Fb *
|
||||
_evas_outbuf_fb_get(Outbuf *ob, struct gbm_bo *bo)
|
||||
{
|
||||
int ret;
|
||||
Ecore_Drm_Fb *fb;
|
||||
uint32_t format;
|
||||
uint32_t handles[4], pitches[4], offsets[4];
|
||||
Ecore_Drm2_Fb *fb;
|
||||
uint32_t format, hdl, stride;
|
||||
int w, h;
|
||||
|
||||
fb = gbm_bo_get_user_data(bo);
|
||||
if (fb) return fb;
|
||||
|
||||
if (!(fb = calloc(1, sizeof(Ecore_Drm_Fb)))) return NULL;
|
||||
|
||||
format = gbm_bo_get_format(bo);
|
||||
w = gbm_bo_get_width(bo);
|
||||
h = gbm_bo_get_height(bo);
|
||||
hdl = gbm_bo_get_handle(bo).u32;
|
||||
stride = gbm_bo_get_stride(bo);
|
||||
/* fb->size = fb->stride * fb->h; */
|
||||
|
||||
fb->w = gbm_bo_get_width(bo);
|
||||
fb->h = gbm_bo_get_height(bo);
|
||||
fb->hdl = gbm_bo_get_handle(bo).u32;
|
||||
fb->stride = gbm_bo_get_stride(bo);
|
||||
fb->size = fb->stride * fb->h;
|
||||
|
||||
handles[0] = fb->hdl;
|
||||
pitches[0] = fb->stride;
|
||||
offsets[0] = 0;
|
||||
|
||||
ret = drmModeAddFB2(dev->drm.fd, fb->w, fb->h, format,
|
||||
handles, pitches, offsets, &(fb->id), 0);
|
||||
if (ret)
|
||||
ret = drmModeAddFB(dev->drm.fd, fb->w, fb->h, 24, 32,
|
||||
fb->stride, fb->hdl, &(fb->id));
|
||||
|
||||
if (ret) ERR("FAILED TO ADD FB: %m");
|
||||
fb =
|
||||
ecore_drm2_fb_gbm_create(ob->fd, w, h, ob->depth, ob->bpp,
|
||||
format, hdl, stride);
|
||||
if (!fb)
|
||||
{
|
||||
ERR("Failed to create FBO");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gbm_bo_set_user_data(bo, fb, _evas_outbuf_fb_cb_destroy);
|
||||
|
||||
|
@ -91,7 +153,9 @@ _evas_outbuf_fb_get(Ecore_Drm_Device *dev, struct gbm_bo *bo)
|
|||
static void
|
||||
_evas_outbuf_buffer_swap(Outbuf *ob, Eina_Rectangle *rects, unsigned int count)
|
||||
{
|
||||
Ecore_Drm_Fb *fb;
|
||||
Ecore_Drm2_Fb *fb;
|
||||
|
||||
if (ob->priv.bo[1]) gbm_surface_release_buffer(ob->surface, ob->priv.bo[1]);
|
||||
|
||||
/* Repulsive hack: Right now we don't actually have a proper way to retire
|
||||
* buffers because the ticker and the flip handler are out of sync, the
|
||||
|
@ -106,15 +170,48 @@ _evas_outbuf_buffer_swap(Outbuf *ob, Eina_Rectangle *rects, unsigned int count)
|
|||
ob->priv.bo[0] = gbm_surface_lock_front_buffer(ob->surface);
|
||||
if (!ob->priv.bo[0])
|
||||
{
|
||||
WRN("Could not lock front buffer");
|
||||
WRN("Could not lock front buffer: %m");
|
||||
return;
|
||||
}
|
||||
fb = _evas_outbuf_fb_get(ob->info->info.dev, ob->priv.bo[0]);
|
||||
|
||||
fb = _evas_outbuf_fb_get(ob, ob->priv.bo[0]);
|
||||
if (fb)
|
||||
{
|
||||
ecore_drm_fb_dirty(fb, rects, count);
|
||||
ecore_drm_fb_send(ob->info->info.dev, fb, NULL, NULL);
|
||||
ecore_drm2_fb_dirty(fb, rects, count);
|
||||
if (ecore_drm2_fb_flip(fb, ob->priv.output, ob) < 0)
|
||||
_outbuf_tick_source_set(NULL);
|
||||
|
||||
/* Ecore_Drm2_Plane *plane; */
|
||||
|
||||
/* plane = ecore_drm2_plane_find(ob->priv.output, fb, ob->format); */
|
||||
/* if (plane) */
|
||||
/* { */
|
||||
/* int ret; */
|
||||
/* drmVBlank vbl = */
|
||||
/* { */
|
||||
/* .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT, */
|
||||
/* .request.sequence = 1, */
|
||||
/* }; */
|
||||
|
||||
/* vbl.request.type |= ecore_drm2_output_vblank_get(ob->priv.output); */
|
||||
/* vbl.request.signal = (unsigned long)ob; */
|
||||
|
||||
/* ecore_drm2_fb_dirty(fb, rects, count); */
|
||||
|
||||
/* if (!ecore_drm2_plane_fb_set(plane, fb)) */
|
||||
/* { */
|
||||
/* ERR("Failed to set FB on Plane"); */
|
||||
/* return; */
|
||||
/* } */
|
||||
|
||||
/* ret = drmWaitVBlank(ob->fd, &vbl); */
|
||||
/* if (ret) return; */
|
||||
/* } */
|
||||
/* else */
|
||||
/* WRN("NO PLANE FOUND"); */
|
||||
}
|
||||
else
|
||||
WRN("Could not get FBO from Bo");
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
|
@ -253,9 +350,6 @@ _evas_outbuf_egl_setup(Outbuf *ob)
|
|||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
DBG("Config Format: %d", format);
|
||||
DBG("OB Format: %d", ob->info->info.format);
|
||||
|
||||
if (format == (int)ob->info->info.format)
|
||||
{
|
||||
ob->egl.config = cfgs[i];
|
||||
|
@ -369,6 +463,11 @@ evas_outbuf_new(Evas_Engine_Info_GL_Drm *info, int w, int h, Render_Engine_Swap_
|
|||
/* ob->vsync = info->info.vsync; */
|
||||
ob->swap_mode = swap_mode;
|
||||
|
||||
ob->fd = info->info.fd;
|
||||
ob->bpp = info->info.bpp;
|
||||
ob->format = info->info.format;
|
||||
ob->priv.output = info->info.output;
|
||||
|
||||
/* if ((num = getenv("EVAS_GL_DRM_VSYNC"))) */
|
||||
/* ob->vsync = atoi(num); */
|
||||
|
||||
|
@ -383,6 +482,8 @@ evas_outbuf_new(Evas_Engine_Info_GL_Drm *info, int w, int h, Render_Engine_Swap_
|
|||
return NULL;
|
||||
}
|
||||
|
||||
_outbuf_tick_source_set(ob);
|
||||
|
||||
return ob;
|
||||
}
|
||||
|
||||
|
@ -577,9 +678,7 @@ evas_outbuf_buffer_state_get(Outbuf *ob)
|
|||
return swap_mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MODE_FULL;
|
||||
}
|
||||
return MODE_FULL;
|
||||
|
||||
return ob->swap_mode;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue