4803 lines
167 KiB
C
4803 lines
167 KiB
C
#define _EVAS_GL_CONTEXT_C
|
|
#include "evas_gl_private.h"
|
|
|
|
#if defined HAVE_DLSYM && ! defined _WIN32
|
|
# include <dlfcn.h> /* dlopen,dlclose,etc */
|
|
#else
|
|
# error gl_common should not get compiled if dlsym is not found on the system!
|
|
#endif
|
|
|
|
#define PRG_INVALID NULL
|
|
|
|
static int tbm_sym_done = 0;
|
|
int _evas_engine_GL_common_log_dom = -1;
|
|
Cutout_Rects *_evas_gl_common_cutout_rects = NULL;
|
|
|
|
typedef void (*glsym_func_void) ();
|
|
typedef void *(*glsym_func_void_ptr) ();
|
|
typedef GLboolean (*glsym_func_boolean) ();
|
|
typedef const char *(*glsym_func_const_char_ptr) ();
|
|
|
|
void (*glsym_glGenFramebuffers) (GLsizei a, GLuint *b) = NULL;
|
|
void (*glsym_glBindFramebuffer) (GLenum a, GLuint b) = NULL;
|
|
void (*glsym_glFramebufferTexture2D) (GLenum a, GLenum b, GLenum c, GLuint d, GLint e) = NULL;
|
|
void (*glsym_glDeleteFramebuffers) (GLsizei a, const GLuint *b) = NULL;
|
|
void (*glsym_glGetProgramBinary) (GLuint a, GLsizei b, GLsizei *c, GLenum *d, void *e) = NULL;
|
|
void (*glsym_glProgramBinary) (GLuint a, GLenum b, const void *c, GLint d) = NULL;
|
|
void (*glsym_glProgramParameteri) (GLuint a, GLuint b, GLint d) = NULL;
|
|
void (*glsym_glReleaseShaderCompiler)(void) = NULL;
|
|
void *(*glsym_glMapBuffer) (GLenum a, GLenum b) = NULL;
|
|
GLboolean (*glsym_glUnmapBuffer) (GLenum a) = NULL;
|
|
void (*glsym_glStartTiling) (GLuint a, GLuint b, GLuint c, GLuint d, GLuint e) = NULL;
|
|
void (*glsym_glEndTiling) (GLuint a) = NULL;
|
|
void (*glsym_glRenderbufferStorageMultisample)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) = NULL;
|
|
|
|
const char *(*glsym_glGetStringi) (GLenum name, GLuint index) = NULL;
|
|
|
|
#ifdef GL_GLES
|
|
|
|
# ifndef GL_LINE_SMOOTH
|
|
# define GL_LINE_SMOOTH 0x0B20
|
|
# endif
|
|
|
|
// just used for finding symbols :)
|
|
typedef void (*_eng_fn) (void);
|
|
|
|
typedef _eng_fn (*glsym_func_eng_fn) ();
|
|
typedef int (*secsym_func_int) ();
|
|
typedef unsigned int (*secsym_func_uint) ();
|
|
typedef void *(*secsym_func_void_ptr) ();
|
|
|
|
unsigned int (*eglsym_eglDestroyImage) (void *a, void *b) = NULL;
|
|
void (*secsym_glEGLImageTargetTexture2DOES) (int a, void *b) = NULL;
|
|
void *(*secsym_eglMapImageSEC) (void *a, void *b, int c, int d) = NULL;
|
|
unsigned int (*secsym_eglUnmapImageSEC) (void *a, void *b, int c) = NULL;
|
|
unsigned int (*secsym_eglGetImageAttribSEC) (void *a, void *b, int c, int *d) = NULL;
|
|
|
|
/* This one is now a local wrapper to avoid type mixups */
|
|
void * evas_gl_common_eglCreateImage (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);
|
|
static void * (*eglsym_eglCreateImage) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list) = NULL;
|
|
static void * (*eglsym_eglCreateImageKHR) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *e) = NULL;
|
|
|
|
////////////////////////////////////
|
|
//libtbm.so.1
|
|
static void *tbm_lib_handle;
|
|
|
|
void *(*secsym_tbm_surface_create) (int width, int height, unsigned int format) = NULL;
|
|
int (*secsym_tbm_surface_destroy) (void *surface) = NULL;
|
|
int (*secsym_tbm_surface_map) (void *surface, int opt, void *info) = NULL;
|
|
int (*secsym_tbm_surface_unmap) (void *surface) = NULL;
|
|
int (*secsym_tbm_surface_get_info) (void *surface, void *info) = NULL;
|
|
////////////////////////////////////
|
|
#else
|
|
typedef void (*_eng_fn) (void);
|
|
|
|
typedef _eng_fn (*glsym_func_eng_fn) ();
|
|
#endif
|
|
|
|
static int dbgflushnum = -1;
|
|
|
|
static void
|
|
sym_missing(void)
|
|
{
|
|
ERR("GL symbols missing!");
|
|
}
|
|
|
|
/* This check is based heavily on the check from libepoxy.
|
|
* Previously we used strstr(), however there are some extensions
|
|
* whose names are subsets of others.
|
|
*/
|
|
EMODAPI Eina_Bool
|
|
evas_gl_extension_string_check(const char *exts, const char *ext)
|
|
{
|
|
const char *ptr;
|
|
int len;
|
|
|
|
if (!exts || !ext) return EINA_FALSE;
|
|
ptr = exts;
|
|
|
|
if (*ptr == '\0')
|
|
return EINA_FALSE;
|
|
|
|
len = strlen(ext);
|
|
|
|
while (1)
|
|
{
|
|
ptr = strstr(ptr, ext);
|
|
if (!ptr)
|
|
return EINA_FALSE;
|
|
|
|
if (ptr[len] == ' ' || ptr[len] == '\0')
|
|
return EINA_TRUE;
|
|
|
|
ptr += len;
|
|
}
|
|
}
|
|
|
|
/* Totally gross, but I didn't want to reindent all the
|
|
* strstr() callers :(
|
|
*/
|
|
static Evas_Gl_Extension_String_Check _ckext = evas_gl_extension_string_check;
|
|
|
|
static int
|
|
_has_ext(const char *ext, const char **pexts, int *pnum)
|
|
{
|
|
if (!ext) return EINA_FALSE;
|
|
|
|
if (glsym_glGetStringi)
|
|
{
|
|
GLint num = *pnum, k;
|
|
if (!num)
|
|
{
|
|
glGetIntegerv(GL_NUM_EXTENSIONS, &num);
|
|
*pnum = num;
|
|
}
|
|
for (k = 0; k < num; k++)
|
|
{
|
|
const char *support = glsym_glGetStringi(GL_EXTENSIONS, k);
|
|
if (support && !strcmp(support, ext))
|
|
return EINA_TRUE;
|
|
}
|
|
return EINA_FALSE;
|
|
}
|
|
else
|
|
{
|
|
const char *exts = *pexts;
|
|
if (!exts)
|
|
{
|
|
exts = (const char *) glGetString(GL_EXTENSIONS);
|
|
if (!exts) return EINA_FALSE;
|
|
*pexts = exts;
|
|
}
|
|
return _ckext(exts, ext);
|
|
}
|
|
}
|
|
|
|
#ifdef GL_GLES
|
|
|
|
EMODAPI void *
|
|
evas_gl_common_eglCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list)
|
|
{
|
|
if (eglsym_eglCreateImageKHR)
|
|
{
|
|
int count, i;
|
|
EGLint *ints = NULL;
|
|
|
|
if (attrib_list)
|
|
{
|
|
for (count = 0; attrib_list[count] != EGL_NONE; count += 2);
|
|
count++;
|
|
ints = alloca(count * sizeof(EGLint));
|
|
for (i = 0; i < count; i++)
|
|
ints[i] = attrib_list[i];
|
|
}
|
|
return eglsym_eglCreateImageKHR(dpy, ctx, target, buffer, ints);
|
|
}
|
|
if (eglsym_eglCreateImage)
|
|
return eglsym_eglCreateImage(dpy, ctx, target, buffer, attrib_list);
|
|
return NULL;
|
|
}
|
|
|
|
EMODAPI int
|
|
evas_gl_common_eglDestroyImage(EGLDisplay dpy, void *im)
|
|
{
|
|
if (eglsym_eglDestroyImage)
|
|
return eglsym_eglDestroyImage(dpy, im);
|
|
return EGL_FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
/* FIXME: return error if a required symbol was not found */
|
|
EMODAPI void
|
|
evas_gl_symbols(void *(*GetProcAddress)(const char *name), const char *extsn)
|
|
{
|
|
int failed = 0, num = 0;
|
|
const char *exts = NULL;
|
|
|
|
static int done = 0;
|
|
if (done) return;
|
|
|
|
if (!extsn) ERR("GL extension string was empty");
|
|
|
|
/* For all extension functions, we need to match with the extension itself
|
|
* since GetProcAddress() can return a non-NULL value even when the function
|
|
* does not exist. Drivers can do a runtime mapping depending on the
|
|
* context. So, we only trust the return value of GetProcAddress() when
|
|
* we know for sure that the extension exists.
|
|
*
|
|
* Thus, if a symbol exists we will always prefer it rather than relying
|
|
* on GetProcAddress().
|
|
*
|
|
* -- jpeg, 2016/08/04
|
|
*/
|
|
|
|
glsym_glGetStringi = dlsym(RTLD_DEFAULT, "glGetStringi");
|
|
|
|
#define FINDSYM(dst, sym, ext, typ) do { \
|
|
if (!dst) { \
|
|
if (_has_ext(ext, &exts, &num) && GetProcAddress) \
|
|
dst = (typ) GetProcAddress(sym); \
|
|
if (!dst) \
|
|
dst = (typ) dlsym(RTLD_DEFAULT, sym); \
|
|
}} while (0)
|
|
#define FALLBAK(dst, typ) do { \
|
|
if (!dst) { \
|
|
ERR("Symbol '%s' could not be found!", (#dst) + 6); \
|
|
dst = (typ) sym_missing; \
|
|
failed = EINA_TRUE; \
|
|
}} while (0)
|
|
|
|
#ifdef GL_GLES
|
|
|
|
FINDSYM(glsym_glGenFramebuffers, "glGenFramebuffers", NULL, glsym_func_void);
|
|
FALLBAK(glsym_glGenFramebuffers, glsym_func_void);
|
|
|
|
FINDSYM(glsym_glBindFramebuffer, "glBindFramebuffer", NULL, glsym_func_void);
|
|
FALLBAK(glsym_glBindFramebuffer, glsym_func_void);
|
|
|
|
#else
|
|
|
|
/*
|
|
Note about FBO APIs (from ARB_framebuffer_object):
|
|
|
|
Framebuffer objects created with the commands defined by the
|
|
GL_EXT_framebuffer_object extension are defined to be shared, while
|
|
FBOs created with commands defined by the OpenGL core or
|
|
GL_ARB_framebuffer_object extension are defined *not* to be shared.
|
|
|
|
[...]
|
|
|
|
Since the above pairs are aliases, the functions of a pair are
|
|
equivalent. Note that the functions BindFramebuffer and
|
|
BindFramebufferEXT are not aliases and neither are the functions
|
|
BindRenderbuffer and BindRenderbufferEXT. Because object creation
|
|
occurs when the framebuffer object is bound for the first time, a
|
|
framebuffer object can be shared across contexts only if it was first
|
|
bound with BindFramebufferEXT. Framebuffers first bound with
|
|
BindFramebuffer may not be shared across contexts. Framebuffer
|
|
objects created with BindFramebufferEXT may subsequently be bound
|
|
using BindFramebuffer. Framebuffer objects created with
|
|
BindFramebuffer may be bound with BindFramebufferEXT provided they are
|
|
bound to the same context they were created on.
|
|
|
|
Undefined behavior results when using FBOs created by EXT commands
|
|
through non-EXT interfaces, or vice-versa.
|
|
|
|
Thus, I believe core should come first, then ARB and use EXT as fallback.
|
|
-- jpeg, 2016/08/04
|
|
|
|
Old note:
|
|
nvidia tegra3 drivers seem to not expose via getprocaddress, but dlsym finds it:
|
|
glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D, glDeleteFramebuffers
|
|
*/
|
|
|
|
FINDSYM(glsym_glGenFramebuffers, "glGenFramebuffers", NULL, glsym_func_void);
|
|
FINDSYM(glsym_glGenFramebuffers, "glGenFramebuffersARB", "GL_ARB_framebuffer_object", glsym_func_void);
|
|
FINDSYM(glsym_glGenFramebuffers, "glGenFramebuffersEXT", "GL_EXT_framebuffer_object", glsym_func_void);
|
|
FALLBAK(glsym_glGenFramebuffers, glsym_func_void);
|
|
|
|
FINDSYM(glsym_glBindFramebuffer, "glBindFramebuffer", NULL, glsym_func_void);
|
|
FINDSYM(glsym_glBindFramebuffer, "glBindFramebufferARB", "GL_ARB_framebuffer_object", glsym_func_void);
|
|
FINDSYM(glsym_glBindFramebuffer, "glBindFramebufferEXT", "GL_EXT_framebuffer_object", glsym_func_void);
|
|
FALLBAK(glsym_glBindFramebuffer, glsym_func_void);
|
|
|
|
#endif
|
|
|
|
FINDSYM(glsym_glFramebufferTexture2D, "glFramebufferTexture2D", NULL, glsym_func_void);
|
|
FINDSYM(glsym_glFramebufferTexture2D, "glFramebufferTexture2DARB", "GL_ARB_framebuffer_object", glsym_func_void);
|
|
FINDSYM(glsym_glFramebufferTexture2D, "glFramebufferTexture2DEXT", "GL_EXT_framebuffer_object", glsym_func_void);
|
|
FALLBAK(glsym_glFramebufferTexture2D, glsym_func_void);
|
|
|
|
FINDSYM(glsym_glDeleteFramebuffers, "glDeleteFramebuffers", NULL, glsym_func_void);
|
|
FINDSYM(glsym_glDeleteFramebuffers, "glDeleteFramebuffersARB", "GL_ARB_framebuffer_object", glsym_func_void);
|
|
FINDSYM(glsym_glDeleteFramebuffers, "glDeleteFramebuffersEXT", "GL_EXT_framebuffer_object", glsym_func_void);
|
|
FALLBAK(glsym_glDeleteFramebuffers, glsym_func_void);
|
|
|
|
// Not sure there's an EXT variant
|
|
FINDSYM(glsym_glGetProgramBinary, "glGetProgramBinary", NULL, glsym_func_void);
|
|
FINDSYM(glsym_glGetProgramBinary, "glGetProgramBinaryOES", "GL_OES_get_program_binary", glsym_func_void);
|
|
FINDSYM(glsym_glGetProgramBinary, "glGetProgramBinaryEXT", "GL_EXT_get_program_binary", glsym_func_void);
|
|
|
|
// Not sure there's an EXT variant
|
|
FINDSYM(glsym_glProgramBinary, "glProgramBinary", NULL, glsym_func_void);
|
|
FINDSYM(glsym_glProgramBinary, "glProgramBinaryOES", "GL_OES_get_program_binary", glsym_func_void);
|
|
FINDSYM(glsym_glProgramBinary, "glProgramBinaryEXT", "GL_EXT_get_program_binary", glsym_func_void);
|
|
|
|
FINDSYM(glsym_glProgramParameteri, "glProgramParameteri", NULL, glsym_func_void);
|
|
FINDSYM(glsym_glProgramParameteri, "glProgramParameteriEXT", "GL_EXT_separate_shader_objects", glsym_func_void);
|
|
FINDSYM(glsym_glProgramParameteri, "glProgramParameteriARB", "GL_ARB_geometry_shader4", glsym_func_void);
|
|
|
|
FINDSYM(glsym_glReleaseShaderCompiler, "glReleaseShaderCompiler", NULL, glsym_func_void);
|
|
#ifndef GL_GLES
|
|
FINDSYM(glsym_glReleaseShaderCompiler, "glReleaseShaderCompiler", "GL_ARB_ES2_compatibility", glsym_func_void);
|
|
#endif
|
|
|
|
// Not sure there's a core variant, glActivateTileQCOM is strange as well
|
|
FINDSYM(glsym_glStartTiling, "glStartTilingQCOM", "GL_QCOM_tiled_rendering", glsym_func_void);
|
|
FINDSYM(glsym_glStartTiling, "glStartTiling", NULL, glsym_func_void);
|
|
FINDSYM(glsym_glStartTiling, "glActivateTileQCOM", NULL, glsym_func_void);
|
|
FINDSYM(glsym_glEndTiling, "glEndTilingQCOM", "GL_QCOM_tiled_rendering", glsym_func_void);
|
|
FINDSYM(glsym_glEndTiling, "glEndTiling", NULL, glsym_func_void);
|
|
|
|
if (!getenv("EVAS_GL_MAPBUFFER_DISABLE"))
|
|
{
|
|
// Not sure there's an EXT variant. (probably no KHR variant)
|
|
FINDSYM(glsym_glMapBuffer, "glMapBuffer", NULL, glsym_func_void_ptr);
|
|
FINDSYM(glsym_glMapBuffer, "glMapBufferOES", "GL_OES_mapbuffer", glsym_func_void_ptr);
|
|
FINDSYM(glsym_glMapBuffer, "glMapBufferARB", "GL_ARB_vertex_buffer_object", glsym_func_void_ptr);
|
|
FINDSYM(glsym_glMapBuffer, "glMapBufferARB", "GLX_ARB_vertex_buffer_object", glsym_func_void_ptr);
|
|
FINDSYM(glsym_glMapBuffer, "glMapBufferEXT", NULL, glsym_func_void_ptr);
|
|
|
|
FINDSYM(glsym_glUnmapBuffer, "glUnmapBuffer", NULL, glsym_func_boolean);
|
|
FINDSYM(glsym_glUnmapBuffer, "glUnmapBufferOES", "GL_OES_mapbuffer", glsym_func_boolean);
|
|
FINDSYM(glsym_glUnmapBuffer, "glUnmapBufferARB", "GL_ARB_vertex_buffer_object", glsym_func_boolean);
|
|
FINDSYM(glsym_glUnmapBuffer, "glUnmapBufferARB", "GLX_ARB_vertex_buffer_object", glsym_func_boolean);
|
|
FINDSYM(glsym_glUnmapBuffer, "glUnmapBufferEXT", NULL, glsym_func_boolean);
|
|
}
|
|
|
|
FINDSYM(glsym_glRenderbufferStorageMultisample, "glRenderbufferStorageMultisample", NULL, glsym_func_void);
|
|
|
|
#ifdef GL_GLES
|
|
#define FINDSYMN(dst, sym, ext, typ) do { \
|
|
if (!dst) { \
|
|
if (_ckext(extsn, ext) && GetProcAddress) \
|
|
dst = (typ) GetProcAddress(sym); \
|
|
if (!dst) \
|
|
dst = (typ) dlsym(RTLD_DEFAULT, sym); \
|
|
}} while (0)
|
|
|
|
// yes - gl core looking for egl stuff. i know it's odd. a reverse-layer thing
|
|
// but it will work as the egl/glx layer calls gl core common stuff and thus
|
|
// these symbols will work. making the glx/egl + x11 layer do this kind-of is
|
|
// wrong as this is not x11 (output) layer specific like the native surface
|
|
// stuff. this is generic zero-copy textures for gl
|
|
|
|
{
|
|
const char *egl_version = eglQueryString(eglGetCurrentDisplay(), EGL_VERSION);
|
|
int vmin = 1, vmaj = 0;
|
|
|
|
if (!egl_version || (sscanf(egl_version, "%d.%d", &vmaj, &vmin) != 2))
|
|
vmaj = 0;
|
|
|
|
// Verify that EGL is >= 1.5 before looking up core function
|
|
if ((vmaj > 1) || (vmaj == 1 && vmin >= 5))
|
|
{
|
|
eglsym_eglCreateImage = dlsym(RTLD_DEFAULT, "eglCreateImage");
|
|
eglsym_eglDestroyImage = dlsym(RTLD_DEFAULT, "eglDestroyImage");
|
|
}
|
|
|
|
// For EGL <= 1.4 only the KHR extension exists: "EGL_KHR_image_base"
|
|
if (!eglsym_eglCreateImage || !eglsym_eglDestroyImage)
|
|
{
|
|
eglsym_eglCreateImage = NULL;
|
|
eglsym_eglDestroyImage = NULL;
|
|
FINDSYMN(eglsym_eglCreateImageKHR, "eglCreateImageKHR", "EGL_KHR_image_base", secsym_func_void_ptr);
|
|
FINDSYMN(eglsym_eglDestroyImage, "eglDestroyImageKHR", "EGL_KHR_image_base", secsym_func_uint);
|
|
}
|
|
}
|
|
|
|
FINDSYM(glsym_glProgramParameteri, "glProgramParameteri", NULL, glsym_func_void);
|
|
FINDSYM(glsym_glProgramParameteri, "glProgramParameteriEXT", "GL_EXT_geometry_shader4", glsym_func_void);
|
|
FINDSYM(glsym_glProgramParameteri, "glProgramParameteriARB", "GL_ARB_geometry_shader4", glsym_func_void);
|
|
|
|
FINDSYM(secsym_glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES", "GL_OES_EGL_image_external", glsym_func_void);
|
|
FINDSYM(secsym_glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES", "GL_OES_EGL_image", glsym_func_void);
|
|
|
|
// Old SEC extensions
|
|
FINDSYMN(secsym_eglMapImageSEC, "eglMapImageSEC", NULL, secsym_func_void_ptr);
|
|
FINDSYMN(secsym_eglUnmapImageSEC, "eglUnmapImageSEC", NULL, secsym_func_uint);
|
|
FINDSYMN(secsym_eglGetImageAttribSEC, "eglGetImageAttribSEC", NULL, secsym_func_uint);
|
|
|
|
#undef FINDSYMN
|
|
|
|
#endif
|
|
|
|
#undef FINDSYM
|
|
#undef FALLBAK
|
|
|
|
if (failed)
|
|
{
|
|
ERR("Some core GL symbols could not be found, the GL engine will not "
|
|
"work properly.");
|
|
}
|
|
|
|
done = 1;
|
|
}
|
|
|
|
static void
|
|
tbm_symbols(void)
|
|
{
|
|
if (tbm_sym_done) return;
|
|
tbm_sym_done = 1;
|
|
|
|
#ifdef GL_GLES
|
|
tbm_lib_handle = dlopen("libtbm.so.1", RTLD_NOW);
|
|
if (!tbm_lib_handle)
|
|
{
|
|
DBG("Unable to open libtbm: %s", dlerror());
|
|
return;
|
|
}
|
|
|
|
#define FINDSYM(dst, sym, typ) \
|
|
if (!dst) dst = (typ)dlsym(tbm_lib_handle, sym); \
|
|
if (!dst) \
|
|
{ \
|
|
ERR("Symbol not found %s\n", sym); \
|
|
return; \
|
|
}
|
|
|
|
FINDSYM(secsym_tbm_surface_create, "tbm_surface_create", secsym_func_void_ptr);
|
|
FINDSYM(secsym_tbm_surface_destroy, "tbm_surface_destroy", secsym_func_int);
|
|
FINDSYM(secsym_tbm_surface_map, "tbm_surface_map", secsym_func_int);
|
|
FINDSYM(secsym_tbm_surface_unmap, "tbm_surface_unmap", secsym_func_int);
|
|
FINDSYM(secsym_tbm_surface_get_info, "tbm_surface_get_info", secsym_func_int);
|
|
|
|
#undef FINDSYM
|
|
#endif
|
|
}
|
|
|
|
static void shader_array_flush(Evas_Engine_GL_Context *gc);
|
|
|
|
static Evas_Engine_GL_Context *_evas_gl_common_context = NULL;
|
|
static Evas_GL_Shared *shared = NULL;
|
|
|
|
EMODAPI void
|
|
__evas_gl_err(int err, const char *file, const char *func, int line, const char *op)
|
|
{
|
|
const char *errmsg;
|
|
char buf[32];
|
|
|
|
switch (err)
|
|
{
|
|
case GL_INVALID_ENUM:
|
|
errmsg = "GL_INVALID_ENUM";
|
|
break;
|
|
case GL_INVALID_VALUE:
|
|
errmsg = "GL_INVALID_VALUE";
|
|
break;
|
|
case GL_INVALID_OPERATION:
|
|
errmsg = "GL_INVALID_OPERATION";
|
|
break;
|
|
case GL_OUT_OF_MEMORY:
|
|
errmsg = "GL_OUT_OF_MEMORY";
|
|
break;
|
|
#ifdef GL_INVALID_FRAMEBUFFER_OPERATION
|
|
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
|
{
|
|
GLenum e = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
switch (e)
|
|
{
|
|
#ifdef GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
|
|
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
|
errmsg = "GL_INVALID_FRAMEBUFFER_OPERATION: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
|
|
break;
|
|
#endif
|
|
#ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
|
|
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
|
|
errmsg = "GL_INVALID_FRAMEBUFFER_OPERATION: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
|
|
break;
|
|
#endif
|
|
#ifdef GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
|
|
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
|
errmsg = "GL_INVALID_FRAMEBUFFER_OPERATION: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
|
|
break;
|
|
#endif
|
|
#ifdef GL_FRAMEBUFFER_UNSUPPORTED
|
|
case GL_FRAMEBUFFER_UNSUPPORTED:
|
|
errmsg = "GL_INVALID_FRAMEBUFFER_OPERATION: GL_FRAMEBUFFER_UNSUPPORTED";
|
|
break;
|
|
#endif
|
|
default:
|
|
errmsg = "GL_INVALID_FRAMEBUFFER_OPERATION";
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
default:
|
|
snprintf(buf, sizeof(buf), "%#x", err);
|
|
errmsg = buf;
|
|
}
|
|
|
|
eina_log_print(_evas_engine_GL_common_log_dom, EINA_LOG_LEVEL_ERR,
|
|
file, func, line, "%s: %s", op, errmsg);
|
|
}
|
|
|
|
static void
|
|
matrix_ortho(GLfloat *m,
|
|
GLfloat l, GLfloat r,
|
|
GLfloat t, GLfloat b,
|
|
GLfloat near_, GLfloat far_,
|
|
int rot, int vw, int vh,
|
|
int foc, GLfloat orth)
|
|
{
|
|
GLfloat rotf;
|
|
GLfloat cosv, sinv;
|
|
GLfloat tx, ty;
|
|
|
|
rotf = (((rot / 90) & 0x3) * M_PI) / 2.0;
|
|
|
|
tx = -0.5 * (1.0 - orth);
|
|
ty = -0.5 * (1.0 - orth);
|
|
|
|
if (rot == 90)
|
|
{
|
|
tx += -(vw * 1.0);
|
|
ty += -(vh * 0.0);
|
|
}
|
|
if (rot == 180)
|
|
{
|
|
tx += -(vw * 1.0);
|
|
ty += -(vh * 1.0);
|
|
}
|
|
if (rot == 270)
|
|
{
|
|
tx += -(vw * 0.0);
|
|
ty += -(vh * 1.0);
|
|
}
|
|
|
|
cosv = cos(rotf);
|
|
sinv = sin(rotf);
|
|
|
|
m[0] = (2.0 / (r - l)) * ( cosv);
|
|
m[1] = (2.0 / (r - l)) * ( sinv);
|
|
m[2] = 0.0;
|
|
m[3] = 0.0;
|
|
|
|
m[4] = (2.0 / (t - b)) * (-sinv);
|
|
m[5] = (2.0 / (t - b)) * ( cosv);
|
|
m[6] = 0.0;
|
|
m[7] = 0.0;
|
|
|
|
m[8] = 0.0;
|
|
m[9] = 0.0;
|
|
m[10] = -(2.0 / (far_ - near_));
|
|
m[11] = 1.0 / (GLfloat)foc;
|
|
|
|
m[12] = (m[0] * tx) + (m[4] * ty) - ((r + l) / (r - l));
|
|
m[13] = (m[1] * tx) + (m[5] * ty) - ((t + b) / (t - b));
|
|
m[14] = (m[2] * tx) + (m[6] * ty) - ((near_ + far_) / (far_ - near_));
|
|
m[15] = (m[3] * tx) + (m[7] * ty) + orth;
|
|
}
|
|
|
|
int
|
|
evas_gl_common_version_check(int *minor_version)
|
|
{
|
|
char *version;
|
|
char *tmp;
|
|
char *tmp2;
|
|
int major = 0;
|
|
int minor = 0;
|
|
|
|
/*
|
|
* glGetString returns a string describing the current GL connection.
|
|
* GL_VERSION is used to get the version of the connection
|
|
*/
|
|
|
|
if (minor_version) *minor_version = 0;
|
|
|
|
version = (char *)glGetString(GL_VERSION);
|
|
if (!version)
|
|
{
|
|
/* Something is wrong! */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* OpengL ES
|
|
*
|
|
* 1.* : The form is:
|
|
*
|
|
* OpenGL ES-<profile> <major>.<minor>
|
|
*
|
|
* where <profile> is either "CM" or "CL". The minor can be followed by the vendor
|
|
* specific information
|
|
*
|
|
* 2.0 : The form is:
|
|
*
|
|
* OpenGL<space>ES<space><version number><space><vendor-specific information>
|
|
*/
|
|
|
|
/* OpenGL ES 1.* ? */
|
|
|
|
if (strstr(version, "OpenGL ES-CM ") || strstr(version, "OpenGL ES-CL "))
|
|
{
|
|
/* Not supported */
|
|
return 0;
|
|
}
|
|
|
|
/* OpenGL ES 3.* */
|
|
|
|
if (strstr(version, "OpenGL ES 3"))
|
|
{
|
|
/* Supported */
|
|
if (minor_version)
|
|
{
|
|
if ((version[11] == '.') && isdigit(version[12]))
|
|
*minor_version = atoi(&version[12]);
|
|
else *minor_version = 0;
|
|
}
|
|
return 3;
|
|
}
|
|
|
|
/* OpenGL ES 2.* ? */
|
|
|
|
if (strstr(version, "OpenGL ES "))
|
|
{
|
|
/* Supported */
|
|
if (minor_version)
|
|
{
|
|
if ((version[10] == '2') &&
|
|
(version[11] == '.') && isdigit(version[12]))
|
|
*minor_version = atoi(&version[12]);
|
|
else *minor_version = 0;
|
|
}
|
|
return 2;
|
|
}
|
|
|
|
/*
|
|
* OpenGL
|
|
*
|
|
* The GL_VERSION and GL_SHADING_LANGUAGE_VERSION strings begin with a
|
|
* version number. The version number uses one of these forms:
|
|
*
|
|
* major_number.minor_number
|
|
* major_number.minor_number.release_number
|
|
*
|
|
* Vendor-specific information may follow the version number. Its format
|
|
* depends on the implementation, but a space always separates the
|
|
* version number and the vendor-specific information.
|
|
*/
|
|
|
|
/* glGetString() returns a static string, and we are going to */
|
|
/* modify it, so we get a copy first */
|
|
version = strdup(version);
|
|
if (!version)
|
|
return 0;
|
|
|
|
tmp = strchr(version, '.');
|
|
if (!tmp) goto fail;
|
|
/* the first '.' always exists */
|
|
*tmp = '\0';
|
|
major = atoi(version);
|
|
/* FIXME: maybe we can assume that minor in only a cipher */
|
|
tmp2 = ++tmp;
|
|
while ((*tmp != '.') && (*tmp != ' ') && (*tmp != '\0'))
|
|
tmp++;
|
|
/* *tmp is '\0' : version is major_number.minor_number */
|
|
/* *tmp is '.' : version is major_number.minor_number.release_number */
|
|
/* *tmp is ' ' : version is major_number.minor_number followed by vendor */
|
|
*tmp = '\0';
|
|
minor = atoi(tmp2);
|
|
|
|
fail:
|
|
free(version);
|
|
|
|
// OpenGL 4.5 is supposed to be a superset of GLES 3.1
|
|
if ((major == 4) && (minor >= 5))
|
|
{
|
|
if (minor_version) *minor_version = 1;
|
|
return 3;
|
|
}
|
|
|
|
// OpenGL 4.3 is supposed to be a superset of GLES 3.0
|
|
if ((major == 4) && (minor >= 3))
|
|
return 3;
|
|
|
|
// Extension GL_ARB_ES3_compatibility means OpenGL is a superset of GLES 3.0
|
|
if ((major > 3) || ((major == 3) && (minor >= 3)))
|
|
{
|
|
const char *exts = NULL;
|
|
int num = 0;
|
|
|
|
if (_has_ext("GL_ARB_ES3_compatibility", &exts, &num))
|
|
return 3;
|
|
}
|
|
|
|
// OpenGL >= 1.4 is a superset of the features of GLES 2 (albeit not an
|
|
// exact function match)
|
|
if (((major == 1) && (minor >= 4)) || (major >= 2))
|
|
return 2; /* emulated support */
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
_evas_gl_common_viewport_set(Evas_Engine_GL_Context *gc)
|
|
{
|
|
int w = 1, h = 1, m = 1, rot = 1, foc = 0;
|
|
int offx = 0, offy = 0;
|
|
Evas_GL_Program *prog;
|
|
Eina_Iterator *it;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(gc);
|
|
foc = gc->foc;
|
|
// surface in pipe 0 will be the same as all pipes
|
|
if ((gc->pipe[0].shader.surface == gc->def_surface) ||
|
|
(!gc->pipe[0].shader.surface))
|
|
{
|
|
w = gc->w;
|
|
h = gc->h;
|
|
rot = gc->rot;
|
|
}
|
|
else
|
|
{
|
|
w = gc->pipe[0].shader.surface->w;
|
|
h = gc->pipe[0].shader.surface->h;
|
|
rot = 0;
|
|
m = -1;
|
|
offx = gc->pipe[0].shader.surface->tex->x;
|
|
offy = gc->pipe[0].shader.surface->tex->y;
|
|
}
|
|
|
|
#ifdef GL_GLES
|
|
if (gc->shared->eglctxt == gc->eglctxt)
|
|
#endif
|
|
{
|
|
if (((offx == gc->shared->offx) && (offy == gc->shared->offy)) &&
|
|
((!gc->change.size) ||
|
|
(
|
|
(gc->shared->w == w) && (gc->shared->h == h) &&
|
|
(gc->shared->rot == rot) && (gc->shared->foc == gc->foc) &&
|
|
(gc->shared->mflip == m)
|
|
)
|
|
)
|
|
)
|
|
return;
|
|
}
|
|
#ifdef GL_GLES
|
|
gc->shared->eglctxt = gc->eglctxt;
|
|
#endif
|
|
|
|
gc->shared->w = w;
|
|
gc->shared->h = h;
|
|
gc->shared->rot = rot;
|
|
gc->shared->mflip = m;
|
|
gc->shared->foc = foc;
|
|
gc->shared->z0 = gc->z0;
|
|
gc->shared->px = gc->px;
|
|
gc->shared->py = gc->py;
|
|
gc->change.size = 0;
|
|
gc->shared->offx = offx;
|
|
gc->shared->offy = offy;
|
|
|
|
if (foc == 0)
|
|
{
|
|
if ((rot == 0) || (rot == 180))
|
|
glViewport(offx, offy, w, h);
|
|
else
|
|
glViewport(offx, offy, h, w);
|
|
// std matrix
|
|
if (m == 1)
|
|
matrix_ortho(gc->shared->proj,
|
|
0, w, 0, h,
|
|
-1000000.0, 1000000.0,
|
|
rot, w, h,
|
|
1, 1.0);
|
|
// v flipped matrix for render-to-texture
|
|
else
|
|
matrix_ortho(gc->shared->proj,
|
|
0, w, h, 0,
|
|
-1000000.0, 1000000.0,
|
|
rot, w, h,
|
|
1, 1.0);
|
|
}
|
|
else
|
|
{
|
|
int px, py, vx, vy, vw = 0, vh = 0, ax = 0, ay = 0, ppx = 0, ppy = 0;
|
|
|
|
px = gc->shared->px;
|
|
py = gc->shared->py;
|
|
|
|
if ((rot == 0 ) || (rot == 90 )) ppx = px;
|
|
else if ((rot == 180) || (rot == 270)) ppx = w - px;
|
|
if ((rot == 0 ) || (rot == 270)) ppy = py;
|
|
else if ((rot == 90 ) || (rot == 180)) ppy = h - py;
|
|
|
|
vx = ((w / 2) - ppx);
|
|
if (vx >= 0)
|
|
{
|
|
vw = w + (2 * vx);
|
|
if ((rot == 0 ) || (rot == 90 )) ax = 2 * vx;
|
|
else if ((rot == 180) || (rot == 270)) ax = 0;
|
|
}
|
|
else
|
|
{
|
|
vw = w - (2 * vx);
|
|
if ((rot == 0 ) || (rot == 90 )) ax = 0;
|
|
else if ((rot == 180) || (rot == 270)) ax = ppx - px;
|
|
vx = 0;
|
|
}
|
|
|
|
vy = ((h / 2) - ppy);
|
|
if (vy < 0)
|
|
{
|
|
vh = h - (2 * vy);
|
|
if (rot == 0) ay = 0;
|
|
else if ((rot == 90 ) || (rot == 180) || (rot == 270)) ay = ppy - py;
|
|
vy = -vy;
|
|
}
|
|
else
|
|
{
|
|
vh = h + (2 * vy);
|
|
if ((rot == 0 ) || (rot == 270)) ay = 2 * vy;
|
|
else if ((rot == 90 ) || (rot == 180)) ay = 0;
|
|
vy = 0;
|
|
}
|
|
|
|
if (m == -1) ay = vy * 2;
|
|
|
|
if ((rot == 0) || (rot == 180))
|
|
glViewport(offx + (-2 * vx), offy + (-2 * vy), vw, vh);
|
|
else
|
|
glViewport(offx + (-2 * vy), offy + (-2 * vx), vh, vw);
|
|
if (m == 1)
|
|
matrix_ortho(gc->shared->proj,
|
|
0, vw, 0, vh,
|
|
-1000000.0, 1000000.0,
|
|
rot, vw, vh,
|
|
foc, 0.0);
|
|
else
|
|
matrix_ortho(gc->shared->proj,
|
|
0, vw, vh, 0,
|
|
-1000000.0, 1000000.0,
|
|
rot, vw, vh,
|
|
foc, 0.0);
|
|
gc->shared->ax = ax;
|
|
gc->shared->ay = ay;
|
|
}
|
|
|
|
// FIXME: Is this heavy work?
|
|
it = eina_hash_iterator_data_new(gc->shared->shaders_hash);
|
|
EINA_ITERATOR_FOREACH(it, prog)
|
|
prog->reset = EINA_TRUE;
|
|
eina_iterator_free(it);
|
|
|
|
if (gc->state.current.prog != PRG_INVALID)
|
|
{
|
|
prog = gc->state.current.prog;
|
|
glUseProgram(prog->prog);
|
|
glUniform1i(prog->uniform.rotation_id, gc->rot / 90);
|
|
glUniformMatrix4fv(prog->uniform.mvp, 1, GL_FALSE, gc->shared->proj);
|
|
}
|
|
}
|
|
|
|
EMODAPI Evas_Engine_GL_Context *
|
|
evas_gl_common_context_new(void)
|
|
{
|
|
Evas_Engine_GL_Context *gc;
|
|
const char *s;
|
|
int i, gles_version;
|
|
|
|
#if 1
|
|
if (_evas_gl_common_context)
|
|
{
|
|
_evas_gl_common_context->references++;
|
|
return _evas_gl_common_context;
|
|
}
|
|
#endif
|
|
|
|
if (!glsym_glGetStringi)
|
|
glsym_glGetStringi = dlsym(RTLD_DEFAULT, "glGetStringi");
|
|
|
|
gles_version = evas_gl_common_version_check(NULL);
|
|
if (!gles_version) return NULL;
|
|
|
|
gc = calloc(1, sizeof(Evas_Engine_GL_Context));
|
|
if (!gc) return NULL;
|
|
|
|
tbm_symbols();
|
|
gc->gles_version = gles_version;
|
|
|
|
gc->references = 1;
|
|
|
|
_evas_gl_common_context = gc;
|
|
|
|
for (i = 0; i < MAX_PIPES; i++)
|
|
{
|
|
gc->pipe[i].shader.render_op = EVAS_RENDER_BLEND;
|
|
if (glsym_glMapBuffer && glsym_glUnmapBuffer)
|
|
{
|
|
glGenBuffers(1, &gc->pipe[i].array.buffer);
|
|
gc->pipe[i].array.buffer_alloc = 0;
|
|
gc->pipe[i].array.buffer_use = 0;
|
|
}
|
|
}
|
|
|
|
gc->state.current.tex_target = GL_TEXTURE_2D;
|
|
|
|
if (!shared)
|
|
{
|
|
const char *ext;
|
|
|
|
shared = calloc(1, sizeof(Evas_GL_Shared));
|
|
ext = (const char *) glGetString(GL_EXTENSIONS);
|
|
if (ext)
|
|
{
|
|
if (getenv("EVAS_GL_INFO"))
|
|
fprintf(stderr, "EXT:\n%s\n", ext);
|
|
if ((_ckext(ext, "GL_ARB_texture_non_power_of_two")) ||
|
|
(_ckext(ext, "OES_texture_npot")) ||
|
|
(_ckext(ext, "GL_IMG_texture_npot")))
|
|
shared->info.tex_npo2 = 1;
|
|
if ((_ckext(ext, "GL_NV_texture_rectangle")) ||
|
|
(_ckext(ext, "GL_EXT_texture_rectangle")) ||
|
|
(_ckext(ext, "GL_ARB_texture_rectangle")))
|
|
shared->info.tex_rect = 1;
|
|
if ((_ckext(ext, "GL_ARB_get_program_binary")) ||
|
|
(_ckext(ext, "GL_OES_get_program_binary")))
|
|
shared->info.bin_program = 1;
|
|
else
|
|
glsym_glGetProgramBinary = NULL;
|
|
#ifdef GL_UNPACK_ROW_LENGTH
|
|
shared->info.unpack_row_length = 1;
|
|
# ifdef GL_GLES
|
|
if (!_ckext(ext, "_unpack_subimage"))
|
|
shared->info.unpack_row_length = 0;
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
|
|
if ((_ckext(ext, "GL_EXT_texture_filter_anisotropic")))
|
|
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,
|
|
&(shared->info.anisotropic));
|
|
#endif
|
|
#ifdef GL_BGRA
|
|
if ((_ckext(ext, "GL_EXT_bgra")) ||
|
|
(_ckext(ext, "GL_EXT_texture_format_BGRA8888")))
|
|
shared->info.bgra = 1;
|
|
#endif
|
|
if (_ckext(ext, "OES_compressed_ETC1_RGB8_texture"))
|
|
shared->info.etc1 = 1;
|
|
if (_ckext(ext, "GL_EXT_texture_compression_s3tc") ||
|
|
_ckext(ext, "GL_S3_s3tc"))
|
|
shared->info.s3tc = 1;
|
|
#ifdef GL_GLES
|
|
// FIXME: there should be an extension name/string to check for
|
|
// not just symbols in the lib
|
|
i = 0;
|
|
s = getenv("EVAS_GL_NO_MAP_IMAGE_SEC");
|
|
if (s) i = atoi(s);
|
|
if (!i)
|
|
{
|
|
// test for all needed symbols - be "conservative" and
|
|
// need all of it
|
|
if ((eglsym_eglDestroyImage) &&
|
|
(secsym_glEGLImageTargetTexture2DOES) &&
|
|
(secsym_eglMapImageSEC) &&
|
|
(secsym_eglUnmapImageSEC) &&
|
|
(secsym_eglGetImageAttribSEC))
|
|
shared->info.sec_image_map = 1;
|
|
}
|
|
i = 0;
|
|
|
|
if ((secsym_tbm_surface_create) &&
|
|
(secsym_tbm_surface_destroy) &&
|
|
(secsym_tbm_surface_map) &&
|
|
(secsym_tbm_surface_unmap) &&
|
|
(secsym_tbm_surface_get_info))
|
|
shared->info.sec_tbm_surface = 1;
|
|
#endif
|
|
if (!_ckext(ext, "GL_QCOM_tiled_rendering"))
|
|
{
|
|
glsym_glStartTiling = NULL;
|
|
glsym_glEndTiling = NULL;
|
|
}
|
|
}
|
|
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS,
|
|
&(shared->info.max_texture_units));
|
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE,
|
|
&(shared->info.max_texture_size));
|
|
shared->info.max_vertex_elements = 6 * 100;
|
|
#ifdef GL_MAX_ELEMENTS_VERTICES
|
|
/* only applies to glDrawRangeElements. don't really need to get it.
|
|
glGetIntegerv(GL_MAX_ELEMENTS_VERTICES,
|
|
&(shared->info.max_vertex_elements));
|
|
*/
|
|
#endif
|
|
s = getenv("EVAS_GL_VERTEX_MAX");
|
|
if (s) shared->info.max_vertex_elements = atoi(s);
|
|
if (shared->info.max_vertex_elements < 6)
|
|
shared->info.max_vertex_elements = 6;
|
|
|
|
// magic numbers that are a result of imperical testing and getting
|
|
// "best case" performance across a range of systems
|
|
shared->info.tune.cutout.max = DEF_CUTOUT;
|
|
shared->info.tune.pipes.max = DEF_PIPES;
|
|
shared->info.tune.atlas.max_alloc_size = DEF_ATLAS_ALLOC;
|
|
shared->info.tune.atlas.max_alloc_alpha_size = DEF_ATLAS_ALLOC_ALPHA;
|
|
shared->info.tune.atlas.max_w = DEF_ATLAS_W;
|
|
shared->info.tune.atlas.max_h = DEF_ATLAS_H;
|
|
|
|
// per gpu hacks. based on impirical measurement of some known gpu's
|
|
s = (const char *)glGetString(GL_RENDERER);
|
|
if (s)
|
|
{
|
|
if (strstr(s, "PowerVR SGX 540"))
|
|
shared->info.tune.pipes.max = DEF_PIPES_SGX_540;
|
|
else if (strstr(s, "NVIDIA Tegra 3"))
|
|
shared->info.tune.pipes.max = DEF_PIPES_TEGRA_3;
|
|
else if (strstr(s, "NVIDIA Tegra"))
|
|
shared->info.tune.pipes.max = DEF_PIPES_TEGRA_2;
|
|
}
|
|
if (!getenv("EVAS_GL_MAPBUFFER"))
|
|
{
|
|
glsym_glMapBuffer = NULL;
|
|
glsym_glUnmapBuffer= NULL;
|
|
}
|
|
|
|
#define GETENVOPT(name, tune_param, min, max) \
|
|
do { \
|
|
const char *__v = getenv(name); \
|
|
if (__v) { \
|
|
shared->info.tune.tune_param = atoi(__v); \
|
|
if (shared->info.tune.tune_param > max) \
|
|
shared->info.tune.tune_param = max; \
|
|
else if (shared->info.tune.tune_param < min) \
|
|
shared->info.tune.tune_param = min; \
|
|
} \
|
|
} while (0)
|
|
|
|
GETENVOPT("EVAS_GL_CUTOUT_MAX", cutout.max, -1, 0x7fffffff);
|
|
GETENVOPT("EVAS_GL_PIPES_MAX", pipes.max, 1, MAX_PIPES);
|
|
GETENVOPT("EVAS_GL_ATLAS_ALLOC_SIZE", atlas.max_alloc_size, MIN_ATLAS_ALLOC, MAX_ATLAS_ALLOC);
|
|
GETENVOPT("EVAS_GL_ATLAS_ALLOC_ALPHA_SIZE", atlas.max_alloc_alpha_size, MIN_ATLAS_ALLOC_ALPHA, MAX_ATLAS_ALLOC_ALPHA);
|
|
GETENVOPT("EVAS_GL_ATLAS_MAX_W", atlas.max_w, 0, MAX_ATLAS_W);
|
|
GETENVOPT("EVAS_GL_ATLAS_MAX_H", atlas.max_h, 0, MAX_ATLAS_H);
|
|
s = (const char *)getenv("EVAS_GL_GET_PROGRAM_BINARY");
|
|
if (s)
|
|
{
|
|
if (atoi(s) == 0) shared->info.bin_program = 0;
|
|
}
|
|
|
|
#ifdef GL_GLES
|
|
// Detect ECT2 support. We need both RGB and RGBA formats.
|
|
{
|
|
GLint texFormatCnt = 0;
|
|
glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &texFormatCnt);
|
|
if (texFormatCnt > 0)
|
|
{
|
|
GLenum *texFormats = malloc(texFormatCnt * sizeof(GLenum));
|
|
if (texFormats)
|
|
{
|
|
int k, cnt = 0;
|
|
glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, (GLint *) texFormats);
|
|
for (k = 0; k < texFormatCnt && cnt < 2; k++)
|
|
{
|
|
if (texFormats[k] == GL_COMPRESSED_RGB8_ETC2)
|
|
cnt++;
|
|
else if (texFormats[k] == GL_COMPRESSED_RGBA8_ETC2_EAC)
|
|
cnt++;
|
|
}
|
|
shared->info.etc2 = (cnt == 2);
|
|
free(texFormats);
|
|
|
|
// Note: If we support ETC2 we'll try to always use ETC2 even when the
|
|
// image has colorspace ETC1 (backwards compatibility).
|
|
|
|
if (_ckext(ext, "GL_EXT_compressed_ETC1_RGB8_sub_texture"))
|
|
shared->info.etc1_subimage = 1;
|
|
else
|
|
shared->info.etc1_subimage = shared->info.etc2;
|
|
|
|
// FIXME: My NVIDIA driver advertises ETC2 texture formats
|
|
// but does not support them. Driver bug? Logic bug?
|
|
// This is in #ifdef GL_GLES because Khronos recommends
|
|
// use of GL_COMPRESSED_TEXTURE_FORMATS but OpenGL 4.x
|
|
// does not.
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (getenv("EVAS_GL_INFO"))
|
|
fprintf(stderr,
|
|
"max tex size %ix%i\n"
|
|
"max units %i\n"
|
|
"non-power-2 tex %i\n"
|
|
"rect tex %i\n"
|
|
"bgra : %i\n"
|
|
"etc1 : %i\n"
|
|
"etc2 : %i%s\n"
|
|
"s3tc : %i\n"
|
|
"max ansiotropic filtering: %3.3f\n"
|
|
"egl sec map image: %i\n"
|
|
"max vertex count: %i\n"
|
|
"\n"
|
|
"(can set EVAS_GL_VERTEX_MAX EVAS_GL_NO_MAP_IMAGE_SEC EVAS_GL_INFO EVAS_GL_MEMINFO )\n"
|
|
"\n"
|
|
"EVAS_GL_GET_PROGRAM_BINARY: %i\n"
|
|
"EVAS_GL_CUTOUT_MAX: %i\n"
|
|
"EVAS_GL_PIPES_MAX: %i\n"
|
|
"EVAS_GL_ATLAS_ALLOC_SIZE: %i\n"
|
|
"EVAS_GL_ATLAS_ALLOC_ALPHA_SIZE: %i\n"
|
|
"EVAS_GL_ATLAS_MAX_W x EVAS_GL_ATLAS_MAX_H: %i x %i\n"
|
|
,
|
|
(int)shared->info.max_texture_size, (int)shared->info.max_texture_size,
|
|
(int)shared->info.max_texture_units,
|
|
(int)shared->info.tex_npo2,
|
|
(int)shared->info.tex_rect,
|
|
(int)shared->info.bgra,
|
|
(int)shared->info.etc1,
|
|
(int)shared->info.etc2, shared->info.etc2 ? " (GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGBA8_ETC2_EAC)" : "",
|
|
(int)shared->info.s3tc,
|
|
(double)shared->info.anisotropic,
|
|
(int)shared->info.sec_image_map,
|
|
(int)shared->info.max_vertex_elements,
|
|
|
|
(int)shared->info.bin_program,
|
|
(int)shared->info.tune.cutout.max,
|
|
(int)shared->info.tune.pipes.max,
|
|
(int)shared->info.tune.atlas.max_alloc_size,
|
|
(int)shared->info.tune.atlas.max_alloc_alpha_size,
|
|
(int)shared->info.tune.atlas.max_w, (int)shared->info.tune.atlas.max_h
|
|
);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
glEnable(GL_DITHER);
|
|
glDisable(GL_BLEND);
|
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
// no dest alpha
|
|
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // dest alpha
|
|
// glBlendFunc(GL_SRC_ALPHA, GL_ONE); // ???
|
|
glDepthMask(GL_FALSE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
|
|
if (shared->info.anisotropic > 0.0)
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0);
|
|
#endif
|
|
|
|
glEnableVertexAttribArray(SHAD_VERTEX);
|
|
glEnableVertexAttribArray(SHAD_COLOR);
|
|
|
|
if (!evas_gl_common_shader_program_init(shared))
|
|
goto error;
|
|
|
|
if (gc->state.current.prog)
|
|
glUseProgram(gc->state.current.prog->prog);
|
|
|
|
// in shader:
|
|
// uniform sampler2D tex[8];
|
|
//
|
|
// in code:
|
|
// GLuint texes[8];
|
|
// GLint loc = glGetUniformLocation(prog, "tex");
|
|
// glUniform1iv(loc, 8, texes);
|
|
|
|
shared->native_pm_hash = eina_hash_int32_new(NULL);
|
|
shared->native_tex_hash = eina_hash_int32_new(NULL);
|
|
shared->native_wl_hash = eina_hash_pointer_new(NULL);
|
|
shared->native_tbm_hash = eina_hash_pointer_new(NULL);
|
|
shared->native_evasgl_hash = eina_hash_pointer_new(NULL);
|
|
}
|
|
gc->shared = shared;
|
|
gc->shared->references++;
|
|
_evas_gl_common_viewport_set(gc);
|
|
|
|
gc->def_surface = evas_gl_common_image_surface_new(gc, 1, 1, 1, EINA_FALSE);
|
|
gc->err_img = evas_gl_common_image_surface_new(gc, 1, 1, 0, EINA_FALSE);
|
|
|
|
return gc;
|
|
|
|
error:
|
|
evas_gl_common_context_free(gc);
|
|
return NULL;
|
|
}
|
|
|
|
#define VERTEX_CNT 3
|
|
#define COLOR_CNT 4
|
|
#define TEX_CNT 2
|
|
#define SAM_CNT 2
|
|
#define MASK_CNT 4
|
|
|
|
#define PUSH_VERTEX(n, x, y, z) do { \
|
|
gc->pipe[n].array.vertex[nv++] = x; \
|
|
gc->pipe[n].array.vertex[nv++] = y; \
|
|
gc->pipe[n].array.vertex[nv++] = z; } while(0)
|
|
#define PUSH_COLOR(n, r, g, b, a) do { \
|
|
gc->pipe[n].array.color[nc++] = r; \
|
|
gc->pipe[n].array.color[nc++] = g; \
|
|
gc->pipe[n].array.color[nc++] = b; \
|
|
gc->pipe[n].array.color[nc++] = a; } while(0)
|
|
#define PUSH_TEXUV(n, u, v) do { \
|
|
gc->pipe[n].array.texuv[nu++] = u; \
|
|
gc->pipe[n].array.texuv[nu++] = v; } while(0)
|
|
#define PUSH_TEXUV2(n, u, v) do { \
|
|
gc->pipe[n].array.texuv2[nu2++] = u; \
|
|
gc->pipe[n].array.texuv2[nu2++] = v; } while(0)
|
|
#define PUSH_TEXUV3(n, u, v) do { \
|
|
gc->pipe[n].array.texuv3[nu3++] = u; \
|
|
gc->pipe[n].array.texuv3[nu3++] = v; } while(0)
|
|
#define PUSH_TEXA(n, u, v) do { \
|
|
gc->pipe[n].array.texa[na++] = u; \
|
|
gc->pipe[n].array.texa[na++] = v; } while(0)
|
|
#define PUSH_TEXM(n, u, v, w, z) do { \
|
|
gc->pipe[n].array.mask[nm++] = u; \
|
|
gc->pipe[n].array.mask[nm++] = v; \
|
|
gc->pipe[n].array.mask[nm++] = w; \
|
|
gc->pipe[n].array.mask[nm++] = z; } while(0)
|
|
#define PUSH_TEXSAM(n, x, y) do { \
|
|
gc->pipe[n].array.texsam[ns++] = x; \
|
|
gc->pipe[n].array.texsam[ns++] = y; } while(0)
|
|
|
|
#define PUSH_6_VERTICES(pn, x, y, w, h) do { \
|
|
PUSH_VERTEX(pn, x , y , 0); PUSH_VERTEX(pn, x + w, y , 0); \
|
|
PUSH_VERTEX(pn, x , y + h, 0); PUSH_VERTEX(pn, x + w, y , 0); \
|
|
PUSH_VERTEX(pn, x + w, y + h, 0); PUSH_VERTEX(pn, x , y + h, 0); \
|
|
} while (0)
|
|
#define PUSH_6_QUAD(pn, x1, y1, x2, y2, x3, y3, x4, y4) \
|
|
PUSH_TEXUV(pn, x1, y1); PUSH_TEXUV(pn, x2, y2); PUSH_TEXUV(pn, x4, y4);\
|
|
PUSH_TEXUV(pn, x2, y2); PUSH_TEXUV(pn, x3, y3); PUSH_TEXUV(pn, x4, y4);
|
|
|
|
#define PUSH_6_TEXUV(pn, x1, y1, x2, y2) \
|
|
PUSH_6_QUAD(pn, x1, y1, x2, y1, x2, y2, x1, y2);
|
|
|
|
#define PUSH_6_TEXUV2(pn, x1, y1, x2, y2) do { \
|
|
PUSH_TEXUV2(pn, x1, y1); PUSH_TEXUV2(pn, x2, y1); PUSH_TEXUV2(pn, x1, y2); \
|
|
PUSH_TEXUV2(pn, x2, y1); PUSH_TEXUV2(pn, x2, y2); PUSH_TEXUV2(pn, x1, y2); \
|
|
} while (0)
|
|
#define PUSH_6_TEXUV3(pn, x1, y1, x2, y2) do { \
|
|
PUSH_TEXUV3(pn, x1, y1); PUSH_TEXUV3(pn, x2, y1); PUSH_TEXUV3(pn, x1, y2); \
|
|
PUSH_TEXUV3(pn, x2, y1); PUSH_TEXUV3(pn, x2, y2); PUSH_TEXUV3(pn, x1, y2); \
|
|
} while (0)
|
|
#define PUSH_6_TEXA(pn, x1, y1, x2, y2) do { \
|
|
PUSH_TEXA(pn, x1, y1); PUSH_TEXA(pn, x2, y1); PUSH_TEXA(pn, x1, y2); \
|
|
PUSH_TEXA(pn, x2, y1); PUSH_TEXA(pn, x2, y2); PUSH_TEXA(pn, x1, y2); \
|
|
} while (0)
|
|
#define PUSH_SAMPLES(pn, dx, dy) do { \
|
|
PUSH_TEXSAM(pn, dx, dy); PUSH_TEXSAM(pn, dx, dy); PUSH_TEXSAM(pn, dx, dy); \
|
|
PUSH_TEXSAM(pn, dx, dy); PUSH_TEXSAM(pn, dx, dy); PUSH_TEXSAM(pn, dx, dy); \
|
|
} while (0)
|
|
#define PUSH_MASKSAM(pn, x, y, cnt) do { int _i; for (_i = 0; _i < cnt; _i++) { \
|
|
gc->pipe[pn].array.masksam[nms++] = x; gc->pipe[pn].array.masksam[nms++] = y; \
|
|
} } while (0)
|
|
#define PUSH_6_COLORS(pn, r, g, b, a) \
|
|
do { int i; for (i = 0; i < 6; i++) PUSH_COLOR(pn, r, g, b, a); } while(0)
|
|
|
|
#define PIPE_GROW(gc, pn, inc) \
|
|
int nv = gc->pipe[pn].array.num * VERTEX_CNT; (void) nv; \
|
|
int nc = gc->pipe[pn].array.num * COLOR_CNT; (void) nc; \
|
|
int nu = gc->pipe[pn].array.num * TEX_CNT; (void) nu; \
|
|
int nu2 = gc->pipe[pn].array.num * TEX_CNT; (void) nu2; \
|
|
int nu3 = gc->pipe[pn].array.num * TEX_CNT; (void) nu3; \
|
|
int na = gc->pipe[pn].array.num * TEX_CNT; (void) na; \
|
|
int ns = gc->pipe[pn].array.num * SAM_CNT; (void) ns; \
|
|
int nm = gc->pipe[pn].array.num * MASK_CNT; (void) nm; \
|
|
int nms = gc->pipe[pn].array.num * SAM_CNT; (void) nms; \
|
|
gc->pipe[pn].array.num += inc; \
|
|
array_alloc(gc, pn);
|
|
|
|
#define PIPE_FREE(x) \
|
|
do { _pipebuf_free(x); (x) = NULL; } while (0)
|
|
|
|
#define FREE(x) \
|
|
do { free(x); (x) = NULL; } while (0)
|
|
|
|
typedef struct _Pipebuf
|
|
{
|
|
int skipped, alloc;
|
|
} Pipebuf;
|
|
|
|
static int _pipe_bufs_max = 0;
|
|
static int _pipe_bufs_skipped = 0;
|
|
static Eina_List *_pipe_bufs = NULL;
|
|
|
|
/*
|
|
static int _used = 0, _alloced = 0, _realloced = 0;
|
|
static int _searches = 0, _looks = 0;
|
|
*/
|
|
|
|
static void *
|
|
_pipebuf_resize(void *pb, int size)
|
|
{
|
|
Pipebuf *buf, *buf2;
|
|
Eina_List *l, *ll;
|
|
|
|
if (size > _pipe_bufs_max) _pipe_bufs_max = size;
|
|
|
|
if (!pb)
|
|
{
|
|
if (_pipe_bufs)
|
|
{
|
|
// _searches++;
|
|
EINA_LIST_FOREACH(_pipe_bufs, l, buf)
|
|
{
|
|
// _looks++;
|
|
if (buf->alloc >= size) break;
|
|
buf->skipped++;
|
|
_pipe_bufs_skipped++;
|
|
}
|
|
if (l)
|
|
{
|
|
// _used++;
|
|
_pipe_bufs = eina_list_remove_list(_pipe_bufs, l);
|
|
_pipe_bufs_skipped -= buf->skipped;
|
|
buf->skipped = 0;
|
|
goto done;
|
|
}
|
|
}
|
|
buf = malloc(size + sizeof(Pipebuf));
|
|
if (!buf) return NULL;
|
|
buf->skipped = 0;
|
|
buf->alloc = size;
|
|
// _alloced++;
|
|
goto done;
|
|
}
|
|
buf = (Pipebuf *)(((unsigned char *)pb) - sizeof(Pipebuf));
|
|
if (buf->alloc < size)
|
|
{
|
|
buf2 = realloc(buf, size + sizeof(Pipebuf));
|
|
if (!buf2) return NULL;
|
|
// _realloced++;
|
|
buf = buf2;
|
|
buf->alloc = size;
|
|
}
|
|
done:
|
|
if (_pipe_bufs_skipped > 100)
|
|
{
|
|
EINA_LIST_REVERSE_FOREACH_SAFE(_pipe_bufs, l, ll, buf2)
|
|
{
|
|
if (buf2->skipped > 5)
|
|
{
|
|
_pipe_bufs = eina_list_remove_list(_pipe_bufs, l);
|
|
_pipe_bufs_skipped -= buf2->skipped;
|
|
free(buf2);
|
|
if (_pipe_bufs_skipped == 0) break;
|
|
}
|
|
}
|
|
}
|
|
// if ((_used + _alloced + _realloced) % 1000 == 0)
|
|
// printf("MAX=%i/%i skipped=%i searching=%i/%i - %i | %i | %i\n",
|
|
// _pipe_bufs_max, eina_list_count(_pipe_bufs), _pipe_bufs_skipped,
|
|
// _looks, _searches,
|
|
// _used, _alloced, _realloced);
|
|
return ((unsigned char *)buf) + sizeof(Pipebuf);
|
|
}
|
|
|
|
static void
|
|
_pipebuf_free(void *pb)
|
|
{
|
|
Pipebuf *buf;
|
|
|
|
if (!pb) return;
|
|
buf = (Pipebuf *)(((unsigned char *)pb) - sizeof(Pipebuf));
|
|
_pipe_bufs_max = (_pipe_bufs_max * 19) / 20;
|
|
if (buf->alloc > (_pipe_bufs_max * 4))
|
|
{
|
|
free(buf);
|
|
return;
|
|
}
|
|
if ((!_pipe_bufs) || (eina_list_count(_pipe_bufs) < 20))
|
|
{
|
|
_pipe_bufs = eina_list_prepend(_pipe_bufs, buf);
|
|
return;
|
|
}
|
|
free(buf);
|
|
}
|
|
|
|
static void
|
|
_pipebuf_clear(void)
|
|
{
|
|
Pipebuf *buf;
|
|
|
|
_pipe_bufs_max = 0;
|
|
EINA_LIST_FREE(_pipe_bufs, buf)
|
|
{
|
|
free(buf);
|
|
}
|
|
}
|
|
|
|
static void
|
|
array_alloc(Evas_Engine_GL_Context *gc, int n)
|
|
{
|
|
gc->havestuff = EINA_TRUE;
|
|
if (gc->pipe[n].array.num <= gc->pipe[n].array.alloc) return;
|
|
|
|
gc->pipe[n].array.alloc += 6 * 256;
|
|
|
|
#define RALOC(field, type, size) \
|
|
if (gc->pipe[n].array.use_##field) \
|
|
gc->pipe[n].array.field = _pipebuf_resize(gc->pipe[n].array.field, \
|
|
gc->pipe[n].array.alloc * sizeof(type) * size)
|
|
|
|
RALOC(vertex, GLfloat, VERTEX_CNT);
|
|
RALOC(color, GLubyte, COLOR_CNT);
|
|
RALOC(texuv, GLfloat, TEX_CNT);
|
|
RALOC(texa, GLfloat, TEX_CNT);
|
|
RALOC(texuv2, GLfloat, TEX_CNT);
|
|
RALOC(texuv3, GLfloat, TEX_CNT);
|
|
RALOC(texsam, GLfloat, SAM_CNT);
|
|
RALOC(mask, GLfloat, MASK_CNT);
|
|
RALOC(masksam, GLfloat, SAM_CNT);
|
|
|
|
#undef ALOC
|
|
#undef RALOC
|
|
}
|
|
|
|
EMODAPI void
|
|
evas_gl_common_context_free(Evas_Engine_GL_Context *gc)
|
|
{
|
|
int i, j;
|
|
Eina_List *l;
|
|
|
|
gc->references--;
|
|
if (gc->references > 0) return;
|
|
if (gc->shared) gc->shared->references--;
|
|
|
|
if (gc->err_img) evas_gl_common_image_free(gc->err_img);
|
|
if (gc->def_surface) evas_gl_common_image_free(gc->def_surface);
|
|
|
|
if (gc->font_surface)
|
|
evas_cache_image_drop(&gc->font_surface->cache_entry);
|
|
|
|
if (glsym_glMapBuffer && glsym_glUnmapBuffer)
|
|
{
|
|
for (i = 0; i < MAX_PIPES; i++)
|
|
glDeleteBuffers(1, &gc->pipe[i].array.buffer);
|
|
}
|
|
|
|
if (gc->shared)
|
|
{
|
|
for (i = 0; i < gc->shared->info.tune.pipes.max; i++)
|
|
{
|
|
PIPE_FREE(gc->pipe[i].array.vertex);
|
|
PIPE_FREE(gc->pipe[i].array.color);
|
|
PIPE_FREE(gc->pipe[i].array.texuv);
|
|
PIPE_FREE(gc->pipe[i].array.texuv2);
|
|
PIPE_FREE(gc->pipe[i].array.texuv3);
|
|
PIPE_FREE(gc->pipe[i].array.texa);
|
|
PIPE_FREE(gc->pipe[i].array.texsam);
|
|
PIPE_FREE(gc->pipe[i].array.mask);
|
|
PIPE_FREE(gc->pipe[i].array.masksam);
|
|
FREE(gc->pipe[i].array.filter_data);
|
|
}
|
|
}
|
|
|
|
while (gc->font_glyph_textures)
|
|
evas_gl_common_texture_free(gc->font_glyph_textures->data, EINA_TRUE);
|
|
|
|
while (gc->font_glyph_images)
|
|
evas_gl_common_image_free(gc->font_glyph_images->data);
|
|
|
|
if ((gc->shared) && (gc->shared->references == 0))
|
|
{
|
|
Evas_GL_Texture_Pool *pt;
|
|
|
|
evas_gl_common_shader_program_shutdown(gc->shared);
|
|
|
|
while (gc->shared->images)
|
|
{
|
|
evas_gl_common_image_free(gc->shared->images->data);
|
|
}
|
|
|
|
for (j = 0; j < ATLAS_FORMATS_COUNT; j++)
|
|
{
|
|
EINA_LIST_FOREACH(gc->shared->tex.atlas[j], l, pt)
|
|
evas_gl_texture_pool_empty(pt);
|
|
eina_list_free(gc->shared->tex.atlas[j]);
|
|
}
|
|
EINA_LIST_FOREACH(gc->shared->tex.whole, l, pt)
|
|
evas_gl_texture_pool_empty(pt);
|
|
eina_list_free(gc->shared->info.cspaces);
|
|
eina_list_free(gc->shared->tex.whole);
|
|
eina_hash_free(gc->shared->native_pm_hash);
|
|
eina_hash_free(gc->shared->native_tex_hash);
|
|
eina_hash_free(gc->shared->native_wl_hash);
|
|
eina_hash_free(gc->shared->native_tbm_hash);
|
|
eina_hash_free(gc->shared->native_evasgl_hash);
|
|
eina_stringshare_del(gc->shared->shaders_checksum);
|
|
free(gc->shared);
|
|
shared = NULL;
|
|
}
|
|
if (gc == _evas_gl_common_context)
|
|
{
|
|
_pipebuf_clear();
|
|
_evas_gl_common_context = NULL;
|
|
}
|
|
free(gc);
|
|
if (_evas_gl_common_cutout_rects)
|
|
{
|
|
evas_common_draw_context_apply_clear_cutouts(_evas_gl_common_cutout_rects);
|
|
_evas_gl_common_cutout_rects = NULL;
|
|
}
|
|
}
|
|
|
|
EMODAPI void
|
|
evas_gl_common_context_use(Evas_Engine_GL_Context *gc)
|
|
{
|
|
if (_evas_gl_common_context == gc) return;
|
|
_evas_gl_common_context = gc;
|
|
if (gc) _evas_gl_common_viewport_set(gc);
|
|
}
|
|
|
|
EMODAPI void
|
|
evas_gl_common_context_newframe(Evas_Engine_GL_Context *gc)
|
|
{
|
|
int i;
|
|
|
|
if (_evas_gl_common_cutout_rects)
|
|
{
|
|
evas_common_draw_context_apply_clear_cutouts(_evas_gl_common_cutout_rects);
|
|
_evas_gl_common_cutout_rects = NULL;
|
|
}
|
|
if (dbgflushnum < 0)
|
|
{
|
|
dbgflushnum = 0;
|
|
if (getenv("EVAS_GL_DBG")) dbgflushnum = 1;
|
|
}
|
|
if (dbgflushnum) printf("----prev-flushnum: %i -----------------------------------\n", gc->flushnum);
|
|
// fprintf(stderr, "------------------------\n");
|
|
|
|
gc->flushnum = 0;
|
|
gc->state.current.prog = NULL;
|
|
gc->state.current.cur_tex = 0;
|
|
gc->state.current.cur_texu = 0;
|
|
gc->state.current.cur_texv = 0;
|
|
gc->state.current.cur_texa = 0;
|
|
gc->state.current.cur_texm = 0;
|
|
gc->state.current.tex_target = GL_TEXTURE_2D;
|
|
gc->state.current.render_op = EVAS_RENDER_COPY;
|
|
gc->state.current.smooth = 0;
|
|
gc->state.current.blend = 0;
|
|
gc->state.current.clip = 0;
|
|
gc->state.current.cx = 0;
|
|
gc->state.current.cy = 0;
|
|
gc->state.current.cw = 0;
|
|
gc->state.current.ch = 0;
|
|
|
|
for (i = 0; i < gc->shared->info.tune.pipes.max; i++)
|
|
{
|
|
gc->pipe[i].region.x = 0;
|
|
gc->pipe[i].region.y = 0;
|
|
gc->pipe[i].region.w = 0;
|
|
gc->pipe[i].region.h = 0;
|
|
gc->pipe[i].region.type = 0;
|
|
//gc->pipe[i].shader.surface = NULL;
|
|
gc->pipe[i].shader.prog = NULL;
|
|
gc->pipe[i].shader.cur_tex = 0;
|
|
gc->pipe[i].shader.cur_texu = 0;
|
|
gc->pipe[i].shader.cur_texv = 0;
|
|
gc->pipe[i].shader.cur_texa = 0;
|
|
gc->pipe[i].shader.cur_texm = 0;
|
|
gc->pipe[i].shader.tex_target = GL_TEXTURE_2D;
|
|
gc->pipe[i].shader.render_op = EVAS_RENDER_COPY;
|
|
gc->pipe[i].shader.smooth = 0;
|
|
gc->pipe[i].shader.blend = 0;
|
|
gc->pipe[i].shader.clip = 0;
|
|
gc->pipe[i].shader.cx = 0;
|
|
gc->pipe[i].shader.cy = 0;
|
|
gc->pipe[i].shader.cw = 0;
|
|
gc->pipe[i].shader.ch = 0;
|
|
}
|
|
gc->change.size = 1;
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glScissor(0, 0, 0, 0);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
glEnable(GL_DITHER);
|
|
glDisable(GL_BLEND);
|
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
// no dest alpha
|
|
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // dest alpha
|
|
// glBlendFunc(GL_SRC_ALPHA, GL_ONE); // ???
|
|
glDepthMask(GL_FALSE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
|
|
if (shared->info.anisotropic > 0.0)
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0);
|
|
#endif
|
|
|
|
glEnableVertexAttribArray(SHAD_VERTEX);
|
|
glEnableVertexAttribArray(SHAD_COLOR);
|
|
if (gc->state.current.prog != PRG_INVALID)
|
|
glUseProgram(gc->state.current.prog->prog);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(gc->pipe[0].shader.tex_target, gc->pipe[0].shader.cur_tex);
|
|
|
|
_evas_gl_common_viewport_set(gc);
|
|
}
|
|
|
|
EMODAPI void
|
|
evas_gl_common_context_resize(Evas_Engine_GL_Context *gc, int w, int h, int rot)
|
|
{
|
|
if ((gc->w == w) && (gc->h == h) && (gc->rot == rot)) return;
|
|
evas_gl_common_context_flush(gc);
|
|
gc->change.size = 1;
|
|
gc->rot = rot;
|
|
gc->w = w;
|
|
gc->h = h;
|
|
if (_evas_gl_common_context == gc) _evas_gl_common_viewport_set(gc);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_tiling_start(Evas_Engine_GL_Context *gc EINA_UNUSED,
|
|
int rot, int gw, int gh,
|
|
int cx, int cy, int cw, int ch,
|
|
int bitmask)
|
|
{
|
|
if (!glsym_glStartTiling) return;
|
|
switch (rot)
|
|
{
|
|
case 0: // UP this way: ^
|
|
glsym_glStartTiling(cx, cy, cw, ch, bitmask);
|
|
break;
|
|
case 90: // UP this way: <
|
|
glsym_glStartTiling(gh - (cy + ch), cx, ch, cw, bitmask);
|
|
break;
|
|
case 180: // UP this way: v
|
|
glsym_glStartTiling(gw - (cx + cw), gh - (cy + ch), cw, ch, bitmask);
|
|
break;
|
|
case 270: // UP this way: >
|
|
glsym_glStartTiling(cy, gw - (cx + cw), ch, cw, bitmask);
|
|
break;
|
|
default: // assume up is up
|
|
glsym_glStartTiling(cx, cy, cw, ch, bitmask);
|
|
break;
|
|
}
|
|
GLERRV("glsym_glStartTiling");
|
|
}
|
|
|
|
void
|
|
evas_gl_common_tiling_done(Evas_Engine_GL_Context *gc EINA_UNUSED)
|
|
{
|
|
if (glsym_glEndTiling)
|
|
{
|
|
glsym_glEndTiling(GL_COLOR_BUFFER_BIT0_QCOM);
|
|
GLERRV("glsym_glEndTiling");
|
|
}
|
|
}
|
|
|
|
|
|
EMODAPI void
|
|
evas_gl_common_context_done(Evas_Engine_GL_Context *gc)
|
|
{
|
|
if (gc->master_clip.used)
|
|
{
|
|
if (glsym_glEndTiling)
|
|
{
|
|
glsym_glEndTiling(GL_COLOR_BUFFER_BIT0_QCOM);
|
|
GLERRV("glsym_glEndTiling");
|
|
}
|
|
gc->master_clip.used = EINA_FALSE;
|
|
}
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_target_surface_set(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Image *surface)
|
|
{
|
|
if (surface == gc->pipe[0].shader.surface) return;
|
|
|
|
evas_gl_common_context_flush(gc);
|
|
evas_gl_common_context_done(gc);
|
|
|
|
gc->state.current.prog = NULL;
|
|
gc->state.current.cur_tex = 0;
|
|
gc->state.current.cur_texu = 0;
|
|
gc->state.current.cur_texv = 0;
|
|
gc->state.current.cur_texa = 0;
|
|
gc->state.current.cur_texm = 0;
|
|
gc->state.current.tex_target = GL_TEXTURE_2D;
|
|
gc->state.current.render_op = -1;
|
|
gc->state.current.smooth = -1;
|
|
gc->state.current.blend = -1;
|
|
gc->state.current.clip = -1;
|
|
gc->state.current.cx = -1;
|
|
gc->state.current.cy = -1;
|
|
gc->state.current.cw = -1;
|
|
gc->state.current.ch = -1;
|
|
gc->state.current.anti_alias = -1;
|
|
|
|
gc->pipe[0].shader.surface = surface;
|
|
gc->change.size = 1;
|
|
#ifdef GL_GLES
|
|
# ifndef GL_FRAMEBUFFER
|
|
# define GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
|
|
# endif
|
|
#else
|
|
# ifndef GL_FRAMEBUFFER
|
|
# define GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
|
|
# endif
|
|
#endif
|
|
if (gc->pipe[0].shader.surface == gc->def_surface)
|
|
glsym_glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
else
|
|
glsym_glBindFramebuffer(GL_FRAMEBUFFER, surface->tex->pt->fb);
|
|
_evas_gl_common_viewport_set(gc);
|
|
}
|
|
|
|
static inline Eina_Bool
|
|
_push_mask(Evas_Engine_GL_Context *gc, const int pn, int nm, Evas_GL_Texture *mtex,
|
|
int mx, int my, int mw, int mh, Shader_Sampling msam, int nms)
|
|
{
|
|
double glmx, glmy, glmw, glmh, yinv = -1.f;
|
|
int gw = gc->w, gh = gc->h, i, cnt = 6;
|
|
|
|
if (!((gc->pipe[0].shader.surface == gc->def_surface) ||
|
|
(!gc->pipe[0].shader.surface)))
|
|
{
|
|
gw = gc->pipe[0].shader.surface->w;
|
|
gh = gc->pipe[0].shader.surface->h;
|
|
yinv = 1.f;
|
|
}
|
|
|
|
if (!gw || !gh || !mw || !mh || !mtex->pt->w || !mtex->pt->h)
|
|
return EINA_FALSE;
|
|
|
|
/* Vertex shader:
|
|
*
|
|
* INPUTS:
|
|
* vec4 mask_coord = vec4(glmx, glmy, glmw, glmh);
|
|
* int rotation_id = gc->rot / 90;
|
|
*
|
|
* CODE:
|
|
* vec4 mask_Position = mvp * vertex * vec4(0.5, sign(mask_coord.w) * 0.5, 0.5, 0.5) + vec4(0.5, 0.5, 0, 0);
|
|
* vec2 pos[4]; // no ctor-style init because of GLSL-ES (version 100)
|
|
* pos[0] = vec2(mask_Position.xy);
|
|
* pos[1] = vec2(1.0 - mask_Position.y, mask_Position.x);
|
|
* pos[2] = vec2(1.0 - mask_Position.xy);
|
|
* pos[3] = vec2(mask_Position.y, 1.0 - mask_Position.x);
|
|
* tex_m = pos[rotation_id].xy * abs(mask_coord.zw) + mask_coord.xy;
|
|
*/
|
|
glmx = (double)((mtex->x * mw) - (mtex->w * mx)) / (double)(mw * mtex->pt->w);
|
|
glmy = (double)((mtex->y * mh) - (mtex->h * my)) / (double)(mh * mtex->pt->h);
|
|
glmw = (double)(gw * mtex->w) / (double)(mw * mtex->pt->w);
|
|
glmh = (double)(gh * mtex->h) / (double)(mh * mtex->pt->h);
|
|
glmh *= yinv;
|
|
|
|
if (gc->pipe[pn].array.line)
|
|
cnt = 2;
|
|
|
|
for (i = 0; i < cnt; i++)
|
|
PUSH_TEXM(pn, glmx, glmy, glmw, glmh);
|
|
|
|
if (msam)
|
|
{
|
|
double samx = (double)(mtex->w) / (double)(mtex->pt->w * mw * 4);
|
|
double samy = (double)(mtex->h) / (double)(mtex->pt->h * mh * 4);
|
|
PUSH_MASKSAM(pn, samx, samy, cnt);
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
#define PUSH_MASK(pn, mtex, mx, my, mw, mh, msam) if (mtex) do { \
|
|
_push_mask(gc, pn, nm, mtex, mx, my, mw, mh, msam, nms); \
|
|
} while(0)
|
|
|
|
static int
|
|
pipe_region_intersects(Evas_Engine_GL_Context *gc, int n,
|
|
int x, int y, int w, int h)
|
|
{
|
|
#define SPANS_INTERSECT(x1, w1, x2, w2) \
|
|
(!((((x2) + (w2)) <= (x1)) || ((x2) >= ((x1) + (w1)))))
|
|
|
|
#define REGIONS_INTERSECT(x, y, w, h, xx, yy, ww, hh) \
|
|
((SPANS_COMMON((x), (w), (xx), (ww))) && (SPANS_COMMON((y), (h), (yy), (hh))))
|
|
|
|
float rx, ry, rw, rh;
|
|
int ii, end;
|
|
const GLfloat *v;
|
|
|
|
rx = gc->pipe[n].region.x;
|
|
ry = gc->pipe[n].region.y;
|
|
rw = gc->pipe[n].region.w;
|
|
rh = gc->pipe[n].region.h;
|
|
if (!REGIONS_INTERSECT(x, y, w, h, rx, ry, rw, rh)) return 0;
|
|
|
|
// a hack for now. map pipes use their whole bounding box for intersects
|
|
// which at worst case reduces to old pipeline flushes, but cheaper than
|
|
// full quad region or triangle intersects right now
|
|
if (gc->pipe[n].region.type == SHD_MAP) return 1;
|
|
|
|
v = gc->pipe[n].array.vertex;
|
|
end = gc->pipe[n].array.num * 3;
|
|
for (ii = 0; ii < end; ii += (3 * 3 * 2))
|
|
{ // tri 1...
|
|
// 0, 1, 2 < top left
|
|
// 3, 4, 5 < top right
|
|
// 6, 7, 8 < bottom left
|
|
rx = v[ii + 0];
|
|
ry = v[ii + 1];
|
|
rw = v[ii + 3] - rx;
|
|
rh = v[ii + 7] - ry;
|
|
if (REGIONS_INTERSECT(x, y, w, h, rx, ry, rw, rh)) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
pipe_region_expand(Evas_Engine_GL_Context *gc, int n,
|
|
int x, int y, int w, int h)
|
|
{
|
|
int x1, y1, x2, y2;
|
|
|
|
if (gc->pipe[n].region.w <= 0)
|
|
{
|
|
gc->pipe[n].region.x = x;
|
|
gc->pipe[n].region.y = y;
|
|
gc->pipe[n].region.w = w;
|
|
gc->pipe[n].region.h = h;
|
|
return;
|
|
}
|
|
x1 = gc->pipe[n].region.x;
|
|
y1 = gc->pipe[n].region.y;
|
|
x2 = gc->pipe[n].region.x + gc->pipe[n].region.w;
|
|
y2 = gc->pipe[n].region.y + gc->pipe[n].region.h;
|
|
if (x < x1) x1 = x;
|
|
if (y < y1) y1 = y;
|
|
if ((x + w) > x2) x2 = x + w;
|
|
if ((y + h) > y2) y2 = y + h;
|
|
gc->pipe[n].region.x = x1;
|
|
gc->pipe[n].region.y = y1;
|
|
gc->pipe[n].region.w = x2 - x1;
|
|
gc->pipe[n].region.h = y2 - y1;
|
|
}
|
|
|
|
static Eina_Bool
|
|
vertex_array_size_check(Evas_Engine_GL_Context *gc, int pn, int n)
|
|
{
|
|
// return 1;
|
|
if ((gc->pipe[pn].array.num + n) > gc->shared->info.max_vertex_elements)
|
|
{
|
|
shader_array_flush(gc);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_evas_gl_common_context_push(Shader_Type rtype,
|
|
Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
Evas_GL_Texture *texm,
|
|
Evas_GL_Program *prog,
|
|
int x, int y, int w, int h,
|
|
Eina_Bool blend,
|
|
Eina_Bool smooth,
|
|
Eina_Bool clip,
|
|
int cx, int cy, int cw, int ch,
|
|
Eina_Bool mask_smooth)
|
|
{
|
|
GLuint current_tex = 0;
|
|
int pn = 0;
|
|
|
|
if (tex)
|
|
current_tex = tex->ptt ? tex->ptt->texture : tex->pt->texture;
|
|
|
|
again:
|
|
vertex_array_size_check(gc, gc->state.top_pipe, (rtype == SHD_LINE) ? 2 : 6);
|
|
pn = gc->state.top_pipe;
|
|
|
|
if (!((pn == 0) && (gc->pipe[pn].array.num == 0)))
|
|
{
|
|
int found = 0;
|
|
int i;
|
|
|
|
for (i = pn; i >= 0; i--)
|
|
{
|
|
if ((gc->pipe[i].region.type == rtype)
|
|
&& (!tex || gc->pipe[i].shader.cur_tex == current_tex)
|
|
&& (!texm || ((gc->pipe[i].shader.cur_texm == texm->pt->texture)
|
|
&& (gc->pipe[i].shader.mask_smooth == mask_smooth)))
|
|
&& (gc->pipe[i].shader.prog == prog)
|
|
&& (gc->pipe[i].shader.smooth == smooth)
|
|
&& (gc->pipe[i].shader.blend == blend)
|
|
&& (gc->pipe[i].shader.render_op == gc->dc->render_op)
|
|
&& (gc->pipe[i].shader.clip == clip)
|
|
&& (!clip || ((gc->pipe[i].shader.cx == cx)
|
|
&& (gc->pipe[i].shader.cy == cy)
|
|
&& (gc->pipe[i].shader.cw == cw)
|
|
&& (gc->pipe[i].shader.ch == ch))))
|
|
{
|
|
found = 1;
|
|
pn = i;
|
|
break;
|
|
}
|
|
if (pipe_region_intersects(gc, i, x, y, w, h)) break;
|
|
}
|
|
if (!found)
|
|
{
|
|
pn = gc->state.top_pipe + 1;
|
|
if (pn >= gc->shared->info.tune.pipes.max)
|
|
{
|
|
shader_array_flush(gc);
|
|
goto again;
|
|
}
|
|
gc->state.top_pipe = pn;
|
|
}
|
|
}
|
|
if ((tex) && (((tex->im) && (tex->im->native.data)) || tex->pt->dyn.img))
|
|
{
|
|
if (gc->pipe[pn].array.im != tex->im)
|
|
{
|
|
shader_array_flush(gc);
|
|
pn = gc->state.top_pipe; // 0 after flush
|
|
gc->pipe[pn].array.im = tex->im;
|
|
goto again;
|
|
}
|
|
}
|
|
return pn;
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_line_push(Evas_Engine_GL_Context *gc,
|
|
int x1, int y1, int x2, int y2,
|
|
int clip, int cx, int cy, int cw, int ch,
|
|
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
|
|
Eina_Bool mask_smooth, Eina_Bool mask_color,
|
|
int r, int g, int b, int a)
|
|
{
|
|
Eina_Bool blend = EINA_FALSE;
|
|
Evas_GL_Program *prog;
|
|
int pn = 0, i;
|
|
GLuint mtexid = mtex ? mtex->pt->texture : 0;
|
|
Shader_Sampling masksam = SHD_SAM11;
|
|
int x = MIN(x1, x2);
|
|
int y = MIN(y1, y2);
|
|
int w = abs(x2 - x1);
|
|
int h = abs(y2 - y1);
|
|
|
|
if (!(gc->dc->render_op == EVAS_RENDER_COPY) && ((a < 255) || (mtex)))
|
|
blend = EINA_TRUE;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, SHD_LINE, NULL, 0, r, g, b, a,
|
|
0, 0, 0, 0, EINA_FALSE, NULL, EINA_FALSE,
|
|
mtex, mask_smooth, mask_color, mw, mh,
|
|
EINA_FALSE, NULL, NULL, &masksam);
|
|
|
|
pn = _evas_gl_common_context_push(SHD_LINE,
|
|
gc, NULL, mtex,
|
|
prog,
|
|
x, y, w, h,
|
|
blend,
|
|
EINA_FALSE,
|
|
0, 0, 0, 0, 0,
|
|
mask_smooth);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = SHD_LINE;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = 0;
|
|
gc->pipe[pn].shader.cur_texm = mtexid;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.clip = clip;
|
|
gc->pipe[pn].shader.cx = cx;
|
|
gc->pipe[pn].shader.cy = cy;
|
|
gc->pipe[pn].shader.cw = cw;
|
|
gc->pipe[pn].shader.ch = ch;
|
|
gc->pipe[pn].shader.mask_smooth = mask_smooth;
|
|
|
|
gc->pipe[pn].array.line = 1;
|
|
gc->pipe[pn].array.anti_alias = gc->dc->anti_alias;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = 1;
|
|
gc->pipe[pn].array.use_texuv = 0;
|
|
gc->pipe[pn].array.use_texuv2 = 0;
|
|
gc->pipe[pn].array.use_texuv3 = 0;
|
|
gc->pipe[pn].array.use_texa = 0;
|
|
gc->pipe[pn].array.use_texsam = 0;
|
|
gc->pipe[pn].array.use_masksam = (masksam != SHD_SAM11);
|
|
gc->pipe[pn].array.use_mask = !!mtex;
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 2);
|
|
PUSH_VERTEX(pn, x1, y1, 0);
|
|
PUSH_VERTEX(pn, x2, y2, 0);
|
|
PUSH_MASK(pn, mtex, mx, my, mw, mh, masksam);
|
|
for (i = 0; i < 2; i++)
|
|
PUSH_COLOR(pn, r, g, b, a);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_rectangle_push(Evas_Engine_GL_Context *gc,
|
|
int x, int y, int w, int h,
|
|
int r, int g, int b, int a,
|
|
Evas_GL_Texture *mtex,
|
|
int mx, int my, int mw, int mh,
|
|
Eina_Bool mask_smooth, Eina_Bool mask_color)
|
|
{
|
|
Eina_Bool blend = EINA_FALSE;
|
|
Shader_Sampling masksam = SHD_SAM11;
|
|
Evas_GL_Program *prog;
|
|
GLuint mtexid = mtex ? mtex->pt->texture : 0;
|
|
int pn = 0;
|
|
|
|
if (!(gc->dc->render_op == EVAS_RENDER_COPY) && ((a < 255) || mtex))
|
|
blend = EINA_TRUE;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, SHD_RECT, NULL, 0, r, g, b, a,
|
|
0, 0, 0, 0, EINA_FALSE, NULL, EINA_FALSE,
|
|
mtex, mask_smooth, mask_color, mw, mh,
|
|
EINA_FALSE, NULL, NULL, &masksam);
|
|
|
|
|
|
pn = _evas_gl_common_context_push(SHD_RECT,
|
|
gc, NULL, mtex,
|
|
prog,
|
|
x, y, w, h,
|
|
blend,
|
|
EINA_FALSE,
|
|
0, 0, 0, 0, 0,
|
|
mask_smooth);
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = SHD_RECT;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = 0;
|
|
gc->pipe[pn].shader.cur_texm = mtexid;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.mask_smooth = mask_smooth;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = 1;
|
|
gc->pipe[pn].array.use_texuv = 0;
|
|
gc->pipe[pn].array.use_texuv2 = 0;
|
|
gc->pipe[pn].array.use_texuv3 = 0;
|
|
gc->pipe[pn].array.use_texa = 0;
|
|
gc->pipe[pn].array.use_texsam = 0;
|
|
gc->pipe[pn].array.use_masksam = (masksam != SHD_SAM11);
|
|
gc->pipe[pn].array.use_mask = !!mtex;
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
PUSH_6_VERTICES(pn, x, y, w, h);
|
|
PUSH_MASK(pn, mtex, mx, my, mw, mh, masksam);
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
|
|
#define SWAP(a, b, tmp) \
|
|
tmp = *a; \
|
|
*a = *b; \
|
|
*b = tmp;
|
|
|
|
// 1-2 4-1
|
|
// | | => | |
|
|
// 4-3 3-2
|
|
static void
|
|
_rotate_90(double *x1, double *y1, double *x2, double *y2, double *x3, double *y3, double *x4, double *y4)
|
|
{
|
|
double tmp;
|
|
|
|
SWAP(x1, x4, tmp);
|
|
SWAP(y1, y4, tmp);
|
|
|
|
SWAP(x4, x3, tmp);
|
|
SWAP(y4, y3, tmp);
|
|
|
|
SWAP(x3, x2, tmp);
|
|
SWAP(y3, y2, tmp);
|
|
}
|
|
|
|
// 1-2 3-4
|
|
// | | => | |
|
|
// 4-3 2-1
|
|
static void
|
|
_rotate_180(double *x1, double *y1, double *x2, double *y2, double *x3, double *y3, double *x4, double *y4)
|
|
{
|
|
double tmp;
|
|
|
|
SWAP(x1, x3, tmp);
|
|
SWAP(y1, y3, tmp);
|
|
|
|
SWAP(x2, x4, tmp);
|
|
SWAP(y2, y4, tmp);
|
|
}
|
|
|
|
// 1-2 2-3
|
|
// | | => | |
|
|
// 4-3 1-4
|
|
static void
|
|
_rotate_270(double *x1, double *y1, double *x2, double *y2, double *x3, double *y3, double *x4, double *y4)
|
|
{
|
|
double tmp;
|
|
|
|
SWAP(x1, x2, tmp);
|
|
SWAP(y1, y2, tmp);
|
|
|
|
SWAP(x2, x3, tmp);
|
|
SWAP(y2, y3, tmp);
|
|
|
|
SWAP(x3, x4, tmp);
|
|
SWAP(y3, y4, tmp);
|
|
}
|
|
|
|
// 1-2 2-1
|
|
// | | => | |
|
|
// 4-3 3-4
|
|
static void
|
|
_flip_horizontal(double *x1, double *y1, double *x2, double *y2, double *x3, double *y3, double *x4, double *y4)
|
|
{
|
|
double tmp;
|
|
|
|
SWAP(x1, x2, tmp);
|
|
SWAP(y1, y2, tmp);
|
|
|
|
SWAP(x3, x4, tmp);
|
|
SWAP(y3, y4, tmp);
|
|
}
|
|
|
|
// 1-2 4-3
|
|
// | | => | |
|
|
// 4-3 1-2
|
|
static void
|
|
_flip_vertical(double *x1, double *y1, double *x2, double *y2, double *x3, double *y3, double *x4, double *y4)
|
|
{
|
|
double tmp;
|
|
|
|
SWAP(x1, x4, tmp);
|
|
SWAP(y1, y4, tmp);
|
|
|
|
SWAP(x2, x3, tmp);
|
|
SWAP(y2, y3, tmp);
|
|
}
|
|
|
|
// 1-2 1-4
|
|
// | | => | |
|
|
// 4-3 2-3
|
|
static void
|
|
_transpose(double *x1 EINA_UNUSED, double *y1 EINA_UNUSED, double *x2, double *y2,
|
|
double *x3 EINA_UNUSED, double *y3 EINA_UNUSED, double *x4, double *y4)
|
|
{
|
|
double tmp;
|
|
|
|
SWAP(x2, x4, tmp);
|
|
SWAP(y2, y4, tmp);
|
|
}
|
|
|
|
// 1-2 3-2
|
|
// | | => | |
|
|
// 4-3 4-1
|
|
static void
|
|
_transverse(double *x1, double *y1, double *x2 EINA_UNUSED, double *y2 EINA_UNUSED,
|
|
double *x3, double *y3, double *x4 EINA_UNUSED, double *y4 EINA_UNUSED)
|
|
{
|
|
double tmp;
|
|
|
|
SWAP(x1, x3, tmp);
|
|
SWAP(y1, y3, tmp);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_image_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
double sx, double sy, double sw, double sh,
|
|
int x, int y, int w, int h,
|
|
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
|
|
Eina_Bool mask_smooth, Eina_Bool mask_color,
|
|
int r, int g, int b, int a,
|
|
Eina_Bool smooth, Eina_Bool tex_only,
|
|
Eina_Bool alphaonly)
|
|
{
|
|
|
|
Evas_GL_Texture_Pool *pt;
|
|
double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4;
|
|
GLfloat tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4;
|
|
GLfloat offsetx, offsety;
|
|
double pw, ph;
|
|
Eina_Bool blend = EINA_FALSE;
|
|
Evas_GL_Program *prog;
|
|
int pn = 0, render_op = gc->dc->render_op, nomul = 0;
|
|
Shader_Sampling sam = 0, masksam = 0;
|
|
int yinvert = 0;
|
|
Shader_Type shd_in = SHD_IMAGE;
|
|
int tex_target = GL_TEXTURE_2D;
|
|
|
|
if (tex->im)
|
|
{
|
|
if (tex->im->native.data)
|
|
shd_in = SHD_IMAGENATIVE;
|
|
if (tex->im->native.target == GL_TEXTURE_EXTERNAL_OES)
|
|
tex_target = GL_TEXTURE_EXTERNAL_OES;
|
|
}
|
|
|
|
if (!!mtex)
|
|
{
|
|
// masking forces BLEND mode (mask with COPY does not make sense)
|
|
blend = EINA_TRUE;
|
|
render_op = EVAS_RENDER_BLEND;
|
|
}
|
|
else if (!(render_op == EVAS_RENDER_COPY) && ((a < 255) || (tex->alpha)))
|
|
blend = EINA_TRUE;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, shd_in, NULL, 0, r, g, b, a,
|
|
sw, sh, w, h, smooth, tex, tex_only,
|
|
mtex, mask_smooth, mask_color, mw, mh,
|
|
alphaonly, &sam, &nomul, &masksam);
|
|
|
|
if (tex->ptt)
|
|
{
|
|
pt = tex->ptt;
|
|
offsetx = tex->tx;
|
|
offsety = tex->ty;
|
|
smooth = EINA_TRUE;
|
|
|
|
// Adjusting sx, sy, sw and sh to real size of tiny texture
|
|
sx = sx * (EVAS_GL_TILE_SIZE - 2) / tex->w;
|
|
sw = sw * (EVAS_GL_TILE_SIZE - 2) / tex->w;
|
|
sy = sy * (EVAS_GL_TILE_SIZE - 1) / tex->h;
|
|
sh = sh * (EVAS_GL_TILE_SIZE - 1) / tex->h;
|
|
}
|
|
else
|
|
{
|
|
pt = tex->pt;
|
|
offsetx = tex->x;
|
|
offsety = tex->y;
|
|
}
|
|
|
|
pn = _evas_gl_common_context_push(SHD_IMAGE,
|
|
gc, tex, mtex,
|
|
prog,
|
|
x, y, w, h,
|
|
blend,
|
|
smooth,
|
|
0, 0, 0, 0, 0,
|
|
mask_smooth);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = SHD_IMAGE;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = pt->texture;
|
|
gc->pipe[pn].shader.cur_texm = mtex ? mtex->pt->texture : 0;
|
|
gc->pipe[pn].shader.tex_target = tex_target;
|
|
gc->pipe[pn].shader.smooth = smooth;
|
|
gc->pipe[pn].shader.mask_smooth = mask_smooth;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = render_op;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = !nomul;
|
|
gc->pipe[pn].array.use_texuv = 1;
|
|
gc->pipe[pn].array.use_texuv2 = 0;
|
|
gc->pipe[pn].array.use_texuv3 = 0;
|
|
gc->pipe[pn].array.use_texsam = (sam != SHD_SAM11);
|
|
gc->pipe[pn].array.use_mask = !!mtex;
|
|
gc->pipe[pn].array.use_masksam = (masksam != SHD_SAM11);
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
pw = pt->w;
|
|
ph = pt->h;
|
|
|
|
if (tex->im &&
|
|
(tex->im->orient == EVAS_IMAGE_ORIENT_90))
|
|
{
|
|
double tmp;
|
|
|
|
SWAP(&sw, &sh, tmp);
|
|
SWAP(&sx, &sy, tmp);
|
|
|
|
sy = tex->im->h - sh - sy;
|
|
}
|
|
|
|
else if (tex->im &&
|
|
(tex->im->orient == EVAS_IMAGE_ORIENT_180))
|
|
{
|
|
sx = tex->im->w - sw - sx;
|
|
sy = tex->im->h - sh - sy;
|
|
}
|
|
|
|
else if (tex->im &&
|
|
(tex->im->orient == EVAS_IMAGE_ORIENT_270))
|
|
{
|
|
double tmp;
|
|
|
|
SWAP(&sw, &sh, tmp);
|
|
SWAP(&sx, &sy, tmp);
|
|
|
|
sx = tex->im->w - sw - sx;
|
|
}
|
|
|
|
else if (tex->im &&
|
|
(tex->im->orient == EVAS_IMAGE_FLIP_HORIZONTAL))
|
|
{
|
|
sx = tex->im->w - sw - sx;
|
|
}
|
|
|
|
else if (tex->im &&
|
|
(tex->im->orient == EVAS_IMAGE_FLIP_VERTICAL))
|
|
{
|
|
sy = tex->im->h - sh - sy;
|
|
}
|
|
|
|
else if (tex->im &&
|
|
(tex->im->orient == EVAS_IMAGE_FLIP_TRANSVERSE))
|
|
{
|
|
double tmp;
|
|
|
|
SWAP(&sw, &sh, tmp);
|
|
SWAP(&sx, &sy, tmp);
|
|
|
|
sx = tex->im->w - sw - sx;
|
|
sy = tex->im->h - sh - sy;
|
|
}
|
|
|
|
else if (tex->im &&
|
|
(tex->im->orient == EVAS_IMAGE_FLIP_TRANSPOSE))
|
|
{
|
|
double tmp;
|
|
|
|
SWAP(&sw, &sh, tmp);
|
|
SWAP(&sx, &sy, tmp);
|
|
}
|
|
|
|
ox1 = sx;
|
|
oy1 = sy;
|
|
ox2 = sx + sw;
|
|
oy2 = sy;
|
|
ox3 = sx + sw;
|
|
oy3 = sy + sh;
|
|
ox4 = sx;
|
|
oy4 = sy + sh;
|
|
|
|
if ((tex->im) && (tex->im->native.data))
|
|
{
|
|
if (tex->im->native.func.yinvert)
|
|
yinvert = tex->im->native.func.yinvert(tex->im);
|
|
else
|
|
yinvert = tex->im->native.yinvert;
|
|
}
|
|
|
|
if ((tex->im) && (!yinvert))
|
|
{
|
|
// FIXME: What if yinvert is true? How to test that?
|
|
switch (tex->im->orient)
|
|
{
|
|
case EVAS_IMAGE_ORIENT_NONE:
|
|
break;
|
|
case EVAS_IMAGE_ORIENT_90:
|
|
_rotate_90(&ox1, &oy1, &ox2, &oy2, &ox3, &oy3, &ox4, &oy4);
|
|
break;
|
|
case EVAS_IMAGE_ORIENT_180:
|
|
_rotate_180(&ox1, &oy1, &ox2, &oy2, &ox3, &oy3, &ox4, &oy4);
|
|
break;
|
|
case EVAS_IMAGE_ORIENT_270:
|
|
_rotate_270(&ox1, &oy1, &ox2, &oy2, &ox3, &oy3, &ox4, &oy4);
|
|
break;
|
|
case EVAS_IMAGE_FLIP_HORIZONTAL:
|
|
_flip_horizontal(&ox1, &oy1, &ox2, &oy2, &ox3, &oy3, &ox4, &oy4);
|
|
break;
|
|
case EVAS_IMAGE_FLIP_VERTICAL:
|
|
_flip_vertical(&ox1, &oy1, &ox2, &oy2, &ox3, &oy3, &ox4, &oy4);
|
|
break;
|
|
case EVAS_IMAGE_FLIP_TRANSVERSE:
|
|
_transverse(&ox1, &oy1, &ox2, &oy2, &ox3, &oy3, &ox4, &oy4);
|
|
break;
|
|
case EVAS_IMAGE_FLIP_TRANSPOSE:
|
|
_transpose(&ox1, &oy1, &ox2, &oy2, &ox3, &oy3, &ox4, &oy4);
|
|
break;
|
|
default:
|
|
ERR("Wrong orientation ! %i", tex->im->orient);
|
|
}
|
|
}
|
|
|
|
tx1 = ((double)(offsetx) + ox1) / pw;
|
|
ty1 = ((double)(offsety) + oy1) / ph;
|
|
tx2 = ((double)(offsetx) + ox2) / pw;
|
|
ty2 = ((double)(offsety) + oy2) / ph;
|
|
tx3 = ((double)(offsetx) + ox3) / pw;
|
|
ty3 = ((double)(offsety) + oy3) / ph;
|
|
tx4 = ((double)(offsetx) + ox4) / pw;
|
|
ty4 = ((double)(offsety) + oy4) / ph;
|
|
if ((tex->im) && (tex->im->native.data) && (!tex->im->native.yinvert))
|
|
{
|
|
ty1 = 1.0 - ty1;
|
|
ty2 = 1.0 - ty2;
|
|
ty3 = 1.0 - ty3;
|
|
ty4 = 1.0 - ty4;
|
|
}
|
|
|
|
PUSH_6_VERTICES(pn, x, y, w, h);
|
|
PUSH_6_QUAD(pn, tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4);
|
|
|
|
if (sam)
|
|
{
|
|
double samx = (double)(sw) / (double)(tex->pt->w * w * 4);
|
|
double samy = (double)(sh) / (double)(tex->pt->h * h * 4);
|
|
PUSH_SAMPLES(pn, samx, samy);
|
|
}
|
|
|
|
PUSH_MASK(pn, mtex, mx, my, mw, mh, masksam);
|
|
|
|
if (!nomul)
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_font_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
double sx, double sy, double sw, double sh,
|
|
int x, int y, int w, int h,
|
|
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
|
|
Eina_Bool mask_smooth, Eina_Bool mask_color,
|
|
int r, int g, int b, int a)
|
|
{
|
|
GLfloat tx1, tx2, ty1, ty2;
|
|
Shader_Sampling masksam = SHD_SAM11;
|
|
Evas_GL_Program *prog;
|
|
int pn = 0;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, SHD_FONT, NULL, 0, r, g, b, a,
|
|
sw, sh, w, h, EINA_FALSE, tex, EINA_FALSE,
|
|
mtex, mask_smooth, mask_color, mw, mh,
|
|
EINA_FALSE, NULL, NULL, &masksam);
|
|
|
|
pn = _evas_gl_common_context_push(SHD_FONT,
|
|
gc, tex, mtex,
|
|
prog,
|
|
x, y, w, h,
|
|
1,
|
|
0,
|
|
0, 0, 0, 0, 0,
|
|
mask_smooth);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = SHD_FONT;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = tex->pt->texture;
|
|
gc->pipe[pn].shader.cur_texm = mtex ? mtex->pt->texture : 0;
|
|
gc->pipe[pn].shader.smooth = 0;
|
|
gc->pipe[pn].shader.blend = 1;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.mask_smooth = mask_smooth;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = 1;
|
|
gc->pipe[pn].array.use_texuv = 1;
|
|
gc->pipe[pn].array.use_texuv2 = 0;
|
|
gc->pipe[pn].array.use_texuv3 = 0;
|
|
gc->pipe[pn].array.use_texsam = 0;
|
|
gc->pipe[pn].array.use_mask = !!mtex;
|
|
gc->pipe[pn].array.use_masksam = (masksam != SHD_SAM11);
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
if (EINA_DBL_EQ(sw, 0.0))
|
|
{
|
|
tx1 = tex->sx1;
|
|
ty1 = tex->sy1;
|
|
tx2 = tex->sx2;
|
|
ty2 = tex->sy2;
|
|
}
|
|
else
|
|
{
|
|
tx1 = ((double)(tex->x) + sx) / (double)tex->pt->w;
|
|
ty1 = ((double)(tex->y) + sy) / (double)tex->pt->h;
|
|
tx2 = ((double)(tex->x) + sx + sw) / (double)tex->pt->w;
|
|
ty2 = ((double)(tex->y) + sy + sh) / (double)tex->pt->h;
|
|
}
|
|
|
|
PUSH_6_VERTICES(pn, x, y, w, h);
|
|
PUSH_6_TEXUV(pn, tx1, ty1, tx2, ty2);
|
|
PUSH_MASK(pn, mtex, mx, my, mw, mh, masksam);
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_yuv_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
double sx, double sy, double sw, double sh,
|
|
int x, int y, int w, int h,
|
|
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
|
|
Eina_Bool mask_smooth, Eina_Bool mask_color,
|
|
int r, int g, int b, int a,
|
|
Eina_Bool smooth)
|
|
{
|
|
GLfloat tx1, tx2, ty1, ty2, t2x1, t2x2, t2y1, t2y2;
|
|
Shader_Sampling masksam = SHD_SAM11;
|
|
Eina_Bool blend = 0;
|
|
Evas_GL_Program *prog;
|
|
int pn = 0, nomul = 0;
|
|
|
|
if ((a < 255) || (!!mtex))
|
|
blend = 1;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, SHD_YUV, NULL, 0, r, g, b, a,
|
|
w, h, w, h, smooth, tex, 0,
|
|
mtex, mask_smooth, mask_color, mw, mh,
|
|
EINA_FALSE, NULL, &nomul, &masksam);
|
|
|
|
pn = _evas_gl_common_context_push(SHD_YUV,
|
|
gc, tex, mtex,
|
|
prog,
|
|
x, y, w, h,
|
|
blend,
|
|
smooth,
|
|
0, 0, 0, 0, 0,
|
|
mask_smooth);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = SHD_YUV;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = tex->pt->texture;
|
|
gc->pipe[pn].shader.cur_texu = tex->ptu->texture;
|
|
gc->pipe[pn].shader.cur_texv = tex->ptv->texture;
|
|
gc->pipe[pn].shader.cur_texm = mtex ? mtex->pt->texture : 0;
|
|
gc->pipe[pn].shader.smooth = smooth;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.mask_smooth = mask_smooth;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = !nomul;
|
|
gc->pipe[pn].array.use_texuv = 1;
|
|
gc->pipe[pn].array.use_texuv2 = 1;
|
|
gc->pipe[pn].array.use_texuv3 = 1;
|
|
gc->pipe[pn].array.use_mask = !!mtex;
|
|
gc->pipe[pn].array.use_texsam = 0;
|
|
gc->pipe[pn].array.use_masksam = (masksam != SHD_SAM11);
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
tx1 = (sx) / (double)tex->pt->w;
|
|
ty1 = (sy) / (double)tex->pt->h;
|
|
tx2 = (sx + sw) / (double)tex->pt->w;
|
|
ty2 = (sy + sh) / (double)tex->pt->h;
|
|
|
|
t2x1 = ((sx) / 2.0) / (double)tex->ptu->w;
|
|
t2y1 = ((sy) / 2.0) / (double)tex->ptu->h;
|
|
t2x2 = ((sx + sw) / 2.0) / (double)tex->ptu->w;
|
|
t2y2 = ((sy + sh) / 2.0) / (double)tex->ptu->h;
|
|
|
|
PUSH_6_VERTICES(pn, x, y, w, h);
|
|
PUSH_6_TEXUV(pn, tx1, ty1, tx2, ty2);
|
|
PUSH_6_TEXUV2(pn, t2x1, t2y1, t2x2, t2y2);
|
|
PUSH_6_TEXUV3(pn, t2x1, t2y1, t2x2, t2y2);
|
|
PUSH_MASK(pn, mtex, mx, my, mw, mh, masksam);
|
|
if (!nomul)
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_yuv_709_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
double sx, double sy, double sw, double sh,
|
|
int x, int y, int w, int h,
|
|
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
|
|
Eina_Bool mask_smooth, Eina_Bool mask_color,
|
|
int r, int g, int b, int a,
|
|
Eina_Bool smooth)
|
|
{
|
|
GLfloat tx1, tx2, ty1, ty2, t2x1, t2x2, t2y1, t2y2;
|
|
Shader_Sampling masksam = SHD_SAM11;
|
|
Eina_Bool blend = 0;
|
|
Evas_GL_Program *prog;
|
|
int pn = 0, nomul = 0;
|
|
|
|
if ((a < 255) || (!!mtex))
|
|
blend = 1;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, SHD_YUV_709, NULL, 0, r, g, b, a,
|
|
w, h, w, h, smooth, tex, 0,
|
|
mtex, mask_smooth, mask_color, mw, mh,
|
|
EINA_FALSE, NULL, &nomul, &masksam);
|
|
|
|
pn = _evas_gl_common_context_push(SHD_YUV_709,
|
|
gc, tex, mtex,
|
|
prog,
|
|
x, y, w, h,
|
|
blend,
|
|
smooth,
|
|
0, 0, 0, 0, 0,
|
|
mask_smooth);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = SHD_YUV_709;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = tex->pt->texture;
|
|
gc->pipe[pn].shader.cur_texu = tex->ptu->texture;
|
|
gc->pipe[pn].shader.cur_texv = tex->ptv->texture;
|
|
gc->pipe[pn].shader.cur_texm = mtex ? mtex->pt->texture : 0;
|
|
gc->pipe[pn].shader.smooth = smooth;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.mask_smooth = mask_smooth;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = !nomul;
|
|
gc->pipe[pn].array.use_texuv = 1;
|
|
gc->pipe[pn].array.use_texuv2 = 1;
|
|
gc->pipe[pn].array.use_texuv3 = 1;
|
|
gc->pipe[pn].array.use_mask = !!mtex;
|
|
gc->pipe[pn].array.use_texsam = 0;
|
|
gc->pipe[pn].array.use_masksam = (masksam != SHD_SAM11);
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
tx1 = (sx) / (double)tex->pt->w;
|
|
ty1 = (sy) / (double)tex->pt->h;
|
|
tx2 = (sx + sw) / (double)tex->pt->w;
|
|
ty2 = (sy + sh) / (double)tex->pt->h;
|
|
|
|
t2x1 = ((sx) / 2.0) / (double)tex->ptu->w;
|
|
t2y1 = ((sy) / 2.0) / (double)tex->ptu->h;
|
|
t2x2 = ((sx + sw) / 2.0) / (double)tex->ptu->w;
|
|
t2y2 = ((sy + sh) / 2.0) / (double)tex->ptu->h;
|
|
|
|
PUSH_6_VERTICES(pn, x, y, w, h);
|
|
PUSH_6_TEXUV(pn, tx1, ty1, tx2, ty2);
|
|
PUSH_6_TEXUV2(pn, t2x1, t2y1, t2x2, t2y2);
|
|
PUSH_6_TEXUV3(pn, t2x1, t2y1, t2x2, t2y2);
|
|
PUSH_MASK(pn, mtex, mx, my, mw, mh, masksam);
|
|
if (!nomul)
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_yuy2_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
double sx, double sy, double sw, double sh,
|
|
int x, int y, int w, int h,
|
|
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
|
|
Eina_Bool mask_smooth, Eina_Bool mask_color,
|
|
int r, int g, int b, int a,
|
|
Eina_Bool smooth)
|
|
{
|
|
GLfloat tx1, tx2, ty1, ty2, t2x1, t2x2, t2y1, t2y2;
|
|
Shader_Sampling masksam = SHD_SAM11;
|
|
Eina_Bool blend = 0;
|
|
Evas_GL_Program *prog;
|
|
int pn = 0, nomul = 0;
|
|
|
|
if ((a < 255) || (!!mtex))
|
|
blend = 1;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, SHD_YUY2, NULL, 0, r, g, b, a,
|
|
sw, sh, w, h, smooth, tex, 0,
|
|
mtex, mask_smooth, mask_color, mw, mh,
|
|
EINA_FALSE, NULL, &nomul, &masksam);
|
|
|
|
pn = _evas_gl_common_context_push(SHD_YUY2,
|
|
gc, tex, mtex,
|
|
prog,
|
|
x, y, w, h,
|
|
blend,
|
|
smooth,
|
|
0, 0, 0, 0, 0,
|
|
mask_smooth);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = SHD_YUY2;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = tex->pt->texture;
|
|
gc->pipe[pn].shader.cur_texu = tex->ptuv->texture;
|
|
gc->pipe[pn].shader.cur_texm = mtex ? mtex->pt->texture : 0;
|
|
gc->pipe[pn].shader.smooth = smooth;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.mask_smooth = mask_smooth;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = !nomul;
|
|
gc->pipe[pn].array.use_texuv = 1;
|
|
gc->pipe[pn].array.use_texuv2 = 1;
|
|
gc->pipe[pn].array.use_texuv3 = 0;
|
|
gc->pipe[pn].array.use_mask = !!mtex;
|
|
gc->pipe[pn].array.use_texsam = 0;
|
|
gc->pipe[pn].array.use_masksam = (masksam != SHD_SAM11);
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
tx1 = (sx) / (double)tex->pt->w;
|
|
ty1 = (sy) / (double)tex->pt->h;
|
|
tx2 = (sx + sw) / (double)tex->pt->w;
|
|
ty2 = (sy + sh) / (double)tex->pt->h;
|
|
|
|
t2x1 = sx / (double)tex->ptuv->w;
|
|
t2y1 = sy / (double)tex->ptuv->h;
|
|
t2x2 = (sx + sw) / (double)tex->ptuv->w;
|
|
t2y2 = (sy + sh) / (double)tex->ptuv->h;
|
|
|
|
PUSH_6_VERTICES(pn, x, y, w, h);
|
|
PUSH_6_TEXUV(pn, tx1, ty1, tx2, ty2);
|
|
PUSH_6_TEXUV2(pn, t2x1, t2y1, t2x2, t2y2);
|
|
PUSH_MASK(pn, mtex, mx, my, mw, mh, masksam);
|
|
if (!nomul)
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_nv12_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
double sx, double sy, double sw, double sh,
|
|
int x, int y, int w, int h,
|
|
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
|
|
Eina_Bool mask_smooth, Eina_Bool mask_color,
|
|
int r, int g, int b, int a,
|
|
Eina_Bool smooth)
|
|
{
|
|
GLfloat tx1, tx2, ty1, ty2, t2x1, t2x2, t2y1, t2y2;
|
|
Shader_Sampling masksam = SHD_SAM11;
|
|
Eina_Bool blend = 0;
|
|
Evas_GL_Program *prog;
|
|
int pn = 0, nomul = 0;
|
|
|
|
if ((a < 255) || (!!mtex))
|
|
blend = 1;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, SHD_NV12, NULL, 0, r, g, b, a,
|
|
sw, sh, w, h, smooth, tex, 0,
|
|
mtex, mask_smooth, mask_color, mw, mh,
|
|
EINA_FALSE, NULL, &nomul, &masksam);
|
|
|
|
pn = _evas_gl_common_context_push(SHD_NV12,
|
|
gc, tex, mtex,
|
|
prog,
|
|
x, y, w, h,
|
|
blend,
|
|
smooth,
|
|
0, 0, 0, 0, 0,
|
|
mask_smooth);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = SHD_NV12;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = tex->pt->texture;
|
|
gc->pipe[pn].shader.cur_tex_dyn = tex->pt->dyn.img;
|
|
gc->pipe[pn].shader.cur_texu = tex->ptuv->texture;
|
|
gc->pipe[pn].shader.cur_texu_dyn = tex->ptuv->dyn.img;
|
|
gc->pipe[pn].shader.cur_texm = mtex ? mtex->pt->texture : 0;
|
|
gc->pipe[pn].shader.smooth = smooth;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.mask_smooth = mask_smooth;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = !nomul;
|
|
gc->pipe[pn].array.use_texuv = 1;
|
|
gc->pipe[pn].array.use_texuv2 = 1;
|
|
gc->pipe[pn].array.use_texuv3 = 0;
|
|
gc->pipe[pn].array.use_mask = !!mtex;
|
|
gc->pipe[pn].array.use_texsam = 0;
|
|
gc->pipe[pn].array.use_masksam = (masksam != SHD_SAM11);
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
tx1 = (sx) / (double)tex->pt->w;
|
|
ty1 = (sy) / (double)tex->pt->h;
|
|
tx2 = (sx + sw) / (double)tex->pt->w;
|
|
ty2 = (sy + sh) / (double)tex->pt->h;
|
|
|
|
t2x1 = sx / (double)tex->ptuv->w;
|
|
t2y1 = sy / (double)tex->ptuv->h;
|
|
t2x2 = (sx + sw) / (double)tex->ptuv->w;
|
|
t2y2 = (sy + sh) / (double)tex->ptuv->h;
|
|
|
|
PUSH_6_VERTICES(pn, x, y, w, h);
|
|
PUSH_6_TEXUV(pn, tx1, ty1, tx2, ty2);
|
|
PUSH_6_TEXUV2(pn, t2x1, t2y1, t2x2, t2y2);
|
|
PUSH_MASK(pn, mtex, mx, my, mw, mh, masksam);
|
|
if (!nomul)
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_rgb_a_pair_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
double sx, double sy,
|
|
double sw, double sh,
|
|
int x, int y, int w, int h,
|
|
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
|
|
Eina_Bool mask_smooth, Eina_Bool mask_color,
|
|
int r, int g, int b, int a,
|
|
Eina_Bool smooth)
|
|
|
|
{
|
|
/* This RGB+Alpha mode is used for ETC1+Alpha textures, where the shader
|
|
* will multiply RGB by alpha. Two textures are created: tex->{pt,pta}.
|
|
* Since the exact encoding doesn't matter here (decoding is transparent
|
|
* from the shader point of view), this method could be used for other
|
|
* colorspaces as well (eg. RGB565+Alpha4, ...).
|
|
*/
|
|
|
|
GLfloat tx1, tx2, ty1, ty2, t2x1, t2x2, t2y1, t2y2;
|
|
Shader_Sampling masksam = SHD_SAM11;
|
|
Evas_GL_Program *prog;
|
|
int pn, nomul = 0;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, SHD_RGB_A_PAIR, NULL, 0, r, g, b, a,
|
|
sw, sh, w, h, smooth, tex, 0,
|
|
mtex, mask_smooth, mask_color, mw, mh,
|
|
EINA_FALSE, NULL, &nomul, &masksam);
|
|
|
|
pn = _evas_gl_common_context_push(SHD_RGB_A_PAIR,
|
|
gc, tex, mtex,
|
|
prog,
|
|
x, y, w, h,
|
|
EINA_TRUE,
|
|
smooth,
|
|
EINA_FALSE, 0, 0, 0, 0,
|
|
mask_smooth);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = SHD_RGB_A_PAIR;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = tex->pt->texture;
|
|
gc->pipe[pn].shader.cur_texa = tex->pta->texture;
|
|
gc->pipe[pn].shader.cur_texm = mtex ? mtex->pt->texture : 0;
|
|
gc->pipe[pn].shader.smooth = smooth;
|
|
gc->pipe[pn].shader.blend = EINA_TRUE;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.mask_smooth = mask_smooth;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = EINA_TRUE;
|
|
gc->pipe[pn].array.use_color = !nomul;
|
|
gc->pipe[pn].array.use_texuv = EINA_TRUE;
|
|
gc->pipe[pn].array.use_texuv2 = 0;
|
|
gc->pipe[pn].array.use_texuv3 = 0;
|
|
gc->pipe[pn].array.use_texa = EINA_TRUE;
|
|
gc->pipe[pn].array.use_texsam = 0;
|
|
gc->pipe[pn].array.use_mask = !!mtex;
|
|
gc->pipe[pn].array.use_masksam = (masksam != SHD_SAM11);
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
// FIXME: pt and pta could have different x,y
|
|
tx1 = (tex->x + sx) / (double)tex->pt->w;
|
|
ty1 = (tex->y + sy) / (double)tex->pt->h;
|
|
tx2 = (tex->x + sx + sw) / (double)tex->pt->w;
|
|
ty2 = (tex->y + sy + sh) / (double)tex->pt->h;
|
|
|
|
t2x1 = (tex->x + sx) / (double)tex->pta->w;
|
|
t2y1 = (tex->y + sy) / (double)tex->pta->h;
|
|
t2x2 = (tex->x + sx + sw) / (double)tex->pta->w;
|
|
t2y2 = (tex->y + sy + sh) / (double)tex->pta->h;
|
|
|
|
PUSH_6_VERTICES(pn, x, y, w, h);
|
|
PUSH_6_TEXUV(pn, tx1, ty1, tx2, ty2);
|
|
PUSH_6_TEXA(pn, t2x1, t2y1, t2x2, t2y2);
|
|
PUSH_MASK(pn, mtex, mx, my, mw, mh, masksam);
|
|
if (!nomul)
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_context_image_map_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
int npoints,
|
|
RGBA_Map_Point *p,
|
|
int clip, int cx, int cy, int cw, int ch,
|
|
Evas_GL_Texture *mtex, int mx, int my, int mw, int mh,
|
|
Eina_Bool mask_smooth, Eina_Bool mask_color,
|
|
int r, int g, int b, int a,
|
|
Eina_Bool smooth, Eina_Bool tex_only,
|
|
Evas_Colorspace cspace)
|
|
{
|
|
const int points[6] = { 0, 1, 2, 0, 2, 3 };
|
|
int x = 0, y = 0, w = 0, h = 0, px = 0, py = 0;
|
|
GLfloat tx[4], ty[4], t2x[4], t2y[4];
|
|
DATA32 cmul;
|
|
Shader_Sampling masksam = SHD_SAM11;
|
|
Evas_GL_Program *prog;
|
|
Eina_Bool utexture = EINA_FALSE;
|
|
Eina_Bool uvtexture = EINA_FALSE;
|
|
Eina_Bool use_texa = EINA_FALSE;
|
|
Shader_Type type;
|
|
int pn = 0, i;
|
|
int nomul = 0, yinvert = 0;
|
|
Eina_Bool flat = EINA_FALSE;
|
|
Eina_Bool blend = EINA_FALSE;
|
|
|
|
if (!(gc->dc->render_op == EVAS_RENDER_COPY) &&
|
|
((a < 255) || (tex->alpha) || (!!mtex))) blend = EINA_TRUE;
|
|
|
|
if ((A_VAL(&(p[0].col)) < 0xff) || (A_VAL(&(p[1].col)) < 0xff) ||
|
|
(A_VAL(&(p[2].col)) < 0xff) || (A_VAL(&(p[3].col)) < 0xff))
|
|
blend = EINA_TRUE;
|
|
|
|
if (((p[0].z == p[1].z) && (p[1].z == p[2].z) && (p[2].z == p[3].z)) ||
|
|
(p[0].foc <= 0))
|
|
{
|
|
flat = EINA_TRUE;
|
|
}
|
|
|
|
if (!clip) cx = cy = cw = ch = 0;
|
|
|
|
switch (cspace)
|
|
{
|
|
case EVAS_COLORSPACE_YCBCR422P601_PL:
|
|
type = SHD_YUV;
|
|
utexture = EINA_TRUE;
|
|
break;
|
|
case EVAS_COLORSPACE_YCBCR422P709_PL:
|
|
type = SHD_YUV_709;
|
|
utexture = EINA_TRUE;
|
|
break;
|
|
case EVAS_COLORSPACE_YCBCR422601_PL:
|
|
type = SHD_YUY2;
|
|
uvtexture = EINA_TRUE;
|
|
break;
|
|
case EVAS_COLORSPACE_YCBCR420NV12601_PL:
|
|
case EVAS_COLORSPACE_YCBCR420TM12601_PL:
|
|
type = SHD_NV12;
|
|
uvtexture = EINA_TRUE;
|
|
break;
|
|
case EVAS_COLORSPACE_ETC1_ALPHA:
|
|
type = SHD_RGB_A_PAIR;
|
|
use_texa = EINA_TRUE;
|
|
break;
|
|
default:
|
|
type = SHD_MAP;
|
|
break;
|
|
}
|
|
prog = evas_gl_common_shader_program_get(gc, type, p, npoints, r, g, b, a,
|
|
w, h, w, h, smooth, tex, tex_only,
|
|
mtex, mask_smooth, mask_color, mw, mh,
|
|
EINA_FALSE, NULL, &nomul, &masksam);
|
|
|
|
x = w = (p[0].x >> FP);
|
|
y = h = (p[0].y >> FP);
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
tx[i] = ((double)(tex->x) + (((double)p[i].u) / FP1)) /
|
|
(double)tex->pt->w;
|
|
ty[i] = ((double)(tex->y) + (((double)p[i].v) / FP1)) /
|
|
(double)tex->pt->h;
|
|
px = (p[i].x >> FP);
|
|
if (px < x) x = px;
|
|
else if (px > w) w = px;
|
|
py = (p[i].y >> FP);
|
|
if (py < y) y = py;
|
|
else if (py > h) h = py;
|
|
if (utexture)
|
|
{
|
|
t2x[i] = ((((double)p[i].u / 2) / FP1)) / (double)tex->ptu->w;
|
|
t2y[i] = ((((double)p[i].v / 2) / FP1)) / (double)tex->ptu->h;
|
|
}
|
|
else if (uvtexture)
|
|
{
|
|
t2x[i] = ((((double)p[i].u / 2) / FP1)) / (double)tex->ptuv->w;
|
|
t2y[i] = ((((double)p[i].v / 2) / FP1)) / (double)tex->ptuv->h;
|
|
}
|
|
}
|
|
w = w - x;
|
|
h = h - y;
|
|
|
|
// FUZZZZ!
|
|
x -= 3;
|
|
y -= 3;
|
|
w += 6;
|
|
h += 6;
|
|
|
|
if (!flat)
|
|
{
|
|
shader_array_flush(gc);
|
|
gc->foc = p[0].foc >> FP;
|
|
gc->z0 = p[0].z0 >> FP;
|
|
gc->px = p[0].px >> FP;
|
|
gc->py = p[0].py >> FP;
|
|
gc->change.size = 1;
|
|
_evas_gl_common_viewport_set(gc);
|
|
}
|
|
else if (clip)
|
|
{
|
|
int nx = x, ny = y, nw = w, nh = h;
|
|
|
|
RECTS_CLIP_TO_RECT(nx, ny, nw, nh, cx, cy, cw, ch);
|
|
if ((nx == x) && (ny == y) && (nw == w) && (nh == h))
|
|
{
|
|
clip = 0; cx = 0; cy = 0; cw = 0; ch = 0;
|
|
}
|
|
x = nx; y = ny; w = nw; h = nh;
|
|
}
|
|
|
|
pn = _evas_gl_common_context_push(SHD_MAP,
|
|
gc, tex, mtex,
|
|
prog,
|
|
x, y, w, h,
|
|
blend,
|
|
smooth,
|
|
clip, cx, cy, cw, ch,
|
|
mask_smooth);
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = SHD_MAP;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = tex->pt->texture;
|
|
gc->pipe[pn].shader.tex_target = GL_TEXTURE_2D;
|
|
|
|
if (utexture)
|
|
{
|
|
gc->pipe[pn].shader.cur_texu = tex->ptu->texture;
|
|
gc->pipe[pn].shader.cur_texu_dyn = tex->ptu->dyn.img;
|
|
gc->pipe[pn].shader.cur_texv = tex->ptv->texture;
|
|
gc->pipe[pn].shader.cur_texv_dyn = tex->ptv->dyn.img;
|
|
}
|
|
else if (uvtexture)
|
|
{
|
|
gc->pipe[pn].shader.cur_texu = tex->ptuv->texture;
|
|
gc->pipe[pn].shader.cur_texu_dyn = tex->ptuv->dyn.img;
|
|
}
|
|
gc->pipe[pn].shader.cur_texm = mtex ? mtex->pt->texture : 0;
|
|
gc->pipe[pn].shader.smooth = smooth;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.mask_smooth = mask_smooth;
|
|
gc->pipe[pn].shader.clip = clip;
|
|
gc->pipe[pn].shader.cx = cx;
|
|
gc->pipe[pn].shader.cy = cy;
|
|
gc->pipe[pn].shader.cw = cw;
|
|
gc->pipe[pn].shader.ch = ch;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = !nomul;
|
|
gc->pipe[pn].array.use_texuv = 1;
|
|
gc->pipe[pn].array.use_texuv2 = (utexture || uvtexture) ? 1 : 0;
|
|
gc->pipe[pn].array.use_texuv3 = (utexture) ? 1 : 0;
|
|
gc->pipe[pn].array.use_mask = !!mtex;
|
|
gc->pipe[pn].array.use_texa = use_texa;
|
|
gc->pipe[pn].array.use_texsam = 0;
|
|
gc->pipe[pn].array.use_masksam = (masksam != SHD_SAM11);
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
if ((tex->im) && (tex->im->native.data))
|
|
{
|
|
if (tex->im->native.func.yinvert)
|
|
yinvert = tex->im->native.func.yinvert(tex->im);
|
|
else
|
|
yinvert = tex->im->native.yinvert;
|
|
}
|
|
|
|
if ((tex->im) && (tex->im->native.data) && (!yinvert))
|
|
{
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
ty[i] = 1.0 - ty[i];
|
|
if (utexture || uvtexture)
|
|
t2y[i] = 1.0 - t2y[i];
|
|
}
|
|
}
|
|
|
|
cmul = ARGB_JOIN(a, r, g, b);
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
DATA32 cl = MUL4_SYM(cmul, p[points[i]].col);
|
|
if (flat)
|
|
{
|
|
PUSH_VERTEX(pn,
|
|
p[points[i]].fx,
|
|
p[points[i]].fy,
|
|
0);
|
|
}
|
|
else
|
|
{
|
|
PUSH_VERTEX(pn,
|
|
(p[points[i]].fx) + gc->shared->ax,
|
|
(p[points[i]].fy) + gc->shared->ay,
|
|
(p[points[i]].fz)
|
|
+ (gc->shared->foc - gc->shared->z0));
|
|
}
|
|
PUSH_TEXUV(pn,
|
|
tx[points[i]],
|
|
ty[points[i]]);
|
|
if (utexture)
|
|
{
|
|
PUSH_TEXUV2(pn,
|
|
t2x[points[i]],
|
|
t2y[points[i]]);
|
|
PUSH_TEXUV3(pn,
|
|
t2x[points[i]],
|
|
t2y[points[i]]);
|
|
}
|
|
else if (uvtexture)
|
|
{
|
|
PUSH_TEXUV2(pn,
|
|
t2x[points[i]],
|
|
t2y[points[i]]);
|
|
}
|
|
|
|
if (!nomul)
|
|
{
|
|
PUSH_COLOR(pn,
|
|
R_VAL(&cl),
|
|
G_VAL(&cl),
|
|
B_VAL(&cl),
|
|
A_VAL(&cl));
|
|
}
|
|
}
|
|
|
|
PUSH_MASK(pn, mtex, mx, my, mw, mh, masksam);
|
|
|
|
if (!flat)
|
|
{
|
|
shader_array_flush(gc);
|
|
gc->foc = 0;
|
|
gc->z0 = 0;
|
|
gc->px = 0;
|
|
gc->py = 0;
|
|
gc->change.size = 1;
|
|
_evas_gl_common_viewport_set(gc);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Gfx Filters
|
|
|
|
static inline void
|
|
_filter_data_flush(Evas_Engine_GL_Context *gc, Evas_GL_Program *prog)
|
|
{
|
|
// filter_data is not using a vertex array, which means early flushes
|
|
// are necessary. Vertex arrays crashed for whatever reason :(
|
|
for (size_t k = 0; k < MAX_PIPES; k++)
|
|
if ((gc->pipe[k].array.filter_data || gc->pipe[k].shader.filter.map_tex)
|
|
&& (gc->pipe[k].shader.prog == prog))
|
|
{
|
|
shader_array_flush(gc);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
_filter_data_alloc(Evas_Engine_GL_Context *gc, int pn, int count)
|
|
{
|
|
gc->pipe[pn].array.filter_data_count = count;
|
|
if (count) gc->pipe[pn].array.filter_data = malloc(count * 2 * sizeof(GLfloat));
|
|
else gc->pipe[pn].array.filter_data = NULL;
|
|
}
|
|
|
|
static inline void
|
|
_filter_data_prepare(Evas_Engine_GL_Context *gc EINA_UNUSED,
|
|
Evas_GL_Program *prog, int count)
|
|
{
|
|
if (!prog->filter) prog->filter = calloc(1, sizeof(*prog->filter));
|
|
if (!prog->filter->attribute.known_locations)
|
|
{
|
|
prog->filter->attribute.known_locations = EINA_TRUE;
|
|
for (int k = 0; k < count; k++)
|
|
{
|
|
char name[32];
|
|
|
|
sprintf(name, "filter_data_%d", k);
|
|
prog->filter->attribute.loc[k] = glGetAttribLocation(prog->prog, name);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
evas_gl_common_filter_displace_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex, Evas_GL_Texture *map_tex,
|
|
int x, int y, int w, int h, double dx, double dy,
|
|
Eina_Bool nearest)
|
|
{
|
|
double sx, sy, sw, sh, pw, ph;
|
|
double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4;
|
|
GLfloat tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4;
|
|
Shader_Sampling sam = SHD_SAM11;
|
|
GLfloat offsetx, offsety;
|
|
GLfloat *filter_data;
|
|
int r, g, b, a, nomul = 0, pn;
|
|
Evas_GL_Program *prog;
|
|
Eina_Bool blend = EINA_TRUE;
|
|
Eina_Bool smooth = EINA_TRUE;
|
|
|
|
r = R_VAL(&gc->dc->mul.col);
|
|
g = G_VAL(&gc->dc->mul.col);
|
|
b = B_VAL(&gc->dc->mul.col);
|
|
a = A_VAL(&gc->dc->mul.col);
|
|
if (gc->dc->render_op == EVAS_RENDER_COPY)
|
|
blend = EINA_FALSE;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, SHD_FILTER_DISPLACE, NULL, 0, r, g, b, a,
|
|
w, h, w, h, smooth, tex, EINA_FALSE,
|
|
NULL, EINA_FALSE, EINA_FALSE, 0, 0,
|
|
EINA_FALSE, &sam, &nomul, NULL);
|
|
_filter_data_flush(gc, prog);
|
|
|
|
pn = _evas_gl_common_context_push(SHD_FILTER_DISPLACE, gc, tex, NULL, prog,
|
|
x, y, w, h, blend, smooth,
|
|
0, 0, 0, 0, 0, EINA_FALSE);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = SHD_FILTER_DISPLACE;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = tex->pt->texture;
|
|
gc->pipe[pn].shader.cur_texm = 0;
|
|
gc->pipe[pn].shader.tex_target = GL_TEXTURE_2D;
|
|
gc->pipe[pn].shader.smooth = smooth;
|
|
gc->pipe[pn].shader.mask_smooth = 0;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = !nomul;
|
|
gc->pipe[pn].array.use_texuv = 1;
|
|
gc->pipe[pn].array.use_texuv2 = 0;
|
|
gc->pipe[pn].array.use_texuv3 = 0;
|
|
gc->pipe[pn].array.use_texsam = (sam != SHD_SAM11);
|
|
gc->pipe[pn].array.use_mask = 0;
|
|
gc->pipe[pn].array.use_masksam = 0;
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
// displace properties
|
|
gc->pipe[pn].shader.filter.map_tex = map_tex->pt->texture;
|
|
gc->pipe[pn].shader.filter.map_nearest = nearest;
|
|
_filter_data_prepare(gc, prog, 3);
|
|
_filter_data_alloc(gc, pn, 3);
|
|
|
|
sx = x;
|
|
sy = y;
|
|
sw = w;
|
|
sh = h;
|
|
|
|
pw = tex->pt->w;
|
|
ph = tex->pt->h;
|
|
|
|
ox1 = sx;
|
|
oy1 = sy;
|
|
ox2 = sx + sw;
|
|
oy2 = sy;
|
|
ox3 = sx + sw;
|
|
oy3 = sy + sh;
|
|
ox4 = sx;
|
|
oy4 = sy + sh;
|
|
|
|
offsetx = tex->x;
|
|
offsety = tex->y;
|
|
|
|
tx1 = ((double)(offsetx) + ox1) / pw;
|
|
ty1 = ((double)(offsety) + oy1) / ph;
|
|
tx2 = ((double)(offsetx) + ox2) / pw;
|
|
ty2 = ((double)(offsety) + oy2) / ph;
|
|
tx3 = ((double)(offsetx) + ox3) / pw;
|
|
ty3 = ((double)(offsety) + oy3) / ph;
|
|
tx4 = ((double)(offsetx) + ox4) / pw;
|
|
ty4 = ((double)(offsety) + oy4) / ph;
|
|
|
|
PUSH_6_VERTICES(pn, x, y, w, h);
|
|
PUSH_6_QUAD(pn, tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4);
|
|
|
|
if (sam)
|
|
{
|
|
double samx = (double)(sw) / (double)(tex->pt->w * w * 4);
|
|
double samy = (double)(sh) / (double)(tex->pt->h * h * 4);
|
|
PUSH_SAMPLES(pn, samx, samy);
|
|
}
|
|
|
|
filter_data = gc->pipe[pn].array.filter_data;
|
|
filter_data[0] = (dx * tex->w / pw) / w;
|
|
filter_data[1] = (dy * tex->h / ph) / h;
|
|
filter_data[2] = tex->x / pw;
|
|
filter_data[3] = tex->y / ph;
|
|
filter_data[4] = (tex->x + tex->w) / pw;
|
|
filter_data[5] = (tex->y + tex->h) / ph;
|
|
|
|
if (!nomul)
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_filter_curve_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
int x, int y, int w, int h,
|
|
const uint8_t *points, int channel)
|
|
{
|
|
double sx, sy, sw, sh, pw, ph;
|
|
double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4;
|
|
GLfloat tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4;
|
|
Shader_Sampling sam = SHD_SAM11;
|
|
GLfloat offsetx, offsety;
|
|
int r, g, b, a, nomul = 0, pn, k;
|
|
uint32_t values[256];
|
|
Evas_GL_Program *prog;
|
|
Eina_Bool blend = EINA_TRUE;
|
|
Eina_Bool smooth = EINA_TRUE;
|
|
GLuint map_tex;
|
|
|
|
r = R_VAL(&gc->dc->mul.col);
|
|
g = G_VAL(&gc->dc->mul.col);
|
|
b = B_VAL(&gc->dc->mul.col);
|
|
a = A_VAL(&gc->dc->mul.col);
|
|
if (gc->dc->render_op == EVAS_RENDER_COPY)
|
|
blend = EINA_FALSE;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, SHD_FILTER_CURVE, NULL, 0, r, g, b, a,
|
|
w, h, w, h, smooth, tex, EINA_FALSE,
|
|
NULL, EINA_FALSE, EINA_FALSE, 0, 0,
|
|
EINA_FALSE, &sam, &nomul, NULL);
|
|
_filter_data_flush(gc, prog);
|
|
|
|
pn = _evas_gl_common_context_push(SHD_FILTER_CURVE, gc, tex, NULL, prog,
|
|
x, y, w, h, blend, smooth,
|
|
0, 0, 0, 0, 0, EINA_FALSE);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = SHD_FILTER_CURVE;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = tex->pt->texture;
|
|
gc->pipe[pn].shader.cur_texm = 0;
|
|
gc->pipe[pn].shader.tex_target = GL_TEXTURE_2D;
|
|
gc->pipe[pn].shader.smooth = smooth;
|
|
gc->pipe[pn].shader.mask_smooth = 0;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = !nomul;
|
|
gc->pipe[pn].array.use_texuv = 1;
|
|
gc->pipe[pn].array.use_texuv2 = 0;
|
|
gc->pipe[pn].array.use_texuv3 = 0;
|
|
gc->pipe[pn].array.use_texsam = (sam != SHD_SAM11);
|
|
gc->pipe[pn].array.use_mask = 0;
|
|
gc->pipe[pn].array.use_masksam = 0;
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
// Build 256 colors map in RGBA
|
|
switch (channel)
|
|
{
|
|
case 0: // EVAS_FILTER_CHANNEL_ALPHA
|
|
for (k = 0; k < 256; k++)
|
|
values[k] = ARGB_JOIN(points[k], k, k, k);
|
|
break;
|
|
case 1: // EVAS_FILTER_CHANNEL_RED
|
|
for (k = 0; k < 256; k++)
|
|
values[k] = ARGB_JOIN(k, points[k], k, k);
|
|
break;
|
|
case 2: // EVAS_FILTER_CHANNEL_GREEN
|
|
for (k = 0; k < 256; k++)
|
|
values[k] = ARGB_JOIN(k, k, points[k], k);
|
|
break;
|
|
case 3: // EVAS_FILTER_CHANNEL_BLUE
|
|
for (k = 0; k < 256; k++)
|
|
values[k] = ARGB_JOIN(k, k, k, points[k]);
|
|
break;
|
|
case 4: // EVAS_FILTER_CHANNEL_RGB
|
|
for (k = 0; k < 256; k++)
|
|
values[k] = ARGB_JOIN(k, points[k], points[k], points[k]);
|
|
break;
|
|
case 5: // ALPHA only
|
|
for (k = 0; k < 256; k++)
|
|
values[k] = ARGB_JOIN(points[k], points[k], points[k], points[k]);
|
|
break;
|
|
default: // INVALID: no curve applied
|
|
for (k = 0; k < 256; k++)
|
|
values[k] = ARGB_JOIN(k, k, k, k);
|
|
break;
|
|
}
|
|
|
|
// Synchronous upload of 256x1 RGBA texture (FIXME: no reuse)
|
|
glGenTextures(1, &map_tex);
|
|
glBindTexture(GL_TEXTURE_2D, map_tex);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, values);
|
|
|
|
// Set curve properties (no need for filter_data)
|
|
gc->pipe[pn].shader.filter.map_tex = map_tex;
|
|
gc->pipe[pn].shader.filter.map_nearest = EINA_TRUE;
|
|
gc->pipe[pn].shader.filter.map_delete = EINA_TRUE;
|
|
gc->pipe[pn].array.filter_data_count = 0;
|
|
|
|
sx = x;
|
|
sy = y;
|
|
sw = w;
|
|
sh = h;
|
|
|
|
pw = tex->pt->w;
|
|
ph = tex->pt->h;
|
|
|
|
ox1 = sx;
|
|
oy1 = sy;
|
|
ox2 = sx + sw;
|
|
oy2 = sy;
|
|
ox3 = sx + sw;
|
|
oy3 = sy + sh;
|
|
ox4 = sx;
|
|
oy4 = sy + sh;
|
|
|
|
offsetx = tex->x;
|
|
offsety = tex->y;
|
|
|
|
tx1 = ((double)(offsetx) + ox1) / pw;
|
|
ty1 = ((double)(offsety) + oy1) / ph;
|
|
tx2 = ((double)(offsetx) + ox2) / pw;
|
|
ty2 = ((double)(offsety) + oy2) / ph;
|
|
tx3 = ((double)(offsetx) + ox3) / pw;
|
|
ty3 = ((double)(offsety) + oy3) / ph;
|
|
tx4 = ((double)(offsetx) + ox4) / pw;
|
|
ty4 = ((double)(offsety) + oy4) / ph;
|
|
|
|
PUSH_6_VERTICES(pn, x, y, w, h);
|
|
PUSH_6_QUAD(pn, tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4);
|
|
|
|
if (sam)
|
|
{
|
|
double samx = (double)(sw) / (double)(tex->pt->w * w * 4);
|
|
double samy = (double)(sh) / (double)(tex->pt->h * h * 4);
|
|
PUSH_SAMPLES(pn, samx, samy);
|
|
}
|
|
|
|
if (!nomul)
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_filter_blend_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
double sx, double sy, double sw, double sh,
|
|
double dx, double dy, double dw, double dh,
|
|
Eina_Bool alphaonly)
|
|
{
|
|
int r, g, b, a;
|
|
|
|
r = R_VAL(&gc->dc->mul.col);
|
|
g = G_VAL(&gc->dc->mul.col);
|
|
b = B_VAL(&gc->dc->mul.col);
|
|
a = A_VAL(&gc->dc->mul.col);
|
|
if (alphaonly)
|
|
r = g = b = a;
|
|
|
|
evas_gl_common_context_image_push(gc, tex, sx, sy, sw, sh, dx, dy, dw, dh,
|
|
NULL, 0, 0, 0, 0, EINA_FALSE, EINA_FALSE,
|
|
r, g, b, a, EINA_TRUE, EINA_FALSE,
|
|
alphaonly);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_filter_blur_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
double sx, double sy, double sw, double sh,
|
|
double dx, double dy, double dw, double dh,
|
|
const double * const weights,
|
|
const double * const offsets, int count,
|
|
double radius, Eina_Bool horiz, Eina_Bool alphaonly)
|
|
{
|
|
double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4, pw, ph, texlen;
|
|
GLfloat tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4;
|
|
GLfloat offsetx, offsety;
|
|
int r, g, b, a, nomul = 0, pn;
|
|
Evas_GL_Program *prog;
|
|
Eina_Bool blend = EINA_TRUE;
|
|
Eina_Bool smooth = EINA_TRUE;
|
|
Shader_Type type = horiz ? SHD_FILTER_BLUR_X : SHD_FILTER_BLUR_Y;
|
|
Eina_Bool update_uniforms = EINA_FALSE;
|
|
GLuint *map_tex_data;
|
|
double sum = 0.0;
|
|
|
|
r = R_VAL(&gc->dc->mul.col);
|
|
g = G_VAL(&gc->dc->mul.col);
|
|
b = B_VAL(&gc->dc->mul.col);
|
|
a = A_VAL(&gc->dc->mul.col);
|
|
if (gc->dc->render_op == EVAS_RENDER_COPY)
|
|
blend = EINA_FALSE;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, type, NULL, 0, r, g, b, a,
|
|
sw, sh, dw, dh, smooth, tex, EINA_FALSE,
|
|
NULL, EINA_FALSE, EINA_FALSE, 0, 0,
|
|
alphaonly, NULL, &nomul, NULL);
|
|
|
|
_filter_data_flush(gc, prog);
|
|
EINA_SAFETY_ON_NULL_RETURN(prog);
|
|
|
|
pw = tex->pt->w;
|
|
ph = tex->pt->h;
|
|
texlen = horiz ? pw : ph;
|
|
|
|
/* Convert double data to RGBA pixel data.
|
|
*
|
|
* We are not using GL_FLOAT or GL_DOUBLE because:
|
|
* - It's not as portable (needs extensions),
|
|
* - GL_DOUBLE didn't work during my tests (dunno why),
|
|
* - GL_FLOAT didn't seem to carry the proper precision all the way to
|
|
* the fragment shader,
|
|
* - Real data buffers are not available in GLES 2.0,
|
|
* - GL_RGBA is 100% portable.
|
|
*/
|
|
map_tex_data = alloca(2 * count * sizeof(*map_tex_data));
|
|
for (int k = 0; k < count; k++)
|
|
{
|
|
GLuint val;
|
|
|
|
if (k == 0) sum = weights[k];
|
|
else sum += 2.0 * weights[k];
|
|
|
|
// Weight is always > 0.0 and < 255.0 by maths
|
|
val = (GLuint) (weights[k] * 256.0 * 256.0 * 256.0);
|
|
map_tex_data[k] = val;
|
|
|
|
// Offset is always in [0.0 , 1.0] by definition
|
|
val = (GLuint) (offsets[k] * 256.0 * 256.0 * 256.0);
|
|
map_tex_data[k + count] = val;
|
|
}
|
|
|
|
// Prepare attributes & uniforms
|
|
_filter_data_prepare(gc, prog, 0);
|
|
if (!prog->filter->uniform.known_locations)
|
|
{
|
|
prog->filter->uniform.known_locations = EINA_TRUE;
|
|
prog->filter->uniform.blur_count_loc = glGetUniformLocation(prog->prog, "blur_count");
|
|
prog->filter->uniform.blur_texlen_loc = glGetUniformLocation(prog->prog, "blur_texlen");
|
|
prog->filter->uniform.blur_div_loc = glGetUniformLocation(prog->prog, "blur_div");
|
|
}
|
|
|
|
if ((prog->filter->uniform.blur_count_value != count - 1) ||
|
|
(!EINA_FLT_EQ(prog->filter->uniform.blur_texlen_value, texlen)) ||
|
|
(!EINA_FLT_EQ(prog->filter->uniform.blur_div_value, sum)))
|
|
{
|
|
update_uniforms = EINA_TRUE;
|
|
shader_array_flush(gc);
|
|
}
|
|
|
|
pn = _evas_gl_common_context_push(type, gc, tex, NULL, prog,
|
|
sx, sy, dw, dh, blend, smooth,
|
|
0, 0, 0, 0, 0, EINA_FALSE);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = type;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = tex->pt->texture;
|
|
gc->pipe[pn].shader.cur_texm = 0;
|
|
gc->pipe[pn].shader.tex_target = GL_TEXTURE_2D;
|
|
gc->pipe[pn].shader.smooth = smooth;
|
|
gc->pipe[pn].shader.mask_smooth = 0;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = !nomul;
|
|
gc->pipe[pn].array.use_texuv = 1;
|
|
gc->pipe[pn].array.use_texuv2 = 0;
|
|
gc->pipe[pn].array.use_texuv3 = 0;
|
|
gc->pipe[pn].array.use_texsam = 0;
|
|
gc->pipe[pn].array.use_mask = 0;
|
|
gc->pipe[pn].array.use_masksam = 0;
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, dx, dy, dw, dh);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
_filter_data_alloc(gc, pn, 0);
|
|
|
|
// Synchronous upload of Nx2 RGBA texture
|
|
if (!EINA_DBL_EQ(prog->filter->blur_radius, radius))
|
|
{
|
|
prog->filter->blur_radius = radius;
|
|
|
|
if (!prog->filter->texture.tex_ids[0])
|
|
glGenTextures(1, prog->filter->texture.tex_ids);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, prog->filter->texture.tex_ids[0]);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
if (tex->gc->shared->info.unpack_row_length)
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, sizeof(*map_tex_data));
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, count, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, map_tex_data);
|
|
}
|
|
|
|
if (update_uniforms)
|
|
{
|
|
prog->filter->uniform.blur_count_value = count - 1;
|
|
prog->filter->uniform.blur_texlen_value = texlen;
|
|
prog->filter->uniform.blur_div_value = sum;
|
|
glUseProgram(prog->prog);
|
|
glUniform1i(prog->filter->uniform.blur_count_loc, prog->filter->uniform.blur_count_value);
|
|
glUniform1f(prog->filter->uniform.blur_texlen_loc, prog->filter->uniform.blur_texlen_value);
|
|
glUniform1f(prog->filter->uniform.blur_div_loc, prog->filter->uniform.blur_div_value);
|
|
}
|
|
|
|
// Set shader properties
|
|
gc->pipe[pn].shader.filter.map_tex = prog->filter->texture.tex_ids[0];
|
|
gc->pipe[pn].shader.filter.map_nearest = EINA_TRUE;
|
|
gc->pipe[pn].shader.filter.map_delete = EINA_FALSE;
|
|
|
|
ox1 = sx;
|
|
oy1 = sy;
|
|
ox2 = sx + sw;
|
|
oy2 = sy;
|
|
ox3 = sx + sw;
|
|
oy3 = sy + sh;
|
|
ox4 = sx;
|
|
oy4 = sy + sh;
|
|
|
|
offsetx = tex->x;
|
|
offsety = tex->y;
|
|
|
|
tx1 = ((double)(offsetx) + ox1) / pw;
|
|
ty1 = ((double)(offsety) + oy1) / ph;
|
|
tx2 = ((double)(offsetx) + ox2) / pw;
|
|
ty2 = ((double)(offsety) + oy2) / ph;
|
|
tx3 = ((double)(offsetx) + ox3) / pw;
|
|
ty3 = ((double)(offsety) + oy3) / ph;
|
|
tx4 = ((double)(offsetx) + ox4) / pw;
|
|
ty4 = ((double)(offsety) + oy4) / ph;
|
|
|
|
PUSH_6_VERTICES(pn, dx, dy, dw, dh);
|
|
PUSH_6_QUAD(pn, tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4);
|
|
|
|
if (!nomul)
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_filter_grayscale_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
int x, int y, int w, int h)
|
|
{
|
|
double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4, pw, ph;
|
|
GLfloat tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4;
|
|
GLfloat offsetx, offsety;
|
|
int r, g, b, a, nomul = 0, pn;
|
|
Evas_GL_Program *prog;
|
|
Eina_Bool blend = EINA_TRUE;
|
|
Eina_Bool smooth = EINA_TRUE;
|
|
Shader_Type type = SHD_FILTER_GRAYSCALE;
|
|
|
|
r = R_VAL(&gc->dc->mul.col);
|
|
g = G_VAL(&gc->dc->mul.col);
|
|
b = B_VAL(&gc->dc->mul.col);
|
|
a = A_VAL(&gc->dc->mul.col);
|
|
if (gc->dc->render_op == EVAS_RENDER_COPY)
|
|
blend = EINA_FALSE;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, type, NULL, 0, r, g, b, a,
|
|
w, h, w, h, smooth, tex, EINA_FALSE,
|
|
NULL, EINA_FALSE, EINA_FALSE, 0, 0,
|
|
EINA_FALSE, NULL, &nomul, NULL);
|
|
|
|
_filter_data_flush(gc, prog);
|
|
EINA_SAFETY_ON_NULL_RETURN(prog);
|
|
|
|
pn = _evas_gl_common_context_push(type, gc, tex, NULL, prog,
|
|
x, y, w, h, blend, smooth,
|
|
0, 0, 0, 0, 0, EINA_FALSE);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = type;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = tex->pt->texture;
|
|
gc->pipe[pn].shader.cur_texm = 0;
|
|
gc->pipe[pn].shader.tex_target = GL_TEXTURE_2D;
|
|
gc->pipe[pn].shader.smooth = smooth;
|
|
gc->pipe[pn].shader.mask_smooth = 0;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = !nomul;
|
|
gc->pipe[pn].array.use_texuv = 1;
|
|
gc->pipe[pn].array.use_texuv2 = 0;
|
|
gc->pipe[pn].array.use_texuv3 = 0;
|
|
gc->pipe[pn].array.use_texsam = 0;
|
|
gc->pipe[pn].array.use_mask = 0;
|
|
gc->pipe[pn].array.use_masksam = 0;
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
_filter_data_alloc(gc, pn, 0);
|
|
|
|
pw = tex->pt->w;
|
|
ph = tex->pt->h;
|
|
|
|
ox1 = x;
|
|
oy1 = y;
|
|
ox2 = x + w;
|
|
oy2 = y;
|
|
ox3 = x + w;
|
|
oy3 = y + h;
|
|
ox4 = x;
|
|
oy4 = y + h;
|
|
|
|
offsetx = tex->x;
|
|
offsety = tex->y;
|
|
|
|
tx1 = ((double)(offsetx) + ox1) / pw;
|
|
ty1 = ((double)(offsety) + oy1) / ph;
|
|
tx2 = ((double)(offsetx) + ox2) / pw;
|
|
ty2 = ((double)(offsety) + oy2) / ph;
|
|
tx3 = ((double)(offsetx) + ox3) / pw;
|
|
ty3 = ((double)(offsety) + oy3) / ph;
|
|
tx4 = ((double)(offsetx) + ox4) / pw;
|
|
ty4 = ((double)(offsety) + oy4) / ph;
|
|
|
|
PUSH_6_VERTICES(pn, x, y, w, h);
|
|
PUSH_6_QUAD(pn, tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4);
|
|
|
|
if (!nomul)
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
|
|
void
|
|
evas_gl_common_filter_inverse_color_push(Evas_Engine_GL_Context *gc,
|
|
Evas_GL_Texture *tex,
|
|
int x, int y, int w, int h)
|
|
{
|
|
double ox1, oy1, ox2, oy2, ox3, oy3, ox4, oy4, pw, ph;
|
|
GLfloat tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4;
|
|
GLfloat offsetx, offsety;
|
|
int r, g, b, a, nomul = 0, pn;
|
|
Evas_GL_Program *prog;
|
|
Eina_Bool blend = EINA_TRUE;
|
|
Eina_Bool smooth = EINA_TRUE;
|
|
Shader_Type type = SHD_FILTER_INVERSE_COLOR;
|
|
|
|
r = R_VAL(&gc->dc->mul.col);
|
|
g = G_VAL(&gc->dc->mul.col);
|
|
b = B_VAL(&gc->dc->mul.col);
|
|
a = A_VAL(&gc->dc->mul.col);
|
|
if (gc->dc->render_op == EVAS_RENDER_COPY)
|
|
blend = EINA_FALSE;
|
|
|
|
prog = evas_gl_common_shader_program_get(gc, type, NULL, 0, r, g, b, a,
|
|
w, h, w, h, smooth, tex, EINA_FALSE,
|
|
NULL, EINA_FALSE, EINA_FALSE, 0, 0,
|
|
EINA_FALSE, NULL, &nomul, NULL);
|
|
|
|
_filter_data_flush(gc, prog);
|
|
EINA_SAFETY_ON_NULL_RETURN(prog);
|
|
|
|
pn = _evas_gl_common_context_push(type, gc, tex, NULL, prog,
|
|
x, y, w, h, blend, smooth,
|
|
0, 0, 0, 0, 0, EINA_FALSE);
|
|
|
|
if (gc->pipe[pn].array.num == 0)
|
|
{
|
|
gc->pipe[pn].region.type = type;
|
|
gc->pipe[pn].shader.prog = prog;
|
|
gc->pipe[pn].shader.cur_tex = tex->pt->texture;
|
|
gc->pipe[pn].shader.cur_texm = 0;
|
|
gc->pipe[pn].shader.tex_target = GL_TEXTURE_2D;
|
|
gc->pipe[pn].shader.smooth = smooth;
|
|
gc->pipe[pn].shader.mask_smooth = 0;
|
|
gc->pipe[pn].shader.blend = blend;
|
|
gc->pipe[pn].shader.render_op = gc->dc->render_op;
|
|
gc->pipe[pn].shader.clip = 0;
|
|
gc->pipe[pn].shader.cx = 0;
|
|
gc->pipe[pn].shader.cy = 0;
|
|
gc->pipe[pn].shader.cw = 0;
|
|
gc->pipe[pn].shader.ch = 0;
|
|
gc->pipe[pn].array.line = 0;
|
|
gc->pipe[pn].array.use_vertex = 1;
|
|
gc->pipe[pn].array.use_color = !nomul;
|
|
gc->pipe[pn].array.use_texuv = 1;
|
|
gc->pipe[pn].array.use_texuv2 = 0;
|
|
gc->pipe[pn].array.use_texuv3 = 0;
|
|
gc->pipe[pn].array.use_texsam = 0;
|
|
gc->pipe[pn].array.use_mask = 0;
|
|
gc->pipe[pn].array.use_masksam = 0;
|
|
}
|
|
|
|
pipe_region_expand(gc, pn, x, y, w, h);
|
|
PIPE_GROW(gc, pn, 6);
|
|
|
|
_filter_data_alloc(gc, pn, 0);
|
|
|
|
pw = tex->pt->w;
|
|
ph = tex->pt->h;
|
|
|
|
ox1 = x;
|
|
oy1 = y;
|
|
ox2 = x + w;
|
|
oy2 = y;
|
|
ox3 = x + w;
|
|
oy3 = y + h;
|
|
ox4 = x;
|
|
oy4 = y + h;
|
|
|
|
offsetx = tex->x;
|
|
offsety = tex->y;
|
|
|
|
tx1 = ((double)(offsetx) + ox1) / pw;
|
|
ty1 = ((double)(offsety) + oy1) / ph;
|
|
tx2 = ((double)(offsetx) + ox2) / pw;
|
|
ty2 = ((double)(offsety) + oy2) / ph;
|
|
tx3 = ((double)(offsetx) + ox3) / pw;
|
|
ty3 = ((double)(offsety) + oy3) / ph;
|
|
tx4 = ((double)(offsetx) + ox4) / pw;
|
|
ty4 = ((double)(offsety) + oy4) / ph;
|
|
|
|
PUSH_6_VERTICES(pn, x, y, w, h);
|
|
PUSH_6_QUAD(pn, tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4);
|
|
|
|
if (!nomul)
|
|
PUSH_6_COLORS(pn, r, g, b, a);
|
|
}
|
|
// ----------------------------------------------------------------------------
|
|
|
|
EMODAPI void
|
|
evas_gl_common_context_flush(Evas_Engine_GL_Context *gc)
|
|
{
|
|
shader_array_flush(gc);
|
|
}
|
|
|
|
static void
|
|
scissor_rot(Evas_Engine_GL_Context *gc EINA_UNUSED,
|
|
int rot, int gw, int gh, int cx, int cy, int cw, int ch)
|
|
{
|
|
switch (rot)
|
|
{
|
|
case 0: // UP this way: ^
|
|
glScissor(cx, cy, cw, ch);
|
|
break;
|
|
case 90: // UP this way: <
|
|
glScissor(gh - (cy + ch), cx, ch, cw);
|
|
break;
|
|
case 180: // UP this way: v
|
|
glScissor(gw - (cx + cw), gh - (cy + ch), cw, ch);
|
|
break;
|
|
case 270: // UP this way: >
|
|
glScissor(cy, gw - (cx + cw), ch, cw);
|
|
break;
|
|
default: // assume up is up
|
|
glScissor(cx, cy, cw, ch);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
start_tiling(Evas_Engine_GL_Context *gc EINA_UNUSED,
|
|
int rot, int gw, int gh, int cx, int cy, int cw, int ch,
|
|
int bitmask)
|
|
{
|
|
if (!glsym_glStartTiling) return;
|
|
switch (rot)
|
|
{
|
|
case 0: // UP this way: ^
|
|
glsym_glStartTiling(cx, cy, cw, ch, bitmask);
|
|
break;
|
|
case 90: // UP this way: <
|
|
glsym_glStartTiling(gh - (cy + ch), cx, ch, cw, bitmask);
|
|
break;
|
|
case 180: // UP this way: v
|
|
glsym_glStartTiling(gw - (cx + cw), gh - (cy + ch), cw, ch, bitmask);
|
|
break;
|
|
case 270: // UP this way: >
|
|
glsym_glStartTiling(cy, gw - (cx + cw), ch, cw, bitmask);
|
|
break;
|
|
default: // assume up is up
|
|
glsym_glStartTiling(cx, cy, cw, ch, bitmask);
|
|
break;
|
|
}
|
|
GLERRV("glsym_glStartTiling");
|
|
}
|
|
|
|
static void
|
|
shader_array_flush(Evas_Engine_GL_Context *gc)
|
|
{
|
|
int i, gw, gh, offx = 0, offy = 0;
|
|
unsigned int pipe_done = 0; //count pipe iteration for debugging
|
|
Eina_Bool setclip;
|
|
Eina_Bool fbo = EINA_FALSE;
|
|
|
|
if (!gc->havestuff) return;
|
|
gw = gc->w;
|
|
gh = gc->h;
|
|
if (!((gc->pipe[0].shader.surface == gc->def_surface) ||
|
|
(!gc->pipe[0].shader.surface)))
|
|
{
|
|
gw = gc->pipe[0].shader.surface->w;
|
|
gh = gc->pipe[0].shader.surface->h;
|
|
fbo = EINA_TRUE;
|
|
offx = gc->pipe[0].shader.surface->tex->x;
|
|
offy = gc->pipe[0].shader.surface->tex->y;
|
|
}
|
|
for (i = 0; i < gc->shared->info.tune.pipes.max; i++)
|
|
{
|
|
Evas_GL_Program *prog;
|
|
|
|
if (gc->pipe[i].array.num <= 0) break;
|
|
|
|
prog = gc->pipe[i].shader.prog;
|
|
setclip = EINA_FALSE;
|
|
pipe_done++;
|
|
gc->flushnum++;
|
|
|
|
if (prog != gc->state.current.prog)
|
|
{
|
|
glUseProgram(prog->prog);
|
|
if (prog->reset)
|
|
{
|
|
glUniform1i(prog->uniform.rotation_id, fbo ? 0 : gc->rot / 90);
|
|
glUniformMatrix4fv(prog->uniform.mvp, 1, GL_FALSE, gc->shared->proj);
|
|
prog->reset = EINA_FALSE;
|
|
}
|
|
}
|
|
|
|
if (gc->pipe[i].shader.cur_tex != gc->state.current.cur_tex)
|
|
{
|
|
#if 0
|
|
if (gc->pipe[i].shader.cur_tex)
|
|
{
|
|
glEnable(GL_TEXTURE_2D);
|
|
}
|
|
else
|
|
{
|
|
glDisable(GL_TEXTURE_2D);
|
|
}
|
|
#endif
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(gc->pipe[i].shader.tex_target, gc->pipe[i].shader.cur_tex);
|
|
}
|
|
if (gc->pipe[i].array.im)
|
|
{
|
|
#ifdef GL_GLES
|
|
if (gc->pipe[i].array.im->tex->pt->dyn.img)
|
|
{
|
|
secsym_glEGLImageTargetTexture2DOES
|
|
(gc->pipe[i].array.im->tex->pt->dyn.target, gc->pipe[i].array.im->tex->pt->dyn.img);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (!gc->pipe[i].array.im->native.loose)
|
|
{
|
|
if (gc->pipe[i].array.im->native.func.bind)
|
|
{
|
|
gc->pipe[i].array.im->native.func.bind(gc->pipe[i].array.im);
|
|
if (gc->pipe[i].array.im->native.invalid)
|
|
{
|
|
fprintf(stderr,
|
|
"Evas GL: native bind failed for %ix%i image\n",
|
|
gc->pipe[i].array.im->w,
|
|
gc->pipe[i].array.im->h);
|
|
if ((gc->err_img) &&
|
|
(gc->err_img->tex) &&
|
|
(gc->err_img->tex->pt))
|
|
{
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture
|
|
(GL_TEXTURE_2D,
|
|
gc->err_img->tex->pt->texture);
|
|
gc->pipe[i].shader.cur_tex =
|
|
gc->err_img->tex->pt->texture;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ((gc->pipe[i].shader.render_op != gc->state.current.render_op) ||
|
|
gc->state.current.anti_alias)
|
|
{
|
|
switch (gc->pipe[i].shader.render_op)
|
|
{
|
|
case EVAS_RENDER_BLEND: /**< default op: d = d*(1-sa) + s */
|
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
break;
|
|
case EVAS_RENDER_BLEND_REL: /**< d = d*(1 - sa) + s*da */
|
|
glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
break;
|
|
case EVAS_RENDER_COPY: /**< d = s */
|
|
gc->pipe[i].shader.blend = 0;
|
|
// just disable blend mode. no need to set blend func
|
|
//glBlendFunc(GL_ONE, GL_ZERO);
|
|
break;
|
|
case EVAS_RENDER_COPY_REL: /**< d = s*da */
|
|
glBlendFunc(GL_DST_ALPHA, GL_ZERO);
|
|
break;
|
|
case EVAS_RENDER_ADD: /**< d = d + s */
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
break;
|
|
case EVAS_RENDER_ADD_REL: /**< d = d + s*da */
|
|
glBlendFunc(GL_DST_ALPHA, GL_ONE);
|
|
break;
|
|
case EVAS_RENDER_SUB: /**< d = d - s */
|
|
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
|
|
break;
|
|
case EVAS_RENDER_SUB_REL: /**< d = d - s*da */
|
|
glBlendFunc(GL_ZERO, GL_ONE_MINUS_DST_ALPHA);
|
|
break;
|
|
case EVAS_RENDER_MASK: /**< d = d*sa */
|
|
glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
|
|
break;
|
|
// FIXME: fix blend funcs below!
|
|
case EVAS_RENDER_TINT: /**< d = d*s + d*(1 - sa) + s*(1 - da) */
|
|
case EVAS_RENDER_TINT_REL: /**< d = d*(1 - sa + s) */
|
|
case EVAS_RENDER_MUL: /**< d = d*s */
|
|
default:
|
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
break;
|
|
}
|
|
}
|
|
if (gc->pipe[i].shader.blend != gc->state.current.blend)
|
|
{
|
|
if (gc->pipe[i].shader.blend)
|
|
glEnable(GL_BLEND);
|
|
else
|
|
glDisable(GL_BLEND);
|
|
}
|
|
if ((gc->pipe[i].shader.smooth != gc->state.current.smooth) ||
|
|
(gc->pipe[i].shader.cur_tex != gc->state.current.cur_tex))
|
|
{
|
|
if (gc->pipe[i].shader.smooth)
|
|
{
|
|
#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
|
|
if (shared->info.anisotropic > 0.0)
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, shared->info.anisotropic);
|
|
#endif
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
}
|
|
else
|
|
{
|
|
#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
|
|
if (shared->info.anisotropic > 0.0)
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0);
|
|
#endif
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
}
|
|
}
|
|
if (gc->pipe[i].shader.clip != gc->state.current.clip)
|
|
{
|
|
int cx, cy, cw, ch;
|
|
|
|
cx = gc->pipe[i].shader.cx;
|
|
cy = gc->pipe[i].shader.cy;
|
|
cw = gc->pipe[i].shader.cw;
|
|
ch = gc->pipe[i].shader.ch;
|
|
if ((gc->master_clip.enabled) && (!fbo))
|
|
{
|
|
if (gc->pipe[i].shader.clip)
|
|
{
|
|
RECTS_CLIP_TO_RECT(cx, cy, cw, ch,
|
|
gc->master_clip.x, gc->master_clip.y,
|
|
gc->master_clip.w, gc->master_clip.h);
|
|
}
|
|
else
|
|
{
|
|
cx = gc->master_clip.x;
|
|
cy = gc->master_clip.y;
|
|
cw = gc->master_clip.w;
|
|
ch = gc->master_clip.h;
|
|
}
|
|
}
|
|
if ((glsym_glStartTiling) && (glsym_glEndTiling) &&
|
|
(gc->master_clip.enabled) &&
|
|
(gc->master_clip.w > 0) && (gc->master_clip.h > 0))
|
|
{
|
|
if (!gc->master_clip.used)
|
|
{
|
|
if (!fbo)
|
|
{
|
|
start_tiling(gc, gc->rot, gw, gh,
|
|
gc->master_clip.x + offx,
|
|
gh - gc->master_clip.y - offy - gc->master_clip.h,
|
|
gc->master_clip.w, gc->master_clip.h,
|
|
gc->preserve_bit);
|
|
if (!gc->preserve_bit)
|
|
gc->preserve_bit = GL_COLOR_BUFFER_BIT0_QCOM;
|
|
}
|
|
else
|
|
start_tiling(gc, 0, gw, gh,
|
|
gc->master_clip.x + offx,
|
|
gc->master_clip.y + offy,
|
|
gc->master_clip.w, gc->master_clip.h, 0);
|
|
gc->master_clip.used = EINA_TRUE;
|
|
}
|
|
}
|
|
if ((gc->pipe[i].shader.clip) ||
|
|
((gc->master_clip.enabled) && (!fbo)))
|
|
{
|
|
glEnable(GL_SCISSOR_TEST);
|
|
if (!fbo)
|
|
scissor_rot(gc, gc->rot, gw, gh,
|
|
cx + offx,
|
|
gh - cy - offy - ch,
|
|
cw, ch);
|
|
else
|
|
glScissor(cx + offx, cy + offy, cw, ch);
|
|
setclip = EINA_TRUE;
|
|
gc->state.current.cx = cx;
|
|
gc->state.current.cy = cy;
|
|
gc->state.current.cw = cw;
|
|
gc->state.current.ch = ch;
|
|
}
|
|
else
|
|
{
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glScissor(0, 0, 0, 0);
|
|
gc->state.current.cx = 0;
|
|
gc->state.current.cy = 0;
|
|
gc->state.current.cw = 0;
|
|
gc->state.current.ch = 0;
|
|
}
|
|
}
|
|
if (((gc->pipe[i].shader.clip) && (!setclip)) ||
|
|
((gc->master_clip.enabled) && (!fbo)))
|
|
{
|
|
int cx, cy, cw, ch;
|
|
|
|
cx = gc->pipe[i].shader.cx;
|
|
cy = gc->pipe[i].shader.cy;
|
|
cw = gc->pipe[i].shader.cw;
|
|
ch = gc->pipe[i].shader.ch;
|
|
if ((gc->master_clip.enabled) && (!fbo))
|
|
{
|
|
if (gc->pipe[i].shader.clip)
|
|
{
|
|
RECTS_CLIP_TO_RECT(cx, cy, cw, ch,
|
|
gc->master_clip.x, gc->master_clip.y,
|
|
gc->master_clip.w, gc->master_clip.h);
|
|
}
|
|
else
|
|
{
|
|
cx = gc->master_clip.x;
|
|
cy = gc->master_clip.y;
|
|
cw = gc->master_clip.w;
|
|
ch = gc->master_clip.h;
|
|
}
|
|
}
|
|
if ((cx != gc->state.current.cx) ||
|
|
(cy != gc->state.current.cy) ||
|
|
(cw != gc->state.current.cw) ||
|
|
(ch != gc->state.current.ch))
|
|
{
|
|
if (!fbo)
|
|
scissor_rot(gc, gc->rot, gw, gh,
|
|
cx + offx,
|
|
gh - cy - offy - ch,
|
|
cw, ch);
|
|
else
|
|
glScissor(cx, cy, cw, ch);
|
|
gc->state.current.cx = cx;
|
|
gc->state.current.cy = cy;
|
|
gc->state.current.cw = cw;
|
|
gc->state.current.ch = ch;
|
|
}
|
|
}
|
|
|
|
unsigned char *vertex_ptr = NULL;
|
|
unsigned char *color_ptr = NULL;
|
|
unsigned char *texuv_ptr = NULL;
|
|
unsigned char *texuv2_ptr = NULL;
|
|
unsigned char *texuv3_ptr = NULL;
|
|
unsigned char *texa_ptr = NULL;
|
|
unsigned char *texsam_ptr = NULL;
|
|
unsigned char *mask_ptr = NULL;
|
|
unsigned char *masksam_ptr = NULL;
|
|
GLint ACTIVE_TEXTURE = GL_TEXTURE0;
|
|
|
|
if (glsym_glMapBuffer && glsym_glUnmapBuffer)
|
|
{
|
|
unsigned char *x;
|
|
|
|
# define VERTEX_SIZE (gc->pipe[i].array.num * sizeof(GLshort) * VERTEX_CNT)
|
|
# define COLOR_SIZE (gc->pipe[i].array.num * sizeof(GLubyte) * COLOR_CNT)
|
|
# define TEX_SIZE (gc->pipe[i].array.num * sizeof(GLfloat) * TEX_CNT)
|
|
# define SAM_SIZE (gc->pipe[i].array.num * sizeof(GLfloat) * SAM_CNT)
|
|
# define MASK_SIZE (gc->pipe[i].array.num * sizeof(GLfloat) * MASK_CNT)
|
|
vertex_ptr = NULL;
|
|
color_ptr = vertex_ptr + VERTEX_SIZE;
|
|
texuv_ptr = color_ptr + COLOR_SIZE;
|
|
texuv2_ptr = texuv_ptr + TEX_SIZE;
|
|
texuv3_ptr = texuv2_ptr + TEX_SIZE;
|
|
texa_ptr = texuv3_ptr + TEX_SIZE;
|
|
texsam_ptr = texa_ptr + TEX_SIZE;
|
|
mask_ptr = texsam_ptr + SAM_SIZE;
|
|
masksam_ptr = mask_ptr + MASK_SIZE;
|
|
# define END_POINTER (masksam_ptr + SAM_SIZE)
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, gc->pipe[i].array.buffer);
|
|
if ((gc->pipe[i].array.buffer_alloc < (long)END_POINTER) ||
|
|
(gc->pipe[i].array.buffer_use >= (ARRAY_BUFFER_USE + ARRAY_BUFFER_USE_SHIFT * i)))
|
|
{
|
|
glBufferData(GL_ARRAY_BUFFER, (long)END_POINTER, NULL, GL_STATIC_DRAW);
|
|
gc->pipe[i].array.buffer_alloc = (long)END_POINTER;
|
|
gc->pipe[i].array.buffer_use = 0;
|
|
}
|
|
gc->pipe[i].array.buffer_use++;
|
|
|
|
x = glsym_glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
|
|
if (x)
|
|
{
|
|
if (gc->pipe[i].array.use_vertex)
|
|
memcpy(x + (unsigned long)vertex_ptr, gc->pipe[i].array.vertex, VERTEX_SIZE);
|
|
if (gc->pipe[i].array.use_color)
|
|
memcpy(x + (unsigned long)color_ptr, gc->pipe[i].array.color, COLOR_SIZE);
|
|
if (gc->pipe[i].array.use_texuv)
|
|
memcpy(x + (unsigned long)texuv_ptr, gc->pipe[i].array.texuv, TEX_SIZE);
|
|
if (gc->pipe[i].array.use_texuv2)
|
|
memcpy(x + (unsigned long)texuv2_ptr, gc->pipe[i].array.texuv2, TEX_SIZE);
|
|
if (gc->pipe[i].array.use_texuv3)
|
|
memcpy(x + (unsigned long)texuv3_ptr, gc->pipe[i].array.texuv3, TEX_SIZE);
|
|
if (gc->pipe[i].array.use_texa)
|
|
memcpy(x + (unsigned long)texa_ptr, gc->pipe[i].array.texa, TEX_SIZE);
|
|
if (gc->pipe[i].array.use_texsam)
|
|
memcpy(x + (unsigned long)texsam_ptr, gc->pipe[i].array.texsam, SAM_SIZE);
|
|
if (gc->pipe[i].array.use_mask)
|
|
{
|
|
memcpy(x + (unsigned long)mask_ptr, gc->pipe[i].array.mask, MASK_SIZE);
|
|
if (gc->pipe[i].array.use_masksam)
|
|
memcpy(x + (unsigned long)masksam_ptr, gc->pipe[i].array.masksam, SAM_SIZE);
|
|
}
|
|
/*
|
|
fprintf(stderr, "copy %i bytes [%i/%i slots] [%i + %i + %i + %i + %i + %i + %i] <%i %i %i %i %i %i %i>\n",
|
|
(int)((unsigned char *)END_POINTER),
|
|
gc->pipe[i].array.num,
|
|
gc->pipe[i].array.alloc,
|
|
VERTEX_SIZE, COLOR_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE,
|
|
gc->pipe[i].array.use_vertex,
|
|
gc->pipe[i].array.use_color,
|
|
gc->pipe[i].array.use_texuv,
|
|
gc->pipe[i].array.use_texuv2,
|
|
gc->pipe[i].array.use_texuv3,
|
|
gc->pipe[i].array.use_texa,
|
|
gc->pipe[i].array.use_texsam,
|
|
gc->pipe[i].array.use_texm);
|
|
*/
|
|
glsym_glUnmapBuffer(GL_ARRAY_BUFFER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vertex_ptr = (unsigned char *)gc->pipe[i].array.vertex;
|
|
color_ptr = (unsigned char *)gc->pipe[i].array.color;
|
|
texuv_ptr = (unsigned char *)gc->pipe[i].array.texuv;
|
|
texuv2_ptr = (unsigned char *)gc->pipe[i].array.texuv2;
|
|
texuv3_ptr = (unsigned char *)gc->pipe[i].array.texuv3;
|
|
texa_ptr = (unsigned char *)gc->pipe[i].array.texa;
|
|
texsam_ptr = (unsigned char *)gc->pipe[i].array.texsam;
|
|
mask_ptr = (unsigned char *)gc->pipe[i].array.mask;
|
|
masksam_ptr = (unsigned char *)gc->pipe[i].array.masksam;
|
|
}
|
|
|
|
// use_vertex is always true
|
|
glVertexAttribPointer(SHAD_VERTEX, VERTEX_CNT, GL_FLOAT, GL_FALSE, 0, vertex_ptr);
|
|
|
|
if (gc->pipe[i].array.use_color)
|
|
{
|
|
glEnableVertexAttribArray(SHAD_COLOR);
|
|
glVertexAttribPointer(SHAD_COLOR, COLOR_CNT, GL_UNSIGNED_BYTE, GL_TRUE, 0, color_ptr);
|
|
}
|
|
else
|
|
glDisableVertexAttribArray(SHAD_COLOR);
|
|
|
|
if (gc->pipe[i].array.line)
|
|
{
|
|
//LINE_SMOOTH is supported at gles 1.x spec.
|
|
if ((gc->gles_version == 1) && gc->pipe[i].array.anti_alias)
|
|
{
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glHint(GL_LINE_SMOOTH, GL_NICEST);
|
|
glEnable(GL_LINE_SMOOTH);
|
|
}
|
|
else
|
|
{
|
|
glDisable(GL_LINE_SMOOTH);
|
|
}
|
|
|
|
glDisableVertexAttribArray(SHAD_TEXUV);
|
|
glDisableVertexAttribArray(SHAD_TEXUV2);
|
|
glDisableVertexAttribArray(SHAD_TEXUV3);
|
|
glDisableVertexAttribArray(SHAD_TEXA);
|
|
glDisableVertexAttribArray(SHAD_TEXSAM);
|
|
|
|
/* kopi pasta from below */
|
|
if (gc->pipe[i].array.use_mask)
|
|
{
|
|
glEnableVertexAttribArray(SHAD_MASK);
|
|
glVertexAttribPointer(SHAD_MASK, MASK_CNT, GL_FLOAT, GL_FALSE, 0, mask_ptr);
|
|
glActiveTexture(ACTIVE_TEXTURE);
|
|
glBindTexture(GL_TEXTURE_2D, gc->pipe[i].shader.cur_texm);
|
|
#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
|
|
if (shared->info.anisotropic > 0.0)
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, shared->info.anisotropic);
|
|
#endif
|
|
if (gc->pipe[i].shader.mask_smooth)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
}
|
|
else
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
}
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
if (gc->pipe[i].array.use_masksam)
|
|
{
|
|
glEnableVertexAttribArray(SHAD_MASKSAM);
|
|
glVertexAttribPointer(SHAD_MASKSAM, SAM_CNT, GL_FLOAT, GL_FALSE, 0, masksam_ptr);
|
|
}
|
|
else glDisableVertexAttribArray(SHAD_MASKSAM);
|
|
}
|
|
else
|
|
{
|
|
glDisableVertexAttribArray(SHAD_MASK);
|
|
glDisableVertexAttribArray(SHAD_MASKSAM);
|
|
}
|
|
|
|
glDrawArrays(GL_LINES, 0, gc->pipe[i].array.num);
|
|
}
|
|
else
|
|
{
|
|
if (gc->pipe[i].array.use_texuv)
|
|
{
|
|
glEnableVertexAttribArray(SHAD_TEXUV);
|
|
glVertexAttribPointer(SHAD_TEXUV, TEX_CNT, GL_FLOAT, GL_FALSE, 0, texuv_ptr);
|
|
|
|
ACTIVE_TEXTURE += 1;
|
|
}
|
|
else
|
|
{
|
|
glDisableVertexAttribArray(SHAD_TEXUV);
|
|
}
|
|
|
|
/* Alpha plane */
|
|
if (gc->pipe[i].array.use_texa)
|
|
{
|
|
glEnableVertexAttribArray(SHAD_TEXA);
|
|
glVertexAttribPointer(SHAD_TEXA, TEX_CNT, GL_FLOAT, GL_FALSE, 0, texa_ptr);
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, gc->pipe[i].shader.cur_texa);
|
|
#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
|
|
if (shared->info.anisotropic > 0.0)
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, shared->info.anisotropic);
|
|
#endif
|
|
if (gc->pipe[i].shader.smooth)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
}
|
|
else
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
}
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
ACTIVE_TEXTURE += 1;
|
|
}
|
|
else
|
|
{
|
|
glDisableVertexAttribArray(SHAD_TEXA);
|
|
}
|
|
|
|
if (gc->pipe[i].array.use_texsam)
|
|
{
|
|
glEnableVertexAttribArray(SHAD_TEXSAM);
|
|
glVertexAttribPointer(SHAD_TEXSAM, SAM_CNT, GL_FLOAT, GL_FALSE, 0, texsam_ptr);
|
|
}
|
|
else
|
|
{
|
|
glDisableVertexAttribArray(SHAD_TEXSAM);
|
|
}
|
|
|
|
if ((gc->pipe[i].array.use_texuv2) && (gc->pipe[i].array.use_texuv3))
|
|
{
|
|
glEnableVertexAttribArray(SHAD_TEXUV2);
|
|
glEnableVertexAttribArray(SHAD_TEXUV3);
|
|
glVertexAttribPointer(SHAD_TEXUV2, TEX_CNT, GL_FLOAT, GL_FALSE, 0, texuv2_ptr);
|
|
glVertexAttribPointer(SHAD_TEXUV3, TEX_CNT, GL_FLOAT, GL_FALSE, 0, texuv3_ptr);
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, gc->pipe[i].shader.cur_texu);
|
|
#ifdef GL_GLES
|
|
if (gc->pipe[i].shader.cur_texu_dyn)
|
|
secsym_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, gc->pipe[i].shader.cur_texu_dyn);
|
|
#endif
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glActiveTexture(GL_TEXTURE2);
|
|
glBindTexture(GL_TEXTURE_2D, gc->pipe[i].shader.cur_texv);
|
|
#ifdef GL_GLES
|
|
if (gc->pipe[i].shader.cur_texv_dyn)
|
|
secsym_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, gc->pipe[i].shader.cur_texv_dyn);
|
|
#endif
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
ACTIVE_TEXTURE += 2;
|
|
}
|
|
else if (gc->pipe[i].array.use_texuv2)
|
|
{
|
|
glEnableVertexAttribArray(SHAD_TEXUV2);
|
|
glVertexAttribPointer(SHAD_TEXUV2, TEX_CNT, GL_FLOAT, GL_FALSE, 0, texuv2_ptr);
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, gc->pipe[i].shader.cur_texu);
|
|
#ifdef GL_GLES
|
|
if (gc->pipe[i].shader.cur_texu_dyn)
|
|
secsym_glEGLImageTargetTexture2DOES
|
|
(GL_TEXTURE_2D, gc->pipe[i].shader.cur_texu_dyn);
|
|
#endif
|
|
if (gc->pipe[i].shader.smooth)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
}
|
|
else
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
}
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
glDisableVertexAttribArray(SHAD_TEXUV3);
|
|
ACTIVE_TEXTURE += 1;
|
|
}
|
|
else
|
|
{
|
|
glDisableVertexAttribArray(SHAD_TEXUV2);
|
|
glDisableVertexAttribArray(SHAD_TEXUV3);
|
|
}
|
|
|
|
/* Mask surface */
|
|
if (gc->pipe[i].array.use_mask)
|
|
{
|
|
glEnableVertexAttribArray(SHAD_MASK);
|
|
glVertexAttribPointer(SHAD_MASK, MASK_CNT, GL_FLOAT, GL_FALSE, 0, mask_ptr);
|
|
glActiveTexture(ACTIVE_TEXTURE);
|
|
glBindTexture(GL_TEXTURE_2D, gc->pipe[i].shader.cur_texm);
|
|
#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
|
|
if (shared->info.anisotropic > 0.0)
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, shared->info.anisotropic);
|
|
#endif
|
|
if (gc->pipe[i].shader.mask_smooth)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
}
|
|
else
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
}
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
if (gc->pipe[i].array.use_masksam)
|
|
{
|
|
glEnableVertexAttribArray(SHAD_MASKSAM);
|
|
glVertexAttribPointer(SHAD_MASKSAM, SAM_CNT, GL_FLOAT, GL_FALSE, 0, masksam_ptr);
|
|
}
|
|
else glDisableVertexAttribArray(SHAD_MASKSAM);
|
|
ACTIVE_TEXTURE += 1;
|
|
}
|
|
else
|
|
{
|
|
glDisableVertexAttribArray(SHAD_MASK);
|
|
glDisableVertexAttribArray(SHAD_MASKSAM);
|
|
}
|
|
|
|
/* Gfx filters: data */
|
|
if (gc->pipe[i].array.filter_data)
|
|
{
|
|
for (int k = 0; k < gc->pipe[i].array.filter_data_count; k++)
|
|
glVertexAttrib2fv(prog->filter->attribute.loc[k], &gc->pipe[i].array.filter_data[k * 2]);
|
|
}
|
|
|
|
/* Gfx filters: texture (or data array as texture) */
|
|
if (gc->pipe[i].shader.filter.map_tex)
|
|
{
|
|
glActiveTexture(ACTIVE_TEXTURE);
|
|
glBindTexture(GL_TEXTURE_2D, gc->pipe[i].shader.filter.map_tex);
|
|
if (gc->pipe[i].shader.filter.map_nearest)
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
}
|
|
else
|
|
{
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
}
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
ACTIVE_TEXTURE += 1;
|
|
}
|
|
|
|
if (dbgflushnum == 1)
|
|
{
|
|
const char *types[] =
|
|
{ "----", "RECT", "IMAG", "FONT", "YUV-", "YUY2", "NV12", "LINE", "PAIR", "EXTR", "MAP-", "FILTER_DISPLACE" };
|
|
printf(" DRAW#%3i %4i -> %p[%4ix%4i] @ %4ix%4i -{ tex %4i type %s }-\n",
|
|
i,
|
|
gc->pipe[i].array.num / 6,
|
|
gc->pipe[0].shader.surface,
|
|
gc->pipe[0].shader.surface ? gc->pipe[0].shader.surface->w : 0,
|
|
gc->pipe[0].shader.surface ? gc->pipe[0].shader.surface->h : 0,
|
|
gw, gh,
|
|
gc->pipe[i].shader.cur_tex,
|
|
types[gc->pipe[i].region.type]
|
|
);
|
|
}
|
|
glDrawArrays(GL_TRIANGLES, 0, gc->pipe[i].array.num);
|
|
}
|
|
if (gc->pipe[i].array.im)
|
|
{
|
|
if (!gc->pipe[i].array.im->native.loose)
|
|
{
|
|
if (gc->pipe[i].array.im->native.func.unbind)
|
|
gc->pipe[i].array.im->native.func.unbind(gc->pipe[i].array.im);
|
|
}
|
|
gc->pipe[i].array.im = NULL;
|
|
}
|
|
|
|
gc->state.current.prog = gc->pipe[i].shader.prog;
|
|
gc->state.current.cur_tex = gc->pipe[i].shader.cur_tex;
|
|
gc->state.current.cur_texm = gc->pipe[i].shader.cur_texm;
|
|
gc->state.current.cur_texa = gc->pipe[i].shader.cur_texa;
|
|
gc->state.current.cur_texu = gc->pipe[i].shader.cur_texu;
|
|
gc->state.current.cur_texv = gc->pipe[i].shader.cur_texv;
|
|
gc->state.current.tex_target = gc->pipe[i].shader.tex_target;
|
|
gc->state.current.render_op = gc->pipe[i].shader.render_op;
|
|
// gc->state.current.cx = gc->pipe[i].shader.cx;
|
|
// gc->state.current.cy = gc->pipe[i].shader.cy;
|
|
// gc->state.current.cw = gc->pipe[i].shader.cw;
|
|
// gc->state.current.ch = gc->pipe[i].shader.ch;
|
|
gc->state.current.smooth = gc->pipe[i].shader.smooth;
|
|
gc->state.current.blend = gc->pipe[i].shader.blend;
|
|
gc->state.current.clip = gc->pipe[i].shader.clip;
|
|
gc->state.current.anti_alias = gc->pipe[i].array.anti_alias;
|
|
|
|
if (gc->pipe[i].shader.filter.map_delete)
|
|
{
|
|
glDeleteTextures(1, &gc->pipe[i].shader.filter.map_tex);
|
|
gc->pipe[i].shader.filter.map_delete = EINA_FALSE;
|
|
gc->pipe[i].shader.filter.map_tex = 0;
|
|
}
|
|
|
|
gc->pipe[i].array.line = 0;
|
|
//gc->pipe[i].array.use_vertex = 0;
|
|
gc->pipe[i].array.use_color = 0;
|
|
gc->pipe[i].array.use_texuv = 0;
|
|
gc->pipe[i].array.use_texuv2 = 0;
|
|
gc->pipe[i].array.use_texuv3 = 0;
|
|
gc->pipe[i].array.use_texa = 0;
|
|
gc->pipe[i].array.use_texsam = 0;
|
|
gc->pipe[i].array.use_mask = 0;
|
|
gc->pipe[i].array.use_masksam = 0;
|
|
gc->pipe[i].array.anti_alias = 0;
|
|
gc->pipe[i].array.filter_data_count = 0;
|
|
|
|
PIPE_FREE(gc->pipe[i].array.vertex);
|
|
PIPE_FREE(gc->pipe[i].array.color);
|
|
PIPE_FREE(gc->pipe[i].array.texuv);
|
|
PIPE_FREE(gc->pipe[i].array.texuv2);
|
|
PIPE_FREE(gc->pipe[i].array.texuv3);
|
|
PIPE_FREE(gc->pipe[i].array.texa);
|
|
PIPE_FREE(gc->pipe[i].array.texsam);
|
|
PIPE_FREE(gc->pipe[i].array.mask);
|
|
PIPE_FREE(gc->pipe[i].array.masksam);
|
|
FREE(gc->pipe[i].array.filter_data);
|
|
|
|
gc->pipe[i].array.num = 0;
|
|
gc->pipe[i].array.alloc = 0;
|
|
|
|
if (glsym_glMapBuffer && glsym_glUnmapBuffer)
|
|
{
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
|
|
gc->pipe[i].region.x = 0;
|
|
gc->pipe[i].region.y = 0;
|
|
gc->pipe[i].region.w = 0;
|
|
gc->pipe[i].region.h = 0;
|
|
gc->pipe[i].region.type = 0;
|
|
}
|
|
gc->state.top_pipe = 0;
|
|
if (dbgflushnum == 1)
|
|
{
|
|
if (pipe_done > 0) printf("DONE (pipes): %i\n", pipe_done);
|
|
}
|
|
gc->havestuff = EINA_FALSE;
|
|
}
|
|
|
|
EMODAPI int
|
|
evas_gl_common_buffer_dump(Evas_Engine_GL_Context *gc, const char* dname, const char* buf_name, int frame, const char *suffix)
|
|
{
|
|
RGBA_Image *im = NULL;
|
|
DATA32 *data1, *data2;
|
|
char fname[100];
|
|
int ok = 0;
|
|
|
|
if (suffix)
|
|
snprintf(fname, sizeof(fname), "./%s/win_%s-fc_%03d_%s.png", dname, buf_name, frame, suffix);
|
|
else
|
|
snprintf(fname, sizeof(fname), "./%s/win_%s-fc_%03d.png", dname, buf_name, frame);
|
|
fname[sizeof(fname) - 1] = '\0';
|
|
|
|
data1 = (DATA32 *)malloc(gc->w * gc->h * sizeof(DATA32));
|
|
data2 = (DATA32 *)malloc(gc->w * gc->h * sizeof(DATA32));
|
|
|
|
if ((!data1) || (!data2)) goto finish;
|
|
|
|
glReadPixels(0, 0, gc->w, gc->h, GL_RGBA,
|
|
GL_UNSIGNED_BYTE, (unsigned char*)data1);
|
|
|
|
// Flip the Y and change from RGBA TO BGRA
|
|
int i, j;
|
|
for (j = 0; j < gc->h; j++)
|
|
for (i = 0; i < gc->w; i++)
|
|
{
|
|
DATA32 d;
|
|
int idx1 = (j * gc->w) + i;
|
|
int idx2 = ((gc->h - 1) - j) * gc->w + i;
|
|
|
|
d = data1[idx1];
|
|
data2[idx2] = ((d & 0x000000ff) << 16) +
|
|
((d & 0x00ff0000) >> 16) +
|
|
((d & 0xff00ff00));
|
|
}
|
|
|
|
evas_common_convert_argb_premul(data2, gc->w * gc->h);
|
|
|
|
im = (RGBA_Image*) evas_cache_image_data(evas_common_image_cache_get(),
|
|
gc->w,
|
|
gc->h,
|
|
(DATA32 *)data2,
|
|
1,
|
|
EVAS_COLORSPACE_ARGB8888);
|
|
if (im)
|
|
{
|
|
im->image.data = data2;
|
|
if (im->image.data)
|
|
{
|
|
ok = evas_common_save_image_to_file(im, fname, NULL, 0, 0, NULL);
|
|
|
|
if (!ok) ERR("Error Saving file.");
|
|
}
|
|
|
|
evas_cache_image_drop(&im->cache_entry);
|
|
}
|
|
|
|
finish:
|
|
if (data1) free(data1);
|
|
if (data2) free(data2);
|
|
if (im) evas_cache_image_drop(&im->cache_entry);
|
|
|
|
if (ok) return 1;
|
|
else return 0;
|
|
}
|
|
|
|
Eina_Bool
|
|
evas_gl_common_module_open(void)
|
|
{
|
|
if (_evas_engine_GL_common_log_dom < 0)
|
|
_evas_engine_GL_common_log_dom = eina_log_domain_register
|
|
("evas-gl_common", EVAS_DEFAULT_LOG_COLOR);
|
|
if (_evas_engine_GL_common_log_dom < 0)
|
|
{
|
|
EINA_LOG_ERR("Can not create a module log domain.");
|
|
return EINA_FALSE;
|
|
}
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
void
|
|
evas_gl_common_module_close(void)
|
|
{
|
|
if (_evas_engine_GL_common_log_dom < 0) return;
|
|
eina_log_domain_unregister(_evas_engine_GL_common_log_dom);
|
|
_evas_engine_GL_common_log_dom = -1;
|
|
}
|