簡體   English   中英

第二個clipPath中的Canvas.clipPath中的SIGSEGV

[英]SIGSEGV in Canvas.clipPath at the second clipPath

我有運行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)

我顯然簡化了上面顯示的代碼,完整的應用程序使用基於某些輸入數據的變換等來生成值。 他們是否有任何關於如何解決這個問題的建議而沒有在一般情況下實現我自己的裁剪代碼?

這看起來像是一個用於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獲得那么大的內存而導致中止。

我看不出任何使用不同參數的方法。 任何避免合並clipPath的東西都必須有所幫助,比如使用Region.Op.REPLACE調用Region.Op.REPLACE 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變得過大。

好吧,讓我把它放在一個答案中,因為它對我來說看起來很合乎邏輯:

要查看問題是否來自對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();

看起來硬件加速不支持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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM