カテゴリー「FPGA」の53件の記事

2018年2月19日 (月)

OLED(有機EL)高速駆動

PMOD用にZyboに繋がるOLEDがDigilentから販売されているので今回試してみました。
こちらのページのとおりやってみるとあっさり動作しました。
Digilentのライブラリの充実っぷりに驚きです。

次にこのOLEDパネルを、高速度撮影の出来る Sony の Xperia XZs で撮影してみました。

机上で計算した限りデフォルト値では、102fps程度の動作のはずです。なのでカメラの露光時間で64line × 102/960 = 6.8ラインが写っていれば目論見どおりです(やや幅広な気もしますが、こんなものな気もします)。

で、ここからデータシートと睨めっこです。どうやらもっとも発行時間の長い GS63 (輝度が6bitなので輝度値63の時の点灯時間)が基準になっているようです。

Digilentのサンプルソースから、初期設定箇所を探して、GS1~GS63 まで 32個あるテーブルを書き換えるコードを追加してみます。ついでに画像も書き込む前に2値化(つまり8色化)してます。
GS63をあまり小さくすると何も見えなくなってきたので、最終的に5まで下げました。

多少試行錯誤はしたのですが、階調さえ落とせば高速化したように見えます。

なお、このおじさんの写真はDigilentのサンプルプログラムに埋まっていた画像です(誰なんでしょう? 開発者とかなのかな? (^^;;  )。

データシートに従って机上計算したところ、内蔵オシレータが Typical値想定で 869Hz 出ているはずです。

960fps撮影なので1コマの間に概ね画面全体が写っていれば正解のはずです。

しかし、ローリングシャッター歪が見えないのはなぜだろう....(悩み)。高速度撮影時もローリングひずみ除去処理が入ってたら逆に計測性が難しくなるなぁ。

今回買ったボードはPMODからSPI接続ですが、SSD1331自体は1cycle 130nsでのパラレル書き込みも出来るようです。

なので、PMODから一旦LVDSなどで出してSERDESデコーダICを載せたボードを起こせばハイフレーム駆動できるんじゃないかと予想しています。

ただ、SSD1331以外のコントローラだと書き込みが300nsというのが多いのですよね(謎)。OLED自体はaitendoさんやAlibabaなんかで安いものが出回っているので、もう少し安くて解像度があって書き込みの早いやつが無いかと探し中です。

先がだいぶ楽しみになりました。

(2018/02/19追記)

パラレルモードでの書き込み速度を調べてみました。

SSD1331  96x 64  130ns
SSD1351 128x128  300ns
SSD1352 160x128  300ns
SSD1353 160x132  300ns
SSD1355 128x160  300ns
SSD1357 128x128  不明

SSD1331以外、結構遅いようです。内蔵メモリの構造とかかなぁ?
困っりました、SSD1331を4枚並べて面積を増やすぐらいしか思いつけない....

Oled_x4

2018年2月18日 (日)

電脳メガネ開発計画(?)

Zybo上で開発しているRealTime-GPUがそこそこ動き始めてきたので、格安な研究費で(つまり趣味で)トライする超リアルタイムな電脳メガネ開発計画(妄想)を公開します。
OLEDがハックできるかが最大の課題なのですが。

Ar_system

GPUの方は、先日書いたリアルタイムアーキテクチャのGPUで、動画映像をテクスチャとしたポリゴン描画が動き始めてきました。
ピクセルクロックは200MHzですが、一旦解像度を置いておけば性能は速度に振れるはずです。

 

OLEDはPMODでのSPI接続では速度が足りないので、SERDES基板は作ってパラレル書き込みにしないといけませんが、例によって Seeed Fusion PCB の $4.9 基板で作れそうに思っています。 まずは低解像度さげていいので時間軸において、人間の視覚がハッキングができる遅延時間&周波数帯までまで持ち上げたいのが今回の計画の趣旨です(お金さえ掛ければ解像度は上がるので)。

実際、今のVRメガネをつけてだとカメラの映像見ながらだとスポーツはおろか、自動車や自転車など日常生活ですら安全に行うのは困難だと思いますが、これはGPUにリアルタイム性がないのも一因と思っています。
ですので、マイクロソフトのHoloLensなど、AR目的のメガネはVR用と異なりあくまで現実世界はそのまま見せて置いて、CGは光学的に重畳しているわけです。

この動画とかみると、マイクロソフトも遅延の重要性はよくわかってるはずで)

メガネなのだから、人間の目以上の性能が必要です。時間分解能と遅延が十分でなければRealTimeとはいえません。OLEDは基本LEDなので応答速度はLCDとは桁違いの筈なのですよね。

カメラは手元のXperia XZs が 960fps ですが、なかなか仕様が開示されていてモジュール単体で手に入るものだと速いものがなく、探した範囲では Raspberry Pi 用の IU233 がまあまあ性能が出そうです(240fps)。Zybo も手元のも(初代)には無いですが、後継機からMIPIインターフェースがついているので繋がるはずです。
もっともまずはカメラはオプション的な位置づけで、ポリゴン描画をリアルタイムに十分速くすることに重点を置ければと思います。

GPUの方はスペック上は今200MHzのピクセルクロックで処理できているので、128x64のOLEDなら数値上は40usで1フレーム更新できちゃう帯域の計算になっちゃいますね(まあI/Fがついて来ませんが....)。

まあ実際1000fpsも厳しいとは思っていますが、もし仮に2万fpsとかでトータル遅延が100usとかのオーダーに出来たとすると、例えば野球で150kmのボールを打つときでも現実とバーチャルのずれがミリメートルオーダーになってくるので(時間軸的には)超リアルなスポーツゲームとかも出来るのではなかろうかと。

打倒ホロレンズ?(笑)。

いつかデンスケに会える日を信じて、夢は大きくがんばりましょう。

2018年2月17日 (土)

バイリニアのXILINX FPGA向け実装

乗算器を使わないバイリニア補間のコードを書いています。その過程の線形補間の作成でちょっと面白い最適化に気がついたので記事にしておきます。

線形補間は2点の比なので、中心(足して2で割る)を求めて片方とリプレースすることを繰り返せば、加算器1段ごとに1bitづつ精度を上げていけます(いわゆる挟み撃ち法)。4bit程度しか精度が要らない今回の場合は、乗算器を使うよりお得かもしれません。

そこで最初下記のような計算ステージ1段で下記のようなことを行うコードを書いていたのですが、


always @(posedge clk) begin
  tmp    = (din0 + din1) / 2;
  dout0 <= sel ? tmp  : din0;
  dout1 <= sel ? din1 : tmp;
end

下記のように書けばコンパクトになるのではないかと思いやってみたところ、見事に(ISEの合成レポート上は)小さくなりました。  


always @(posedge clk) begin
  dout0 <= (din0 + (sel ? din1 : din0)) / 2;
  dout1 <= (din1 + (sel ? din0 : din1)) / 2;
end

リプレースをセレクタによって選択的に行うのではなく、置き換えない場合は自分自身を足して2で割ることで、値をキープするように書き換えています(実際には2で割る部分は最後に纏めてシフトするのが精度の点では良いようですが、今回は説明用ということで)。
前者は加算器2個、後者は1個なのになぜ? と思われる方もおられるかもしれません。

以下、XILINX社のUG474の図2-4を引用させて頂いて説明します。

Slicel

 XILINXのZynqの属するXILINX 7シリーズのSLICEはLUTの後ろに加算などをサポートするキャリーチェーンが必ずついているようです。
 なので

  • LUTを使う場合、キャリーチェーンの利用の有無は消費スライスに影響しない
  • キャリーチェーンを使う後にもロジックがあるとさらにLUTが必要になる

 ということになります。
 なので、加算が2個に増えることによるリソース増加はなく、演算の最後が加算で終わるように書き直すことによるLUT削減の方の効果が出るという一見不思議なことが起こるようです。
 もっとも、別の回路とくっつけて合成したら、結局はいい感じに収まる可能性もありますが。

 ただ、筆者の経験上、加減算を行う場合、FFへの代入の最後の演算が加減算で終わるように式変形してやると若干改善するケースは幾つかあるように思います。
 これはFPGA特有のテクニックで、LSI向けのRTLを書く場合は、回路が増えるデメリットだけだとは思いますので、果たして推奨するべきかは非常に微妙ですが、こういうこともあるのだなという面白い例かとは思います。

 なお、バイリニアなどの線形補間と良く似た計算でアルファブレンディングがあります。線形補間との違いは、線形補間は 256が1.0になるのに対して、アルファブレンディングは255が1.0であることです。

 この問題は、

http://www.cqpub.co.jp/dwm/contents/0104/dwm010400780.pdf

https://qiita.com/andantissimo/items/84be23b0f2937f8b3d90

とかに詳しい解説があるようで、それほど大きな追加コストはなく 256/255倍の計算は出来るように思います。

とはいえちょっと工夫すればはさみうち法でもアルファブレンディングが出来そうに思っています。

これはまた今度機会があれば考えてみたいと思います。

2018年2月12日 (月)

RealTime-GPU テクスチャマップ編

 とりあえず、RTLシミュレーションでテクスチャマッピングが動き出しました。

 ちゃんとパースペクティブ補正入れています。
 メモリに置いた画像が前にテクスチャキャッシュ作ったときの640x480画像ですが、テクスチャは 512x512 設定なので、縦はラップアラウンドさせています(見た目イマイチ)。

 

Texture_map

 RealTime-GPUといいつつ、調子に乗って6面ともテクスチャ張ったら、640x480ですらキャッシュミス頻発で、16.6msに収まっていなかったりします。
 画像サイズ小さくして、BRAMに置けば何の問題も無いのはわかっているのですが、調子に乗ってテクスチャキャッシュでSDRAMから読み込む構成にしてみました。
 ちょっといろいろ工夫は必要そうです。

 コアのみの合成してみると XC7Z010 で 50%程度なので、まあ意外と何とかなるかもです。

 

Texturemap_utilization2

 今週はここまでかな、先が長いです。

2018年2月 2日 (金)

テクスチャキャッシュ追加考察

以前作成したテクスチャキャッシュについて、改善点が幾つか頭にあるので、備忘録として書いておきます。

[セットアソシエイティブ化]
 現在、tagRAM をシングルポートメモリ(READ_FIRST)で作成し、ダイレクトマップを基本に読み出しと更新を1サイクルで纏めて実施することで効率化しているのですが、この際、デュアルポートRAMにしてフォワーディング演算を掛ければ、セットアソシエイティブキャッシュの優先度判定を高クロックのまま押込めそうな気がし始めました。
 高クロックでの合成には引き続き拘りたいので、慎重な検討は必要ですが、6LUTにフィットする履歴記述フォーマットを考えればそれなりに嵌りそうな気がしています。

[バイリニア演算]
 前回は、「DSP48E1の積和機能が使ってみたい」という理由もあって、4 cycle での積和で計算していました。
 が、こちらも挟み撃ち法(2つの画素値の片方をそのまま、もう片方を平均(足して2で割る)に置き換える操作を繰り返す)で安易にサブピクセル値は求まります。
 もちろん、貴重なLUT使うよりDSPが余っているならDSP使った方がおいしいケースも多々あるのもそのとおりなのですが、積和を使うとどうしても1ピクセル順に処理することになります。
 考えているのは、この際、L1キャッシュのワード幅広げて、「一度に隣接2ピクセルが読み出せるときは読み出す」としたほうが、トータル効率上がるんじゃないかと思った次第からです。複数ピクセルを並列に計算するならアーキ変えるべきだよなぁ、とも悩み中なわけです。

まあ、いづれもそのうち再考察できればと思います。

(追記 2018/02/10)
 バイリニアに関しては少し良い方法を思いついたかも知れない。挟み撃ち法で計算する場合でも回路を余り複雑にせずに1ピクセル作るのに3回のバイリニア演算が共用で出来そうな気がしている。1ピクセルの出力計算に4ピクセルの入力の計算を用いるの演算器効率としては 3/4 だし、加算器のみなのでまあまあの密度で組めそうな気がする。

低遅延リアルタイムGPUをジャイロと接続

前回作成したZybo(XILINX XC7Z010-1CLG400)上のGPUですが、まずはシンプルなグーローシェーディングのみの段階で、一旦9軸ジャイロセンサー(MPU-9250)と接続してみました。


とりあえずまだ1軸のみの実験ですが、動き始めたようです。

LCDモニタが普通のモニタなのでイマイチですが、ゲーミングモニタとか使えばもっと改善すると思います。

ビデオ出力のタイミングジェネレーターとVGA出力の間に挟みこむだけで、ほぼゼロレイテンシーで描画を追加できますので、非常にレスポンス性が良く、リアルタイムで描画が可能です。
構成上、既にある映像にCGを重畳するOSD(On Screen Display)的な使い方にも適しています。
VRやAR向への応用ができそうな雰囲気を感じますね。

(というか、HoloLens とかの描画アーキテクチャどうなってるんでしょうね?)

コマ落ちという概念がないので、ある意味「ハードリアルタイム処理」が出来ています。

例えば、自動車のバックモニタのガイド表示なんかも「ハードリアルタイム」に属するクラスの描画処理ですが、リアルタイムできればリアル空間に対していろんなことができます。

引き続き、Zソートの実装とか、テクスチャキャッシュとの組み合わせなど考えたいと思います。

ちなみに今ピクセルクロック200MHzでGPUコア動かせています。HDMIが150MHzだせれば1080@60pも可能な計算なのですが、ZyboのHDMIが150MHz無理なのと、もろもろ手抜きで今は最後にFIFO入れて昔作った回路でVGAで出してます。(^^;;

 

はじめて Xilinx SDK まじめに使いましたが、standaloneでもC++11で書いていても普通に動いてくれました。
3Dの行列演算と頂点バッファだらけなので、クラスとstd::vectorが使えるとかなり楽ですね。とりあえず256KBのOCMだけでも結構なことが出来そうなので、OpenCVとか使わなければ、Linuxまで入れなくともある程度リッチな開発は出来そうです。

(追記) アナログVGA端子だと問題なく Full HD(1920x1080@60p) 出力できることに気がつきました。

2018年1月27日 (土)

ZeroPath-GPUのシャドウマッピングを考えてみる

ZeroPath-GPUのFPGA実装の方はコツコツと検討中です。実装はまだ掛かりそうなので机上の空論を少し書いてみたいと思います。

目論見どおりいけば最大ポリゴン数Nを増やすと O(N・log N) のオーダーで回路消費が増えるというレベルに収まるはずです(ほんとかな?、一応、判別式回路がO(N)で増え、最小値探索がO(N log N)の見込みです。 あれ?支配項は最小値探索?)

まあ、フレームメモリが不要なのと低遅延なところにメリットを見出そうとしているのですが可能性としてこのやり方でどこまでやれるのかということで、その1つとしてシャドウマッピングを考え中です。

従来型GPUでシャドウマッピングをやる場合は、一旦光源視点でZマップを作り、次にカメラ視点で、レンダリングを行います。

これはZバッファを見ながら上書きを繰り返していくので、描画段階でまだ演算対象となっていない他のポリゴンが視点や光源に対して手前に来ない保証が無いのでこうせざるを得ないのであり、その為、シャドウアクネなどの課題が常に付きまといます。

今回は走査順にピクセル単位で絵を作っていく為に、すべてのポリゴンの演算を並行して行わけなので、ピクセル描画の段階で一括してデータを揃えるため、マルチパスの演算を行わずにレイトレーシングのようにピクセル誤差無くシャドウマッピングが出来きないものかと考えているわけです。

ポリゴンが描画点と光源間に存在するか否かの判定をポリゴン数だけある回路で並列に求めればいいはずなのですが、コンパクトなうまいロジックを思いつけずに悩んでいる次第です。

ピクセル位置で比較演算が終わるまで不定なのはZ座標だけですので、描画時に確定したZ座標に対して即座に該当ポリゴン領域が光源間の領域にあるかどうか判定できる判別式がインクリメンタルに求まればラスタライザと同じような機構でやれそうな気もします。

理屈としては光源とポリゴンのエッジとを通る平面の式を判別式とすればいいはずなのですが、厄介そうなのがラスタライズする物理座標はカメラからみた投影変換の絡んだ座標なので、除算的な補正が必須な気もしています。うーん、悩ましい。

回路サイズ2倍程度で実現できればこれはこれで面白そうなのですが...

まずはどこかで理屈が正しいか、シミュレーション実験できればとは思うのですが、なかなか先は長そうです。

(追記:2018/02/03)
ピクセルに関しての情報だけは常に一括で揃うのはいろいろ美味しそうな気がします。
いわゆる Deferred Rendering だと、沢山のバッファを吐き出さないといけない演算が可能になります。
アンチエイリアシングや異方向性みたいなことも実はその場で(Zソートを待たずに)、最終法線ベクトルやエッジ向きが確定できるのでいろいろ有利な気もします。
「トランジスタ数で最大ポリゴン数が制約される」以外のことに関しては、この方式で出来なくなる従来技法はほとんど無いのではないかと想像しています。

(追記:2018/02/14)
 マルチパスレンダリングとかの定義で言うと、1パスすらなくでいきなり出力を始めるので、ZeroPathにタイトルを変えました。

2018年1月14日 (日)

ZeroPath-GPUのC++モデルを書いてみた

以前Zyboにも収まるテクスチャキャッシュができたので、Zybo向けにテクスチャマッピングのできるフレームメモリレスの1パスGPU自作を検討中ですが、先立ってC++で簡単に実験してみました。

 思惑としてはピクセル走査順にピクセル値を計算していくことで

 ・ 描画時間が保証されている(リアルタイムシステムに使える)
  ・ フレームバッファやZバッファが不要
  ・ 描画ステージもバッファリングステージも無く、いきなり出力なので、超低遅延
     (ゲームとかのインタラクション向け?)
  ・ 映像クオリティーは一旦置いておいて、Zyboとかにコンパクトに入れ込みたい

 あたりを狙った描画方式を検討中です。

例によってソースはgithubで、

https://github.com/ryuz/render_model/blob/master/JellyGL.h?ts=4

境界チェックとかこまかいところで時間食いましたが、原理的にはシンプルな作りで意外と行けそうですね。





 上記は1キューブ6面で合計12ポリゴンですが、テクスチャマッピングと組み合わせれば、少数のポリゴンでもそれなりに遊べそうです(もちろんテクスチャ座標を色に変えれば普通のグーローシェーディングも可能です)。
  エッジ数が24個、uvwのパラメータが24個で、32bitのカウンターが48個で上記描画に必要なパラメータは求まる見積もりです。
  初期計算(行列演算だけ)floatでARMにやらせればよいので、Zyboでも十分入らないかなと、取らぬ狸の皮算用中です。

 ポリゴンの数がハードウェア規模で律速する変わりに、フレームバッファもZバッファも不要でちゃんとZ判定まで動くので、意外に実用になりそうな気もします。

 かつてディスプレイがVGA(640x480)で、1個のCPUが描画していた時代に比べて、現在のGPUはシェーダーが数千個のオーダーで搭載されていたりします。

 画像サイズが 4k でも 30倍程度にしか増えていないのに、シェーダーはかなりのレートで増えてきていますので既存のGPUの描画方式では

  そのうち、ポリゴン数やシェーダー数がピクセル数超えるるのでは?

  といった議論は昔からなされていたとおもいます。
(いつかレイトレーシングとかの方が速くなるんじゃない? といった話も聞いたことがありますし。)

 既存GPUの計算方法では、Z方向に重なり合ったピクセルは、別ポリゴンで上書きが発生した箇所については丸々演算結果を捨てることになります。

 今回とった方法は、アルゴリズム自体は従来のポリゴン描画の方法そのものですが、ピクセル順に計算しているのでZ判定以降の計算については無駄が無い筈です。

 またフレームメモリを持たないので、低遅延の描画ができるはずです。

 ポリゴン数がトランジスタ数で制約されるので、汎用性という点ではどうなんだというところですが、特定用途にて、トランジスタ数よりもメモリ帯域の方が貴重なケースなどはありえるのではなかろうかと思ってみたりもする次第です。

(追記:2018/02/14)
 マルチパスレンダリングとかの定義で言うと、1パスすらなくでいきなり出力を始めるので、ZeroPathにタイトルを変えました。

2018年1月 8日 (月)

ポリゴン描画実験

正月休みにいろいろやろうと思いきや、体調を崩してしまいほとんど何もしないまま終わってしまいました。

Cg

とりあえずまだC++でのシミュレーションの段階ですが、なんとなくポリゴン描画のアルゴリズム的なところは見えてきました。

やはり複数ポリゴン描画し始めると立体っぽく見え始めますね。

加えて、テクスチャマッピングやろうとするとパースペクティブコレクションは重要ですね。

また除算器と精度に悩みそうです。

2017年12月23日 (土)

FPGAでラスタライザ再考察

仕事が忙しく、ずいぶん間が空いてしまいましたが、再びGPU考察です。
ポリゴンのお絵かきにラスタライザは必須です。

以前、ソフトやシミュレーションレベルでは軽く実験しましたが、その際にお世話になったのが下記のページ。

http://ushiroad.com/rasterizer-refs/
http://memo.render.jp/tekitou-hon-yaku-memo/re

で、FPGA化踏まえて再考察。

Zynq UltraScale+ には Mali-400 というARM社のGPUがつくらしいですし、同じようなもの作るメリットが無いので、ちょっと変わったものを作ろうと考えている。

手元に「デジタル数値演算回路の実用設計」という本があり、パースペクティブ補正用のの逆数計算で非常にお世話になった本である。
この本にビデオ映像のページめくりのような面白いリアルタイム画像変形が載っており、以前作ったテクスチャキャッシュと組み合わせれば効率よくいろんな変形ができそうだなと考えている。ここにGPU色を出した自由度の高い変換を考え中だ。

当方μITRONのRTOS書いて遊んでいたころから、リアルタイムシステムには馴染んでおり、GPUのハードリアルタイム処理に使いにくい事には前々から思うところがあったので、今回は、ハードリアルタイムに耐えるGPU。すなわちビデオ映像の加工に使えてインタラクション性の高いGPUを目指してみたいと思う。

具体的には、「デジタル数値演算回路の実用設計」同様に、出力の走査順に絵を作っていく事を考えている。これはレイトレーシングの分野とかでは普通にある演算順序ではあるが、リアルタイム保証のやりやすい考え方に思える。

ただ、その場合の課題は、同時に描画可能なポリゴンの数だけラスタライザが必要!

ってことである。

で、今日はラスタライザの考察です。

ラスタライザのお仕事は、とかく物理的なピクセルと対応づくなX-Y座標に対して

・そのピクセル座標はポリゴンの範囲か?
・そのピクセル座標の色は? 法線は?
・そのピクセル座標に対応するテクスチャのUVアドレスは?

といった、実際にピクセルシェーディングするX-Yピクセル座標(物理的なモニタのピクセルに対応)から、CGの論理座標への変換が多数発生します。

で、上記は全部

a*x + b*y + c

を計算することに他ならないわけで、同じ演算器ずらっと並ぶことになります(多分)。

加えて、先のURLにあるように、境界判定は

> 大部分の人々がそのような状況ですることは、倍精度浮動小数点数を使うことです。

と、固定小数点が基本で、FPGA向けです。
これは、浮動小数点でやっちゃうと、隣接するポリゴン間で、隙間ができたり、重なりができたりするからです(隙間はもちろん、重なりもαブレンドするときは問題)。

そして、

> 24.8フォーマットは12ビットの解像度、つまり4096ピクセル表せる。
> 4ビットサブピクセルにつかったとしても、十分な解像度がある。

と、ある。
記事はソフトの計算なので、16bit*16bitして32bitの結果から16bit引っ張り出しているが、FPGAならいるところしか使わないので、つまるところ16bit精度でよいとなる。
(2018/01/14追記、すみませんやっぱり32bit必要でした。ピクセル12bit サブピクセル4bitの場合、傾き計算で32bit精度が要りますね)。
色情報はもともと8bit精度しかないし、UV座標も最後は画面同様の精度であるので、FPGAならそれぞれの項目で必要な最終結果にあう精度を用意すればよい(ただ、uv計算とかパースペクティブ補正で逆数を扱い場合の固定小数点の範囲は注意が必要そう)。

加えて

> 三角形の辺Eが(X, Y)から(X+dx, Y+dy)を結ぶとき
> E(x, y) = (x - X) * dy - (y - Y) * dx
> として、
> 全ての辺について E(x, y) <= 0 なら(x, y)は三角形の内部にある(y軸が下向き、辺が時計回りの場合)

というわかりやすい関係から、隣接するポリゴンの境界チェックの演算器は共用可能です(符号ひっくり返すだけ)。

で、a*x + b*y + c をどこまでコンパクトに計算できるか書いてみました。

> ですが、一度どこかの点についてE(x, y)を計算してしまえば > E(x+1, y) = E(x, y) + dy > E(x, y+1) = E(x, y) - dx > という計算量の少ない式で、

はい、まったくそのとおりですね(以前の実験でもやりました)。
つまりRTLにすると

    reg        signed    [WIDTH-1:0]        reg_value;

    always @(posedge clk) begin
        if ( reset ) begin
            reg_value <= {WIDTH{1'b0}};
        end
        else if ( cke ) begin
            reg_value <= reg_value + dx;
            if ( x_first ) begin
                reg_value <= reg_value + dy_stride;
                if ( y_first ) begin
                    reg_value <= reg_value + offset;
                end
            end
        end
    end

で、すんじゃうわけです。

合成結果は LUT16個のみで、Maximum Frequency: 630.517MHz だそうです。

小型化するにはコツがあって、XILINXのCLBはLUTの後に加算のためのキャリーチェーンがあるので、リセット以外の論理が加算の手前に来るように論理を考える必要があります。

なので、

・ 一旦リセットしてから初期値を足す(1フレームに1サイクルだけ余分が必要)
・ 右端から次のラインに走査する時のストライドを別途計算しておく
・ハンドシェークはCEで止めることで行う

などの工夫が必要ですが、特に困る制約ではないわけです。

なんかいろいろ期待が持てそうですね。

ただ問題は、走査に先立ってこれらのパラメータの計算をやる部分が必要でして、ZynqのARMにやらせてもいいのですが、ここは高速なシェーダーが書きたいなと考える次第です。

 

[追記]

上記の演算器を3つ並べてVeritakで三角形を描いてみました。
Photo

とりあえず目論見どおりには動きました。
ただ、精度に関しては安直に書くには画素サイズの2倍精度が要りそうですね。上記はVGAサイズですが、20bit幅で計算しています。

[さらに追記]
2

同じロジックでグーローシェーディングしてみました。
うーん、何も考えずに外積で平面求めたら精度に苦労してしまった。
領域内での精度が8bitあればよいだけなので、うまいこと調整が必要そうだ。

結論から言うと、

・傾きMAXは1pixelで 0→255  or 255->0
・傾きの最小精度は、画面の端から端の距離で最後のpixelで1増える
・ポリゴン範囲外でのオーバーフロー/アンダーフローは無視してよい

なので、必然的に精度が決まりそうだ。
テクスチャ座標の場合はバイリニア補完があるので小数点以下の精度の話も出てくるが同様に上下限を決めることはできそうだ。

ただ、テクスチャも画面サイズ程度の以上を用意しても意味が無いので、結果的に画面サイズ表すのに必要なbit数の2倍程度あれば一通りやりたいことには足りる気がする。

より以前の記事一覧