7

我有一个运行 Android 4.2.2 的 ASUS 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)

我显然已经将代码简化为上面显示的代码,完整的应用程序使用转换等基于一些输入数据来生成值。他们是否有任何关于如何解决这个问题的建议,而不是在一般情况下实现我自己的剪辑代码?

4

3 回答 3

5

这看起来像是一个命运多舛的角落案例clipPath

canvas.clipPath(fourthPath);

导致与先前的合并,firstPath但是因为这些是复杂的(非矩形)形状系统尝试将它们绘制为scanlines并在之后合并它。要进行此合并,它需要分配一些内存,但正如您在 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.

使用不同的参数,我看不到任何方法。任何避免合并clipPaths 的东西都必须有帮助,比如用 . 调用 clipPath Region.Op.REPLACERegion.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变得太大。

于 2013-06-28T14:16:45.910 回答
1

Ok, let me put this in an answer, since it looks quite logical to me:

To see if the problem is comming from the consequtive calls to clipPath(Path), try removing the call at first or putting canvas.clipPath(fourthPath, Region.Op.REPLACE); in the place of canvas.clipPath(fourthPath); and see if that's the cause.

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();
于 2013-06-27T12:53:08.297 回答
0

看起来 Canvas.clipPath() 不支持硬件加速,至少文档说: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

于 2013-06-24T13:41:50.920 回答