efl/src/modules/evas/engines/gl_common/evas_gl_shader.c

668 lines
16 KiB
C

#include "evas_gl_private.h"
/////////////////////////////////////////////
const char rect_frag_glsl[] =
#include "shader/rect_frag.h"
;
Evas_GL_Program_Source shader_rect_frag_src =
{
rect_frag_glsl,
NULL, 0
};
const char rect_vert_glsl[] =
#include "shader/rect_vert.h"
;
Evas_GL_Program_Source shader_rect_vert_src =
{
rect_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char font_frag_glsl[] =
#include "shader/font_frag.h"
;
Evas_GL_Program_Source shader_font_frag_src =
{
font_frag_glsl,
NULL, 0
};
const char font_vert_glsl[] =
#include "shader/font_vert.h"
;
Evas_GL_Program_Source shader_font_vert_src =
{
font_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char yuv_frag_glsl[] =
#include "shader/yuv_frag.h"
;
Evas_GL_Program_Source shader_yuv_frag_src =
{
yuv_frag_glsl,
NULL, 0
};
const char yuv_vert_glsl[] =
#include "shader/yuv_vert.h"
;
Evas_GL_Program_Source shader_yuv_vert_src =
{
yuv_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char yuy2_frag_glsl[] =
#include "shader/yuy2_frag.h"
;
Evas_GL_Program_Source shader_yuy2_frag_src =
{
yuy2_frag_glsl,
NULL, 0
};
const char yuy2_vert_glsl[] =
#include "shader/yuy2_vert.h"
;
Evas_GL_Program_Source shader_yuy2_vert_src =
{
yuy2_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char yuy2_nomul_frag_glsl[] =
#include "shader/yuy2_nomul_frag.h"
;
Evas_GL_Program_Source shader_yuy2_nomul_frag_src =
{
yuy2_nomul_frag_glsl,
NULL, 0
};
const char yuy2_nomul_vert_glsl[] =
#include "shader/yuy2_nomul_vert.h"
;
Evas_GL_Program_Source shader_yuy2_nomul_vert_src =
{
yuy2_nomul_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char nv12_nomul_vert_glsl[] =
#include "shader/nv12_nomul_vert.h"
;
Evas_GL_Program_Source shader_nv12_nomul_vert_src =
{
nv12_nomul_vert_glsl,
NULL, 0
};
const char nv12_vert_glsl[] =
#include "shader/nv12_vert.h"
;
Evas_GL_Program_Source shader_nv12_vert_src =
{
nv12_vert_glsl,
NULL, 0
};
const char nv12_frag_glsl[] =
#include "shader/nv12_frag.h"
;
Evas_GL_Program_Source shader_nv12_frag_src =
{
nv12_frag_glsl,
NULL, 0
};
const char nv12_nomul_frag_glsl[] =
#include "shader/nv12_nomul_frag.h"
;
Evas_GL_Program_Source shader_nv12_nomul_frag_src =
{
nv12_nomul_frag_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char yuv_nomul_frag_glsl[] =
#include "shader/yuv_nomul_frag.h"
;
Evas_GL_Program_Source shader_yuv_nomul_frag_src =
{
yuv_nomul_frag_glsl,
NULL, 0
};
const char yuv_nomul_vert_glsl[] =
#include "shader/yuv_nomul_vert.h"
;
Evas_GL_Program_Source shader_yuv_nomul_vert_src =
{
yuv_nomul_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char tex_frag_glsl[] =
#include "shader/tex_frag.h"
;
Evas_GL_Program_Source shader_tex_frag_src =
{
tex_frag_glsl,
NULL, 0
};
const char tex_vert_glsl[] =
#include "shader/tex_vert.h"
;
Evas_GL_Program_Source shader_tex_vert_src =
{
tex_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char tex_nomul_frag_glsl[] =
#include "shader/tex_nomul_frag.h"
;
Evas_GL_Program_Source shader_tex_nomul_frag_src =
{
tex_nomul_frag_glsl,
NULL, 0
};
const char tex_nomul_vert_glsl[] =
#include "shader/tex_nomul_vert.h"
;
Evas_GL_Program_Source shader_tex_nomul_vert_src =
{
tex_nomul_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char img_frag_glsl[] =
#include "shader/img_frag.h"
;
Evas_GL_Program_Source shader_img_frag_src =
{
img_frag_glsl,
NULL, 0
};
const char img_vert_glsl[] =
#include "shader/img_vert.h"
;
Evas_GL_Program_Source shader_img_vert_src =
{
img_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char img_nomul_frag_glsl[] =
#include "shader/img_nomul_frag.h"
;
Evas_GL_Program_Source shader_img_nomul_frag_src =
{
img_nomul_frag_glsl,
NULL, 0
};
const char img_nomul_vert_glsl[] =
#include "shader/img_nomul_vert.h"
;
Evas_GL_Program_Source shader_img_nomul_vert_src =
{
img_nomul_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char img_bgra_frag_glsl[] =
#include "shader/img_bgra_frag.h"
;
Evas_GL_Program_Source shader_img_bgra_frag_src =
{
img_bgra_frag_glsl,
NULL, 0
};
const char img_bgra_vert_glsl[] =
#include "shader/img_bgra_vert.h"
;
Evas_GL_Program_Source shader_img_bgra_vert_src =
{
img_bgra_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char img_mask_frag_glsl[] =
#include "shader/img_mask_frag.h"
;
Evas_GL_Program_Source shader_img_mask_frag_src =
{
img_mask_frag_glsl,
NULL, 0
};
const char img_mask_vert_glsl[] =
#include "shader/img_mask_vert.h"
;
Evas_GL_Program_Source shader_img_mask_vert_src =
{
img_mask_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
const char img_bgra_nomul_frag_glsl[] =
#include "shader/img_bgra_nomul_frag.h"
;
Evas_GL_Program_Source shader_img_bgra_nomul_frag_src =
{
img_bgra_nomul_frag_glsl,
NULL, 0
};
const char img_bgra_nomul_vert_glsl[] =
#include "shader/img_bgra_nomul_vert.h"
;
Evas_GL_Program_Source shader_img_bgra_nomul_vert_src =
{
img_bgra_nomul_vert_glsl,
NULL, 0
};
/////////////////////////////////////////////
static void
gl_compile_link_error(GLuint target, const char *action)
{
int loglen = 0, chars = 0;
char *logtxt;
/* Shader info log */
glGetShaderiv(target, GL_INFO_LOG_LENGTH, &loglen);
if (loglen > 0)
{
logtxt = calloc(loglen, sizeof(char));
if (logtxt)
{
glGetShaderInfoLog(target, loglen, &chars, logtxt);
ERR("Failed to %s: %s", action, logtxt);
free(logtxt);
}
}
/* Program info log */
glGetProgramiv(target, GL_INFO_LOG_LENGTH, &loglen);
if (loglen > 0)
{
logtxt = calloc(loglen, sizeof(char));
if (logtxt)
{
glGetProgramInfoLog(target, loglen, &chars, logtxt);
ERR("Failed to %s: %s", action, logtxt);
free(logtxt);
}
}
}
static int
_evas_gl_common_shader_program_binary_init(Evas_GL_Program *p,
const char *pname,
Eet_File *ef)
{
int res = 0, num = 0, length = 0;
int *formats = NULL;
void *data = NULL;
GLint ok = 0;
if (!ef) return res;
data = eet_read(ef, pname, &length);
if ((!data) || (length <= 0)) goto finish;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &num);
if (num <= 0) goto finish;
formats = calloc(num, sizeof(int));
if (!formats) goto finish;
glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, formats);
if (!formats[0]) goto finish;
p->prog = glCreateProgram();
#if 1
// TODO: invalid rendering error occurs when attempting to use a
// glProgramBinary. in order to render correctly we should create a dummy
// vertex shader.
p->vert = glCreateShader(GL_VERTEX_SHADER);
glAttachShader(p->prog, p->vert);
p->frag = glCreateShader(GL_FRAGMENT_SHADER);
glAttachShader(p->prog, p->frag);
#endif
glsym_glProgramBinary(p->prog, formats[0], data, length);
glBindAttribLocation(p->prog, SHAD_VERTEX, "vertex");
glBindAttribLocation(p->prog, SHAD_COLOR, "color");
glBindAttribLocation(p->prog, SHAD_TEXUV, "tex_coord");
glBindAttribLocation(p->prog, SHAD_TEXUV2, "tex_coord2");
glBindAttribLocation(p->prog, SHAD_TEXUV3, "tex_coord3");
glBindAttribLocation(p->prog, SHAD_TEXM, "tex_coordm");
glGetProgramiv(p->prog, GL_LINK_STATUS, &ok);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
if (!ok)
{
gl_compile_link_error(p->prog, "load a program object");
ERR("Abort load of program (%s)", pname);
goto finish;
}
res = 1;
finish:
if (formats) free(formats);
if (data) free(data);
if ((!res) && (p->prog))
{
glDeleteProgram(p->prog);
p->prog = 0;
}
return res;
}
static int
_evas_gl_common_shader_program_binary_save(Evas_GL_Program *p,
const char *pname,
Eet_File *ef)
{
void* data = NULL;
GLenum format;
int length = 0, size = 0;
if (!glsym_glGetProgramBinary) return 0;
glGetProgramiv(p->prog, GL_PROGRAM_BINARY_LENGTH, &length);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
if (length <= 0) return 0;
data = malloc(length);
if (!data) return 0;
glsym_glGetProgramBinary(p->prog, length, &size, &format, data);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
if (length != size)
{
free(data);
return 0;
}
if (eet_write(ef, pname, data, length, 1) < 0)
{
if (data) free(data);
return 0;
}
if (data) free(data);
return 1;
}
static int
_evas_gl_common_shader_program_source_init(Evas_GL_Program *p,
Evas_GL_Program_Source *vert,
Evas_GL_Program_Source *frag,
const char *name)
{
GLint ok;
p->vert = glCreateShader(GL_VERTEX_SHADER);
p->frag = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(p->vert, 1,
(const char **)&(vert->src), NULL);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glCompileShader(p->vert);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
ok = 0;
glGetShaderiv(p->vert, GL_COMPILE_STATUS, &ok);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
if (!ok)
{
gl_compile_link_error(p->vert, "compile vertex shader");
ERR("Abort compile of shader vert (%s): %s", name, vert->src);
return 0;
}
glShaderSource(p->frag, 1,
(const char **)&(frag->src), NULL);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glCompileShader(p->frag);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
ok = 0;
glGetShaderiv(p->frag, GL_COMPILE_STATUS, &ok);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
if (!ok)
{
gl_compile_link_error(p->frag, "compile fragment shader");
ERR("Abort compile of shader frag (%s): %s", name, frag->src);
return 0;
}
p->prog = glCreateProgram();
#ifdef GL_GLES
#else
if ((glsym_glGetProgramBinary) && (glsym_glProgramParameteri))
glsym_glProgramParameteri(p->prog, GL_PROGRAM_BINARY_RETRIEVABLE_HINT,
GL_TRUE);
#endif
glAttachShader(p->prog, p->vert);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glAttachShader(p->prog, p->frag);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glBindAttribLocation(p->prog, SHAD_VERTEX, "vertex");
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glBindAttribLocation(p->prog, SHAD_COLOR, "color");
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glBindAttribLocation(p->prog, SHAD_TEXUV, "tex_coord");
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glBindAttribLocation(p->prog, SHAD_TEXUV2, "tex_coord2");
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glBindAttribLocation(p->prog, SHAD_TEXUV3, "tex_coord3");
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glBindAttribLocation(p->prog, SHAD_TEXM, "tex_coordm");
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glLinkProgram(p->prog);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
ok = 0;
glGetProgramiv(p->prog, GL_LINK_STATUS, &ok);
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
if (!ok)
{
gl_compile_link_error(p->prog, "link fragment and vertex shaders");
ERR("Abort compile of shader frag (%s): %s", name, frag->src);
ERR("Abort compile of shader vert (%s): %s", name, vert->src);
return 0;
}
return 1;
}
#define SHADER_SOURCE_LINE(Big, Small) \
{ SHADER_##Big, &(shader_##Small##_vert_src), &(shader_##Small##_frag_src), #Small }
#define SHADER_SOURCE_FILTER_LINE(Big, Small) \
{ SHADER_##Big, &(shader_img_vert_src), &(shader_##Small##_frag_src), #Small }
static const struct {
Evas_GL_Shader id;
Evas_GL_Program_Source *vert;
Evas_GL_Program_Source *frag;
const char *name;
} _shaders_source[] = {
SHADER_SOURCE_LINE(RECT, rect),
SHADER_SOURCE_LINE(FONT, font),
SHADER_SOURCE_LINE(IMG, img),
SHADER_SOURCE_LINE(IMG_NOMUL, img_nomul),
SHADER_SOURCE_LINE(IMG_BGRA, img_bgra),
SHADER_SOURCE_LINE(IMG_BGRA_NOMUL, img_bgra_nomul),
SHADER_SOURCE_LINE(IMG_MASK, img_mask),
SHADER_SOURCE_LINE(YUV, yuv),
SHADER_SOURCE_LINE(YUV_NOMUL, yuv_nomul),
SHADER_SOURCE_LINE(YUY2, yuy2),
SHADER_SOURCE_LINE(YUY2_NOMUL, yuy2_nomul),
SHADER_SOURCE_LINE(NV12, nv12),
SHADER_SOURCE_LINE(NV12_NOMUL, nv12_nomul),
SHADER_SOURCE_LINE(TEX, tex),
SHADER_SOURCE_LINE(TEX_NOMUL, tex_nomul),
};
static int
_evas_gl_common_shader_source_init(Evas_GL_Shared *shared)
{
unsigned int i;
for (i = 0; i < sizeof (_shaders_source) / sizeof (_shaders_source[0]); ++i)
if (!_evas_gl_common_shader_program_source_init(&(shared->shader[_shaders_source[i].id]),
_shaders_source[i].vert,
_shaders_source[i].frag,
_shaders_source[i].name))
return 0;
return 1;
}
static int
_evas_gl_common_shader_binary_init(Evas_GL_Shared *shared)
{
/* check eet */
Eet_File *et = NULL;
char bin_dir_path[PATH_MAX];
char bin_file_path[PATH_MAX];
unsigned int i;
if (!evas_gl_common_file_cache_dir_check(bin_dir_path, sizeof(bin_dir_path)))
return 0;
if (!evas_gl_common_file_cache_file_check(bin_dir_path, "binary_shader", bin_file_path,
sizeof(bin_dir_path)))
return 0;
/* use eet */
if (!eet_init()) return 0;
et = eet_open(bin_file_path, EET_FILE_MODE_READ);
if (!et) goto error;
for (i = 0; i < sizeof (_shaders_source) / sizeof (_shaders_source[0]); ++i)
if (!_evas_gl_common_shader_program_binary_init(&(shared->shader[_shaders_source[i].id]),
_shaders_source[i].name,
et))
goto error;
if (et) eet_close(et);
eet_shutdown();
return 1;
error:
if (et) eet_close(et);
eet_shutdown();
return 0;
}
static int
_evas_gl_common_shader_binary_save(Evas_GL_Shared *shared)
{
/* check eet */
Eet_File *et = NULL; //check eet file
int tmpfd;
int res = 0;
char bin_dir_path[PATH_MAX];
char bin_file_path[PATH_MAX];
char tmp_file[PATH_MAX];
unsigned int i;
if (!evas_gl_common_file_cache_dir_check(bin_dir_path, sizeof(bin_dir_path)))
{
res = evas_gl_common_file_cache_mkpath(bin_dir_path);
if (!res) return 0; /* we can't make directory */
}
evas_gl_common_file_cache_file_check(bin_dir_path, "binary_shader", bin_file_path,
sizeof(bin_dir_path));
/* use mkstemp for writing */
snprintf(tmp_file, sizeof(tmp_file), "%s.XXXXXX", bin_file_path);
tmpfd = mkstemp(tmp_file);
if (tmpfd < 0) goto error;
close(tmpfd);
/* use eet */
if (!eet_init()) goto error;
et = eet_open(tmp_file, EET_FILE_MODE_WRITE);
if (!et) goto error;
for (i = 0; i < sizeof (_shaders_source) / sizeof (_shaders_source[0]); ++i)
if (!_evas_gl_common_shader_program_binary_save(&(shared->shader[_shaders_source[i].id]),
_shaders_source[i].name,
et))
goto error;
if (eet_close(et) != EET_ERROR_NONE) goto error;
if (rename(tmp_file,bin_file_path) < 0) goto error;
eet_shutdown();
return 1;
error:
if (et) eet_close(et);
if (evas_gl_common_file_cache_file_exists(tmp_file)) unlink(tmp_file);
eet_shutdown();
return 0;
}
int
evas_gl_common_shader_program_init(Evas_GL_Shared *shared)
{
// gl support binary shader and get env of binary shader path
if (shared->info.bin_program &&
_evas_gl_common_shader_binary_init(shared)) return 1;
/* compile all shader.*/
if (!_evas_gl_common_shader_source_init(shared)) return 0;
/* success compile all shader. if gl support binary shader, we need to save */
if (shared->info.bin_program) _evas_gl_common_shader_binary_save(shared);
return 1;
}
void
evas_gl_common_shader_program_init_done(void)
{
#ifdef GL_GLES
glReleaseShaderCompiler();
#else
if (glsym_glReleaseShaderCompiler) glsym_glReleaseShaderCompiler();
#endif
}
void
evas_gl_common_shader_program_shutdown(Evas_GL_Program *p)
{
if (p->vert) glDeleteShader(p->vert);
if (p->frag) glDeleteShader(p->frag);
if (p->prog) glDeleteProgram(p->prog);
}