/** * Return string name for given program/register file. */ const char * _mesa_register_file_name(gl_register_file f) { switch (f) { case PROGRAM_TEMPORARY: return "TEMP"; case PROGRAM_STATE_VAR: return "STATE"; case PROGRAM_INPUT: return "INPUT"; case PROGRAM_OUTPUT: return "OUTPUT"; case PROGRAM_CONSTANT: return "CONST"; case PROGRAM_UNIFORM: return "UNIFORM"; case PROGRAM_ADDRESS: return "ADDR"; case PROGRAM_SAMPLER: return "SAMPLER"; case PROGRAM_SYSTEM_VALUE: return "SYSVAL"; case PROGRAM_UNDEFINED: return "UNDEFINED"; default: { static char s[20]; _mesa_snprintf(s, sizeof(s), "FILE%u", f); return s; } } }
static void compute_version_es2(struct gl_context *ctx) { static const int max = 100; /* OpenGL ES 2.0 is derived from OpenGL 2.0 */ const GLboolean ver_2_0 = (ctx->Extensions.ARB_texture_cube_map && ctx->Extensions.EXT_blend_color && ctx->Extensions.EXT_blend_func_separate && ctx->Extensions.EXT_blend_minmax && ctx->Extensions.ARB_shader_objects && ctx->Extensions.ARB_vertex_shader && ctx->Extensions.ARB_fragment_shader && ctx->Extensions.ARB_texture_non_power_of_two && ctx->Extensions.EXT_blend_equation_separate); if (ver_2_0) { ctx->VersionMajor = 2; ctx->VersionMinor = 0; } else { _mesa_problem(ctx, "Incomplete OpenGL ES 2.0 support."); } ctx->VersionString = (char *) malloc(max); if (ctx->VersionString) { _mesa_snprintf(ctx->VersionString, max, "OpenGL ES 2.0 Mesa " MESA_VERSION_STRING #ifdef MESA_GIT_SHA1 " (" MESA_GIT_SHA1 ")" #endif ); } }
/** * Append the shader's uniform info/values to the shader log file. * The log file will typically have been created by the * _mesa_write_shader_to_file function. */ void _mesa_append_uniforms_to_file(const struct gl_shader *shader) { const struct gl_program *const prog = shader->Program; const char *type; char filename[100]; FILE *f; if (shader->Stage == MESA_SHADER_FRAGMENT) type = "frag"; else type = "vert"; _mesa_snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type); f = fopen(filename, "a"); /* append */ if (!f) { fprintf(stderr, "Unable to open %s for appending\n", filename); return; } fprintf(f, "/* First-draw parameters / constants */\n"); fprintf(f, "/*\n"); _mesa_fprint_parameter_list(f, prog->Parameters); fprintf(f, "*/\n"); fclose(f); }
static void compute_version_es1(struct gl_context *ctx) { static const int max = 100; /* OpenGL ES 1.0 is derived from OpenGL 1.3 */ const GLboolean ver_1_0 = (ctx->Extensions.ARB_texture_env_combine && ctx->Extensions.ARB_texture_env_dot3); /* OpenGL ES 1.1 is derived from OpenGL 1.5 */ const GLboolean ver_1_1 = (ver_1_0 && ctx->Extensions.EXT_point_parameters); if (ver_1_1) { ctx->VersionMajor = 1; ctx->VersionMinor = 1; } else if (ver_1_0) { ctx->VersionMajor = 1; ctx->VersionMinor = 0; } else { _mesa_problem(ctx, "Incomplete OpenGL ES 1.0 support."); } ctx->VersionString = (char *) malloc(max); if (ctx->VersionString) { _mesa_snprintf(ctx->VersionString, max, "OpenGL ES-CM 1.%d Mesa " MESA_VERSION_STRING #ifdef MESA_GIT_SHA1 " (" MESA_GIT_SHA1 ")" #endif , ctx->VersionMinor); } }
/** * Write shader and associated info to a file. */ void _mesa_write_shader_to_file(const struct gl_shader *shader) { const char *type = "????"; char filename[100]; FILE *f; switch (shader->Stage) { case MESA_SHADER_FRAGMENT: type = "frag"; break; case MESA_SHADER_TESS_CTRL: type = "tesc"; break; case MESA_SHADER_TESS_EVAL: type = "tese"; break; case MESA_SHADER_VERTEX: type = "vert"; break; case MESA_SHADER_GEOMETRY: type = "geom"; break; case MESA_SHADER_COMPUTE: type = "comp"; break; } _mesa_snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type); f = fopen(filename, "w"); if (!f) { fprintf(stderr, "Unable to open %s for writing\n", filename); return; } fprintf(f, "/* Shader %u source, checksum %u */\n", shader->Name, shader->SourceChecksum); fputs(shader->Source, f); fprintf(f, "\n"); fprintf(f, "/* Compile status: %s */\n", shader->CompileStatus ? "ok" : "fail"); fprintf(f, "/* Log Info: */\n"); if (shader->InfoLog) { fputs(shader->InfoLog, f); } if (shader->CompileStatus && shader->Program) { fprintf(f, "/* GPU code */\n"); fprintf(f, "/*\n"); _mesa_fprint_program_opt(f, shader->Program, PROG_PRINT_DEBUG, GL_TRUE); fprintf(f, "*/\n"); fprintf(f, "/* Parameters / constants */\n"); fprintf(f, "/*\n"); _mesa_fprint_parameter_list(f, shader->Program->Parameters); fprintf(f, "*/\n"); } fclose(f); }
/** * Return string name for given program opcode. */ const char * _mesa_opcode_string(gl_inst_opcode opcode) { if (opcode < MAX_OPCODE) return InstInfo[opcode].Name; else { static char s[20]; _mesa_snprintf(s, sizeof(s), "OP%u", opcode); return s; } }
static GLvoid grammar_error_to_log (slang_info_log *log) { char buf[1024]; GLint pos; grammar_get_last_error ((byte *) (buf), sizeof (buf), &pos); if (buf[0] == 0) { _mesa_snprintf(buf, sizeof(buf), "Preprocessor error"); } slang_info_log_error (log, buf); }
static void output_if_debug(const char *prefixString, const char *outputString, GLboolean newline) { static int debug = -1; /* Init the local 'debug' var once. * Note: the _mesa_init_debug() function should have been called * by now so MESA_DEBUG_FLAGS will be initialized. */ if (debug == -1) { /* If MESA_LOG_FILE env var is set, log Mesa errors, warnings, * etc to the named file. Otherwise, output to stderr. */ const char *logFile = getenv("MESA_LOG_FILE"); if (logFile) LogFile = fopen(logFile, "w"); if (!LogFile) LogFile = stderr; #ifdef DEBUG /* in debug builds, print messages unless MESA_DEBUG="silent" */ if (MESA_DEBUG_FLAGS & DEBUG_SILENT) debug = 0; else debug = 1; #else /* in release builds, be silent unless MESA_DEBUG is set */ debug = getenv("MESA_DEBUG") != NULL; #endif } /* Now only print the string if we're required to do so. */ if (debug) { if (prefixString) fprintf(LogFile, "%s: %s", prefixString, outputString); else fprintf(LogFile, "%s", outputString); if (newline) fprintf(LogFile, "\n"); fflush(LogFile); #if defined(_WIN32) /* stderr from windows applications without console is not usually * visible, so communicate with the debugger instead */ { char buf[4096]; _mesa_snprintf(buf, sizeof(buf), "%s: %s%s", prefixString, outputString, newline ? "\n" : ""); OutputDebugStringA(buf); } #endif } }
/** * When a new type of error is recorded, print a message describing * previous errors which were accumulated. */ static void flush_delayed_errors( struct gl_context *ctx ) { char s[MAX_DEBUG_MESSAGE_LENGTH]; if (ctx->ErrorDebugCount) { _mesa_snprintf(s, MAX_DEBUG_MESSAGE_LENGTH, "%d similar %s errors", ctx->ErrorDebugCount, _mesa_enum_to_string(ctx->ErrorValue)); output_if_debug("Mesa", s, GL_TRUE); ctx->ErrorDebugCount = 0; } }
extern "C" bool _mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg, char *errMsg, size_t errMsgLength) { /* Shader does not have samplers. */ if (shProg->NumUniformStorage == 0) return true; if (!shProg->SamplersValidated) { _mesa_snprintf(errMsg, errMsgLength, "active samplers with a different type " "refer to the same texture image unit"); return false; } return true; }
/** * Builds the MESA version string. */ static GLboolean create_version_string(struct gl_context *ctx, const char *prefix) { static const int max = 100; ctx->VersionString = malloc(max); if (ctx->VersionString) { _mesa_snprintf(ctx->VersionString, max, "%s%u.%u Mesa " MESA_VERSION_STRING #ifdef MESA_GIT_SHA1 " (" MESA_GIT_SHA1 ")" #endif , prefix, ctx->Version / 10, ctx->Version % 10); } }
/** * Write shader and associated info to a file. */ void _mesa_write_shader_to_file(const struct gl_shader *shader) { const char *type; char filename[100]; FILE *f; if (shader->Type == GL_FRAGMENT_SHADER) type = "frag"; else if (shader->Type == GL_VERTEX_SHADER) type = "vert"; else type = "geom"; _mesa_snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type); f = fopen(filename, "w"); if (!f) { fprintf(stderr, "Unable to open %s for writing\n", filename); return; } fprintf(f, "/* Shader %u source, checksum %u */\n", shader->Name, shader->SourceChecksum); fputs(shader->Source, f); fprintf(f, "\n"); fprintf(f, "/* Compile status: %s */\n", shader->CompileStatus ? "ok" : "fail"); fprintf(f, "/* Log Info: */\n"); if (shader->InfoLog) { fputs(shader->InfoLog, f); } if (shader->CompileStatus && shader->Program) { fprintf(f, "/* GPU code */\n"); fprintf(f, "/*\n"); _mesa_fprint_program_opt(f, shader->Program, PROG_PRINT_DEBUG, GL_TRUE); fprintf(f, "*/\n"); fprintf(f, "/* Parameters / constants */\n"); fprintf(f, "/*\n"); _mesa_fprint_parameter_list(f, shader->Program->Parameters); fprintf(f, "*/\n"); } fclose(f); }
/** * Builds the MESA version string. */ static void create_version_string(struct gl_context *ctx, const char *prefix) { static const int max = 100; ctx->VersionString = malloc(max); if (ctx->VersionString) { _mesa_snprintf(ctx->VersionString, max, "%s%u.%u%s Mesa " MESA_VERSION_STRING #ifdef MESA_GIT_SHA1 " (" MESA_GIT_SHA1 ")" #endif , prefix, ctx->Version / 10, ctx->Version % 10, (ctx->API == API_OPENGL_CORE) ? " (Core Profile)" : "" ); } }
extern "C" bool _mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg, char *errMsg, size_t errMsgLength) { const glsl_type *unit_types[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; memset(unit_types, 0, sizeof(unit_types)); for (unsigned i = 0; i < shProg->NumUserUniformStorage; i++) { const struct gl_uniform_storage *const storage = &shProg->UniformStorage[i]; const glsl_type *const t = (storage->type->is_array()) ? storage->type->fields.array : storage->type; if (!t->is_sampler()) continue; const unsigned count = MAX2(1, storage->type->array_size()); for (unsigned j = 0; j < count; j++) { const unsigned unit = storage->storage[j].i; /* The types of the samplers associated with a particular texture * unit must be an exact match. Page 74 (page 89 of the PDF) of the * OpenGL 3.3 core spec says: * * "It is not allowed to have variables of different sampler * types pointing to the same texture image unit within a program * object." */ if (unit_types[unit] == NULL) { unit_types[unit] = t; } else if (unit_types[unit] != t) { _mesa_snprintf(errMsg, errMsgLength, "Texture unit %d is accessed both as %s and %s", unit, unit_types[unit]->name, t->name); return false; } } } return true; }
/** * Return string name for given program/register file. */ static const char * file_string(gl_register_file f, gl_prog_print_mode mode) { switch (f) { case PROGRAM_TEMPORARY: return "TEMP"; case PROGRAM_LOCAL_PARAM: return "LOCAL"; case PROGRAM_ENV_PARAM: return "ENV"; case PROGRAM_STATE_VAR: return "STATE"; case PROGRAM_INPUT: return "INPUT"; case PROGRAM_OUTPUT: return "OUTPUT"; case PROGRAM_NAMED_PARAM: return "NAMED"; case PROGRAM_CONSTANT: return "CONST"; case PROGRAM_UNIFORM: return "UNIFORM"; case PROGRAM_VARYING: return "VARYING"; case PROGRAM_WRITE_ONLY: return "WRITE_ONLY"; case PROGRAM_ADDRESS: return "ADDR"; case PROGRAM_SAMPLER: return "SAMPLER"; case PROGRAM_UNDEFINED: return "UNDEFINED"; default: { static char s[20]; _mesa_snprintf(s, sizeof(s), "FILE%u", f); return s; } } }
/** * Record an OpenGL state error. These usually occur when the user * passes invalid parameters to a GL function. * * If debugging is enabled (either at compile-time via the DEBUG macro, or * run-time via the MESA_DEBUG environment variable), report the error with * _mesa_debug(). * * \param ctx the GL context. * \param error the error value. * \param fmtString printf() style format string, followed by optional args */ void _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... ) { GLboolean do_output, do_log; /* Ideally this would be set up by the caller, so that we had proper IDs * per different message. */ static GLuint error_msg_id = 0; _mesa_debug_get_id(&error_msg_id); do_output = should_output(ctx, error, fmtString); mtx_lock(&ctx->DebugMutex); if (ctx->Debug) { do_log = _mesa_debug_is_message_enabled(ctx->Debug, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_ERROR, error_msg_id, MESA_DEBUG_SEVERITY_HIGH); } else { do_log = GL_FALSE; } mtx_unlock(&ctx->DebugMutex); if (do_output || do_log) { char s[MAX_DEBUG_MESSAGE_LENGTH], s2[MAX_DEBUG_MESSAGE_LENGTH]; int len; va_list args; va_start(args, fmtString); len = _mesa_vsnprintf(s, MAX_DEBUG_MESSAGE_LENGTH, fmtString, args); va_end(args); if (len >= MAX_DEBUG_MESSAGE_LENGTH) { /* Too long error message. Whoever calls _mesa_error should use * shorter strings. */ assert(0); return; } len = _mesa_snprintf(s2, MAX_DEBUG_MESSAGE_LENGTH, "%s in %s", _mesa_enum_to_string(error), s); if (len >= MAX_DEBUG_MESSAGE_LENGTH) { /* Same as above. */ assert(0); return; } /* Print the error to stderr if needed. */ if (do_output) { output_if_debug("Mesa: User error", s2, GL_TRUE); } /* Log the error via ARB_debug_output if needed.*/ if (do_log) { _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_ERROR, error_msg_id, MESA_DEBUG_SEVERITY_HIGH, len, s2); } } /* Set the GL context error state for glGetError. */ _mesa_record_error(ctx, error); }
/** * Linking varying vars involves rearranging varying vars so that the * vertex program's output varyings matches the order of the fragment * program's input varyings. * We'll then rewrite instructions to replace PROGRAM_VARYING with either * PROGRAM_INPUT or PROGRAM_OUTPUT depending on whether it's a vertex or * fragment shader. * This is also where we set program Input/OutputFlags to indicate * which inputs are centroid-sampled, invariant, etc. */ static GLboolean link_varying_vars(GLcontext *ctx, struct gl_shader_program *shProg, struct gl_program *prog) { GLuint *map, i, firstVarying, newFile; GLbitfield *inOutFlags; map = (GLuint *) malloc(prog->Varying->NumParameters * sizeof(GLuint)); if (!map) return GL_FALSE; /* Varying variables are treated like other vertex program outputs * (and like other fragment program inputs). The position of the * first varying differs for vertex/fragment programs... * Also, replace File=PROGRAM_VARYING with File=PROGRAM_INPUT/OUTPUT. */ if (prog->Target == GL_VERTEX_PROGRAM_ARB) { firstVarying = VERT_RESULT_VAR0; newFile = PROGRAM_OUTPUT; inOutFlags = prog->OutputFlags; } else { assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB); firstVarying = FRAG_ATTRIB_VAR0; newFile = PROGRAM_INPUT; inOutFlags = prog->InputFlags; } for (i = 0; i < prog->Varying->NumParameters; i++) { /* see if this varying is in the linked varying list */ const struct gl_program_parameter *var = prog->Varying->Parameters + i; GLint j = _mesa_lookup_parameter_index(shProg->Varying, -1, var->Name); if (j >= 0) { /* varying is already in list, do some error checking */ const struct gl_program_parameter *v = &shProg->Varying->Parameters[j]; if (var->Size != v->Size) { link_error(shProg, "mismatched varying variable types"); free(map); return GL_FALSE; } if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_CENTROID)) { char msg[100]; _mesa_snprintf(msg, sizeof(msg), "centroid modifier mismatch for '%s'", var->Name); link_error(shProg, msg); free(map); return GL_FALSE; } if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_INVARIANT)) { char msg[100]; _mesa_snprintf(msg, sizeof(msg), "invariant modifier mismatch for '%s'", var->Name); link_error(shProg, msg); free(map); return GL_FALSE; } } else { /* not already in linked list */ j = _mesa_add_varying(shProg->Varying, var->Name, var->Size, var->Flags); } if (shProg->Varying->NumParameters > ctx->Const.MaxVarying) { link_error(shProg, "Too many varying variables"); free(map); return GL_FALSE; } /* Map varying[i] to varying[j]. * Note: the loop here takes care of arrays or large (sz>4) vars. */ { GLint sz = var->Size; while (sz > 0) { inOutFlags[firstVarying + j] = var->Flags; /*printf("Link varying from %d to %d\n", i, j);*/ map[i++] = j++; sz -= 4; } i--; /* go back one */ } } /* OK, now scan the program/shader instructions looking for varying vars, * replacing the old index with the new index. */ for (i = 0; i < prog->NumInstructions; i++) { struct prog_instruction *inst = prog->Instructions + i; GLuint j; if (inst->DstReg.File == PROGRAM_VARYING) { inst->DstReg.File = newFile; inst->DstReg.Index = map[ inst->DstReg.Index ] + firstVarying; } for (j = 0; j < 3; j++) { if (inst->SrcReg[j].File == PROGRAM_VARYING) { inst->SrcReg[j].File = newFile; inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ] + firstVarying; } } } free(map); /* these will get recomputed before linking is completed */ prog->InputsRead = 0x0; prog->OutputsWritten = 0x0; return GL_TRUE; }
/** * Called via glShaderSource() and glShaderSourceARB() API functions. * Basically, concatenate the source code strings into one long string * and pass it to _mesa_shader_source(). */ void GLAPIENTRY _mesa_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count, const GLcharARB ** string, const GLint * length) { GET_CURRENT_CONTEXT(ctx); GLint *offsets; GLsizei i, totalLength; GLcharARB *source; GLuint checksum; if (!shaderObj || string == NULL) { _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB"); return; } /* * This array holds offsets of where the appropriate string ends, thus the * last element will be set to the total length of the source code. */ offsets = (GLint *) malloc(count * sizeof(GLint)); if (offsets == NULL) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB"); return; } for (i = 0; i < count; i++) { if (string[i] == NULL) { free((GLvoid *) offsets); _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderSourceARB(null string)"); return; } if (length == NULL || length[i] < 0) offsets[i] = strlen(string[i]); else offsets[i] = length[i]; /* accumulate string lengths */ if (i > 0) offsets[i] += offsets[i - 1]; } /* Total length of source string is sum off all strings plus two. * One extra byte for terminating zero, another extra byte to silence * valgrind warnings in the parser/grammer code. */ totalLength = offsets[count - 1] + 2; source = (GLcharARB *) malloc(totalLength * sizeof(GLcharARB)); if (source == NULL) { free((GLvoid *) offsets); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB"); return; } for (i = 0; i < count; i++) { GLint start = (i > 0) ? offsets[i - 1] : 0; memcpy(source + start, string[i], (offsets[i] - start) * sizeof(GLcharARB)); } source[totalLength - 1] = '\0'; source[totalLength - 2] = '\0'; if (SHADER_SUBST) { /* Compute the shader's source code checksum then try to open a file * named newshader_<CHECKSUM>. If it exists, use it in place of the * original shader source code. For debugging. */ char filename[100]; GLcharARB *newSource; checksum = _mesa_str_checksum(source); _mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum); newSource = read_shader(filename); if (newSource) { fprintf(stderr, "Mesa: Replacing shader %u chksum=%d with %s\n", shaderObj, checksum, filename); free(source); source = newSource; } } shader_source(ctx, shaderObj, source); if (SHADER_SUBST) { struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj); if (sh) sh->SourceChecksum = checksum; /* save original checksum */ } free(offsets); }
/** * Examine enabled GL extensions to determine GL version. */ static void compute_version(struct gl_context *ctx) { GLuint major, minor; static const int max = 100; const GLboolean ver_1_3 = (ctx->Extensions.ARB_texture_border_clamp && ctx->Extensions.ARB_texture_cube_map && ctx->Extensions.ARB_texture_env_combine && ctx->Extensions.ARB_texture_env_dot3); const GLboolean ver_1_4 = (ver_1_3 && ctx->Extensions.ARB_depth_texture && ctx->Extensions.ARB_shadow && ctx->Extensions.ARB_texture_env_crossbar && ctx->Extensions.ARB_window_pos && ctx->Extensions.EXT_blend_color && ctx->Extensions.EXT_blend_func_separate && ctx->Extensions.EXT_blend_minmax && ctx->Extensions.EXT_fog_coord && ctx->Extensions.EXT_point_parameters && ctx->Extensions.EXT_secondary_color); const GLboolean ver_1_5 = (ver_1_4 && ctx->Extensions.ARB_occlusion_query && ctx->Extensions.EXT_shadow_funcs); const GLboolean ver_2_0 = (ver_1_5 && ctx->Extensions.ARB_point_sprite && ctx->Extensions.ARB_shader_objects && ctx->Extensions.ARB_vertex_shader && ctx->Extensions.ARB_fragment_shader && ctx->Extensions.ARB_texture_non_power_of_two && ctx->Extensions.EXT_blend_equation_separate && /* Technically, 2.0 requires the functionality * of the EXT version. Enable 2.0 if either * extension is available, and assume that a * driver that only exposes the ATI extension * will fallback to software when necessary. */ (ctx->Extensions.EXT_stencil_two_side || ctx->Extensions.ATI_separate_stencil)); const GLboolean ver_2_1 = (ver_2_0 && ctx->Const.GLSLVersion >= 120 && ctx->Extensions.EXT_pixel_buffer_object && ctx->Extensions.EXT_texture_sRGB); const GLboolean ver_3_0 = (ver_2_1 && ctx->Const.GLSLVersion >= 130 && ctx->Const.MaxSamples >= 4 && ctx->Extensions.ARB_color_buffer_float && ctx->Extensions.ARB_depth_buffer_float && ctx->Extensions.ARB_half_float_pixel && ctx->Extensions.ARB_half_float_vertex && ctx->Extensions.ARB_map_buffer_range && ctx->Extensions.ARB_shader_texture_lod && ctx->Extensions.ARB_texture_float && ctx->Extensions.ARB_texture_rg && ctx->Extensions.ARB_texture_compression_rgtc && ctx->Extensions.APPLE_vertex_array_object && ctx->Extensions.EXT_draw_buffers2 && ctx->Extensions.ARB_framebuffer_object && ctx->Extensions.EXT_framebuffer_sRGB && ctx->Extensions.EXT_packed_float && ctx->Extensions.EXT_texture_array && ctx->Extensions.EXT_texture_shared_exponent && ctx->Extensions.EXT_transform_feedback && ctx->Extensions.NV_conditional_render); const GLboolean ver_3_1 = (ver_3_0 && ctx->Const.GLSLVersion >= 140 && ctx->Extensions.ARB_copy_buffer && ctx->Extensions.ARB_draw_instanced && ctx->Extensions.ARB_texture_buffer_object && ctx->Extensions.ARB_uniform_buffer_object && ctx->Extensions.EXT_texture_snorm && ctx->Extensions.NV_primitive_restart && ctx->Extensions.NV_texture_rectangle && ctx->Const.MaxVertexTextureImageUnits >= 16); const GLboolean ver_3_2 = (ver_3_1 && ctx->Const.GLSLVersion >= 150 && ctx->Extensions.ARB_depth_clamp && ctx->Extensions.ARB_draw_elements_base_vertex && ctx->Extensions.ARB_fragment_coord_conventions && ctx->Extensions.ARB_geometry_shader4 && ctx->Extensions.EXT_provoking_vertex && ctx->Extensions.ARB_seamless_cube_map && ctx->Extensions.ARB_sync && ctx->Extensions.ARB_texture_multisample && ctx->Extensions.EXT_vertex_array_bgra); const GLboolean ver_3_3 = (ver_3_2 && ctx->Const.GLSLVersion >= 330 && ctx->Extensions.ARB_blend_func_extended && ctx->Extensions.ARB_explicit_attrib_location && ctx->Extensions.ARB_instanced_arrays && ctx->Extensions.ARB_occlusion_query2 && ctx->Extensions.ARB_sampler_objects && ctx->Extensions.ARB_shader_bit_encoding && ctx->Extensions.ARB_texture_rgb10_a2ui && ctx->Extensions.ARB_timer_query && ctx->Extensions.ARB_vertex_type_2_10_10_10_rev && ctx->Extensions.EXT_texture_swizzle); if (ver_3_3) { major = 3; minor = 3; } else if (ver_3_2) { major = 3; minor = 2; } else if (ver_3_1) { major = 3; minor = 1; } else if (ver_3_0) { major = 3; minor = 0; } else if (ver_2_1) { major = 2; minor = 1; } else if (ver_2_0) { major = 2; minor = 0; } else if (ver_1_5) { major = 1; minor = 5; } else if (ver_1_4) { major = 1; minor = 4; } else if (ver_1_3) { major = 1; minor = 3; } else { major = 1; minor = 2; } ctx->VersionMajor = major; ctx->VersionMinor = minor; override_version(ctx, &ctx->VersionMajor, &ctx->VersionMinor); ctx->VersionString = (char *) malloc(max); if (ctx->VersionString) { _mesa_snprintf(ctx->VersionString, max, "%u.%u Mesa " MESA_VERSION_STRING #ifdef MESA_GIT_SHA1 " (" MESA_GIT_SHA1 ")" #endif , ctx->VersionMajor, ctx->VersionMinor); } }
void GLAPIENTRY _mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len, const GLvoid *string) { struct gl_program *base; bool failed; GET_CURRENT_CONTEXT(ctx); FLUSH_VERTICES(ctx, _NEW_PROGRAM); if (!ctx->Extensions.ARB_vertex_program && !ctx->Extensions.ARB_fragment_program) { _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramStringARB()"); return; } if (format != GL_PROGRAM_FORMAT_ASCII_ARB) { _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)"); return; } if (target == GL_VERTEX_PROGRAM_ARB && ctx->Extensions.ARB_vertex_program) { struct gl_vertex_program *prog = ctx->VertexProgram.Current; _mesa_parse_arb_vertex_program(ctx, target, string, len, prog); base = & prog->Base; } else if (target == GL_FRAGMENT_PROGRAM_ARB && ctx->Extensions.ARB_fragment_program) { struct gl_fragment_program *prog = ctx->FragmentProgram.Current; _mesa_parse_arb_fragment_program(ctx, target, string, len, prog); base = & prog->Base; } else { _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(target)"); return; } failed = ctx->Program.ErrorPos != -1; if (!failed) { /* finally, give the program to the driver for translation/checking */ if (!ctx->Driver.ProgramStringNotify(ctx, target, base)) { failed = true; _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramStringARB(rejected by driver"); } } if (ctx->_Shader->Flags & GLSL_DUMP) { const char *shader_type = target == GL_FRAGMENT_PROGRAM_ARB ? "fragment" : "vertex"; fprintf(stderr, "ARB_%s_program source for program %d:\n", shader_type, base->Id); fprintf(stderr, "%s\n", (const char *) string); if (failed) { fprintf(stderr, "ARB_%s_program %d failed to compile.\n", shader_type, base->Id); } else { fprintf(stderr, "Mesa IR for ARB_%s_program %d:\n", shader_type, base->Id); _mesa_print_program(base); fprintf(stderr, "\n"); } fflush(stderr); } /* Capture vp-*.shader_test/fp-*.shader_test files. */ const char *capture_path = _mesa_get_shader_capture_path(); if (capture_path != NULL) { FILE *file; char filename[PATH_MAX]; const char *shader_type = target == GL_FRAGMENT_PROGRAM_ARB ? "fragment" : "vertex"; _mesa_snprintf(filename, sizeof(filename), "%s/%cp-%u.shader_test", capture_path, shader_type[0], base->Id); file = fopen(filename, "w"); if (file) { fprintf(file, "[require]\nGL_ARB_%s_program\n\n[%s program]\n%s\n", shader_type, shader_type, (const char *) string); fclose(file); } else { _mesa_warning(ctx, "Failed to open %s", filename); } } }