PIXI.Graphics GPU 최적화

천둥상어

·

2024. 3. 19. 12:28

반응형

 

PIXI.Graphics 은 도형을 그릴 수 있는 클래스이다.

캔버스 화면에 렌더링 되는 요소이기에 사용함에 있어서 성능을 고려해야 한다.

그래서 몇가지 방법으로 GPU 성능 테스트를 해보았다.

 

테스트 방법

테스트 방법은 간단하다.

가로 세로 100픽셀인 사각형 10,000개를 화면에 그릴 것이다.

그려지는 위치는 모두 동일하다.

결과는 아래 이미지 처럼 나오게 된다. 

 

[테스트 1] 그래픽 객체를 10,000개 생성해서 그리기

사각형을 그리는 그래픽 객체를 개별로 10,000개를 생성해서 배치한다.

import * as PIXI from 'pixi.js';

export default class Exam_0 extends PIXI.Container {
  constructor() {
    super();
    this.ct = new PIXI.Container();
    this.addChild(this.ct);
    this.init();
  }

  async init() {
    for (let i = 0; i < 10000; i++) {
      const grp = new PIXI.Graphics();
      grp.beginFill(0xffffff);
      grp.drawRect(10, 10, 100, 100);
      grp.endFill();
      this.ct.addChild(grp);
    }
  }
}

 

GPU 결과

GPU 사용률이 약 45% ~ 80

정적 요소이고 같은 위치에 드래그 했지만 실 인스턴스 개수는 10000개라서 그만큼 자원을 소모한다.

 

[테스트 2] 그래픽 객체 하나에 사각형 10,000개 그리기

그래픽 객체 하나에 사각형을 10,000개 그려본다.

import * as PIXI from 'pixi.js';

export default class Exam_0 extends PIXI.Container {
  constructor() {
    super();
    this.ct = new PIXI.Container();
    this.grp = new PIXI.Graphics();
    this.ct.addChild(this.grp);
    this.addChild(this.ct);
    this.init();
  }

  async init() {
    for (let i = 0; i < 10000; i++) {
      this.grp.beginFill(0xffffff);
      this.grp.drawRect(10, 10, 100, 100);
      this.grp.endFill();
    }
    console.log('a');
  }
}

 

GPU  결과

GPU  사용률이 약 44% ~ 75%

사용률이 줄어들긴 했지만, 기대에는 한참 미치지 못했다.

하나의 그래픽 객체에 드로잉이 계속 일어나면 최종 드로잉 정보로 최적화가 되지 않을까 했는데,

내부적으로는 쌓인다고 봐야 할 것 같다.

 

[테스트 3] 테스트 2 코드에서 clear() 함수 호출 추가

하나의 그래픽 객체에 도형을 그릴 때, 이전에 그려진 도형을 초기화 시켜준다.

  async init() {
    for (let i = 0; i < 10000; i++) {
      this.grp.clear();
      this.grp.beginFill(0xffffff);
      this.grp.drawRect(10, 10, 100, 100);
      this.grp.endFill();
    }
    console.log('a');
  }

 

GPU  결과

GPU 사용률 약 17% ~ 19%

clear() 함수가 호출되면 이전에 그려진 도형들은 모두 지워지게 된다.

결과적으로는 for문이 10,000번을 돌아도 그려진 사각형은 하나가 되는 셈이다.

이 테스트에서는 그래픽 인스턴스에 동일하 위치로 동일한 도형을 그려도

이전 도형을 꼭 삭제햐야 한다는 점을 알 수 있다.

 

[테스트 4] 테스트1 코드에서 최적화 ( cacheAsBitmap 적용 )

먼전 진행된 테스트에서 여러 그래픽 객체를 사용하는 것보다

하나의 그래픽 객체에 드로잉 하는게 좀 더 나은 성능을 보여줬다.

하지만 실 작업에서 개별 객체로 배치해서 사용하는 경우가 더 많을 것이다.

모든 그래픽 객체를 담고 있는 컨테이너 객체에 텍스쳐 처리를 적용해 본다.

import * as PIXI from 'pixi.js';

export default class Exam_0 extends PIXI.Container {
  constructor() {
    super();
    this.ct = new PIXI.Container();
    this.grp = new PIXI.Graphics();
    this.ct.addChild(this.grp);
    this.addChild(this.ct);
    this.init();
  }

  async init() {
    for (let i = 0; i < 10000; i++) {
      const grp = new PIXI.Graphics();
      grp.beginFill(0xffffff);
      grp.drawRect(10, 10, 100, 100);
      grp.endFill();
      this.ct.addChild(grp);
    }
    this.ct.cacheAsBitmap = true;
  }
}

 

GPU 결과

GPU 사용률 약 17% ~ 19%

성능은 [테스트 3]과 거의 동일했다.

cacheAsBitmap 옵션이 적용되면 해당 객체는 텍스처(이미지화) 처리가 된다. 

환경에 따라 다르겠지만 정적인 요소라면 해당 옵션을 활성화는게 좋아 보인다.

 

[테스트5] 개별 그래픽 객체에 cacheAsBitmap 적용

컨테이너가 아닌 각 그래픽 객체에 텍스처 처리를 하면 어떨가 싶어서 진행해 봤다.

  async init() {
    for (let i = 0; i < 10000; i++) {
      const grp = new PIXI.Graphics();
      grp.beginFill(0xffffff);
      grp.drawRect(10, 10, 100, 100);
      grp.endFill();
      grp.cacheAsBitmap = true;
      this.ct.addChild(grp);
    }
  }

 

GPU 결과

GPU 사용률 약 55% ~ 63%

[테스트 1] 보다 성능은 좋았지만 이것도 결국 이미지 10,000개가

메모리에 올라간거라 사용률이 높았다.

 

결론

  • 그래픽 객체를 개별로 사용하기 보다는 하나의 그래픽 객체에 드로잉을 하는 것이 좋다.
  • 하나의 그래픽 객체에 동일한 작업을 하더라도 이전 도형은 꼭 지워줘야 한다.
  • 정적인 요소라면 cacheAsBitamp을 활성하여 텍스처 처리 해준다면 성능에 좋을 수 있다.

 

참고로 pixi는 WebGL을 사용함에 있어서 그래픽 카드 성능을 많이 타는 것으로 알고 있다.

환경에 따라서 테스트 결과가 다르게 나올수도 있다.

 

반응형