[Study Note] Example 예제가 실제로 화면에 그려지기까지의 코드 흐름 추적하기. - 2 #31
jeongsunyong
started this conversation in
Blog
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
[Study Note] ThorVG 실행 흐름 분석 (2)
어제는 example의
StudyShape::content()가 호출되는 지점까지 확인했다.이 네 개의 Public API가 ThorVG 내부에 어떤 상태를 만드는지 추적.
1. 네 개의 Public API
화면에 벡터 도형 하나를 출력하려면 필요한 최소의 정보들은 다음과 같다.
Shape::gen()appendRect()fill()Canvas::add()이를 한 줄로 정리하면
이 단계에서는 Renderer가 나중에 처리할 backend 독립적인 장면 데이터를 구성한다. 직접 픽셀을 기록하지 않음
Shape의 geometry와 appearance를 구성하고, 변경 flag를 누적한 뒤 Canvas의 root Scene에 ownership과 함께 등록하는 과정이다.
2. Shape::gen()
Public API의 반환 타입은
Shape*이고, 실제 구현에서는ShapeImpl을 생성한다.tvgShape.cpp — Shape::gen()
ShapeImpl은Shape를 상속하고, 내부에Paint::Impl과RenderShape를 가진다.tvgShape.h — ShapeImpl
Paint::Impl
Paint::Impl은 Shape뿐 아니라 다른 Paint 계열에도 필요한 공통 관리 상태를 가진다.tvgPaint.h — Paint::Impl
RenderShape
RenderShape는 Shape 고유의 렌더링 입력을 가진다.tvgRender.h — RenderShape
중간 정리하자면,
ShapeImpl은Paint와RenderShape를 가진다.그래서 Paint와 RenderShape은 그래서 무엇인지? 상태 관리와 렌더링 입력이라는게 무엇인가?
→
라고 할 수 있다.
표로 정리해보면
Paint::ImplRenderShapeparent, ownershiprefCntrenderFlagRenderPath결국 ShapeImpl은
Scene에 소속되는 그래픽 객체와Renderer가 그릴 벡터 도형 데이터를 결합한 실제 Shape 객체다.Public API의 관점에서는
Shape에는 내부 필드가 노출되지 않고, client는Shape인터페이스만 사용하면 된다. ThorVG 내부에서ShapeImpl과RenderShape를 이용해 실제 상태를 관리.3. appendRect() - 사각형도 내부에서는 Path다
Shape::appendRect()는ShapeImpl::addRect()에 위임.tvgShape.cpp — Shape::appendRect()
ShapeImpl::addRect()는RenderShape::path에 사각형을 추가하고Pathupdate flag를 표시한다.tvgShape.h — ShapeImpl::addRect()
example (빨간 사각형) 에서는 radius를 전달하지 않았으므로 sharp rectangle 분기로 들어간다.
이 사각형은 내부에서 command 5개와 point 4개로 표현된다.
실제 구현은 다음과 같다.
tvgRender.cpp — RenderPath::addRect()
호출 전후의 상태는 다음과 같다.
여기서 한가지, Public API에는
appendRect()라는 함수가 있지만, 내부 입력 모델에서는 사각형도 결국 Path command와 point로 표현된다.이후 Software Renderer가 단순 사각형을 별도의 fast-track으로 처리할 수 있지만, 이는 Renderer 단계의 최적화라고 한다.
4. fill() — 단색 색상 저장.
Shape::fill(r, g, b, a)도ShapeImpl에 위임한다.tvgShape.cpp — Shape::fill()
내부 구현에서는 기존 Gradient가 있다면 제거하고 단색 RGBA를
RenderShape::color에 저장한다.tvgShape.h — ShapeImpl::fill()
StudyShape의 상태 변화는 다음과 같다.
단색과 Gradient는 다음처럼 구분된다. (rs.fill 이 nullptr이냐 아니냐)
참고로, 현재는 단색 칠을 했기 때문에 Fill을 확인했지만 실제로 Fill은 Shape의 여러 표현 속성 중 하나일 뿐이다.
Shape는 geometry만 가지는 것이 아니라 다음과 같은 여러 표현 정보를 함께 가진다는 점 참고.5. RenderUpdateFlag — 무엇이 바뀌었는지 기록하기
appendRect()와fill()은 데이터를 바꾸는 것과 함께 update flag를 표시한다.tvgRender.h — RenderUpdateFlag
Paint::Impl::mark()는 bit OR로 변경 사항을 누적한다.tvgPaint.h — Paint::Impl::mark()
appendRect()호출 후Paint::Impl::renderFlag에는Path가 표시된다.이어서
fill()을 호출하면Colorflag가 OR 연산으로 누적되므로, Canvas에 추가하기 전 상태는Path | Color가 된다.이후
Canvas::add()과정에서 Shape가 root Scene 좌표계로 편입되면서Transformflag도 추가된다. 따라서content()가 끝날 때의 최종 변경 상태는Path | Color | Transform이다.API를 호출할 때마다 즉시 그림을 다시 만드는 것이 아니라, 어떤 속성이 변경됐는지 기록해 두고 이후 update 단계에서 필요한 부분을 준비하는 것.
6. Canvas::add() — Shape는 어느 Scene에 들어갈까
: 위 Fill까지 수행했을 때, Fill까지 완료된 Shape는 아직 어디에도 소속되지 않은 독립 객체이다.
어떻게 생겼는가는 정의됐지만 어느 화면에 그릴 것인가는 결정되지 않은 상태이다.
ThorVG가 어떤 Paint를 렌더링해야 하는지 알기 위해서는 해당 Paint가 Canvas가 관리하는 장면에 포함돼야 한다. 이 역할을 하는 API가 Canvas::add().
Canvas는 내부에 root Scene을 하나 가진다.
tvgCanvas.h — Canvas::Impl
Canvas::Impl생성 시Scene::gen()으로 root Scene을 생성한다.독립된 Shape는 Canvas의 root Scene에 등록 → 이후 update/draw 대상이 된다.
따라서 Canvas는 개념적으로 다음 구조를 가진다.
add()의 실제 위임 경로
Canvas::Impl::add()은 먼저 Paint가 다른 Renderer에 연결돼 있는지와 현재 Canvas가 Drawing 중인지 검사한다.tvgCanvas.h — Canvas::Impl::add()
그다음
SceneImpl::insert()가 Shape를 실제 Paint 목록에 넣는다.tvgScene.h — SceneImpl::insert()
StudyShape가 추가되면 상태가 다음처럼 바뀐다.
Renderer가 아직
nullptr인 이유는add()가 Scene 등록까지만 담당하기 때문이다. Shape와 실제SwRenderer의 연결 및 backend 전용 RenderData 준비는 이후 update 단계에서 일어난다.7. API 호출이 끝난 시점의 전체 상태
StudyShape::content()가 반환되기 직전 상태를 하나로 합치면 다음과 같다.8. Next
내부 구현을 따라가 보니 Example에서 빨간 사각형을 그리고자하는 API들은
바로 픽셀을 그리는 함수가 아니라, backend 독립적인 Shape 데이터를 구성하고 이를 Canvas의 렌더링 Scene에 등록하는 과정이었다.
다음 렌더링 루프를 위한 데이터를 단계적으로 구성하는 과정이라고 볼수도 있을 것 같다.
이 지점까지는 backend 독립적인 상태 구성이다. 아직 Software Rasterizer는 등장하지 않는다.
다음 글에서는
Window::ready()가 호출하는Canvas::draw()내부를 분석해 볼 것이다.All reactions