diff options
Diffstat (limited to 'libvo/gl_common.c')
-rw-r--r-- | libvo/gl_common.c | 860 |
1 files changed, 623 insertions, 237 deletions
diff --git a/libvo/gl_common.c b/libvo/gl_common.c index 3b723493db..621bfa39a8 100644 --- a/libvo/gl_common.c +++ b/libvo/gl_common.c @@ -37,6 +37,7 @@ #include <stdio.h> #include <string.h> #include <ctype.h> +#include <stdbool.h> #include <math.h> #include "talloc.h" #include "gl_common.h" @@ -48,6 +49,31 @@ //! \defgroup glgeneral OpenGL general helper functions +// GLU has this as gluErrorString (we don't use GLU, as it is legacy-OpenGL) +static const char *gl_error_to_string(GLenum error) +{ + switch (error) { + case GL_INVALID_ENUM: return "INVALID_ENUM"; + case GL_INVALID_VALUE: return "INVALID_VALUE"; + case GL_INVALID_OPERATION: return "INVALID_OPERATION"; + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "INVALID_FRAMEBUFFER_OPERATION"; + case GL_OUT_OF_MEMORY: return "OUT_OF_MEMORY"; + default: return "unknown"; + } +} + +void glCheckError(GL *gl, const char *info) +{ + for (;;) { + GLenum error = gl->GetError(); + if (error == GL_NO_ERROR) + break; + mp_msg(MSGT_VO, MSGL_ERR, "[gl] %s: OpenGL error %s.\n", info, + gl_error_to_string(error)); + } +} + //! \defgroup glcontext OpenGL context management helper functions //! \defgroup gltexture OpenGL texture handling helper functions @@ -74,62 +100,6 @@ void glAdjustAlignment(GL *gl, int stride) gl->PixelStorei(GL_PACK_ALIGNMENT, gl_alignment); } -struct gl_name_map_struct { - GLint value; - const char *name; -}; - -#undef MAP -#define MAP(a) {a, # a} -//! mapping table for the glValName function -static const struct gl_name_map_struct gl_name_map[] = { - // internal format - MAP(GL_R3_G3_B2), MAP(GL_RGB4), MAP(GL_RGB5), MAP(GL_RGB8), - MAP(GL_RGB10), MAP(GL_RGB12), MAP(GL_RGB16), MAP(GL_RGBA2), - MAP(GL_RGBA4), MAP(GL_RGB5_A1), MAP(GL_RGBA8), MAP(GL_RGB10_A2), - MAP(GL_RGBA12), MAP(GL_RGBA16), MAP(GL_LUMINANCE8), MAP(GL_LUMINANCE16), - MAP(GL_R16), - - // format - MAP(GL_RGB), MAP(GL_RGBA), MAP(GL_RED), MAP(GL_GREEN), MAP(GL_BLUE), - MAP(GL_ALPHA), MAP(GL_LUMINANCE), MAP(GL_LUMINANCE_ALPHA), - MAP(GL_COLOR_INDEX), - // rest 1.2 only - MAP(GL_BGR), MAP(GL_BGRA), - - //type - MAP(GL_BYTE), MAP(GL_UNSIGNED_BYTE), MAP(GL_SHORT), MAP(GL_UNSIGNED_SHORT), - MAP(GL_INT), MAP(GL_UNSIGNED_INT), MAP(GL_FLOAT), MAP(GL_DOUBLE), - MAP(GL_2_BYTES), MAP(GL_3_BYTES), MAP(GL_4_BYTES), - // rest 1.2 only - MAP(GL_UNSIGNED_BYTE_3_3_2), MAP(GL_UNSIGNED_BYTE_2_3_3_REV), - MAP(GL_UNSIGNED_SHORT_5_6_5), MAP(GL_UNSIGNED_SHORT_5_6_5_REV), - MAP(GL_UNSIGNED_SHORT_4_4_4_4), MAP(GL_UNSIGNED_SHORT_4_4_4_4_REV), - MAP(GL_UNSIGNED_SHORT_5_5_5_1), MAP(GL_UNSIGNED_SHORT_1_5_5_5_REV), - MAP(GL_UNSIGNED_INT_8_8_8_8), MAP(GL_UNSIGNED_INT_8_8_8_8_REV), - MAP(GL_UNSIGNED_INT_10_10_10_2), MAP(GL_UNSIGNED_INT_2_10_10_10_REV), - {0, 0} -}; -#undef MAP - -/** - * \brief return the name of an OpenGL constant - * \param value the constant - * \return name of the constant or "Unknown format!" - * \ingroup glgeneral - */ -const char *glValName(GLint value) -{ - int i = 0; - - while (gl_name_map[i].name) { - if (gl_name_map[i].value == value) - return gl_name_map[i].name; - i++; - } - return "Unknown format!"; -} - //! always return this format as internal texture format in glFindFormat #define TEXTUREFORMAT_ALWAYS GL_RGB8 #undef TEXTUREFORMAT_ALWAYS @@ -218,8 +188,8 @@ int glFindFormat(uint32_t fmt, int have_texture_rg, int *bpp, GLint *gl_texfmt, // we do not support palettized formats, although the format the // swscale produces works case IMGFMT_RGB8: - gl_format = GL_RGB; - gl_type = GL_UNSIGNED_BYTE_2_3_3_REV; + *gl_format = GL_RGB; + *gl_type = GL_UNSIGNED_BYTE_2_3_3_REV; break; #endif case IMGFMT_RGB15: @@ -232,12 +202,12 @@ int glFindFormat(uint32_t fmt, int have_texture_rg, int *bpp, GLint *gl_texfmt, break; #if 0 case IMGFMT_BGR8: - // special case as red and blue have a differen number of bits. + // special case as red and blue have a different number of bits. // GL_BGR and GL_UNSIGNED_BYTE_3_3_2 isn't supported at least // by nVidia drivers, and in addition would give more bits to // blue than to red, which isn't wanted - gl_format = GL_RGB; - gl_type = GL_UNSIGNED_BYTE_3_3_2; + *gl_format = GL_RGB; + *gl_type = GL_UNSIGNED_BYTE_3_3_2; break; #endif case IMGFMT_BGR15: @@ -295,45 +265,28 @@ typedef struct { const char *extstr; const char *funcnames[7]; void *fallback; + bool is_gl3; } extfunc_desc_t; #define DEF_FUNC_DESC(name) \ - {offsetof(GL, name), NULL, {"gl" # name, NULL}, gl ## name} + {offsetof(GL, name), NULL, {"gl" # name}, gl ## name} #define DEF_EXT_FUNCS(...) __VA_ARGS__ #define DEF_EXT_DESC(name, ext, funcnames) \ {offsetof(GL, name), ext, {DEF_EXT_FUNCS funcnames}} +// These are mostly handled the same, but needed because at least the MESA +// headers don't define any function prototypes for these. +#define DEF_GL3_DESC(name) \ + {offsetof(GL, name), NULL, {"gl" # name}, NULL, .is_gl3 = true} static const extfunc_desc_t extfuncs[] = { // these aren't extension functions but we query them anyway to allow // different "backends" with one binary - DEF_FUNC_DESC(Begin), - DEF_FUNC_DESC(End), DEF_FUNC_DESC(Viewport), - DEF_FUNC_DESC(MatrixMode), - DEF_FUNC_DESC(LoadIdentity), - DEF_FUNC_DESC(Translated), - DEF_FUNC_DESC(Scaled), - DEF_FUNC_DESC(Ortho), - DEF_FUNC_DESC(Frustum), - DEF_FUNC_DESC(PushMatrix), - DEF_FUNC_DESC(PopMatrix), DEF_FUNC_DESC(Clear), - DEF_FUNC_DESC(GenLists), - DEF_FUNC_DESC(DeleteLists), - DEF_FUNC_DESC(NewList), - DEF_FUNC_DESC(EndList), - DEF_FUNC_DESC(CallList), - DEF_FUNC_DESC(CallLists), DEF_FUNC_DESC(GenTextures), DEF_FUNC_DESC(DeleteTextures), - DEF_FUNC_DESC(TexEnvf), DEF_FUNC_DESC(TexEnvi), - DEF_FUNC_DESC(Color4ub), - DEF_FUNC_DESC(Color3f), - DEF_FUNC_DESC(Color4f), DEF_FUNC_DESC(ClearColor), - DEF_FUNC_DESC(ClearDepth), - DEF_FUNC_DESC(DepthFunc), DEF_FUNC_DESC(Enable), DEF_FUNC_DESC(Disable), DEF_FUNC_DESC(DrawBuffer), @@ -349,19 +302,43 @@ static const extfunc_desc_t extfuncs[] = { DEF_FUNC_DESC(TexParameteri), DEF_FUNC_DESC(TexParameterf), DEF_FUNC_DESC(TexParameterfv), - DEF_FUNC_DESC(TexCoord2f), - DEF_FUNC_DESC(TexCoord2fv), - DEF_FUNC_DESC(Vertex2f), - DEF_FUNC_DESC(Vertex3f), - DEF_FUNC_DESC(Normal3f), - DEF_FUNC_DESC(Lightfv), - DEF_FUNC_DESC(ColorMaterial), - DEF_FUNC_DESC(ShadeModel), DEF_FUNC_DESC(GetIntegerv), + DEF_FUNC_DESC(GetBooleanv), DEF_FUNC_DESC(ColorMask), DEF_FUNC_DESC(ReadPixels), DEF_FUNC_DESC(ReadBuffer), + DEF_FUNC_DESC(DrawArrays), + DEF_FUNC_DESC(GetString), + DEF_FUNC_DESC(GetError), + // legacy GL functions (1.x - 2.x) + DEF_FUNC_DESC(Begin), + DEF_FUNC_DESC(End), + DEF_FUNC_DESC(MatrixMode), + DEF_FUNC_DESC(LoadIdentity), + DEF_FUNC_DESC(Translated), + DEF_FUNC_DESC(Scaled), + DEF_FUNC_DESC(Ortho), + DEF_FUNC_DESC(PushMatrix), + DEF_FUNC_DESC(PopMatrix), + DEF_FUNC_DESC(GenLists), + DEF_FUNC_DESC(DeleteLists), + DEF_FUNC_DESC(NewList), + DEF_FUNC_DESC(EndList), + DEF_FUNC_DESC(CallList), + DEF_FUNC_DESC(CallLists), + DEF_FUNC_DESC(Color4ub), + DEF_FUNC_DESC(Color4f), + DEF_FUNC_DESC(TexCoord2f), + DEF_FUNC_DESC(TexCoord2fv), + DEF_FUNC_DESC(Vertex2f), + DEF_FUNC_DESC(VertexPointer), + DEF_FUNC_DESC(ColorPointer), + DEF_FUNC_DESC(TexCoordPointer), + DEF_FUNC_DESC(EnableClientState), + DEF_FUNC_DESC(DisableClientState), + + // OpenGL extension functions DEF_EXT_DESC(GenBuffers, NULL, ("glGenBuffers", "glGenBuffersARB")), DEF_EXT_DESC(DeleteBuffers, NULL, @@ -374,18 +351,6 @@ static const extfunc_desc_t extfuncs[] = { ("glUnmapBuffer", "glUnmapBufferARB")), DEF_EXT_DESC(BufferData, NULL, ("glBufferData", "glBufferDataARB")), - DEF_EXT_DESC(BeginFragmentShader, "ATI_fragment_shader", - ("glBeginFragmentShaderATI")), - DEF_EXT_DESC(EndFragmentShader, "ATI_fragment_shader", - ("glEndFragmentShaderATI")), - DEF_EXT_DESC(SampleMap, "ATI_fragment_shader", - ("glSampleMapATI")), - DEF_EXT_DESC(ColorFragmentOp2, "ATI_fragment_shader", - ("glColorFragmentOp2ATI")), - DEF_EXT_DESC(ColorFragmentOp3, "ATI_fragment_shader", - ("glColorFragmentOp3ATI")), - DEF_EXT_DESC(SetFragmentShaderConstant, "ATI_fragment_shader", - ("glSetFragmentShaderConstantATI")), DEF_EXT_DESC(ActiveTexture, NULL, ("glActiveTexture", "glActiveTextureARB")), DEF_EXT_DESC(BindTexture, NULL, @@ -400,7 +365,7 @@ static const extfunc_desc_t extfuncs[] = { ("glBindProgramARB")), DEF_EXT_DESC(ProgramString, "_program", ("glProgramStringARB")), - DEF_EXT_DESC(GetProgramiv, "_program", + DEF_EXT_DESC(GetProgramivARB, "_program", ("glGetProgramivARB")), DEF_EXT_DESC(ProgramEnvParameter4f, "_program", ("glProgramEnvParameter4fARB")), @@ -409,6 +374,64 @@ static const extfunc_desc_t extfuncs[] = { "wglSwapInterval", "wglSwapIntervalEXT")), DEF_EXT_DESC(TexImage3D, NULL, ("glTexImage3D")), + + // ancient ATI extensions + DEF_EXT_DESC(BeginFragmentShader, "ATI_fragment_shader", + ("glBeginFragmentShaderATI")), + DEF_EXT_DESC(EndFragmentShader, "ATI_fragment_shader", + ("glEndFragmentShaderATI")), + DEF_EXT_DESC(SampleMap, "ATI_fragment_shader", + ("glSampleMapATI")), + DEF_EXT_DESC(ColorFragmentOp2, "ATI_fragment_shader", + ("glColorFragmentOp2ATI")), + DEF_EXT_DESC(ColorFragmentOp3, "ATI_fragment_shader", + ("glColorFragmentOp3ATI")), + DEF_EXT_DESC(SetFragmentShaderConstant, "ATI_fragment_shader", + ("glSetFragmentShaderConstantATI")), + + // GL 3, possibly in GL 2.x as well in form of extensions + DEF_GL3_DESC(GenBuffers), + DEF_GL3_DESC(DeleteBuffers), + DEF_GL3_DESC(BindBuffer), + DEF_GL3_DESC(MapBuffer), + DEF_GL3_DESC(UnmapBuffer), + DEF_GL3_DESC(BufferData), + DEF_GL3_DESC(ActiveTexture), + DEF_GL3_DESC(BindTexture), + DEF_GL3_DESC(GenVertexArrays), + DEF_GL3_DESC(BindVertexArray), + DEF_GL3_DESC(GetAttribLocation), + DEF_GL3_DESC(EnableVertexAttribArray), + DEF_GL3_DESC(DisableVertexAttribArray), + DEF_GL3_DESC(VertexAttribPointer), + DEF_GL3_DESC(DeleteVertexArrays), + DEF_GL3_DESC(UseProgram), + DEF_GL3_DESC(GetUniformLocation), + DEF_GL3_DESC(CompileShader), + DEF_GL3_DESC(CreateProgram), + DEF_GL3_DESC(CreateShader), + DEF_GL3_DESC(ShaderSource), + DEF_GL3_DESC(LinkProgram), + DEF_GL3_DESC(AttachShader), + DEF_GL3_DESC(DeleteShader), + DEF_GL3_DESC(DeleteProgram), + DEF_GL3_DESC(GetShaderInfoLog), + DEF_GL3_DESC(GetShaderiv), + DEF_GL3_DESC(GetProgramInfoLog), + DEF_GL3_DESC(GetProgramiv), + DEF_GL3_DESC(GetStringi), + DEF_GL3_DESC(BindAttribLocation), + DEF_GL3_DESC(BindFramebuffer), + DEF_GL3_DESC(GenFramebuffers), + DEF_GL3_DESC(DeleteFramebuffers), + DEF_GL3_DESC(CheckFramebufferStatus), + DEF_GL3_DESC(FramebufferTexture2D), + DEF_GL3_DESC(Uniform1f), + DEF_GL3_DESC(Uniform3f), + DEF_GL3_DESC(Uniform1i), + DEF_GL3_DESC(UniformMatrix3fv), + DEF_GL3_DESC(UniformMatrix4x3fv), + {-1} }; @@ -418,43 +441,53 @@ static const extfunc_desc_t extfuncs[] = { * \param ext2 an extra extension string */ static void getFunctions(GL *gl, void *(*getProcAddress)(const GLubyte *), - const char *ext2) + const char *ext2, bool is_gl3) { const extfunc_desc_t *dsc; - const char *extensions; - char *allexts; + char *allexts = talloc_strdup(NULL, ext2 ? ext2 : ""); + + *gl = (GL) {0}; if (!getProcAddress) getProcAddress = (void *)getdladdr; - // special case, we need glGetString before starting to find the other functions - gl->GetString = getProcAddress("glGetString"); - if (!gl->GetString) - gl->GetString = glGetString; - - extensions = (const char *)gl->GetString(GL_EXTENSIONS); - if (!extensions) - extensions = ""; - if (!ext2) - ext2 = ""; - allexts = malloc(strlen(extensions) + strlen(ext2) + 2); - strcpy(allexts, extensions); - strcat(allexts, " "); - strcat(allexts, ext2); + if (is_gl3) { + gl->GetStringi = getProcAddress("glGetStringi"); + gl->GetIntegerv = getProcAddress("glGetIntegerv"); + + if (!(gl->GetStringi && gl->GetIntegerv)) + return; + + GLint exts; + gl->GetIntegerv(GL_NUM_EXTENSIONS, &exts); + for (int n = 0; n < exts; n++) { + allexts = talloc_asprintf_append(allexts, " %s", + gl->GetStringi(GL_EXTENSIONS, n)); + } + } else { + gl->GetString = getProcAddress("glGetString"); + if (!gl->GetString) + gl->GetString = glGetString; + const char *ext = (char*)gl->GetString(GL_EXTENSIONS); + allexts = talloc_asprintf_append(allexts, " %s", ext); + } + mp_msg(MSGT_VO, MSGL_DBG2, "OpenGL extensions string:\n%s\n", allexts); for (dsc = extfuncs; dsc->offset >= 0; dsc++) { void *ptr = NULL; - int i; if (!dsc->extstr || strstr(allexts, dsc->extstr)) { - for (i = 0; !ptr && dsc->funcnames[i]; i++) + for (int i = 0; !ptr && dsc->funcnames[i]; i++) ptr = getProcAddress((const GLubyte *)dsc->funcnames[i]); } if (!ptr) ptr = dsc->fallback; + if (!ptr && !dsc->extstr && (!dsc->is_gl3 || is_gl3)) + mp_msg(MSGT_VO, MSGL_WARN, "[gl] OpenGL function not found: %s\n", + dsc->funcnames[0]); void **funcptr = (void**)(((char*)gl) + dsc->offset); *funcptr = ptr; } - free(allexts); + talloc_free(allexts); } /** @@ -859,11 +892,41 @@ static void gen_spline_lookup_tex(GL *gl, GLenum unit) free(tex); } +#define NOISE_RES 2048 + +/** + * \brief creates the 1D lookup texture needed to generate pseudo-random numbers. + * \param unit texture unit to attach texture to + */ +static void gen_noise_lookup_tex(GL *gl, GLenum unit) { + GLfloat *tex = calloc(NOISE_RES, sizeof(*tex)); + uint32_t lcg = 0x79381c11; + int i; + for (i = 0; i < NOISE_RES; i++) + tex[i] = (double)i / (NOISE_RES - 1); + for (i = 0; i < NOISE_RES - 1; i++) { + int remain = NOISE_RES - i; + int idx = i + (lcg >> 16) % remain; + GLfloat tmp = tex[i]; + tex[i] = tex[idx]; + tex[idx] = tmp; + lcg = lcg * 1664525 + 1013904223; + } + gl->ActiveTexture(unit); + gl->TexImage1D(GL_TEXTURE_1D, 0, 1, NOISE_RES, 0, GL_RED, GL_FLOAT, tex); + gl->TexParameterf(GL_TEXTURE_1D, GL_TEXTURE_PRIORITY, 1.0); + gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); + gl->ActiveTexture(GL_TEXTURE0); + free(tex); +} + #define SAMPLE(dest, coord, texture) \ "TEX textemp, " coord ", " texture ", $tex_type;\n" \ "MOV " dest ", textemp.r;\n" -static const char *bilin_filt_template = +static const char bilin_filt_template[] = SAMPLE("yuv.$out_comp","fragment.texcoord[$in_tex]","texture[$in_tex]"); #define BICUB_FILT_MAIN \ @@ -880,7 +943,7 @@ static const char *bilin_filt_template = /* x-interpolation */ \ "LRP yuv.$out_comp, parmx.b, a.bbbb, a.aaaa;\n" -static const char *bicub_filt_template_2D = +static const char bicub_filt_template_2D[] = "MAD coord.xy, fragment.texcoord[$in_tex], {$texw, $texh}, {0.5, 0.5};\n" "TEX parmx, coord.x, texture[$texs], 1D;\n" "MUL cdelta.xz, parmx.rrgg, {-$ptw, 0, $ptw, 0};\n" @@ -888,7 +951,7 @@ static const char *bicub_filt_template_2D = "MUL cdelta.yw, parmy.rrgg, {0, -$pth, 0, $pth};\n" BICUB_FILT_MAIN; -static const char *bicub_filt_template_RECT = +static const char bicub_filt_template_RECT[] = "ADD coord, fragment.texcoord[$in_tex], {0.5, 0.5};\n" "TEX parmx, coord.x, texture[$texs], 1D;\n" "MUL cdelta.xz, parmx.rrgg, {-1, 0, 1, 0};\n" @@ -906,7 +969,7 @@ static const char *bicub_filt_template_RECT = "ADD "t ".x, "t ".xxxx, "s ";\n" \ "SUB "t ".y, "t ".yyyy, "s ";\n" -static const char *bicub_notex_filt_template_2D = +static const char bicub_notex_filt_template_2D[] = "MAD coord.xy, fragment.texcoord[$in_tex], {$texw, $texh}, {0.5, 0.5};\n" "FRC coord.xy, coord.xyxy;\n" CALCWEIGHTS("parmx", "coord.xxxx") @@ -915,7 +978,7 @@ static const char *bicub_notex_filt_template_2D = "MUL cdelta.yw, parmy.rrgg, {0, -$pth, 0, $pth};\n" BICUB_FILT_MAIN; -static const char *bicub_notex_filt_template_RECT = +static const char bicub_notex_filt_template_RECT[] = "ADD coord, fragment.texcoord[$in_tex], {0.5, 0.5};\n" "FRC coord.xy, coord.xyxy;\n" CALCWEIGHTS("parmx", "coord.xxxx") @@ -932,19 +995,19 @@ static const char *bicub_notex_filt_template_RECT = /* x-interpolation */ \ "LRP yuv.$out_comp, parmx.b, a.rrrr, b.rrrr;\n" -static const char *bicub_x_filt_template_2D = +static const char bicub_x_filt_template_2D[] = "MAD coord.x, fragment.texcoord[$in_tex], {$texw}, {0.5};\n" "TEX parmx, coord, texture[$texs], 1D;\n" "MUL cdelta.xyz, parmx.rrgg, {-$ptw, 0, $ptw};\n" BICUB_X_FILT_MAIN; -static const char *bicub_x_filt_template_RECT = +static const char bicub_x_filt_template_RECT[] = "ADD coord.x, fragment.texcoord[$in_tex], {0.5};\n" "TEX parmx, coord, texture[$texs], 1D;\n" "MUL cdelta.xyz, parmx.rrgg, {-1, 0, 1};\n" BICUB_X_FILT_MAIN; -static const char *unsharp_filt_template = +static const char unsharp_filt_template[] = "PARAM dcoord$out_comp = {$ptw_05, $pth_05, $ptw_05, -$pth_05};\n" "ADD coord, fragment.texcoord[$in_tex].xyxy, dcoord$out_comp;\n" "SUB coord2, fragment.texcoord[$in_tex].xyxy, dcoord$out_comp;\n" @@ -959,7 +1022,7 @@ static const char *unsharp_filt_template = "MAD textemp.r, b.r, {$strength}, a.r;\n" "MOV yuv.$out_comp, textemp.r;\n"; -static const char *unsharp_filt_template2 = +static const char unsharp_filt_template2[] = "PARAM dcoord$out_comp = {$ptw_12, $pth_12, $ptw_12, -$pth_12};\n" "PARAM dcoord2$out_comp = {$ptw_15, 0, 0, $pth_15};\n" "ADD coord, fragment.texcoord[$in_tex].xyxy, dcoord$out_comp;\n" @@ -984,7 +1047,7 @@ static const char *unsharp_filt_template2 = "MAD textemp.r, b.r, {$strength}, a.r;\n" "MOV yuv.$out_comp, textemp.r;\n"; -static const char *yuv_prog_template = +static const char yuv_prog_template[] = "PARAM ycoef = {$cm11, $cm21, $cm31};\n" "PARAM ucoef = {$cm12, $cm22, $cm32};\n" "PARAM vcoef = {$cm13, $cm23, $cm33};\n" @@ -992,10 +1055,9 @@ static const char *yuv_prog_template = "TEMP res;\n" "MAD res.rgb, yuv.rrrr, ycoef, offsets;\n" "MAD res.rgb, yuv.gggg, ucoef, res;\n" - "MAD result.color.rgb, yuv.bbbb, vcoef, res;\n" - "END"; + "MAD res.rgb, yuv.bbbb, vcoef, res;\n"; -static const char *yuv_pow_prog_template = +static const char yuv_pow_prog_template[] = "PARAM ycoef = {$cm11, $cm21, $cm31};\n" "PARAM ucoef = {$cm12, $cm22, $cm32};\n" "PARAM vcoef = {$cm13, $cm23, $cm33};\n" @@ -1005,12 +1067,11 @@ static const char *yuv_pow_prog_template = "MAD res.rgb, yuv.rrrr, ycoef, offsets;\n" "MAD res.rgb, yuv.gggg, ucoef, res;\n" "MAD_SAT res.rgb, yuv.bbbb, vcoef, res;\n" - "POW result.color.r, res.r, gamma.r;\n" - "POW result.color.g, res.g, gamma.g;\n" - "POW result.color.b, res.b, gamma.b;\n" - "END"; + "POW res.r, res.r, gamma.r;\n" + "POW res.g, res.g, gamma.g;\n" + "POW res.b, res.b, gamma.b;\n"; -static const char *yuv_lookup_prog_template = +static const char yuv_lookup_prog_template[] = "PARAM ycoef = {$cm11, $cm21, $cm31, 0};\n" "PARAM ucoef = {$cm12, $cm22, $cm32, 0};\n" "PARAM vcoef = {$cm13, $cm23, $cm33, 0};\n" @@ -1019,16 +1080,23 @@ static const char *yuv_lookup_prog_template = "MAD res, yuv.rrrr, ycoef, offsets;\n" "MAD res.rgb, yuv.gggg, ucoef, res;\n" "MAD res.rgb, yuv.bbbb, vcoef, res;\n" - "TEX result.color.r, res.raaa, texture[$conv_tex0], 2D;\n" + "TEX res.r, res.raaa, texture[$conv_tex0], 2D;\n" "ADD res.a, res.a, 0.25;\n" - "TEX result.color.g, res.gaaa, texture[$conv_tex0], 2D;\n" + "TEX res.g, res.gaaa, texture[$conv_tex0], 2D;\n" "ADD res.a, res.a, 0.25;\n" - "TEX result.color.b, res.baaa, texture[$conv_tex0], 2D;\n" - "END"; + "TEX res.b, res.baaa, texture[$conv_tex0], 2D;\n"; -static const char *yuv_lookup3d_prog_template = - "TEX result.color, yuv, texture[$conv_tex0], 3D;\n" - "END"; +static const char yuv_lookup3d_prog_template[] = + "TEMP res;\n" + "TEX res, yuv, texture[$conv_tex0], 3D;\n"; + +static const char noise_filt_template[] = + "MUL coord.xy, fragment.texcoord[0], {$noise_sx, $noise_sy};\n" + "TEMP rand;\n" + "TEX rand.r, coord.x, texture[$noise_filt_tex], 1D;\n" + "ADD rand.r, rand.r, coord.y;\n" + "TEX rand.r, rand.r, texture[$noise_filt_tex], 1D;\n" + "MAD res.rgb, rand.rrrr, {$noise_str, $noise_str, $noise_str}, res;\n"; /** * \brief creates and initializes helper textures needed for scaling texture read @@ -1236,12 +1304,12 @@ int loadGPUProgram(GL *gl, GLenum target, char *prog) gl->GetString(GL_PROGRAM_ERROR_STRING), &prog[err]); return 0; } - if (!gl->GetProgramiv || !mp_msg_test(MSGT_VO, MSGL_DBG2)) + if (!gl->GetProgramivARB || !mp_msg_test(MSGT_VO, MSGL_DBG2)) return 1; mp_msg(MSGT_VO, MSGL_V, "[gl] Program statistics:\n"); for (i = 0; progstats[i].name; i++) { - gl->GetProgramiv(target, progstats[i].cur, &cur); - gl->GetProgramiv(target, progstats[i].max, &max); + gl->GetProgramivARB(target, progstats[i].cur, &cur); + gl->GetProgramivARB(target, progstats[i].max, &max); mp_msg(MSGT_VO, MSGL_V, "[gl] %s: %i/%i\n", progstats[i].name, cur, max); } @@ -1273,10 +1341,12 @@ static void glSetupYUVFragprog(GL *gl, gl_conversion_params_t *params) char lum_scale_texs[1]; char chrom_scale_texs[1]; char conv_texs[1]; + char filt_texs[1] = {0}; GLint i; // this is the conversion matrix, with y, u, v factors // for red, green, blue and the constant offsets float yuv2rgb[3][4]; + int noise = params->noise_strength != 0; create_conv_textures(gl, params, &cur_texu, conv_texs); create_scaler_textures(gl, YUV_LUM_SCALER(type), &cur_texu, lum_scale_texs); if (YUV_CHROM_SCALER(type) == YUV_LUM_SCALER(type)) @@ -1284,6 +1354,12 @@ static void glSetupYUVFragprog(GL *gl, gl_conversion_params_t *params) else create_scaler_textures(gl, YUV_CHROM_SCALER(type), &cur_texu, chrom_scale_texs); + + if (noise) { + gen_noise_lookup_tex(gl, cur_texu); + filt_texs[0] = '0' + cur_texu++; + } + gl->GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &i); if (i < cur_texu) mp_msg(MSGT_VO, MSGL_ERR, @@ -1332,6 +1408,25 @@ static void glSetupYUVFragprog(GL *gl, gl_conversion_params_t *params) replace_var_float(prog, "gamma_g", (float)1.0 / params->csp_params.ggamma); replace_var_float(prog, "gamma_b", (float)1.0 / params->csp_params.bgamma); replace_var_char(prog, "conv_tex0", conv_texs[0]); + + if (noise) { + // 1.0 strength is suitable for dithering 8 to 6 bit + double str = params->noise_strength * (1.0 / 64); + double scale_x = (double)NOISE_RES / texw; + double scale_y = (double)NOISE_RES / texh; + if (rect) { + scale_x /= texw; + scale_y /= texh; + } + append_template(prog, noise_filt_template); + replace_var_float(prog, "noise_sx", scale_x); + replace_var_float(prog, "noise_sy", scale_y); + replace_var_char(prog, "noise_filt_tex", filt_texs[0]); + replace_var_float(prog, "noise_str", str); + } + + append_template(prog, "MOV result.color.rgb, res;\nEND"); + mp_msg(MSGT_VO, MSGL_DBG2, "[gl] generated fragment program:\n%s\n", yuv_prog); loadGPUProgram(gl, GL_FRAGMENT_PROGRAM, yuv_prog); @@ -1619,16 +1714,29 @@ void glDrawTex(GL *gl, GLfloat x, GLfloat y, GLfloat w, GLfloat h, static int create_window_cocoa(struct MPGLContext *ctx, uint32_t d_width, uint32_t d_height, uint32_t flags) { - if (vo_cocoa_create_window(ctx->vo, d_width, d_height, flags) == 0) { + if (vo_cocoa_create_window(ctx->vo, d_width, d_height, flags, 0) == 0) { return SET_WINDOW_OK; } else { return SET_WINDOW_FAILED; } } + +static int create_window_cocoa_gl3(struct MPGLContext *ctx, int gl_flags, + int gl_version, uint32_t d_width, + uint32_t d_height, uint32_t flags) +{ + int rv = vo_cocoa_create_window(ctx->vo, d_width, d_height, flags, 1); + getFunctions(ctx->gl, (void *)vo_cocoa_glgetaddr, NULL, true); + ctx->depth_r = vo_cocoa_cgl_color_size(); + ctx->depth_g = vo_cocoa_cgl_color_size(); + ctx->depth_b = vo_cocoa_cgl_color_size(); + return rv; +} + static int setGlWindow_cocoa(MPGLContext *ctx) { vo_cocoa_change_attributes(ctx->vo); - getFunctions(ctx->gl, (void *)vo_cocoa_glgetaddr, NULL); + getFunctions(ctx->gl, (void *)vo_cocoa_glgetaddr, NULL, false); if (!ctx->gl->SwapInterval) ctx->gl->SwapInterval = vo_cocoa_swap_interval; return SET_WINDOW_OK; @@ -1660,12 +1768,18 @@ static void cocoa_fullscreen(struct vo *vo) #endif #ifdef CONFIG_GL_WIN32 +#include <windows.h> #include "w32_common.h" +struct w32_context { + int vinfo; + HGLRC context; +}; + static int create_window_w32(struct MPGLContext *ctx, uint32_t d_width, uint32_t d_height, uint32_t flags) { - if (!vo_w32_config(d_width, d_height, flags)) + if (!vo_w32_config(ctx->vo, d_width, d_height, flags)) return -1; return 0; } @@ -1686,13 +1800,112 @@ static void *w32gpa(const GLubyte *procName) return GetProcAddress(oglmod, procName); } +static int create_window_w32_gl3(struct MPGLContext *ctx, int gl_flags, + int gl_version, uint32_t d_width, + uint32_t d_height, uint32_t flags) { + if (!vo_w32_config(ctx->vo, d_width, d_height, flags)) + return -1; + + struct w32_context *w32_ctx = ctx->priv; + HGLRC *context = &w32_ctx->context; + + if (*context) // reuse existing context + return 0; // not reusing it breaks gl3! + + HWND win = ctx->vo->w32->window; + HDC windc = vo_w32_get_dc(ctx->vo, win); + HGLRC new_context = 0; + + new_context = wglCreateContext(windc); + if (!new_context) { + mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GL context!\n"); + return -1; + } + + // set context + if (!wglMakeCurrent(windc, new_context)) { + mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GL context!\n"); + goto out; + } + + const char *(GLAPIENTRY *wglGetExtensionsStringARB)(HDC hdc) + = w32gpa((const GLubyte*)"wglGetExtensionsStringARB"); + + if (!wglGetExtensionsStringARB) + goto unsupported; + + const char *wgl_exts = wglGetExtensionsStringARB(windc); + if (!strstr(wgl_exts, "WGL_ARB_create_context")) + goto unsupported; + + HGLRC (GLAPIENTRY *wglCreateContextAttribsARB)(HDC hDC, HGLRC hShareContext, + const int *attribList) + = w32gpa((const GLubyte*)"wglCreateContextAttribsARB"); + + if (!wglCreateContextAttribsARB) + goto unsupported; + + int attribs[] = { + WGL_CONTEXT_MAJOR_VERSION_ARB, MPGL_VER_GET_MAJOR(gl_version), + WGL_CONTEXT_MINOR_VERSION_ARB, MPGL_VER_GET_MINOR(gl_version), + WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + 0 + }; + + *context = wglCreateContextAttribsARB(windc, 0, attribs); + if (! *context) { + // NVidia, instead of ignoring WGL_CONTEXT_FLAGS_ARB, will error out if + // it's present on pre-3.2 contexts. + // Remove it from attribs and retry the context creation. + attribs[6] = attribs[7] = 0; + *context = wglCreateContextAttribsARB(windc, 0, attribs); + } + if (! *context) { + int err = GetLastError(); + mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create an OpenGL 3.x" + " context: error 0x%x\n", err); + goto out; + } + + wglMakeCurrent(NULL, NULL); + wglDeleteContext(new_context); + + if (!wglMakeCurrent(windc, *context)) { + mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GL3 context!\n"); + wglDeleteContext(*context); + return -1; + } + + /* update function pointers */ + getFunctions(ctx->gl, w32gpa, NULL, true); + + int pfmt = GetPixelFormat(windc); + PIXELFORMATDESCRIPTOR pfd; + if (DescribePixelFormat(windc, pfmt, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { + ctx->depth_r = pfd.cRedBits; + ctx->depth_g = pfd.cGreenBits; + ctx->depth_b = pfd.cBlueBits; + } + + return 0; + +unsupported: + mp_msg(MSGT_VO, MSGL_ERR, "[gl] The current OpenGL implementation does" + " not support OpenGL 3.x \n"); +out: + wglDeleteContext(new_context); + return -1; +} + static int setGlWindow_w32(MPGLContext *ctx) { - HWND win = vo_w32_window; - int *vinfo = &ctx->vinfo.w32; - HGLRC *context = &ctx->context.w32; + HWND win = ctx->vo->w32->window; + struct w32_context *w32_ctx = ctx->priv; + int *vinfo = &w32_ctx->vinfo; + HGLRC *context = &w32_ctx->context; int new_vinfo; - HDC windc = vo_w32_get_dc(win); + HDC windc = vo_w32_get_dc(ctx->vo, win); HGLRC new_context = 0; int keep_context = 0; int res = SET_WINDOW_FAILED; @@ -1725,7 +1938,6 @@ static int setGlWindow_w32(MPGLContext *ctx) } // set new values - vo_w32_window = win; { RECT rect; GetClientRect(win, &rect); @@ -1737,7 +1949,8 @@ static int setGlWindow_w32(MPGLContext *ctx) wglDeleteContext(*context); *context = new_context; *vinfo = new_vinfo; - getFunctions(gl, w32gpa, NULL); + + getFunctions(ctx->gl, w32gpa, NULL, false); // and inform that reinit is neccessary res = SET_WINDOW_REINIT; @@ -1745,14 +1958,15 @@ static int setGlWindow_w32(MPGLContext *ctx) res = SET_WINDOW_OK; out: - vo_w32_release_dc(win, windc); + vo_w32_release_dc(ctx->vo, win, windc); return res; } static void releaseGlContext_w32(MPGLContext *ctx) { - int *vinfo = &ctx->vinfo.w32; - HGLRC *context = &ctx->context.w32; + struct w32_context *w32_ctx = ctx->priv; + int *vinfo = &w32_ctx->vinfo; + HGLRC *context = &w32_ctx->context; *vinfo = 0; if (*context) { wglMakeCurrent(0, 0); @@ -1763,21 +1977,22 @@ static void releaseGlContext_w32(MPGLContext *ctx) static void swapGlBuffers_w32(MPGLContext *ctx) { - HDC vo_hdc = vo_w32_get_dc(vo_w32_window); + HDC vo_hdc = vo_w32_get_dc(ctx->vo, ctx->vo->w32->window); SwapBuffers(vo_hdc); - vo_w32_release_dc(vo_w32_window, vo_hdc); + vo_w32_release_dc(ctx->vo, ctx->vo->w32->window, vo_hdc); } - -//trivial wrappers (w32 code uses old vo API) -static void new_vo_w32_ontop(struct vo *vo) { vo_w32_ontop(); } -static void new_vo_w32_border(struct vo *vo) { vo_w32_border(); } -static void new_vo_w32_fullscreen(struct vo *vo) { vo_w32_fullscreen(); } -static int new_vo_w32_check_events(struct vo *vo) { return vo_w32_check_events(); } -static void new_w32_update_xinerama_info(struct vo *vo) { w32_update_xinerama_info(); } #endif + #ifdef CONFIG_GL_X11 +#include <X11/Xlib.h> +#include <GL/glx.h> #include "x11_common.h" +struct glx_context { + XVisualInfo *vinfo; + GLXContext context; +}; + static int create_window_x11(struct MPGLContext *ctx, uint32_t d_width, uint32_t d_height, uint32_t flags) { @@ -1832,21 +2047,6 @@ static XVisualInfo *getWindowVisualInfo(MPGLContext *ctx, Window win) return XGetVisualInfo(ctx->vo->x11->display, VisualIDMask, &vinfo_template, &tmp); } -static void appendstr(char **dst, const char *str) -{ - int newsize; - char *newstr; - if (!str) - return; - newsize = strlen(*dst) + 1 + strlen(str) + 1; - newstr = realloc(*dst, newsize); - if (!newstr) - return; - *dst = newstr; - strcat(*dst, " "); - strcat(*dst, str); -} - /** * \brief Changes the window in which video is displayed. * If possible only transfers the context to the new window, otherwise @@ -1861,8 +2061,9 @@ static void appendstr(char **dst, const char *str) */ static int setGlWindow_x11(MPGLContext *ctx) { - XVisualInfo **vinfo = &ctx->vinfo.x11; - GLXContext *context = &ctx->context.x11; + struct glx_context *glx_context = ctx->priv; + XVisualInfo **vinfo = &glx_context->vinfo; + GLXContext *context = &glx_context->context; Display *display = ctx->vo->x11->display; Window win = ctx->vo->x11->window; XVisualInfo *new_vinfo; @@ -1907,8 +2108,6 @@ static int setGlWindow_x11(MPGLContext *ctx) vo_x11_update_geometry(ctx->vo, 1); if (!keep_context) { void *(*getProcAddress)(const GLubyte *); - const char *(*glXExtStr)(Display *, int); - char *glxstr = strdup(""); if (*context) glXDestroyContext(display, *context); *context = new_context; @@ -1918,25 +2117,21 @@ static int setGlWindow_x11(MPGLContext *ctx) getProcAddress = getdladdr("glXGetProcAddress"); if (!getProcAddress) getProcAddress = getdladdr("glXGetProcAddressARB"); - glXExtStr = getdladdr("glXQueryExtensionsString"); - if (glXExtStr) - appendstr(&glxstr, glXExtStr(display, DefaultScreen(display))); - glXExtStr = getdladdr("glXGetClientString"); - if (glXExtStr) - appendstr(&glxstr, glXExtStr(display, GLX_EXTENSIONS)); - glXExtStr = getdladdr("glXGetServerString"); + + const char *glxstr = ""; + const char *(*glXExtStr)(Display *, int) + = getdladdr("glXQueryExtensionsString"); if (glXExtStr) - appendstr(&glxstr, glXExtStr(display, GLX_EXTENSIONS)); + glxstr = glXExtStr(display, ctx->vo->x11->screen); - getFunctions(gl, getProcAddress, glxstr); + getFunctions(gl, getProcAddress, glxstr, false); if (!gl->GenPrograms && gl->GetString && getProcAddress && strstr(gl->GetString(GL_EXTENSIONS), "GL_ARB_vertex_program")) { mp_msg(MSGT_VO, MSGL_WARN, "Broken glXGetProcAddress detected, trying workaround\n"); - getFunctions(gl, NULL, glxstr); + getFunctions(gl, NULL, glxstr, false); } - free(glxstr); // and inform that reinit is neccessary return SET_WINDOW_REINIT; @@ -1944,14 +2139,154 @@ static in |