summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2015-10-08 15:01:21 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2015-10-12 13:44:44 +0900
commitd271afd66c5a1c160f2d19941d00217f370bfeae (patch)
tree0e09b95dda1d43647d5fa4f6407c4afb43c44cfb
parenta8243ed382780615dd572babfeee3a333375ba80 (diff)
Evas filters: Fix some crash and reduce insanity
In a rare situation the filter would access an invalid buffer. Solution: Stop messing with buffer references by properly referencing and releasing them when not needed, rather than stealing references and hoping for the best. (There were flags tracking stolen references, but that was still madness)
-rw-r--r--src/lib/evas/canvas/evas_filter_mixin.c3
-rw-r--r--src/lib/evas/filters/evas_filter.c145
-rw-r--r--src/lib/evas/filters/evas_filter_private.h3
3 files changed, 36 insertions, 115 deletions
diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c
index 46bf5fe2e1..2722a484d6 100644
--- a/src/lib/evas/canvas/evas_filter_mixin.c
+++ b/src/lib/evas/canvas/evas_filter_mixin.c
@@ -238,8 +238,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
238 238
239 // Steal output and release previous 239 // Steal output and release previous
240 filter_output = evas_filter_buffer_backing_steal(filter, EVAS_FILTER_BUFFER_OUTPUT_ID); 240 filter_output = evas_filter_buffer_backing_steal(filter, EVAS_FILTER_BUFFER_OUTPUT_ID);
241 if (filter_output != previous) 241 evas_filter_buffer_backing_release(filter, previous);
242 evas_filter_buffer_backing_release(filter, previous);
243 242
244 // Request rendering from the object itself (child class) 243 // Request rendering from the object itself (child class)
245 evas_filter_program_padding_get(pd->data->chain, &l, &r, &t, &b); 244 evas_filter_program_padding_get(pd->data->chain, &l, &r, &t, &b);
diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c
index bd2ccfc946..484f44d65e 100644
--- a/src/lib/evas/filters/evas_filter.c
+++ b/src/lib/evas/filters/evas_filter.c
@@ -125,38 +125,21 @@ _filter_buffer_backing_free(Evas_Filter_Buffer *fb)
125{ 125{
126 if (!fb) return; 126 if (!fb) return;
127 127
128 if (!fb->stolen) 128 _backing_free(fb->ctx, fb->backing);
129 { 129 if (fb->glimage)
130 if (fb->allocated) 130 fb->ENFN->image_free(fb->ENDT, fb->glimage);
131 _backing_free(fb->ctx, fb->backing); 131 fb->backing = NULL;
132 if (fb->glimage && fb->allocated_gl) 132 fb->glimage = NULL;
133 fb->ENFN->image_free(fb->ENDT, fb->glimage);
134 fb->backing = NULL;
135 fb->glimage = NULL;
136 }
137 else
138 {
139 if (!fb->ctx->gl_engine)
140 {
141 fb->delete_me = fb->allocated;
142 }
143 else if (fb->glimage && fb->allocated)
144 {
145 _backing_free(fb->ctx, fb->backing);
146 fb->backing = NULL;
147 }
148 }
149} 133}
150 134
151/* GL engine stuff: read-back from texture */ 135/* GL engine stuff: read-back from texture */
152static Eina_Bool 136static Eina_Bool
153_filter_buffer_glimage_pixels_read(Evas_Filter_Buffer *fb) 137_filter_buffer_glimage_pixels_read(Evas_Filter_Buffer *fb, void *glimage)
154{ 138{
155 Eina_Bool ok; 139 Eina_Bool ok;
156 140
157 EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE); 141 EINA_SAFETY_ON_NULL_RETURN_VAL(fb, EINA_FALSE);
158 EINA_SAFETY_ON_FALSE_RETURN_VAL(fb->ctx->gl_engine, EINA_FALSE); 142 EINA_SAFETY_ON_FALSE_RETURN_VAL(fb->ctx->gl_engine, EINA_FALSE);
159 EINA_SAFETY_ON_NULL_RETURN_VAL(fb->glimage, EINA_FALSE);
160 143
161 if (fb->backing) 144 if (fb->backing)
162 return EINA_TRUE; 145 return EINA_TRUE;
@@ -166,17 +149,16 @@ _filter_buffer_glimage_pixels_read(Evas_Filter_Buffer *fb)
166 EINA_SAFETY_ON_NULL_RETURN_VAL(fb->ENFN->gl_surface_unlock, EINA_FALSE); 149 EINA_SAFETY_ON_NULL_RETURN_VAL(fb->ENFN->gl_surface_unlock, EINA_FALSE);
167 150
168 fb->backing = _rgba_image_alloc(fb, NULL); 151 fb->backing = _rgba_image_alloc(fb, NULL);
169 fb->allocated = EINA_TRUE;
170 EINA_SAFETY_ON_NULL_RETURN_VAL(fb->backing, EINA_FALSE); 152 EINA_SAFETY_ON_NULL_RETURN_VAL(fb->backing, EINA_FALSE);
171 153
172 ok = fb->ENFN->gl_surface_lock(fb->ENDT, fb->glimage); 154 ok = fb->ENFN->gl_surface_lock(fb->ENDT, glimage);
173 if (!ok) 155 if (!ok)
174 { 156 {
175 ERR("Failed to lock the image pixels"); 157 ERR("Failed to lock the image pixels");
176 return EINA_FALSE; 158 return EINA_FALSE;
177 } 159 }
178 160
179 ok = fb->ENFN->gl_surface_read_pixels(fb->ENDT, fb->glimage, 161 ok = fb->ENFN->gl_surface_read_pixels(fb->ENDT, glimage,
180 0, 0, fb->w, fb->h, fb->alpha_only 162 0, 0, fb->w, fb->h, fb->alpha_only
181 ? EVAS_COLORSPACE_GRY8 163 ? EVAS_COLORSPACE_GRY8
182 : EVAS_COLORSPACE_ARGB8888, 164 : EVAS_COLORSPACE_ARGB8888,
@@ -184,7 +166,7 @@ _filter_buffer_glimage_pixels_read(Evas_Filter_Buffer *fb)
184 if (!ok) 166 if (!ok)
185 ERR("Could not read the image pixels!"); 167 ERR("Could not read the image pixels!");
186 168
187 ok &= fb->ENFN->gl_surface_unlock(fb->ENDT, fb->glimage); 169 ok &= fb->ENFN->gl_surface_unlock(fb->ENDT, glimage);
188 return ok; 170 return ok;
189} 171}
190 172
@@ -212,19 +194,6 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj,
212 { 194 {
213 XDBG("Source already rendered: '%s' of type '%s'", 195 XDBG("Source already rendered: '%s' of type '%s'",
214 fb->source_name, eo_class_name_get(eo_class_get(fb->source))); 196 fb->source_name, eo_class_name_get(eo_class_get(fb->source)));
215 _filter_buffer_backing_free(fb);
216 if (!ctx->gl_engine)
217 {
218 fb->backing = source->proxy->surface;
219 fb->allocated = EINA_FALSE;
220 }
221 else
222 {
223 fb->glimage = source->proxy->surface;
224 fb->allocated_gl = EINA_FALSE;
225 _filter_buffer_glimage_pixels_read(fb);
226 }
227 fb->alpha_only = EINA_FALSE;
228 } 197 }
229 else 198 else
230 { 199 {
@@ -232,20 +201,16 @@ evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj,
232 fb->source_name, eo_class_name_get(eo_class_get(fb->source)), 201 fb->source_name, eo_class_name_get(eo_class_get(fb->source)),
233 source->proxy->redraw ? "redraw" : "no surface"); 202 source->proxy->redraw ? "redraw" : "no surface");
234 evas_render_proxy_subrender(ctx->evas->evas, fb->source, eo_obj, obj, do_async); 203 evas_render_proxy_subrender(ctx->evas->evas, fb->source, eo_obj, obj, do_async);
235 _filter_buffer_backing_free(fb);
236 if (!ctx->gl_engine)
237 {
238 fb->backing = source->proxy->surface;
239 fb->allocated = EINA_FALSE;
240 }
241 else
242 {
243 fb->glimage = source->proxy->surface;
244 fb->allocated_gl = EINA_FALSE;
245 _filter_buffer_glimage_pixels_read(fb);
246 }
247 fb->alpha_only = EINA_FALSE;
248 } 204 }
205 _filter_buffer_backing_free(fb);
206 if (!ctx->gl_engine)
207 fb->backing = ENFN->image_ref(ENDT, source->proxy->surface);
208 else
209 {
210 fb->glimage = ENFN->image_ref(ENDT, source->proxy->surface);
211 _filter_buffer_glimage_pixels_read(fb, fb->glimage);
212 }
213 fb->alpha_only = EINA_FALSE;
249 XDBG("Source has dimensions %dx%d (buffer %d)", fb->w, fb->h, fb->id); 214 XDBG("Source has dimensions %dx%d (buffer %d)", fb->w, fb->h, fb->id);
250 } 215 }
251} 216}
@@ -442,9 +407,7 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx)
442 407
443 EINA_LIST_FOREACH(ctx->buffers, li, fb) 408 EINA_LIST_FOREACH(ctx->buffers, li, fb)
444 { 409 {
445 RGBA_Image *im; 410 if (fb->backing || fb->source || fb->glimage)
446 im = fb->backing;
447 if (im || fb->source || fb->glimage)
448 continue; 411 continue;
449 412
450 if (!fb->w && !fb->h) 413 if (!fb->w && !fb->h)
@@ -454,11 +417,8 @@ evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx)
454 } 417 }
455 418
456 XDBG("Allocating buffer of size %ux%u %s", fb->w, fb->h, fb->alpha_only ? "alpha" : "rgba"); 419 XDBG("Allocating buffer of size %ux%u %s", fb->w, fb->h, fb->alpha_only ? "alpha" : "rgba");
457 im = _rgba_image_alloc(fb, NULL); 420 fb->backing = _rgba_image_alloc(fb, NULL);
458 if (!im) goto alloc_fail; 421 if (!fb->backing) goto alloc_fail;
459
460 fb->backing = im;
461 fb->allocated = (im != NULL);
462 } 422 }
463 423
464 return EINA_TRUE; 424 return EINA_TRUE;
@@ -506,8 +466,7 @@ _filter_buffer_data_set(Evas_Filter_Context *ctx, int bufid, void *data,
506 fb->h = h; 466 fb->h = h;
507 467
508 fb->backing = _rgba_image_alloc(fb, data); 468 fb->backing = _rgba_image_alloc(fb, data);
509 fb->allocated = (fb->backing != NULL); 469 return (fb->backing != NULL);
510 return fb->allocated;
511} 470}
512 471
513int 472int
@@ -516,6 +475,8 @@ evas_filter_buffer_image_new(Evas_Filter_Context *ctx, void *image)
516 Evas_Filter_Buffer *fb; 475 Evas_Filter_Buffer *fb;
517 476
518 EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1); 477 EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
478
479 image = ENFN->image_ref(ENDT, image);
519 EINA_SAFETY_ON_NULL_RETURN_VAL(image, -1); 480 EINA_SAFETY_ON_NULL_RETURN_VAL(image, -1);
520 481
521 fb = calloc(1, sizeof(Evas_Filter_Buffer)); 482 fb = calloc(1, sizeof(Evas_Filter_Buffer));
@@ -523,16 +484,10 @@ evas_filter_buffer_image_new(Evas_Filter_Context *ctx, void *image)
523 484
524 fb->id = ++(ctx->last_buffer_id); 485 fb->id = ++(ctx->last_buffer_id);
525 fb->ctx = ctx; 486 fb->ctx = ctx;
526 if (!fb->ctx->gl_engine) 487 if (!ctx->gl_engine)
527 { 488 fb->backing = image;
528 fb->backing = image;
529 fb->allocated = EINA_FALSE;
530 }
531 else 489 else
532 { 490 fb->glimage = image;
533 fb->glimage = image;
534 fb->allocated_gl = EINA_FALSE;
535 }
536 ENFN->image_size_get(ENDT, image, &fb->w, &fb->h); 491 ENFN->image_size_get(ENDT, image, &fb->w, &fb->h);
537 fb->alpha_only = (ENFN->image_colorspace_get(ENDT, image) 492 fb->alpha_only = (ENFN->image_colorspace_get(ENDT, image)
538 == EVAS_COLORSPACE_GRY8); 493 == EVAS_COLORSPACE_GRY8);
@@ -602,47 +557,26 @@ evas_filter_buffer_backing_get(Evas_Filter_Context *ctx, int bufid)
602void * 557void *
603evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid) 558evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid)
604{ 559{
605 Evas_Filter_Buffer *buffer; 560 Evas_Filter_Buffer *fb;
606 561
607 EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL); 562 EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
608 563
609 buffer = _filter_buffer_get(ctx, bufid); 564 fb = _filter_buffer_get(ctx, bufid);
610 if (!buffer) return NULL; 565 if (!fb) return NULL;
611
612 // we don't hold any reference on this buffer anymore
613 buffer->stolen = EINA_TRUE;
614 566
615 if (ctx->gl_engine) 567 if (ctx->gl_engine)
616 return buffer->glimage; 568 return fb->ENFN->image_ref(fb->ENDT, fb->glimage);
617 569 else
618 return buffer->backing; 570 return fb->ENFN->image_ref(fb->ENDT, fb->backing);
619} 571}
620 572
621Eina_Bool 573Eina_Bool
622evas_filter_buffer_backing_release(Evas_Filter_Context *ctx, 574evas_filter_buffer_backing_release(Evas_Filter_Context *ctx,
623 void *stolen_buffer) 575 void *stolen_buffer)
624{ 576{
625 Evas_Filter_Buffer *fb;
626 Eina_List *li;
627
628 if (!stolen_buffer) return EINA_FALSE; 577 if (!stolen_buffer) return EINA_FALSE;
629 EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE); 578 EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
630 579
631 EINA_LIST_FOREACH(ctx->buffers, li, fb)
632 {
633 if ((fb->backing == stolen_buffer) || (fb->glimage == stolen_buffer))
634 {
635 fb->stolen = EINA_FALSE;
636 if (fb->delete_me)
637 {
638 ctx->buffers = eina_list_remove_list(ctx->buffers, li);
639 _buffer_free(fb);
640 return EINA_TRUE;
641 }
642 return EINA_TRUE;
643 }
644 }
645
646 if (ctx->async) 580 if (ctx->async)
647 evas_unref_queue_image_put(ctx->evas, stolen_buffer); 581 evas_unref_queue_image_put(ctx->evas, stolen_buffer);
648 else if (ctx->gl_engine) 582 else if (ctx->gl_engine)
@@ -1710,13 +1644,7 @@ evas_filter_image_draw(Evas_Filter_Context *ctx, void *draw_context, int bufid,
1710 EINA_TRUE, do_async); 1644 EINA_TRUE, do_async);
1711 if (do_async && async_unref) 1645 if (do_async && async_unref)
1712 { 1646 {
1713#ifdef EVAS_CSERVE2 1647 ENFN->image_ref(ENDT, image);
1714 if (evas_cserve2_use_get())
1715 evas_cache2_image_ref((Image_Entry *)image);
1716 else
1717#endif
1718 evas_cache_image_ref((Image_Entry *)image);
1719
1720 evas_unref_queue_image_put(ctx->evas, image); 1648 evas_unref_queue_image_put(ctx->evas, image);
1721 } 1649 }
1722 } 1650 }
@@ -1726,10 +1654,7 @@ evas_filter_image_draw(Evas_Filter_Context *ctx, void *draw_context, int bufid,
1726 1654
1727 fb = _filter_buffer_get(ctx, bufid); 1655 fb = _filter_buffer_get(ctx, bufid);
1728 _filter_buffer_backing_free(fb); 1656 _filter_buffer_backing_free(fb);
1729 fb->glimage = image; 1657 _filter_buffer_glimage_pixels_read(fb, image);
1730 fb->allocated_gl = EINA_FALSE;
1731 _filter_buffer_glimage_pixels_read(fb);
1732 fb->glimage = NULL;
1733 } 1658 }
1734 1659
1735 return EINA_TRUE; 1660 return EINA_TRUE;
diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h
index 683e35a8d0..5770972b6b 100644
--- a/src/lib/evas/filters/evas_filter_private.h
+++ b/src/lib/evas/filters/evas_filter_private.h
@@ -237,11 +237,8 @@ struct _Evas_Filter_Buffer
237 Evas_Object *proxy; 237 Evas_Object *proxy;
238 238
239 Eina_Bool alpha_only : 1; // 1 channel (A) instead of 4 (RGBA) 239 Eina_Bool alpha_only : 1; // 1 channel (A) instead of 4 (RGBA)
240 Eina_Bool allocated : 1; // allocated on demand, belongs to this context
241 Eina_Bool allocated_gl : 1; // allocated on demand the glimage
242 Eina_Bool transient : 1; // temporary buffer (automatic allocation) 240 Eina_Bool transient : 1; // temporary buffer (automatic allocation)
243 Eina_Bool locked : 1; // internal flag 241 Eina_Bool locked : 1; // internal flag
244 Eina_Bool stolen : 1; // stolen by the client
245 Eina_Bool delete_me : 1; // request delete asap (after released by client) 242 Eina_Bool delete_me : 1; // request delete asap (after released by client)
246 Eina_Bool dirty : 1; // Marked as dirty as soon as a command writes to it 243 Eina_Bool dirty : 1; // Marked as dirty as soon as a command writes to it
247}; 244};