gl_common.c
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 1,599 行 · 第 1/4 页
C
1,599 行
static const char *yuv_lookup3d_prog_template = "TEX result.color, yuv, texture[%c], 3D;" "END";/** * \brief creates and initializes helper textures needed for scaling texture read * \param scaler scaler type to create texture for * \param texu contains next free texture unit number * \param texs texture unit ids for the scaler are stored in this array */static void create_scaler_textures(int scaler, int *texu, char *texs) { switch (scaler) { case YUV_SCALER_BILIN: break; case YUV_SCALER_BICUB: case YUV_SCALER_BICUB_X: texs[0] = (*texu)++; gen_spline_lookup_tex(GL_TEXTURE0 + texs[0]); texs[0] += '0'; break; default: mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown scaler type %i\n", scaler); }}static void gen_gamma_map(unsigned char *map, int size, float gamma);static void get_yuv2rgb_coeffs(float brightness, float contrast, float uvcos, float uvsin, float *ry, float *ru, float *rv, float *rc, float *gy, float *gu, float *gv, float *gc, float *by, float *bu, float *bv, float *bc) { *ry = 1.164 * contrast; *gy = 1.164 * contrast; *by = 1.164 * contrast; *ru = 0 * uvcos + 1.596 * uvsin; *rv = 0 * uvsin + 1.596 * uvcos; *gu = -0.391 * uvcos + -0.813 * uvsin; *gv = -0.391 * uvsin + -0.813 * uvcos; *bu = 2.018 * uvcos + 0 * uvsin; *bv = 2.018 * uvsin + 0 * uvcos; *rc = (-16 * *ry + (-128) * *ru + (-128) * *rv) / 255.0 + brightness; *gc = (-16 * *gy + (-128) * *gu + (-128) * *gv) / 255.0 + brightness; *bc = (-16 * *by + (-128) * *bu + (-128) * *bv) / 255.0 + brightness; // these "center" contrast control so that e.g. a contrast of 0 // leads to a grey image, not a black one *rc += 0.5 - contrast / 2.0; *gc += 0.5 - contrast / 2.0; *bc += 0.5 - contrast / 2.0;}//! size of gamma map use to avoid slow exp function in gen_yuv2rgb_map#define GMAP_SIZE (1024)/** * \brief generate a 3D YUV -> RGB map * \param map where to store map. Must provide space for (size + 2)^3 elements * \param size size of the map, excluding border * \param brightness desired brightness adjustment for conversion * \param contrast desired contrast adjustment for conversion * \param uvcos desired hue/saturation adjustment for conversion * \param uvsin desired hue/saturation adjustment for conversion * \param rgamma desired red gamma adjustment for conversion * \param ggamma desired green gamma adjustment for conversion * \param bgamma desired blue gamma adjustment for conversion */static void gen_yuv2rgb_map(unsigned char *map, int size, float brightness, float contrast, float uvcos, float uvsin, float rgamma, float ggamma, float bgamma) { int i, j, k; float step = 1.0 / size; float y, u, v; float r, g, b; float ry, ru, rv, rc; float gy, gu, gv, gc; float by, bu, bv, bc; unsigned char gmaps[3][GMAP_SIZE]; gen_gamma_map(gmaps[0], GMAP_SIZE, rgamma); gen_gamma_map(gmaps[1], GMAP_SIZE, ggamma); gen_gamma_map(gmaps[2], GMAP_SIZE, bgamma); get_yuv2rgb_coeffs(brightness, contrast, uvcos, uvsin, &ry, &ru, &rv, &rc, &gy, &gu, &gv, &gc, &by, &bu, &bv, &bc); ry *= GMAP_SIZE - 1; ru *= GMAP_SIZE - 1; rv *= GMAP_SIZE - 1; rc *= GMAP_SIZE - 1; gy *= GMAP_SIZE - 1; gu *= GMAP_SIZE - 1; gv *= GMAP_SIZE - 1; gc *= GMAP_SIZE - 1; by *= GMAP_SIZE - 1; bu *= GMAP_SIZE - 1; bv *= GMAP_SIZE - 1; bc *= GMAP_SIZE - 1; v = 0; for (i = -1; i <= size; i++) { u = 0; for (j = -1; j <= size; j++) { y = 0; for (k = -1; k <= size; k++) { r = ry * y + ru * u + rv * v + rc; g = gy * y + gu * u + gv * v + gc; b = by * y + bu * u + bv * v + bc; if (r > GMAP_SIZE - 1) r = GMAP_SIZE - 1; if (r < 0) r = 0; if (g > GMAP_SIZE - 1) g = GMAP_SIZE - 1; if (g < 0) g = 0; if (b > GMAP_SIZE - 1) b = GMAP_SIZE - 1; if (b < 0) b = 0; *map++ = gmaps[0][(int)r]; *map++ = gmaps[1][(int)g]; *map++ = gmaps[2][(int)b]; y += (k == -1 || k == size - 1) ? step / 2 : step; } u += (j == -1 || j == size - 1) ? step / 2 : step; } v += (i == -1 || i == size - 1) ? step / 2 : step; }}//! resolution of texture for gamma lookup table#define LOOKUP_RES 512//! resolution for 3D yuv->rgb conversion lookup table#define LOOKUP_3DRES 32/** * \brief creates and initializes helper textures needed for yuv conversion * \param texu contains next free texture unit number * \param texs texture unit ids for the conversion are stored in this array * \param brightness desired brightness adjustment for conversion * \param contrast desired contrast adjustment for conversion * \param uvcos desired hue/saturation adjustment for conversion * \param uvsin desired hue/saturation adjustment for conversion * \param rgamma desired red gamma adjustment for conversion * \param ggamma desired green gamma adjustment for conversion * \param bgamma desired blue gamma adjustment for conversion */static void create_conv_textures(int conv, int *texu, char *texs, float brightness, float contrast, float uvcos, float uvsin, float rgamma, float ggamma, float bgamma) { unsigned char *lookup_data = NULL; switch (conv) { case YUV_CONVERSION_FRAGMENT: case YUV_CONVERSION_FRAGMENT_POW: break; case YUV_CONVERSION_FRAGMENT_LOOKUP: texs[0] = (*texu)++; ActiveTexture(GL_TEXTURE0 + texs[0]); lookup_data = malloc(4 * LOOKUP_RES); gen_gamma_map(lookup_data, LOOKUP_RES, rgamma); gen_gamma_map(&lookup_data[LOOKUP_RES], LOOKUP_RES, ggamma); gen_gamma_map(&lookup_data[2 * LOOKUP_RES], LOOKUP_RES, bgamma); glCreateClearTex(GL_TEXTURE_2D, GL_LUMINANCE8, GL_LINEAR, LOOKUP_RES, 4, 0); glUploadTex(GL_TEXTURE_2D, GL_LUMINANCE, GL_UNSIGNED_BYTE, lookup_data, LOOKUP_RES, 0, 0, LOOKUP_RES, 4, 0); ActiveTexture(GL_TEXTURE0); texs[0] += '0'; break; case YUV_CONVERSION_FRAGMENT_LOOKUP3D: { int sz = LOOKUP_3DRES + 2; // texture size including borders if (!TexImage3D) { mp_msg(MSGT_VO, MSGL_ERR, "[gl] Missing 3D texture function!\n"); break; } texs[0] = (*texu)++; ActiveTexture(GL_TEXTURE0 + texs[0]); lookup_data = malloc(3 * sz * sz * sz); gen_yuv2rgb_map(lookup_data, LOOKUP_3DRES, brightness, contrast, uvcos, uvsin, rgamma, ggamma, bgamma); glAdjustAlignment(sz); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); TexImage3D(GL_TEXTURE_3D, 0, 3, sz, sz, sz, 1, GL_RGB, GL_UNSIGNED_BYTE, lookup_data); glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_PRIORITY, 1.0); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP); ActiveTexture(GL_TEXTURE0); texs[0] += '0'; } break; default: mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", conv); } if (lookup_data) free(lookup_data);}/** * \brief adds a scaling texture read at the current fragment program position * \param scaler type of scaler to insert * \param prog_pos current position in fragment program * \param remain how many bytes remain in the buffer given by prog_pos * \param texs array containing the texture unit identifiers for this scaler * \param in_tex texture unit the scaler should read from * \param out_comp component of the yuv variable the scaler stores the result in * \param rect if rectangular (pixel) adressing should be used for in_tex * \param texw width of the in_tex texture * \param texh height of the in_tex texture */static void add_scaler(int scaler, char **prog_pos, int *remain, char *texs, char in_tex, char out_comp, int rect, int texw, int texh) { switch (scaler) { case YUV_SCALER_BILIN: snprintf(*prog_pos, *remain, bilin_filt_template, out_comp, in_tex, in_tex, rect ? "RECT" : "2D"); break; case YUV_SCALER_BICUB: if (rect) snprintf(*prog_pos, *remain, bicub_filt_template_RECT, in_tex, texs[0], texs[0], in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp); else snprintf(*prog_pos, *remain, bicub_filt_template_2D, in_tex, (float)texw, (float)texh, texs[0], (float)1.0 / texw, (float)1.0 / texw, texs[0], (float)1.0 / texh, (float)1.0 / texh, in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp); break; case YUV_SCALER_BICUB_X: if (rect) snprintf(*prog_pos, *remain, bicub_x_filt_template_RECT, in_tex, texs[0], in_tex, in_tex, in_tex, in_tex, out_comp); else snprintf(*prog_pos, *remain, bicub_x_filt_template_2D, in_tex, (float)texw, (float)texh, texs[0], (float)1.0 / texw, (float)1.0 / texw, in_tex, in_tex, in_tex, in_tex, out_comp); break; case YUV_SCALER_BICUB_NOTEX: if (rect) snprintf(*prog_pos, *remain, bicub_notex_filt_template_RECT, in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp); else snprintf(*prog_pos, *remain, bicub_notex_filt_template_2D, in_tex, (float)texw, (float)texh, (float)1.0 / texw, (float)1.0 / texw, (float)1.0 / texh, (float)1.0 / texh, in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp); break; } *remain -= strlen(*prog_pos); *prog_pos += strlen(*prog_pos);}static const struct { const char *name; GLenum cur; GLenum max;} progstats[] = { {"instructions", 0x88A0, 0x88A1}, {"native instructions", 0x88A2, 0x88A3}, {"temporaries", 0x88A4, 0x88A5}, {"native temporaries", 0x88A6, 0x88A7}, {"parameters", 0x88A8, 0x88A9}, {"native parameters", 0x88AA, 0x88AB}, {"attribs", 0x88AC, 0x88AD}, {"native attribs", 0x88AE, 0x88AF}, {"ALU instructions", 0x8805, 0x880B}, {"TEX instructions", 0x8806, 0x880C}, {"TEX indirections", 0x8807, 0x880D}, {"native ALU instructions", 0x8808, 0x880E}, {"native TEX instructions", 0x8809, 0x880F}, {"native TEX indirections", 0x880A, 0x8810}, {NULL, 0, 0}};/** * \brief load the specified GPU Program * \param target program target to load into, only GL_FRAGMENT_PROGRAM is tested * \param prog program string * \return 1 on success, 0 otherwise */int loadGPUProgram(GLenum target, char *prog) { int i; GLint cur = 0, max = 0, err = 0; if (!ProgramString) { mp_msg(MSGT_VO, MSGL_ERR, "[gl] Missing GPU program function\n"); return 0; } ProgramString(target, GL_PROGRAM_FORMAT_ASCII, strlen(prog), prog); glGetIntegerv(GL_PROGRAM_ERROR_POSITION, &err); if (err != -1) { mp_msg(MSGT_VO, MSGL_ERR, "[gl] Error compiling fragment program, make sure your card supports\n" "[gl] GL_ARB_fragment_program (use glxinfo to check).\n" "[gl] Error message:\n %s at %.10s\n", glGetString(GL_PROGRAM_ERROR_STRING), &prog[err]); return 0; } if (!GetProgramiv || !mp_msg_test(MSGT_VO, MSGL_V)) return 1; mp_msg(MSGT_VO, MSGL_V, "[gl] Program statistics:\n"); for (i = 0; progstats[i].name; i++) { GetProgramiv(target, progstats[i].cur, &cur); GetProgramiv(target, progstats[i].max, &max); mp_msg(MSGT_VO, MSGL_V, "[gl] %s: %i/%i\n", progstats[i].name, cur, max); } return 1;}/** * \brief setup a fragment program that will do YUV->RGB conversion * \param brightness brightness adjustment offset * \param contrast contrast adjustment factor * \param uvcos used for saturation and hue adjustment * \param uvsin used for saturation and hue adjustment * \param lookup use fragment program that uses texture unit 4 to * do additional conversion via lookup. */static void glSetupYUVFragprog(float brightness, float contrast, float uvcos, float uvsin, float rgamma, float ggamma, float bgamma, int type, int rect, int texw, int texh) { char yuv_prog[4000] = "!!ARBfp1.0\n" "OPTION ARB_precision_hint_fastest;" // all scaler variables must go here so they aren't defined // multiple times when the same scaler is used more than once "TEMP coord, coord2, cdelta, parmx, parmy, a, b, yuv;"; int prog_remain = sizeof(yuv_prog) - strlen(yuv_prog); char *prog_pos = &yuv_prog[strlen(yuv_prog)]; int cur_texu = 3; char lum_scale_texs[1]; char chrom_scale_texs[1]; char conv_texs[1]; GLint i; // this is the conversion matrix, with y, u, v factors // for red, green, blue and the constant offsets float ry, ru, rv, rc; float gy, gu, gv, gc; float by, bu, bv, bc; create_scaler_textures(YUV_LUM_SCALER(type), &cur_texu, lum_scale_texs); if (YUV_CHROM_SCALER(type) == YUV_LUM_SCALER(type)) memcpy(chrom_scale_texs, lum_scale_texs, sizeof(chrom_scale_texs)); else create_scaler_textures(YUV_CHROM_SCALER(type), &cur_texu, chrom_scale_texs); create_conv_textures(YUV_CONVERSION(type), &cur_texu, conv_texs, brightness, contrast, uvcos, uvsin, rgamma, ggamma, bgamma); glGetIntegerv(GL_MAX_TEXTURE_UNITS, &i); if (i < cur_texu) mp_msg(MSGT_VO, MSGL_ERR, "[gl] %i texture units needed for this type of YUV fragment support (found %i)\n", cur_texu, i); if (!ProgramString) { mp_msg(MSGT_VO, MSGL_FATAL, "[gl] ProgramString function missing!\n"); return; } add_scaler(YUV_LUM_SCALER(type), &prog_pos, &prog_remain, lum_scale_texs, '0', 'r', rect, texw, texh); add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs, '1', 'g', rect, texw / 2, texh / 2); add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs, '2', 'b', rect, texw / 2, texh / 2); get_yuv2rgb_coeffs(brightness, contrast, uvcos, uvsin, &ry, &ru, &rv, &rc, &gy, &gu, &gv, &gc, &by, &bu, &bv, &bc); switch (YUV_CONVERSION(type)) { case YUV_CONVERSION_FRAGMENT: snprintf(prog_pos, prog_remain, yuv_prog_template, ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc); break; case YUV_CONVERSION_FRAGMENT_POW: snprintf(prog_pos, prog_remain, yuv_pow_prog_template, ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc, (float)1.0 / rgamma, (float)1.0 / bgamma, (float)1.0 / bgamma); break; case YUV_CONVERSION_FRAGMENT_LOOKUP: snprintf(prog_pos, prog_remain, yuv_lookup_prog_template, ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc, conv_texs[0], conv_texs[0], conv_texs[0]); break; case YUV_CONVERSION_FRAGMENT_LOOKUP3D: snprintf(prog_pos, prog_remain, yuv_lookup3d_prog_template, conv_texs[0]); break; default: mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", YUV_CONVERSION(type)); break; } mp_msg(MSGT_VO, MSGL_V, "[gl] generated fragment program:\n%s\n", yuv_prog); loadGPUProgram(GL_FRAGMENT_PROGRAM, yuv_prog);}/** * \brief little helper function to create a lookup table for gamma * \param map buffer to create map into * \param size size of buffer * \param gamma gamma value */static void gen_gamma_map(unsigned char *map, int size, float gamma) { int i; if (gamma == 1.0) { for (i = 0; i < size; i++) map[i] = 255 * i / (size - 1); return; } gamma = 1.0 / gamma; for (i = 0; i < size; i++) { float tmp = (float)i / (size - 1.0); tmp = pow(tmp, gamma); if (tmp > 1.0) tmp = 1.0; if (tmp < 0.0) tmp = 0.0; map[i] = 255 * tmp; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?