2016-09-06 3 views
0

AKA : Canvas requestPaint()가 너무 느립니다. requestAnimationFrame() 너무 빠름Canvas onPaint를 업데이트마다 정확히 한 번 호출 하시겠습니까?

FPS 타이머를 만들기 위해 기본 UI 렌더 루프에서 업데이트 당 한 번 가능한 다시 칠하는 QML Canvas를 만들려고합니다.

import QtQuick 2.7 
import QtQuick.Window 2.2 

Window { 
    visible:true; width:100; height:100 
    Canvas { 
     anchors.fill:parent 
     onPaint: console.log(+new Date) 
    } 
} 

내가 한 번만 콜백을 얻을 :

나는 처음에이 간단한 테스트를 썼다. 그래서 requestPaint()를 추가하지 :

onPaint: { 
    console.log(+new Date) 
    requestPaint() 
} 

변화 없음 : 난 아직 하나의 콜백을 얻는다. markDirty()을 사용하는 경우와 동일합니다. 실제로 각 콜백 캔버스에 무언가를 칠해도 마찬가지입니다.

import QtQuick 2.7 
import QtQuick.Window 2.2 
Window { 
    visible:true; width:100; height:100 
    Canvas { 
     anchors.fill:parent 
     Component.onCompleted: crank() 
     function crank(){ 
      console.log(+new Date) 
      requestAnimationFrame(crank) 
     } 
    } 
} 

가 지금은 콜백을 얻을 수 있지만, 너무 많은 :

그래서 requestAnimationFrame()로 이동. 평균적으로 밀리 초당 77 콜백, 1 밀리 초 내에 127 콜백의 몇 배가 발생합니다. 처음에는 응용 프로그램에 표시되지 않는 수많은 콜백이 있습니다. 비록 내가 console.log()을 제거하더라도, 나는 내가/내가 묶지 않는다는 것을 증명합니다.)

"프레임 당"한 번 캔버스를 다시 칠하는 방법을 알려면 FPS를 반정도 측정 할 수 있습니까? 어떤 이유로 requestPaint()이 실제로 작동하지 않습니까? 그리고 왜 requestAnimationFrame()은 분명히 쓸모가 없습니까?

+1

아, 그리고 FWIW : [웹 브라우저가 하나] (HTTPS와 동일하게 작동 requestAnimationFrame' QML': 계속 다시 그리는 캔버스를 유지 할 것으로 예상하고 원하는대로

다음 코드는 작동 // developer.mozilla.org/en/US/docs/Web/API/window/requestAnimationFrame) : 계속 호출하지 않으면 콜백이 중지됩니다. 이것은 일종의 기하 급수적 인'setInterval()'실수가 아닙니다. – Phrogz

답변

0

Qt 5.9 이전에 bug with requestAnimationFrame()이있었습니다. 이 버그가 수정되었습니다.

Canvas { 
    width:100; height:100; 
    property var ctx 
    onAvailableChanged: if (available) ctx = getContext('2d'); 
    onPaint: { 
     if (!ctx) return; 
     ctx.clearRect(0, 0, width, height); 
     // draw here 
     requestAnimationFrame(paint); 
    } 
} 
2

당신의 접근 방식의 문제는,이 onPaint 이벤트가 내 QQuickItem::polish()

void QQuickItem::polish() 
{ 
    Q_D(QQuickItem); 
    if (!d->polishScheduled) { 
     d->polishScheduled = true; 
     if (d->window) { 
      QQuickWindowPrivate *p = QQuickWindowPrivate::get(d->window); 
      bool maybeupdate = p->itemsToPolish.isEmpty(); 
      p->itemsToPolish.append(this); 
      if (maybeupdate) d->window->maybeUpdate(); 
     } 
    } 
} 

에서 트리거 때문에이 호출 d->polishScheduled 동안 작동하지 않을 onPaint에서 페인트를 요청 true로 설정되어 있다는 것입니다 requestPaint()에 다시 전화하면 아무 일도 일어나지 않습니다. 비동기 적으로 트리거해야합니다. 예를 들어, 0

import QtQuick 2.0 

Canvas { 
    id: canvas 
    width: 200 
    height: 200 
    property real angle 
    property int fps 

    Timer { 
    id: repaintTimer 
    running: false 
    interval: 0 
    onTriggered: { 
     angle += 0.01 
     canvas.requestPaint() 
    } 
    } 

    Timer { 
    interval: 1000 
    running: true 
    repeat: true 
    onTriggered: { 
     console.log(fps) 
     fps = 0 
    } 
    } 

    onPaint: { 
    var ctx = getContext("2d") 
    ctx.save() 
    ctx.clearRect(0, 0, width, height) 
    ctx.moveTo(100, 100) 
    ctx.translate(100,100) 
    ctx.rotate(angle) 
    ctx.beginPath() 
    ctx.lineTo(40, 10) 
    ctx.lineTo(40, 40) 
    ctx.lineTo(10, 40) 
    ctx.lineTo(10, 10) 
    ctx.closePath() 
    ctx.stroke() 
    ctx.restore() 
    fps += 1 
    repaintTimer.start() 
    } 
} 

다른 Timer는 FPS를 기록하는 여기 Timer 간격을 사용한다. qmlscene에서이 코드를 실행하면 60fps가됩니다.

+0

당신은 쓰고, _ "이것은 효과가 없을 것"_. 분명히 그것은 내 질문에,하지만 그것을 작동하지 말아야 왜 정당화 설명 할 수 있습니까? – Phrogz