2014-10-02 9 views
14

윈도우에서 이중 버퍼링 된 GDI를 사용하는 애니메이션, DWM 구성이 활성화 된 시스템에서 애니메이션을 그리며 화면에 tearing이 명확하게 표시됩니다. 이것을 막을 수있는 방법이 있습니까?DWM으로 구성된 윈도우에서 GDI를 사용하여 드로잉 할 때 인위적 인열을 방지 할 수 있습니까?

상세

애니메이션은 동일한 이미지를 받아, 오른쪽 스크린상에서 왼쪽으로 이동한다; 건너 뛴 픽셀 수는 현재 시간과 애니메이션이 시작된 시간과 끝나는 시간의 차이에 의해 결정되어 전체 창 너비에 적용되는 부분을 얻고 1ms resolution이있는 timeGetTime을 사용합니다. 애니메이션은 응용 프로그램 메시지를 처리하지 않고 루프로 그립니다. (VCL 라이브러리) 메서드 Repaint을 호출하여 내부적으로 무효화 한 다음 해당 창에 대해 UpdateWindow을 호출하여 WM_PAINT이라는 메시지 프로 시저를 직접 호출합니다. 페인트 핸들러의 VCL 구현은 BeginBufferedPaint을 사용합니다. 페인팅 자체가 이중 버퍼링됩니다.

이 목표는 가능한 한 높은 프레임 속도를 유지하여 화면에서 부드러운 애니메이션을 얻는 것입니다. (그림은 이중 버퍼링을 사용하여 깜박임 현상을 제거하고 한 번에 전체 이미지 또는 프레임을 화면에 표시합니다. 다른 메시지 처리를 수행하지 않고 메시지 프로 시저를 호출하여 직접 무효화하고 업데이트합니다. 예를 들어, BeginBufferedPaint).이 안에서 페인팅은 두 개의 BitBlt 호출 (애니메이션의 왼쪽면, 즉 화면 밖으로 움직이는 부분과 애니메이션의 오른쪽면, 즉 화면상에서 움직이는 부분)에 대해 수행됩니다.)

애니메이션을 볼 때 명확하게 tearing으로 볼 수 있습니다. 다른 그래픽 카드가있는 여러 시스템의 Windows Vista, 7 및 8.1에서 발생합니다.

이 문제를 해결하기위한 나의 접근 방식은 그리기 속도를 줄이거 나 다시 페인팅하기 전에 VSync를 기다리는 것입니다. 이것은 잘못된 접근 일 수 있으므로이 질문에 대한 대답은 "완전히 다른 일을하십시오 : X"일 수 있습니다. 큰, 그렇다면 :)

(내가 좋아하는 정말 줄 것은 /이 특정 창에 대해서만 완전히 그린 프레임을 사용 구도를 DWM을 요청하는 방법입니다.)

나는 다음과 같은 방법을 시도했습니다 , 눈에 보이는 모든 찢어짐이 제거되는 것은 아닙니다. 따라서 질문은 입니다. DWM 컴포지션을 사용할 때 찢어지지 않도록 할 수 있습니까? 그렇다면 어떻게해야합니까?

접근 시도 :

  • GetDeviceCaps(Application.MainForm.Handle, VREFRESH)를 통해 모니터 주사율을 얻기; 1/새로 고침 빈도 밀리 초 동안 자고 있습니다. 가능한 한 빨리 그림을 약간 개선했지만 희망적인 생각 일 수 있습니다. 지각 적으로 약간 부드러운 애니메이션 속도. (비틀기 : Sleep 정상 및 높은 해상도는 timeGetTime를 사용하여 스핀 기다립니다.)

  • 코드가립니다으로 같은 속도로 업데이트 제한하려고 DwmSetPresentParameters 사용. 대안 : 많은 버퍼 (cBuffer = 8) (눈에 보이지 않는 효과), 위의 코드를 사용하여 모니터 새로 고침 빈도/1의 소스 속도 지정 및 잠자기 (잠자기 방식과 동일), 프레임 당 새로 고침 지정 1, 10 등 (보이는 효과 없음), 소스 프레임 적용 범위 변경 (눈에 띄는 효과 없음.) 다양한 방법으로 DwmGetCompositionTimingInfo를 사용

  • :

      • cFramesPending> 0, 스핀 동안; 이 번호는 변경되지 않습니다 동안
      • cFrame (프레임 구성)과 스핀을 얻으십시오; 이 변경되지 않습니다 동안
      • cFrameDisplayed 스핀을 얻으십시오; QueryPerformanceCounter은 이보다 적은 시간, 스핀을 반환하면서 qpcVBlank + qpcRefreshPeriod을 추가로 잠을 시간을 계산
      • 다음
    • 이러한 모든 방법

    은 그림에 의해 변화되어왔다 , 다시 칠하기 전에 회전/수면. 또는 그 반대로 : 수면 후 그림.

몇 가지 눈에 보이는 효과가있는 것 같고 그 효과는 자격이 없으며 낮은 프레임 속도의 결과 일 수 있습니다. 아무도 찢어짐을 방지합니다. 즉, DWM이 창 DC의 내용 전체를 "창"으로 구성하지 못하게합니다.

조언에 감사드립니다 :)

+1

GDI는 오래되고 피 각질이며 애니메이션이 매끄럽지 않습니다. 어쩌면 Direct2D를 사용해 보시겠습니까? –

+1

@JonathanPotter 좋은 지적입니다. 내가 겪고있는 제약 중 하나는 어떤 종류의 DX도 사용하지 않는 것입니다. 하나의 이유는 플랫폼의 수와 요구 사항이 부족하기 때문입니다. 최종 코드는 계속 실행해야합니다. (모두 최신 Windows가 아닙니다.) Aero가있을 때만 도우미 DX 코드가 ... 아마도? 그러나 시각적 결함이없는 GDI/DX에서 애니메이션을 켜거나 끌 때 끊김없이 전환해야합니다. 그게 가능하니? –

+0

DX를 사용할 수있는 경우 드로퍼 도우미 클래스를 작성하고, 그렇지 않은 경우 GDI로 돌아갈 수도 있습니다. D2D가 아니더라도 Direct3D를 지원하지 않는 시스템을 찾는 것은 매우 드뭅니다. –

답변

2

당신이 BitBlt을 사용하고 있기 때문에, 당신의 DIB의 4 바이트/픽셀되어 있는지 확인합니다. 3 바이트/픽셀을 사용하면 DWM이 실행되는 동안 GDI가 끔찍하게 느려지므로 사용자의 찢어짐의 원인이 될 수 있습니다. 또 다른 BitBlt 문제가 발생했습니다. DIB가 다소 큰 경우 BitBlt 전화 걸기가 예상치 않게 오랜 시간이 걸립니다. 데이터의 일부만 그리는 것보다 작은 통화로 전화를 분할하는 경우 도움이 될 수 있습니다. 이 두 가지 항목 모두 내 경우에 도움이되었습니다. 단지 BitBlt 자체가 너무 느리게 실행되어 비디오 아티팩트가 발생했기 때문입니다.

+0

방금 ​​추가 할 경우 : 전체 창 대신 더러운 rect (GetUpdateRect) 만 업데이트하는 것을 잊지 마세요 ... – Jurlie