Commit 538865a6 authored by Laurent Aimar's avatar Laurent Aimar

Reorganized shader/program building (opengl).

parent a910b4e7
...@@ -204,6 +204,133 @@ static bool IsLuminance16Supported(int target) ...@@ -204,6 +204,133 @@ static bool IsLuminance16Supported(int target)
} }
#endif #endif
static void BuildVertexShader(vout_display_opengl_t *vgl,
GLint *shader)
{
/* Basic vertex shader */
const char *vertexShader =
"#version 120\n"
"varying vec4 TexCoord0,TexCoord1, TexCoord2;"
"attribute vec4 MultiTexCoord0,MultiTexCoord1,MultiTexCoord2;"
"attribute vec4 vertex_position;"
"void main() {"
" TexCoord0 = MultiTexCoord0;"
" TexCoord1 = MultiTexCoord1;"
" TexCoord2 = MultiTexCoord2;"
" gl_Position = vertex_position;"
"}";
*shader = vgl->CreateShader(GL_VERTEX_SHADER);
vgl->ShaderSource(*shader, 1, &vertexShader, NULL);
vgl->CompileShader(*shader);
}
static void BuildYUVFragmentShader(vout_display_opengl_t *vgl,
GLint *shader,
int *local_count,
GLfloat *local_value,
const video_format_t *fmt,
float yuv_range_correction)
{
/* [R/G/B][Y U V O] from TV range to full range
* XXX we could also do hue/brightness/constrast/gamma
* by simply changing the coefficients
*/
const float matrix_bt601_tv2full[12] = {
1.164383561643836, 0.0000, 1.596026785714286, -0.874202217873451 ,
1.164383561643836, -0.391762290094914, -0.812967647237771, 0.531667823499146 ,
1.164383561643836, 2.017232142857142, 0.0000, -1.085630789302022 ,
};
const float matrix_bt709_tv2full[12] = {
1.164383561643836, 0.0000, 1.792741071428571, -0.972945075016308 ,
1.164383561643836, -0.21324861427373, -0.532909328559444, 0.301482665475862 ,
1.164383561643836, 2.112401785714286, 0.0000, -1.133402217873451 ,
};
const float (*matrix) = fmt->i_height > 576 ? matrix_bt709_tv2full
: matrix_bt601_tv2full;
/* Basic linear YUV -> RGB conversion using bilinear interpolation */
const char *template_glsl_yuv =
"#version 120\n"
"uniform sampler2D Texture[3];"
"uniform vec4 coefficient[4];"
"varying vec4 TexCoord0,TexCoord1,TexCoord2;"
"void main(void) {"
" vec4 x,y,z,result;"
" x = texture2D(Texture[0], TexCoord0.st);"
" %c = texture2D(Texture[1], TexCoord1.st);"
" %c = texture2D(Texture[2], TexCoord2.st);"
" result = x * coefficient[0] + coefficient[3];"
" result = (y * coefficient[1]) + result;"
" result = (z * coefficient[2]) + result;"
" gl_FragColor = result;"
"}";
bool swap_uv = fmt->i_chroma == VLC_CODEC_YV12 ||
fmt->i_chroma == VLC_CODEC_YV9;
char *code;
if (asprintf(&code, template_glsl_yuv,
swap_uv ? 'z' : 'y',
swap_uv ? 'y' : 'z') < 0)
code = NULL;
for (int i = 0; i < 4; i++) {
float correction = i < 3 ? yuv_range_correction : 1.0;
/* We place coefficient values for coefficient[4] in one array from matrix values.
Notice that we fill values from top down instead of left to right.*/
for (int j = 0; j < 4; j++)
local_value[*local_count + i*4+j] = j < 3 ? correction * matrix[j*4+i]
: 0.0 ;
}
(*local_count) += 4;
*shader = vgl->CreateShader(GL_FRAGMENT_SHADER);
vgl->ShaderSource(*shader, 1, (const char **)&code, NULL);
vgl->CompileShader(*shader);
free(code);
}
static void BuildRGBFragmentShader(vout_display_opengl_t *vgl,
GLint *shader)
{
// Simple shader for RGB
const char *code =
"#version 120\n"
"uniform sampler2D Texture[3];"
"uniform vec4 fillColor;"
"varying vec4 TexCoord0,TexCoord1,TexCoord2;"
"void main()"
"{ "
" gl_FragColor = texture2D(Texture[0], TexCoord0.st)*fillColor;"
"}";
*shader = vgl->CreateShader(GL_FRAGMENT_SHADER);
vgl->ShaderSource(*shader, 1, &code, NULL);
vgl->CompileShader(*shader);
}
static void BuildRGBAFragmentShader(vout_display_opengl_t *vgl,
GLint *shader)
{
// Simple shader for RGBA
const char *code =
"#version 120\n"
"uniform sampler2D Texture[3];"
"uniform vec4 fillColor;"
"varying vec4 TexCoord0,TexCoord1,TexCoord2;"
"void main()"
"{ "
" gl_FragColor = texture2D(Texture[0], TexCoord0.st)*fillColor;"
"}";
*shader = vgl->CreateShader(GL_FRAGMENT_SHADER);
vgl->ShaderSource(*shader, 1, &code, NULL);
vgl->CompileShader(*shader);
}
vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt, vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
const vlc_fourcc_t **subpicture_chromas, const vlc_fourcc_t **subpicture_chromas,
vlc_gl_t *gl) vlc_gl_t *gl)
...@@ -344,150 +471,67 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt, ...@@ -344,150 +471,67 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
} }
} }
/* Build fragment program if needed */ /* Build program if needed */
vgl->program[0] = 0; vgl->program[0] =
vgl->program[1] = 0; vgl->program[1] = 0;
vgl->shader[0] =
vgl->shader[1] =
vgl->shader[2] = -1;
vgl->local_count = 0; vgl->local_count = 0;
vgl->shader[0] = vgl->shader[1] = vgl->shader[2] = -1;
if (supports_shaders) { if (supports_shaders) {
char *code = NULL; if (need_fs_yuv)
BuildYUVFragmentShader(vgl, &vgl->shader[0],
/* [R/G/B][Y U V O] from TV range to full range &vgl->local_count,
* XXX we could also do hue/brightness/constrast/gamma vgl->local_value,
* by simply changing the coefficients fmt, yuv_range_correction);
*/ else
const float matrix_bt601_tv2full[12] = { BuildRGBFragmentShader(vgl, &vgl->shader[0]);
1.164383561643836, 0.0000, 1.596026785714286, -0.874202217873451 , BuildRGBAFragmentShader(vgl, &vgl->shader[1]);
1.164383561643836, -0.391762290094914, -0.812967647237771, 0.531667823499146 , BuildVertexShader(vgl, &vgl->shader[2]);
1.164383561643836, 2.017232142857142, 0.0000, -1.085630789302022 ,
}; /* Check shaders messages */
const float matrix_bt709_tv2full[12] = { for (unsigned j = 0; j < 3; j++) {
1.164383561643836, 0.0000, 1.792741071428571, -0.972945075016308 , int infoLength;
1.164383561643836, -0.21324861427373, -0.532909328559444, 0.301482665475862 , vgl->GetShaderiv(vgl->shader[j], GL_INFO_LOG_LENGTH, &infoLength);
1.164383561643836, 2.112401785714286, 0.0000, -1.133402217873451 , if (infoLength <= 1)
}; continue;
const float (*matrix) = fmt->i_height > 576 ? matrix_bt709_tv2full
: matrix_bt601_tv2full; char *infolog = malloc(infoLength);
int charsWritten;
/* Basic linear YUV -> RGB conversion using bilinear interpolation */ vgl->GetShaderInfoLog(vgl->shader[j], infoLength, &charsWritten, infolog);
const char *template_glsl_yuv = fprintf(stderr, "shader %d: %s\n", j, infolog);
"#version 120\n" free(infolog);
"uniform sampler2D Texture[3];"
"uniform vec4 coefficient[4];"
"varying vec4 TexCoord0,TexCoord1,TexCoord2;"
"void main(void) {"
" vec4 x,y,z,result;"
" x = texture2D(Texture[0], TexCoord0.st);"
" %c = texture2D(Texture[1], TexCoord1.st);"
" %c = texture2D(Texture[2], TexCoord2.st);"
" result = x * coefficient[0] + coefficient[3];"
" result = (y * coefficient[1]) + result;"
" result = (z * coefficient[2]) + result;"
" gl_FragColor = result;"
"}";
bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
vgl->fmt.i_chroma == VLC_CODEC_YV9;
if (asprintf(&code, template_glsl_yuv,
swap_uv ? 'z' : 'y',
swap_uv ? 'y' : 'z') < 0)
code = NULL;
for (int i = 0; i < 4; i++) {
float correction = i < 3 ? yuv_range_correction : 1.0;
/* We place coefficient values for coefficient[4] in one array from matrix values.
Notice that we fill values from top down instead of left to right.*/
for (int j = 0; j < 4; j++)
vgl->local_value[vgl->local_count + i*4+j] = j < 3 ? correction * matrix[j*4+i] : 0.0 ;
} }
vgl->local_count += 4;
// Basic vertex shader that we use in both cases
const char *vertexShader =
"#version 120\n"
"varying vec4 TexCoord0,TexCoord1, TexCoord2;"
"attribute vec4 MultiTexCoord0,MultiTexCoord1,MultiTexCoord2;"
"attribute vec4 vertex_position;"
"void main() {"
" TexCoord0 = MultiTexCoord0;"
" TexCoord1 = MultiTexCoord1;"
" TexCoord2 = MultiTexCoord2;"
" gl_Position = vertex_position;"
"}";
// Dummy shader for text overlay vgl->program[0] = vgl->CreateProgram();
const char *helloShader = vgl->AttachShader(vgl->program[0], vgl->shader[0]);
"#version 120\n" vgl->AttachShader(vgl->program[0], vgl->shader[2]);
"uniform sampler2D Texture[3];" vgl->LinkProgram(vgl->program[0]);
"uniform vec4 fillColor;"
"varying vec4 TexCoord0,TexCoord1,TexCoord2;"
"void main()"
"{ "
" gl_FragColor = texture2D(Texture[0], TexCoord0.st)*fillColor;"
"}";
vgl->shader[2] = vgl->CreateShader(GL_VERTEX_SHADER);
vgl->ShaderSource(vgl->shader[2], 1, (const GLchar **)&vertexShader, NULL);
vgl->CompileShader(vgl->shader[2]);
/* Create 'dummy' shader that handles subpicture overlay for now*/
vgl->shader[1] = vgl->CreateShader(GL_FRAGMENT_SHADER);
vgl->ShaderSource(vgl->shader[1], 1, &helloShader, NULL);
vgl->CompileShader(vgl->shader[1]);
vgl->program[1] = vgl->CreateProgram(); vgl->program[1] = vgl->CreateProgram();
vgl->AttachShader(vgl->program[1], vgl->shader[1]); vgl->AttachShader(vgl->program[1], vgl->shader[1]);
vgl->AttachShader(vgl->program[1], vgl->shader[2]); vgl->AttachShader(vgl->program[1], vgl->shader[2]);
vgl->LinkProgram(vgl->program[1]); vgl->LinkProgram(vgl->program[1]);
// Create shader from code /* Check program messages */
vgl->shader[0] = vgl->CreateShader(GL_FRAGMENT_SHADER);
vgl->program[0] = vgl->CreateProgram();
if (need_fs_yuv) {
vgl->ShaderSource(vgl->shader[0], 1, (const GLchar **)&code, NULL);
vgl->CompileShader(vgl->shader[0]);
vgl->AttachShader(vgl->program[0], vgl->shader[0]);
} else {
/* Use simpler shader if we don't need to to yuv -> rgb,
for example when input is allready rgb (.bmp image).*/
vgl->AttachShader(vgl->program[0], vgl->shader[1]);
}
vgl->AttachShader(vgl->program[0], vgl->shader[2]);
vgl->LinkProgram(vgl->program[0]);
free(code);
for (GLuint i = 0; i < 2; i++) { for (GLuint i = 0; i < 2; i++) {
int infoLength = 0; int infoLength = 0;
vgl->GetProgramiv(vgl->program[i], GL_INFO_LOG_LENGTH, &infoLength); vgl->GetProgramiv(vgl->program[i], GL_INFO_LOG_LENGTH, &infoLength);
if (infoLength > 1) { if (infoLength <= 1)
int charsWritten; continue;
char *infolog; char *infolog = malloc(infoLength);
int charsWritten;
infolog = malloc(infoLength); vgl->GetProgramInfoLog(vgl->program[i], infoLength, &charsWritten, infolog);
vgl->GetProgramInfoLog(vgl->program[i], infoLength, &charsWritten, infolog); fprintf(stderr, "shader program %d: %s\n", i, infolog);
fprintf(stderr, "shader program %d: %s\n", i, infolog); free(infolog);
free(infolog);
/* If there is some message, better to check linking is ok */
/* Check shaders messages too */ GLint link_status = GL_TRUE;
for (GLuint j = 0; j < 2; j++) { vgl->GetProgramiv(vgl->program[i], GL_LINK_STATUS, &link_status);
vgl->GetShaderiv(vgl->shader[j], GL_INFO_LOG_LENGTH, &infoLength); if (link_status == GL_FALSE) {
if (infoLength > 1) { fprintf(stderr, "Unable to use program %d\n", i);
infolog = malloc(infoLength); free(vgl);
vgl->GetShaderInfoLog(vgl->shader[j], infoLength, &charsWritten, infolog); return NULL;
fprintf(stderr, "shader %d: %s\n", j, infolog);
free(infolog);
}
}
/* If there is some message, better to check linking is ok */
GLint link_status = GL_TRUE;
vgl->GetProgramiv(vgl->program[i], GL_LINK_STATUS, &link_status);
if (link_status == GL_FALSE) {
fprintf(stderr, "Unable to use program %d\n", i);
free(vgl);
return NULL;
}
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment