path: handle slice tex fallback using clip stack
If we are asked to fill a path using any sliced textures then we need to fallback to adding a mask of the path to the stencil buffer and then drawing a bounding rectangle with the source textures instead. Previously we were sharing some of the clip-stack code for adding the path mask to the stencil buffer and being careful to check that the current clip stack has been flushed already. We then made sure to dirty the clip stack to be sure the path mask would be cleared from the stencil buffer later. This patch aims to simplify how this fallback is dealt with by just using the public clipping API instead of relying on more fiddly tricks to modify the stencil buffer directly without conflicting with the clip stack. Reviewed-by: Neil Roberts <neil@linux.intel.com>
This commit is contained in:
parent
a8efe6af06
commit
a400aec51b
@ -25,6 +25,7 @@
|
||||
#define __COGL_PATH_PRIVATE_H
|
||||
|
||||
#include "cogl-object.h"
|
||||
#include "cogl-attribute-private.h"
|
||||
|
||||
typedef struct _floatVec2
|
||||
{
|
||||
|
@ -269,67 +269,62 @@ _cogl_path_get_bounds (CoglPath *path,
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_path_fill_nodes_with_stencil_buffer (CoglPath *path)
|
||||
_cogl_path_fill_nodes_with_clipped_rectangle (CoglPath *path)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
g_assert (ctx->current_clip_stack_valid);
|
||||
if (!cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
|
||||
{
|
||||
static gboolean seen_warning = FALSE;
|
||||
|
||||
_cogl_add_path_to_stencil_buffer (path,
|
||||
ctx->current_clip_stack_uses_stencil,
|
||||
FALSE);
|
||||
if (!seen_warning)
|
||||
{
|
||||
g_warning ("Paths can not be filled using materials with "
|
||||
"sliced textures unless there is a stencil "
|
||||
"buffer");
|
||||
seen_warning = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
_cogl_rectangle_immediate (path->data->path_nodes_min.x,
|
||||
path->data->path_nodes_min.y,
|
||||
path->data->path_nodes_max.x,
|
||||
path->data->path_nodes_max.y);
|
||||
cogl_clip_push_from_path (path);
|
||||
cogl_rectangle (path->data->path_nodes_min.x,
|
||||
path->data->path_nodes_min.y,
|
||||
path->data->path_nodes_max.x,
|
||||
path->data->path_nodes_max.y);
|
||||
cogl_clip_pop ();
|
||||
}
|
||||
|
||||
/* The stencil buffer now contains garbage so the clip area needs to
|
||||
* be rebuilt.
|
||||
*
|
||||
* NB: We only ever try and update the clip state during
|
||||
* _cogl_journal_init (when we flush the framebuffer state) which is
|
||||
* only called when the journal first gets something logged in it; so
|
||||
* we call cogl_flush() to emtpy the journal.
|
||||
static gboolean
|
||||
validate_layer_cb (CoglPipelineLayer *layer, void *user_data)
|
||||
{
|
||||
gboolean *needs_fallback = user_data;
|
||||
CoglTexture *texture = _cogl_pipeline_layer_get_texture (layer);
|
||||
|
||||
/* If any of the layers of the current pipeline contain sliced
|
||||
* textures or textures with waste then it won't work to draw the
|
||||
* path directly. Instead we fallback to pushing the path as a clip
|
||||
* on the clip-stack and drawing the path's bounding rectangle
|
||||
* instead.
|
||||
*/
|
||||
_cogl_clip_stack_dirty ();
|
||||
|
||||
if (texture != NULL && (cogl_texture_is_sliced (texture) ||
|
||||
!_cogl_texture_can_hardware_repeat (texture)))
|
||||
*needs_fallback = TRUE;
|
||||
|
||||
return !*needs_fallback;
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_path_fill_nodes (CoglPath *path)
|
||||
_cogl_path_fill_nodes (CoglPath *path, CoglDrawFlags flags)
|
||||
{
|
||||
const GList *l;
|
||||
gboolean needs_fallback = FALSE;
|
||||
|
||||
/* If any of the layers of the current pipeline contain sliced
|
||||
textures or textures with waste then it won't work to draw the
|
||||
path directly. Instead we can use draw the texture as a quad
|
||||
clipped to the stencil buffer. */
|
||||
for (l = _cogl_pipeline_get_layers (cogl_get_source ()); l; l = l->next)
|
||||
_cogl_pipeline_foreach_layer_internal (cogl_get_source (),
|
||||
validate_layer_cb, &needs_fallback);
|
||||
if (needs_fallback)
|
||||
{
|
||||
CoglHandle layer = l->data;
|
||||
CoglTexture *texture = _cogl_pipeline_layer_get_texture (layer);
|
||||
|
||||
if (texture != NULL &&
|
||||
(cogl_texture_is_sliced (texture) ||
|
||||
!_cogl_texture_can_hardware_repeat (texture)))
|
||||
{
|
||||
if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
|
||||
_cogl_path_fill_nodes_with_stencil_buffer (path);
|
||||
else
|
||||
{
|
||||
static gboolean seen_warning = FALSE;
|
||||
|
||||
if (!seen_warning)
|
||||
{
|
||||
g_warning ("Paths can not be filled using materials with "
|
||||
"sliced textures unless there is a stencil "
|
||||
"buffer");
|
||||
seen_warning = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
_cogl_path_fill_nodes_with_clipped_rectangle (path);
|
||||
return;
|
||||
}
|
||||
|
||||
_cogl_path_build_fill_attribute_buffer (path);
|
||||
@ -340,9 +335,7 @@ _cogl_path_fill_nodes (CoglPath *path)
|
||||
path->data->fill_vbo_indices,
|
||||
path->data->fill_attributes,
|
||||
COGL_PATH_N_ATTRIBUTES,
|
||||
COGL_DRAW_SKIP_JOURNAL_FLUSH |
|
||||
COGL_DRAW_SKIP_PIPELINE_VALIDATION |
|
||||
COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
|
||||
flags);
|
||||
}
|
||||
|
||||
void
|
||||
@ -414,7 +407,10 @@ _cogl_add_path_to_stencil_buffer (CoglPath *path,
|
||||
GE (ctx, glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT));
|
||||
|
||||
if (path->data->path_nodes->len >= 3)
|
||||
_cogl_path_fill_nodes (path);
|
||||
_cogl_path_fill_nodes (path,
|
||||
COGL_DRAW_SKIP_JOURNAL_FLUSH |
|
||||
COGL_DRAW_SKIP_PIPELINE_VALIDATION |
|
||||
COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
|
||||
|
||||
if (merge)
|
||||
{
|
||||
@ -457,8 +453,6 @@ _cogl_add_path_to_stencil_buffer (CoglPath *path,
|
||||
void
|
||||
cogl2_path_fill (CoglPath *path)
|
||||
{
|
||||
CoglFramebuffer *framebuffer;
|
||||
|
||||
g_return_if_fail (cogl_is_path (path));
|
||||
|
||||
if (path->data->path_nodes->len == 0)
|
||||
@ -476,20 +470,7 @@ cogl2_path_fill (CoglPath *path)
|
||||
cogl_rectangle (x_1, y_1, x_2, y_2);
|
||||
}
|
||||
else
|
||||
{
|
||||
framebuffer = cogl_get_draw_framebuffer ();
|
||||
|
||||
_cogl_framebuffer_flush_journal (framebuffer);
|
||||
|
||||
/* 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 (framebuffer,
|
||||
_cogl_get_read_framebuffer (),
|
||||
0);
|
||||
|
||||
_cogl_path_fill_nodes (path);
|
||||
}
|
||||
_cogl_path_fill_nodes (path, 0);
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user