static gboolean _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline, int n_layers, unsigned long pipelines_difference) { CoglPipelineShaderState *shader_state; CoglPipeline *template_pipeline = NULL; CoglProgram *user_program; _COGL_GET_CONTEXT (ctx, FALSE); if (!cogl_features_available (COGL_FEATURE_SHADERS_GLSL)) return FALSE; user_program = cogl_pipeline_get_user_program (pipeline); /* If the user program has a vertex shader that isn't GLSL then the appropriate vertend for that language should handle it */ if (user_program && _cogl_program_has_vertex_shader (user_program) && _cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL) return FALSE; /* Now lookup our glsl backend private state (allocating if * necessary) */ shader_state = get_shader_state (pipeline); if (shader_state == NULL) { CoglPipeline *authority; /* Get the authority for anything affecting vertex shader state */ authority = _cogl_pipeline_find_equivalent_parent (pipeline, COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN & ~COGL_PIPELINE_STATE_LAYERS, COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN); shader_state = get_shader_state (authority); if (shader_state == NULL) { /* Check if there is already a similar cached pipeline whose shader state we can share */ if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES)))) { template_pipeline = _cogl_pipeline_cache_get_vertex_template (ctx->pipeline_cache, authority); shader_state = get_shader_state (template_pipeline); } if (shader_state) shader_state->ref_count++; else shader_state = shader_state_new (); set_shader_state (authority, shader_state); if (template_pipeline) { shader_state->ref_count++; set_shader_state (template_pipeline, shader_state); } } if (authority != pipeline) { shader_state->ref_count++; set_shader_state (pipeline, shader_state); } } if (shader_state->gl_shader) { /* If we already have a valid GLSL shader then we don't need to generate a new one. However if there's a user program and it has changed since the last link then we do need a new shader */ if (user_program == NULL || shader_state->user_program_age == user_program->age) return TRUE; /* We need to recreate the shader so destroy the existing one */ GE( ctx, glDeleteShader (shader_state->gl_shader) ); shader_state->gl_shader = 0; } /* If we make it here then we have a shader_state struct without a gl_shader either because this is the first time we've encountered it or because the user program has changed */ if (user_program) shader_state->user_program_age = user_program->age; /* If the user program contains a vertex shader then we don't need to generate one */ if (user_program && _cogl_program_has_vertex_shader (user_program)) return TRUE; /* We reuse two grow-only GStrings for code-gen. One string contains the uniform and attribute declarations while the other contains the main function. We need two strings because we need to dynamically declare attributes as the add_layer callback is invoked */ g_string_set_size (ctx->codegen_header_buffer, 0); g_string_set_size (ctx->codegen_source_buffer, 0); shader_state->header = ctx->codegen_header_buffer; shader_state->source = ctx->codegen_source_buffer; g_string_append (shader_state->source, "void\n" "main ()\n" "{\n"); if (ctx->driver == COGL_DRIVER_GLES2) /* There is no builtin uniform for the pointsize on GLES2 so we need to copy it from the custom uniform in the vertex shader */ g_string_append (shader_state->source, " cogl_point_size_out = cogl_point_size_in;\n"); /* On regular OpenGL we'll just flush the point size builtin */ else if (pipelines_difference & COGL_PIPELINE_STATE_POINT_SIZE) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_POINT_SIZE); if (ctx->point_size_cache != authority->big_state->point_size) { GE( ctx, glPointSize (authority->big_state->point_size) ); ctx->point_size_cache = authority->big_state->point_size; } } return TRUE; }
static void _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline, int n_layers, unsigned long pipelines_difference) { CoglPipelineShaderState *shader_state; CoglPipeline *template_pipeline = NULL; _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Now lookup our glsl backend private state (allocating if * necessary) */ shader_state = get_shader_state (pipeline); if (shader_state == NULL) { CoglPipeline *authority; /* Get the authority for anything affecting vertex shader state */ authority = _cogl_pipeline_find_equivalent_parent (pipeline, COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN & ~COGL_PIPELINE_STATE_LAYERS, COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN); shader_state = get_shader_state (authority); if (shader_state == NULL) { /* Check if there is already a similar cached pipeline whose shader state we can share */ if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES)))) { template_pipeline = _cogl_pipeline_cache_get_vertex_template (ctx->pipeline_cache, authority); shader_state = get_shader_state (template_pipeline); } if (shader_state) shader_state->ref_count++; else shader_state = shader_state_new (); set_shader_state (authority, shader_state); if (template_pipeline) { shader_state->ref_count++; set_shader_state (template_pipeline, shader_state); } } if (authority != pipeline) { shader_state->ref_count++; set_shader_state (pipeline, shader_state); } } if (shader_state->gl_shader) return; /* If we make it here then we have a shader_state struct without a gl_shader because this is the first time we've encountered it */ /* We reuse two grow-only GStrings for code-gen. One string contains the uniform and attribute declarations while the other contains the main function. We need two strings because we need to dynamically declare attributes as the add_layer callback is invoked */ g_string_set_size (ctx->codegen_header_buffer, 0); g_string_set_size (ctx->codegen_source_buffer, 0); shader_state->header = ctx->codegen_header_buffer; shader_state->source = ctx->codegen_source_buffer; add_layer_declarations (pipeline, shader_state); add_global_declarations (pipeline, shader_state); g_string_append (shader_state->source, "void\n" "cogl_generated_source ()\n" "{\n"); if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM)) /* There is no builtin uniform for the pointsize on GLES2 so we need to copy it from the custom uniform in the vertex shader */ g_string_append (shader_state->source, " cogl_point_size_out = cogl_point_size_in;\n"); }
static CoglBool _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline, int n_layers, unsigned long pipelines_difference, int n_tex_coord_attribs) { CoglPipelineShaderState *shader_state; CoglPipeline *authority; CoglPipeline *template_pipeline = NULL; _COGL_GET_CONTEXT (ctx, FALSE); /* First validate that we can handle the current state using ARBfp */ if (!cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP)) return FALSE; /* TODO: support fog */ if (_cogl_pipeline_get_fog_enabled (pipeline)) return FALSE; /* Fragment snippets are only supported in the GLSL fragend */ if (_cogl_pipeline_has_fragment_snippets (pipeline)) return FALSE; /* Now lookup our ARBfp backend private state */ shader_state = get_shader_state (pipeline); /* If we have a valid shader_state then we are all set and don't * need to generate a new program. */ if (shader_state) return TRUE; /* If we don't have an associated arbfp program yet then find the * arbfp-authority (the oldest ancestor whose state will result in * the same program being generated as for this pipeline). * * We always make sure to associate new programs with the * arbfp-authority to maximize the chance that other pipelines can * share it. */ authority = _cogl_pipeline_find_equivalent_parent (pipeline, _cogl_pipeline_get_state_for_fragment_codegen (ctx) & ~COGL_PIPELINE_STATE_LAYERS, _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx)); shader_state = get_shader_state (authority); if (shader_state) { /* If we are going to share our program state with an arbfp-authority * then add a reference to the program state associated with that * arbfp-authority... */ shader_state->ref_count++; set_shader_state (pipeline, shader_state); return TRUE; } /* If we haven't yet found an existing program then before we resort to * generating a new arbfp program we see if we can find a suitable * program in the pipeline_cache. */ if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES)))) { template_pipeline = _cogl_pipeline_cache_get_fragment_template (ctx->pipeline_cache, authority); shader_state = get_shader_state (template_pipeline); if (shader_state) shader_state->ref_count++; } /* If we still haven't got a shader state then we'll have to create a new one */ if (shader_state == NULL) { shader_state = shader_state_new (n_layers); /* We reuse a single grow-only GString for code-gen */ g_string_set_size (ctx->codegen_source_buffer, 0); shader_state->source = ctx->codegen_source_buffer; g_string_append (shader_state->source, "!!ARBfp1.0\n" "TEMP output;\n" "TEMP tmp0, tmp1, tmp2, tmp3, tmp4;\n" "PARAM half = {.5, .5, .5, .5};\n" "PARAM one = {1, 1, 1, 1};\n" "PARAM two = {2, 2, 2, 2};\n" "PARAM minus_one = {-1, -1, -1, -1};\n"); } set_shader_state (pipeline, shader_state); /* Since we have already resolved the arbfp-authority at this point * we might as well also associate any program we find from the cache * with the authority too... */ if (authority != pipeline) { shader_state->ref_count++; set_shader_state (authority, shader_state); } /* If we found a template then we'll attach it to that too so that next time a similar pipeline is used it can use the same state */ if (template_pipeline) { shader_state->ref_count++; set_shader_state (template_pipeline, shader_state); } return TRUE; }
static void _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline, int n_layers, unsigned long pipelines_difference) { CoglPipelineShaderState *shader_state; CoglPipeline *authority; CoglPipelineCacheEntry *cache_entry = NULL; CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline); _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Now lookup our ARBfp backend private state */ shader_state = get_shader_state (pipeline); /* If we have a valid shader_state then we are all set and don't * need to generate a new program. */ if (shader_state) return; /* If we don't have an associated arbfp program yet then find the * arbfp-authority (the oldest ancestor whose state will result in * the same program being generated as for this pipeline). * * We always make sure to associate new programs with the * arbfp-authority to maximize the chance that other pipelines can * share it. */ authority = _cogl_pipeline_find_equivalent_parent (pipeline, _cogl_pipeline_get_state_for_fragment_codegen (ctx) & ~COGL_PIPELINE_STATE_LAYERS, _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx)); shader_state = get_shader_state (authority); if (shader_state) { /* If we are going to share our program state with an arbfp-authority * then add a reference to the program state associated with that * arbfp-authority... */ set_shader_state (pipeline, shader_state); return; } /* If we haven't yet found an existing program then before we resort to * generating a new arbfp program we see if we can find a suitable * program in the pipeline_cache. */ if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES)))) { cache_entry = _cogl_pipeline_cache_get_fragment_template (ctx->pipeline_cache, authority); shader_state = get_shader_state (cache_entry->pipeline); if (shader_state) shader_state->ref_count++; } /* If we still haven't got a shader state then we'll have to create a new one */ if (shader_state == NULL) { shader_state = shader_state_new (n_layers, cache_entry); shader_state->user_program = user_program; if (user_program == COGL_INVALID_HANDLE) { /* We reuse a single grow-only GString for code-gen */ g_string_set_size (ctx->codegen_source_buffer, 0); shader_state->source = ctx->codegen_source_buffer; g_string_append (shader_state->source, "!!ARBfp1.0\n" "TEMP output;\n" "TEMP tmp0, tmp1, tmp2, tmp3, tmp4;\n" "PARAM half = {.5, .5, .5, .5};\n" "PARAM one = {1, 1, 1, 1};\n" "PARAM two = {2, 2, 2, 2};\n" "PARAM minus_one = {-1, -1, -1, -1};\n"); } } set_shader_state (pipeline, shader_state); shader_state->ref_count--; /* Since we have already resolved the arbfp-authority at this point * we might as well also associate any program we find from the cache * with the authority too... */ if (authority != pipeline) set_shader_state (authority, shader_state); /* If we found a template then we'll attach it to that too so that next time a similar pipeline is used it can use the same state */ if (cache_entry) set_shader_state (cache_entry->pipeline, shader_state); }