我有运行Android 4.2.2的华硕Nexus 7.我的应用程序在运行以下代码时在sk_malloc_flags中生成一个SIGSEGV:
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报告如下:
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)
我显然简化了上面显示的代码,完整的应用程序使用基于某些输入数据的变换等来生成值。他们是否有任何关于如何解决这个问题的建议而没有在一般情况下实现我自己的裁剪代码?
答案 0 :(得分:5)
对于clipPath
处理来说,这似乎是一个命运多变的角落。
canvas.clipPath(fourthPath);
导致与先前的firstPath
合并,但由于这些是复杂的(非矩形)形状,系统会尝试将它们绘制为scanlines
并在之后合并它。要进行此合并,需要分配一些内存,as you can see in SkRegion.cpp,它适用于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);
}
对于您的路径,此worst_case_count
接近2GB并且由于未从malloc
获得大量内存而导致中止。
我看不出任何使用不同参数的方法。任何避免合并clipPath
的东西都必须有所帮助,比如使用Region.Op.REPLACE
调用clipPath。 Region.Op.INTERSECT
也应该失败。
我会集中精力避免在复杂路径上使用复杂路径调用clipPath。
如果它适合您的使用案例,您可以使用相同的Path
对象来设置canvas.clipPath()
。例如:
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;
由于path
包含以前的图纸,您可以继续更新它。如果这不适用于您的情况,您需要将这些数字缩小或将复杂区域划分为较小的区域,以避免worst case heuristic
变得过大。
答案 1 :(得分:1)
好的,让我把它放在一个答案中,因为它看起来很合乎逻辑:
要查看问题是否来自对clipPath(Path)
的连续通话,请先尝试取消通话,或将canvas.clipPath(fourthPath, Region.Op.REPLACE);
放在canvas.clipPath(fourthPath);
的位置,看看是否是原因。
我能想到的另一件事是,如果你单独绘制它们:
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();
答案 2 :(得分:0)
看起来硬件加速不支持Canvas.clipPath(),至少doc说: http://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported
我想到的唯一解决方法是关闭硬件加速。
你可以这样做:
申请级别
<application android:hardwareAccelerated="true" ...>
在清单
活动级别
android:hardwareAccelerated="false"
对于清单中的活动
查看级别
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
对于运行时的单个视图
文档:
http://developer.android.com/guide/topics/graphics/hardware-accel.html#controlling