【问题标题】:SIGSEGV in Canvas.clipPath at the second clipPathCanvas.clipPath 中的 SIGSEGV 在第二个 clipPath
【发布时间】:2013-06-16 03:53:12
【问题描述】:

我有一个运行 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)

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

【问题讨论】:

  • 如果您只留下canvas.clipPath(firstPath);,删除对fourthPath 的调用会怎样?
  • 试一下,如果把canvas.clipPath(fourthPath, , Region.Op.REPLACE);,看看是不是这个原因,如果不是,那么,正如大卫贾希所说,尝试删除呼叫,看看是不是问题。
  • 我能想到的另一件事是,如果你分别绘制它们:Picture picture = new Picture(); Canvas canvas = picture.beginRecording(12240, 15840); canvas.clipPath(firstPath); picture.endRecording(); canvas = picture.beginRecording(12240, 15840); canvas.clipPath(fourthPath, Region.Op.INTERSECT); /*你也可以不使用Region.Op.INTERSECT*/ picture.endRecording();

标签: android segmentation-fault clip


【解决方案1】:

看起来 Canvas.clipPath() 不支持硬件加速,至少文档说: http://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported

我想到的唯一解决方法是关闭硬件加速。

你可以这样做:

  • 应用级别
    &lt;application android:hardwareAccelerated="true" ...&gt;
    在清单中

  • 活动级别
    android:hardwareAccelerated="false"
    清单中的活动

  • 查看级别
    view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    对于运行时的单个视图

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

【讨论】:

  • 开启或关闭硬件加速不会影响崩溃。画布与视图无关。
  • 12240 x 15840 是不是有点太大了?您是否尝试过更小的尺寸?
【解决方案2】:

好的,让我把它放在一个答案中,因为它看起来很合乎逻辑:

要查看问题是否来自对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();

【讨论】:

    【解决方案3】:

    这看起来像是 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 获得那么大的内存,您会中止。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-21
      • 2013-04-01
      • 2018-04-04
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多