SIGSEGV in Canvas.clipPath in the second clip

I have an ASUS Nexus 7 running Android 4.2.2. My application generates SIGSEGV in sk_malloc_flags when running the following code:

static Picture createDrawing() { Path firstPath = new Path(); firstPath.moveTo(3058, 12365); firstPath.lineTo(8499, 3038); firstPath.lineTo(9494, 3619); firstPath.lineTo(4053, 12946); firstPath.close(); Path fourthPath = new Path(); fourthPath.moveTo(3065, 12332); fourthPath.lineTo(4053, 12926); fourthPath.lineTo(9615, 3669); fourthPath.lineTo(8628, 3075); fourthPath.close(); Picture picture = new Picture(); Canvas canvas = picture.beginRecording(12240, 15840); canvas.clipPath(firstPath); canvas.clipPath(fourthPath); << SIGSEGV occurs here picture.endRecording(); return picture; } 

SIGSEGV is reported as follows:

  I/DEBUG ( 124): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad I/DEBUG ( 124): r0 00000027 r1 deadbaad r2 4017f258 r3 00000000 I/DEBUG ( 124): r4 00000000 r5 bed72434 r6 bed72508 r7 1be773bc I/DEBUG ( 124): r8 1be730f9 r9 000042c3 sl 00000001 fp 67185010 I/DEBUG ( 124): ip 40443f3c sp bed72430 lr 401522f9 pc 4014e992 cpsr 60000030 ... I/DEBUG ( 124): backtrace: I/DEBUG ( 124): #00 pc 0001a992 /system/lib/libc.so I/DEBUG ( 124): #01 pc 00018070 /system/lib/libc.so (abort+4) I/DEBUG ( 124): #02 pc 000be4b4 /system/lib/libskia.so (sk_malloc_flags(unsigned int, unsigned int)+28) I/DEBUG ( 124): #03 pc 0008afc0 /system/lib/libskia.so (SkRegion::op(SkRegion const&, SkRegion const&, SkRegion::Op)+1716) I/DEBUG ( 124): #04 pc 00089448 /system/lib/libskia.so (SkRasterClip::op(SkRasterClip const&, SkRegion::Op)+128) 

I obviously simplified the code shown above, the full application uses transforms, etc. based on some input to generate values. Are there any suggestions on how to fix this without introducing my own code for clipping in the general case?

+7
source share
3 answers

This looks like a bad corner case for handling clipPath .

 canvas.clipPath(fourthPath); 

causes merging with the previous firstPath , however, since they are complex (non-rectangular) shapes, the system tries to draw them as scanlines and merge them subsequently. To do this merge, it needs to allocate some memory, but as you can see in SkRegion.cpp , it is suitable for the heuristic worst case .

 static int compute_worst_case_count(int a_count, int b_count) { int a_intervals = count_to_intervals(a_count); int b_intervals = count_to_intervals(b_count); // Our heuristic worst case is ai * (bi + 1) + bi * (ai + 1) int intervals = 2 * a_intervals * b_intervals + a_intervals + b_intervals; // convert back to number of RunType values return intervals_to_count(intervals); } 

For your paths, this worst_case_count approaching 2 GB and you get an interrupt due to not getting this large memory from malloc .

I could not find a way out of this using different parameters. Anything that avoids merging clipPath should help, for example, call clipPath with Region.Op.REPLACE . Region.Op.INTERSECT does not work either.

I would like to focus on avoiding calling a clip in a complex way on top of a complex path.

If this suits your use case, you can use the same Path object to set canvas.clipPath() . For example:

 Picture picture = new Picture(); Canvas canvas = picture.beginRecording(12240, 15840); Path path = new Path(); path.moveTo(3058, 12365); path.lineTo(8499, 3038); path.lineTo(9494, 3619); path.lineTo(4053, 12946); path.close(); canvas.clipPath(path); // do stuff with canvas path.moveTo(3065, 12332); path.lineTo(4053, 12926); path.lineTo(9615, 3669); path.lineTo(8628, 3075); path.close(); canvas.clipPath(path, Region.Op.REPLACE); // do more stuff with canvas picture.endRecording(); return picture; 

Since Path contains the previous figures, you can simply continue updating it. If this does not apply to your case, you need to either make these numbers smaller, or break complex areas into smaller ones to avoid the worst case heuristic , to get too big.

+5
source

Well, let me answer this question, as it seems to me quite logical:

To find out if the problem is caused by successive calls to clipPath(Path) , try removing the call first or placing canvas.clipPath(fourthPath, Region.Op.REPLACE); instead of canvas.clipPath(fourthPath); and see if this is the reason.

Another thing I can think of is if you draw them separately:

 Picture picture = new Picture(); Canvas canvas = picture.beginRecording(12240, 15840); canvas.clipPath(firstPath); picture.endRecording(); canvas = picture.beginRecording(12240, 15840); canvas.clipPath(fourthPath); picture.endRecording(); 
+1
source

It seems that Canvas.clipPath () is not supported by hardware acceleration, at least the doc says that: http://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported

The only solution that comes to my mind is to disable hardware acceleration.

You can do it:

  • Application level
    <application android:hardwareAccelerated="true" ...>
    in manifest

  • Activity level
    android:hardwareAccelerated="false"
    for activity in the manifest

  • View level
    view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    for individual viewing at runtime

Docs:
http://developer.android.com/guide/topics/graphics/hardware-accel.html#controlling

0
source

All Articles