디지털 장인정신

블로그 이미지
WebKit개발자의 혼자쓰는 블로그
스페로

Article Category

All (71)
Technology (47)
Creativity (19)
Private (4)

Recent Comment

Recent Trackback

Calendar

«   2018/10   »
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Archive

My Link

  • Total336,152
  • Today28
  • Yesterday46
  1. 2010.05.08
    Android에 Picture Class는 무엇에 쓰는 물건일까?
  2. 2010.05.08
    Android에서 View를 bitmap으로 정장하는법 (1)
결론은 당신의 View가 canvas를 채우기 위해 jni pass를 하는 연산이 많이 수행된다면 Picture로 한번 canvas를 감싸는것을 고려해 볼수 있다.

developer.android.com의 Picture 설명을 보면
A picture records drawing calls (via the canvas returned by beginRecording) and can then play them back (via picture.draw(canvas) or canvas.drawPicture). The picture's contents can also be written to a stream, and then later restored to a new picture (via writeToStream / createFromStream). For most content (esp. text, lines, rectangles), drawing a sequence from a picture can be faster than the equivalent API calls, since the picture performs its playback without incurring any java-call overhead.
JNI콜의 오버해드를 줄일수 있다고 나온다. 왜그럴까?

http://www.androidjavadoc.com/1.0_r1_src/android/graphics/class-use/Picture.html 를 보면 수많은 View중 굳이 WebView만이 Picture class를 이용해서 그림을 그린다. 그 이유는 WebView의 canvas에 그림을 채우기 위해 WebKit의 Render Object에 수많은 함수 콜을 해야 할 것이다. 그러면 jni의 overhead가 걸릴텐대 그래서 Picture를 쓴다.

어떻게 Picture가 jni의 overhead를 없에는지 설명해보자

우선 사용법부터 설명하면

보통은 View의 Draw를 overriding할때
Draw(canvas) {
super.onDraw(canvas);
}
일텐데 Picture를 사용하면
Draw(canvas) {
super.onDraw(mPicture.beginRecording(getWidth(), getHeight());
mPicture.endRecording();

canvas.drawPicture(mPicture);
}
라는 식으로 코딩을 하게 된다.

한마디로 Picture의 member variable canvas에 View의 child들을 순회하면서 그림을 그린뒤
Picture의 canvas를 대빵 View의 canvas가 받아서 한꺼번에 그리는 것이다.

중간에 중개자가 끼었는데 속도가 오히려 빨라진다? 가 이상하게 느껴질수 있는데.. jni의 overhead를 상쇄하므로써 속도에 이익을 얻는것이 결론이다.

Android의 모든 graphic library는 Skia library와 거이 1:1 매핑된다. 
한마디로 어떤 Class의 method를 쓰더라도  jni를 거쳐서 skia가 실행하는것이다.

Picture.beginRecording을 하면 jni밑에 C에서 SkPicture가 SkCanvas의 instance가 그림을 그릴 준비를 한다. 그 뒤 Picture.beginRecording에 그림을 그리면 java까지 올라올 필요 없이 C에서 skia로 그림을 그린다.. jni오버해드가 사라지는 지점이다. 그림을 다 그리면 java에서 Picture의 canvas를 가지고 그림을 그리는것이다.


결론은
1. jni오버해드를 줄이고 싶을때  Picture를 써라
2. View의 그림을 변형해서 여러번 그리고 싶을때 Picture를 써라 (가령 거울대칭으로 그림을 그리고 싶다 등등)


Trackback 4 and Comment 0
결론은 두가지 방법이 있다.
1. View의 canvas가 그림을 framebuffer가 아닌 bitmap에 그리게 하기
2. View.getDrawingBuffer() 이용하기

우선 성능 측면에서는 1번이 약간 앞선다. 두가지 방법의 메카니즘을 설명해보자

1. View의 canvas가 그림을 framebuffer가 아닌 bitmap에 그리게 하기

우선 사용법은

View를 상속받아  onDraw를 overriding하면 그림을 screen(framebuffer겠죠?)에 그리지 않고 bitmap에 그릴수 있다

public void onDraw(Canvas canvas){
canvas.setBitmap(bitmap);
bitmap.eraseColor(Color.WHITE);
super.onDraw(canvas);
}

위의 코드처럼 bitmap을 하나 잡아서 그것을 canvas에 장착시키면 그림을 bitmap에 그린다. screen에는 안그리므로 까만화면이 나올 뿐이다.

View ----------- canvas ----framebuffer
              Draw                     |---bitmap

즉 canvas 가 그리는 곳을 bitmap으로 살짝 틀어줌으로서 그림이 그려진 memory를 얻을수 있다.
참고로 Draw가 onDraw를 다시 콜한다. 지난 포스트를 참고하자.


2. View.getDrawingBuffer() 이용하기

우선 getDrawingCache의 내부구현을 보면
View.getDrawingCache
                canvas = softref.get(); //cavas를 softReference로 만들어놓고 쓸때 꺼냅니다. 
                bitmap = createBitmap(width, height, config); //이놈이 jni로 c로 가서 SkBitmap을 새로 alloc합니다. 가장 병목인 곳
canvas.setBitmap(bitmap);
bitmap.eraseColor(Color.WHITE);
draw(canvas);
즉 bitmap공간을 새로 잡고 그것을 별도로 사용하는 canvas에 붙여서 그림을 bitmap에 직접 그린다. 전자와 mechanism은 같지만 bitmap을 새로 alloc한다는 단점이 있다.

앞에 그림에서 앞에 몇가지 과정이 더붙은 모양세다

View ---------------------------------- View ----------- canvas ---- bitmap
          getDrawingCache -- canvas.setBitmap                        Draw 

원래 View의 그림도 그린다면 getDrawingCache다 View.draw를 콜하고 원래 그림을 그리는 쓰래드도 View.draw를 콜하므로 똑같은 그림을 그리기 위해 두번 연산하게 된다.



참고로
 - softReference란 cache를 만들때 java에서 잘 사용하는 기법인데, 오직 메모리가 모자를때 garbage collector에 의해 메모리가 해제됩니다. 즉 메모리를 많이 차지하면서 계속써야되는놈을 softReference로 만들어놓으면 out of memory로 app이 중지하는것을 방지할 수 있습니다.
 - Android의 canvas, bitmap, paint 등의 그림을 그리는 class들이 skia의 SkCanvas, SkBitmap, SkPaint들과 거의 1:1로 매핑되어있네요.
Trackback 0 and Comment 1