E D R , A S I H C RSS

Double Buffering

화면의 이미지의 변경시에 깜빡임을 없애는 기법
----

1. 정의

  • 화면에 그림을 그릴때 일일히 그림을 화면에다 찍어주게 되면 깜박거림이 너무 심해진다.
  • 그래서 화면에 그림을 찍어줄 영역과 똑같은 크기의 가상의 버퍼를 만들어서 거기다 다 찍은다음 한번에 화면으로 옮겨주는 기법이다.
  • 해보면 굉장히 부드럽다.

2. 정의2

  1. 화면에 그림 중 일부를 변경, 이동 할때(공의 움직임 따위) 기존의 화면을 일부 지우고 새로운 그림을 그려야 한다.
  2. 만약 새로 그려질 그림이 기존의 지워질 화면에 그려진다면, 화면을 보는 사용자는 지워진 순간을 느끼게 된다.(개념 예제 참고) 이런 공백의 순간을 없애기 위하여 새로 그려질 그림과 배경을 동시에 그리는 기법이다.

2.1. 개념 예제

  1. 예1) 더블버퍼링 미사용시
    ~cpp 
    ▣▣▣▣▣
    
    이전 이미지를 지운다. (배경만 나오는 공백 순간, 깜빡임 유발, 이 순간을 없애는 것이 더블 버퍼링 목적)
    ~cpp 
    
    변경된 위치에 그림을 그린다.
    ~cpp 
         ▣▣▣▣▣
    
  2. 예2) 더블버퍼링 사용시
    ~cpp 
    ▣▣▣▣▣
    
    배경과 함께 그림을 그린다.
    ~cpp 
         ▣▣▣▣▣
    

3. 이 글을 남기게 된 이유

  • ["Lovelyboy^_^"]가 뻑하면 짜논 소스를 날려버리는 위험한 넘이라서..--; 문서로 남겨놓으면
    나중에 다시 할때 도움이 되지 않을까라는 생각--;

4. 예제

  • 제가 더블 버퍼링을 제대로 이해못했었더군요. 또 오랜만에 보니까 제가 뭘 써논건지도 모르겠다는 ..--; 다시 씁니다. 알카노이드가 없어져서 그냥 대충 만들어봤습니다.

    ~cpp 
    class CArcanoidView : public CView
    {
    private:
    	CArcanoidDoc* pDoc;
    
    	CDC m_MemDC;                   // 메모리 DC
    	CBitmap m_MemBitmap;           // 메모리 비트맵
    
    	CDC m_BackgroundDC;            // 배경 DC
    	CBitmap m_BackgroundBitmap;    // 배경 비트맵
     
     	CDC m_ShuttleDC;               // 비행기 DC
             CBitmap m_ShuttleBitmap;       // 비행기 비트맵
    ....
    ....
    
    void CArcanoidView::OnInitialUpdate()
    {
    	CView::OnInitialUpdate();
    
    	// TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.
    	pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    
    	CClientDC dc(this);
    	m_MemDC.CreateCompatibleDC(&dc);                      // 현재 DC와 호환된 메모리 DC
    	m_MemBitmap.CreateCompatibleBitmap(&dc, 1000, 700);   // 호환되는 메모리 비트맵
    	m_MemDC.SelectObject(&m_MemBitmap);
    
    	m_BackgroundBitmap.LoadBitmap(IDB_BACKGROUND);
    	m_BackgroundDC.CreateCompatibleDC(&dc);
    	m_BackgroundDC.SelectObject(&m_BackgroundBitmap);
    
    	m_ShuttleDC.CreateCompatibleDC(&dc);
    	m_ShuttleDC.SelectObject(m_ShuttleBitmap);
    }
      
  • 이렇게 자원 할당 다 해주고, 더블 버퍼링을 하고 싶다고 한다면.. 일단 메모리 DC에 필요한걸 다 그린 다음에, 화면 DC로 BitBlt 해주는겁니다. 이게 더블 버퍼링인데.. 저는 잘못 이해하고 있었거든요. 개념은 알았지만.. 무슨 이상한 생각을 조금 더 해버려서.. 지난번의 그 이상한 코드가 나오게 되었던 겁니다. 훗날 본인도 못 알아보는..--;

    ~cpp 
    // Timer가 호출하는 함수 내부
    m_MemDC.BitBlt(0,0,1000,700,&m_BackgroundDC,0,0,SRCCOPY);    // 메모리 DC로 BitBlt
    m_MemDC.BitBlt(x,y,width,height,&m_ShuttleDC,0,0,SRCCOPY);
    
    Invalidate(FALSE);
      

  • 이렇게 Timer내부에서는 메모리 DC에다 다 그려주고, Invalidate(FALSE)를 호출합니다. FALSE 이거 중요합니다.

    ~cpp 
    // OnDraw 함수 내부
    pDC->BitBlt(0,0,1000,700,&m_MemDC,0,0,SRCCOPY);  // 메모리 DC에 있는걸 화면 DC로 BitBlt
      

5. Thread

데기: 소스코드는 저런 식으로 하면 더 보기 좋은 것 같아서 고쳐봤어. 맘에 안들면 다시 돌려놓길. ^^; 그런데 이거... 공이 있는 영역만 더블버퍼링 하는거야?

["Lovelyboy^_^"]]: 앗. 무슨 그런 말씀을..;; 저야 고쳐 주시면 좋져. 공이랑 막대기 배경 처리 다 더블버퍼링 했는데여. 걍 예를 들라고..;

데기: 난 화면 전체를 한꺼번에 랜더링한 다음에 버퍼를 바꿔주는 방식만 보아왔기에... 독특하다고 생각하는중. 움직이는 영역이 많지 않다면 효과적인 방법인듯해. 공을 그려주는 루틴이 CBall 에 있는것도 독특하고...

1002 : 더블 버퍼링을 하는 이유는, Main Memory <-> Main Memory 간의 메모리복사(Blt하는 것) 이 Main Memory -> Video Memory 간의 메모리 복사보다 빠르기 때문에 하죠.

화면 전체를 한꺼번에 렌더링 한 다음 버퍼를 바꿔주는 방식을 이야기하는 것 보면 아마 Page Fliping 을 이야기하시는듯. 단, 이것은 GDI 로는 불가능하지 않을까요? ^^ DC 핸들을 우리가 직접 조작할 수는 없는 것이고.. 말 그대로, 버퍼를 바꾼다는 것은 화면에 표시해 주는 메모리를 가리키는 포인터의 값을 바꾸는 거니까. Page Fliping 은 DOS나 DX에서는 가능할지 몰라도 GDI 에서는 불가능한 방법일것이라는 개인적 생각. (DC에 Select 되어있는 Bitmap 을 다시 셋팅해주는 방법은 어떨까. 한번도 안해봤지만. --;)

그리고, 전체 그리기 관련 루틴의 경우는 애매한데, 왜냐하면 저렇게 object 별로 그리기 루틴이 있는 경우 사람들 실수하는 것이.. 각각의 Draw에 더블버퍼링하고 또 메인 루틴부분에 더블버퍼링을 중복하는 경우가 있어서리.. (뭐. 요새는 하드웨어가 빨라서 별 속도 저하 없긴 한것 같지만.) 개인적으로는 각각의 Draw부분에는 일반적인 Blt. 그리고 Main 부분에 더블버퍼링 한번이 맞지 않을까 하는. 뭐.. 그냥 생각나서 주저리주저리. --;

데기 : ㅋㅋ, 표현이 조금 문제를 일으킬줄 알았어요. 화면 전체라 함은 클라이언트 영역을 얘기한 것이고, 버퍼를 바꾼다는 얘기는 포인터만 바꾼다는게 아니라 디바이스 버퍼 내용을 바꾼다는 얘기한거예요. 인수야, 내 애매한 표현땜에 페이지 플리핑이랑 헷갈리지 말어. ^^;

neocoin : 결론은 요즘 하드웨어 짱이야? 인거야?

snowflower : 음.. 나의 경우엔.. 화면 전체를 BufferDC에 그려서 나중에 그걸 DC로 옮겼는데... 좀 틀린걸까?

데기 : 보통의 경우는 선호가 하는 방법으로 하지. 렌더링되는 과정이 전혀 안 보이니까...

zennith : 뜬금없는 소리이고, 고루한 이야기 입니다만, PCI 란 기술이 처음 소개되었을때 꽤 미래지향적인 기술로 각광받았던 것이 PCI bus mastering 이란 기술인데.. 무엇인고 하니, pci 채널로 연결되어있는 기기들끼리 서로의 메모리에 DMA 를 할 수 있었던 것이었죠. 대표적으로 이 기술이 사용된 예(라기보단 제가 알고있는 단 하나의 예)는 TV수신카드에서 사용되는 것이었는데요. TV 어플리케이션에서 TV 가 표시될 부분의 region 을 정해놓으면 TV 수신카드에서 그부분에 해당하는 비디오카드 메모리로 직접 쏴주는.. 그런 기술이었는데.. 더블버퍼링을 보니 갑자기 그 생각이 나는군요. 음.. 요즈음은 다들 agp 를 써서.. 저 pci bus mastering 이란 기술이 아직도 살아남아있는건지.. 잘 모르겠군요.
----
홈페이지분류
Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2009-05-27 07:09:19
Processing time 0.2131 sec