gc9a01pyはmicropython派にとって大変有難いライブラリだが、どれくらいの速度で描画できるのかが気になる。
Timerと組み合わせて、簡易的にFPSを調べてみる。
サマリは以下の通り。
関数 |
1回のdot数 |
式 |
fps |
line |
240 |
tft.line(0, 0, 240, i, color565(i,255-i,count&255)) |
5fps |
line |
10 |
tft.line(115, i, 125, i, color565(i,255-i,count&255)) |
106fps |
pixcel |
1 |
tft.pixel(30+i, 30+j, color565(i,255-i,j)) |
948fps |
fill_rect |
1 |
tft.fill_rect(30+i, 30+j, 1, 1, color565(i,255-i,j)) |
868fps |
fill_rect |
100 |
tft.fill_rect(30+i, 30+j, 10, 10, color565(i,255-i,j)) |
755fps |
fill_rect |
240*240 |
tft.fill_rect(0, 0, 240, 240, color565(i,255-i,j)) |
18fps |
line, pixelはdot数律速で、だいたい1秒1000dotが限界。
fill_rectは、SPIの命令送信と液晶内部処理の2つが律速。SPIの命令は最大1000回/s発行できる。
液晶内部での描画は、3パターンという少ない試行数からの試算なので意味があるかは怪しいが、今回の結果からは1dotあたり0.94usかかっていると推測される。
SPIの命令発行にかかる時間が変わらないとして、総塗り替えのときは1dotのときに比べ、54.4ms余分にかかっているので、1dotあたりに直すと0.94usとなる。
この結果を100dotに当てはめると803fpsとなり、実際のfpsに近い値になる。
試してみればいいことではあるが、fill_rectの速度推定にある程度役立つ。
以下は、実際に測定に使ったコードと結果の詳細。
■line:240dot
コードはこのような感じ。
# Timer、計測部分
from machine import Timer
def showFPS(t):
global count, count_prev, tft
fps = count - count_prev
tft.text(font,"FPS: {0}".format(fps),40,120,WHITE,BLACK)
count_prev = count
tim = Timer(period=1000, mode=Timer.PERIODIC, callback=showFPS)
# 描画部分
count = 0
count_prev = 0
while True:
for i in range(240):
count += 1
tft.line(0, 0, 240, i, color565(i,255-i,count&255))
この例は、直線描画の速度を調べている。
結果、ほぼ5fps。ごくまれに6になるときもあるが、無視してよいレベル。
■line:10dot
今度は、線分の式を「tft.line(115, i, 125, i, color565(i,255-i,count&255))
」に変えてみる。
結果、106fpsくらいまで性能向上する。
lineの中身を見てみるとわかるが、これって結局pixelで1dotずつ描画指令を送信しているので、pixel数の多さで速度が決まるということだ。
このライブラリに限らず、なるべく1点ずつ打つのを避けないと、どんどん描画速度が下がってしまう。
■pixel
じゃあ、今度は1秒に何点打てるのか?を測ってみる。
while True:
for i in range(180):
for j in range(180):
count += 1
tft.pixel(30+i, 30+j, color565(i,255-i,j))
見てみると、948点/s行けるようだ。
lineで10点ずつ打つと100fps→1000点/sで、240点ずつだと5fps→1200点/sなので、lineの結果ともマッチする。
■fill_rect:1dot
次は、fill_rectを試す。vline, hline, rectも内部でこの式を呼び出している。
fill_rectは、液晶に対し開始終了地点と色を送るだけなので、実はpixelに比べてSPIで送る指示は2byteしか変わらず、送信回数は同じ。
もしSPIの送信がボトルネックとすれば、pixelと遜色ない速度が出せるはず。
while True:
for i in range(180):
for j in range(180):
count += 1
tft.fill_rect(30+i, 30+j, 1, 1, color565(i,255-i,j))
結果、868fps前後となった。pixelに比べ、8.4%の性能低下で済んでいる。
これは1点ずつの描画だが、次は1回の描画面積が広くなっても変わらないか、試してみる。
■fill_rect:100dot
縦横を10ずつにして、1度に10dotずつ描画させてみる。
while True:
for i in range(180):
for j in range(180):
count += 1
tft.fill_rect(30+i, 30+j, 10, 10, color565(i,255-i,j))
この場合は755 or 761fpsとなった。RP2040⇔GC9A01の間のSPIは変わらないが、液晶内部の描画が増えた分でこれだけ遅くなったということ。とはいえ13%の性能低下で、1回で更新できるdot数ベースならlineに比べて圧倒的に速い。
最後に、240x240全て塗り替えにすると画像は無いが18fpsくらいだった。さすがに全消去は遅い。
以上。