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 + -
显示快捷键?