void cogl_begin_gl (void) { CoglPipeline *pipeline; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (ctx->in_begin_gl_block) { static CoglBool shown = FALSE; if (!shown) g_warning ("You should not nest cogl_begin_gl/cogl_end_gl blocks"); shown = TRUE; return; } ctx->in_begin_gl_block = TRUE; /* Flush all batched primitives */ cogl_flush (); /* Flush framebuffer state, including clip state, modelview and * projection matrix state * * NB: _cogl_framebuffer_flush_state may disrupt various state (such * as the pipeline state) when flushing the clip stack, so should * always be done first when preparing to draw. */ _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (), _cogl_get_read_framebuffer (), COGL_FRAMEBUFFER_STATE_ALL); /* Setup the state for the current pipeline */ /* We considered flushing a specific, minimal pipeline here to try and * simplify the GL state, but decided to avoid special cases and second * guessing what would be actually helpful. * * A user should instead call cogl_set_source_color4ub() before * cogl_begin_gl() to simplify the state flushed. * * XXX: note defining n_tex_coord_attribs using * cogl_pipeline_get_n_layers is a hack, but the problem is that * n_tex_coord_attribs is usually defined when drawing a primitive * which isn't happening here. * * Maybe it would be more useful if this code did flush the * opaque_color_pipeline and then call into cogl-pipeline-opengl.c to then * restore all state for the material's backend back to default OpenGL * values. */ pipeline = cogl_get_source (); _cogl_pipeline_flush_gl_state (ctx, pipeline, cogl_get_draw_framebuffer (), FALSE, FALSE); /* Disable any cached vertex arrays */ _cogl_gl_disable_all_attributes (ctx); }
void _cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer, CoglPipeline *pipeline, CoglFlushLayerState *layers_state, CoglDrawFlags flags, CoglAttribute **attributes, int n_attributes) { CoglContext *ctx = framebuffer->context; int i; CoglBool skip_gl_color = FALSE; CoglPipeline *copy = NULL; /* Iterate the attributes to work out whether blending needs to be enabled and how many texture coords there are. We need to do this before flushing the pipeline. */ for (i = 0; i < n_attributes; i++) switch (attributes[i]->name_state->name_id) { case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY: if ((flags & COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE) == 0 && !_cogl_pipeline_get_real_blend_enabled (pipeline)) { CoglPipelineBlendEnable blend_enable = COGL_PIPELINE_BLEND_ENABLE_ENABLED; copy = cogl_pipeline_copy (pipeline); _cogl_pipeline_set_blend_enabled (copy, blend_enable); pipeline = copy; } skip_gl_color = TRUE; break; default: break; } if (G_UNLIKELY (layers_state->options.flags)) { /* If we haven't already created a derived pipeline... */ if (!copy) { copy = cogl_pipeline_copy (pipeline); pipeline = copy; } _cogl_pipeline_apply_overrides (pipeline, &layers_state->options); /* TODO: * overrides = cogl_pipeline_get_data (pipeline, * last_overrides_key); * if (overrides) * { * age = cogl_pipeline_get_age (pipeline); * XXX: actually we also need to check for legacy_state * and blending overrides for use of glColorPointer... * if (overrides->ags != age || * memcmp (&overrides->options, &options, * sizeof (options) != 0) * { * cogl_object_unref (overrides->weak_pipeline); * g_slice_free (Overrides, overrides); * overrides = NULL; * } * } * if (!overrides) * { * overrides = g_slice_new (Overrides); * overrides->weak_pipeline = * cogl_pipeline_weak_copy (pipeline); * _cogl_pipeline_apply_overrides (overrides->weak_pipeline, * &options); * * cogl_pipeline_set_data (pipeline, last_overrides_key, * weak_overrides, * free_overrides_cb, * NULL); * } * pipeline = overrides->weak_pipeline; */ } _cogl_pipeline_flush_gl_state (pipeline, framebuffer, skip_gl_color); _cogl_bitmask_clear_all (&ctx->enable_builtin_attributes_tmp); _cogl_bitmask_clear_all (&ctx->enable_texcoord_attributes_tmp); _cogl_bitmask_clear_all (&ctx->enable_custom_attributes_tmp); /* Bind the attribute pointers. We need to do this after the * pipeline is flushed because when using GLSL that is the only * point when we can determine the attribute locations */ for (i = 0; i < n_attributes; i++) { CoglAttribute *attribute = attributes[i]; CoglAttributeBuffer *attribute_buffer; CoglBuffer *buffer; uint8_t *base; if (attribute->is_buffered) { attribute_buffer = cogl_attribute_get_buffer (attribute); buffer = COGL_BUFFER (attribute_buffer); /* Note: we don't try and catch errors with binding buffers * here since OOM errors at this point indicate that nothing * has yet been uploaded to attribute buffer which we * consider to be a programmer error. */ base = _cogl_buffer_gl_bind (buffer, COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER, NULL); if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL) setup_generic_buffered_attribute (ctx, pipeline, attribute, base); else setup_legacy_buffered_attribute (ctx, pipeline, attribute, base); _cogl_buffer_gl_unbind (buffer); } else { if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL) setup_generic_const_attribute (ctx, pipeline, attribute); else setup_legacy_const_attribute (ctx, pipeline, attribute); } } apply_attribute_enable_updates (ctx, pipeline); if (copy) cogl_object_unref (copy); }
static void add_stencil_clip_silhouette (CoglFramebuffer *framebuffer, SilhouettePaintCallback silhouette_callback, CoglMatrixEntry *modelview_entry, float bounds_x1, float bounds_y1, float bounds_x2, float bounds_y2, CoglBool merge, CoglBool need_clear, void *user_data) { CoglMatrixStack *projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer); CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); /* NB: This can be called while flushing the journal so we need * to be very conservative with what state we change. */ _cogl_context_set_current_projection_entry (ctx, projection_stack->last_entry); _cogl_context_set_current_modelview_entry (ctx, modelview_entry); _cogl_pipeline_flush_gl_state (ctx, ctx->stencil_pipeline, framebuffer, FALSE, FALSE); GE( ctx, glEnable (GL_STENCIL_TEST) ); GE( ctx, glColorMask (FALSE, FALSE, FALSE, FALSE) ); GE( ctx, glDepthMask (FALSE) ); if (merge) { GE (ctx, glStencilMask (2)); GE (ctx, glStencilFunc (GL_LEQUAL, 0x2, 0x6)); } else { /* If we're not using the stencil buffer for clipping then we don't need to clear the whole stencil buffer, just the area that will be drawn */ if (need_clear) /* If this is being called from the clip stack code then it will have set up a scissor for the minimum bounding box of all of the clips. That box will likely mean that this _cogl_clear won't need to clear the entire buffer. _cogl_framebuffer_clear_without_flush4f is used instead of cogl_clear because it won't try to flush the journal */ _cogl_framebuffer_clear_without_flush4f (framebuffer, COGL_BUFFER_BIT_STENCIL, 0, 0, 0, 0); else { /* Just clear the bounding box */ GE( ctx, glStencilMask (~(GLuint) 0) ); GE( ctx, glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) ); _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, bounds_x1, bounds_y1, bounds_x2, bounds_y2); } GE (ctx, glStencilMask (1)); GE (ctx, glStencilFunc (GL_LEQUAL, 0x1, 0x3)); } GE (ctx, glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT)); silhouette_callback (framebuffer, ctx->stencil_pipeline, user_data); if (merge) { /* Now we have the new stencil buffer in bit 1 and the old stencil buffer in bit 0 so we need to intersect them */ GE (ctx, glStencilMask (3)); GE (ctx, glStencilFunc (GL_NEVER, 0x2, 0x3)); GE (ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR)); /* Decrement all of the bits twice so that only pixels where the value is 3 will remain */ _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry); _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry); _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, -1.0, -1.0, 1.0, 1.0); _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, -1.0, -1.0, 1.0, 1.0); } GE (ctx, glStencilMask (~(GLuint) 0)); GE (ctx, glDepthMask (TRUE)); GE (ctx, glColorMask (TRUE, TRUE, TRUE, TRUE)); GE (ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1)); GE (ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP)); }