Jadi saya melakukan beberapa pengembangan DirectX, menggunakan SharpDX di bawah. NET tepatnya (tetapi solusi DirectX / C ++ API berlaku). Saya mencari cara tercepat untuk membuat baris dalam proyeksi ortogonal (misalnya mensimulasikan gambar garis 2D untuk aplikasi ilmiah) menggunakan DirectX.
Tangkapan layar jenis plot yang saya coba buat berikut:
Tidak jarang plot semacam ini memiliki garis dengan jutaan segmen, dengan ketebalan bervariasi, dengan atau tanpa antialiasing per-garis (atau layar penuh AA hidup / mati). Saya perlu memperbarui simpul untuk garis sangat sering (mis. 20 kali / detik) dan membongkar GPU sebanyak mungkin.
Sejauh ini saya sudah mencoba:
- Render perangkat lunak, mis. GDI + sebenarnya bukan kinerja yang buruk tetapi jelas berat pada CPU
- Direct2D API - lebih lambat dari GDI, terutama dengan Antialiasing aktif
- Direct3D10 menggunakan metode ini untuk meniru AA menggunakan warna titik dan tessellation di sisi CPU. Juga lambat (saya memprofilkannya dan 80% waktu dihabiskan untuk menghitung posisi titik)
Untuk metode ke-3 saya menggunakan Vertex Buffer untuk mengirim strip segitiga ke GPU dan memperbarui setiap 200ms dengan simpul baru. Saya mendapatkan kecepatan refresh sekitar 5FPS untuk 100.000 segmen garis. Saya butuh jutaan idealnya!
Sekarang saya berpikir bahwa cara tercepat adalah melakukan penghentian pada GPU, misalnya dalam Geometry Shader. Saya bisa mengirim simpul sebagai daftar garis atau paket dalam tekstur dan membongkar dalam Geometry Shader untuk membuat paha depan. Atau, cukup kirim poin mentah ke pixel shader dan terapkan menggambar Garis Bresenham sepenuhnya dalam pixel shader. HLSL saya berkarat, model shader 2 dari 2006 jadi saya tidak tahu tentang hal-hal gila yang bisa dilakukan GPU modern.
Jadi pertanyaannya adalah: - Adakah yang pernah melakukan ini sebelumnya, dan apakah Anda punya saran untuk dicoba? - Apakah Anda memiliki saran untuk meningkatkan kinerja dengan memperbarui geometri dengan cepat (mis. Daftar simpul baru setiap 20 ms)?
PEMBARUAN 21 Januari
Saya telah menerapkan metode (3) di atas menggunakan Geometri shader menggunakan LineStrip dan Dynamic Vertex Buffer. Sekarang saya mendapatkan 100FPS pada 100k poin dan 10FPS pada 1.000.000 poin. Ini adalah peningkatan besar tapi sekarang saya mengisi dan menghitung terbatas, jadi saya memikirkan teknik / ide lain.
- Bagaimana dengan Pemunculan Perangkat Keras geometri Segmen Garis?
- Bagaimana dengan Sprite Batch?
- Bagaimana dengan metode berorientasi (Pixel shader) lainnya?
- Bisakah saya memusnahkan GPU atau CPU secara efisien?
Komentar & saran Anda sangat kami hargai!
Jawaban:
Jika Anda akan membuat
Y = f(X)
grafik saja, maka saya sarankan mencoba metode berikut.Data kurva dilewatkan sebagai data tekstur , menjadikannya persisten, dan memungkinkan pembaruan parsial
glTexSubImage2D
misalnya. Jika Anda perlu menggulir, Anda bahkan dapat menerapkan buffer melingkar dan hanya memperbarui beberapa nilai per frame. Setiap kurva ditampilkan sebagai quad layar penuh dan semua pekerjaan dilakukan oleh pixel shader.Konten tekstur satu komponen dapat terlihat seperti ini:
Pekerjaan pixel shader adalah sebagai berikut:
41.3
itu akan memilih40
,41
,42
dan43
.X,Y
pasangan menjadi ruang layarAnda mungkin ingin mengganti 4 dengan nilai yang lebih besar tergantung pada level zoom potensial.
Saya telah menulis shader GLSL yang sangat cepat dan kotor yang mengimplementasikan fitur ini . Saya dapat menambahkan versi HLSL nanti, tetapi Anda harus dapat mengonversinya tanpa terlalu banyak usaha. Hasilnya dapat dilihat di bawah, dengan ukuran garis dan kepadatan data yang berbeda:
Satu keuntungan yang jelas adalah bahwa jumlah data yang ditransfer sangat rendah, dan jumlah drawcall hanya satu.
sumber
Ada bab Permata GPU tentang rendering baris antialiased: Fast Prefiltered Lines . Ide dasarnya adalah membuat setiap segmen garis sebagai kuad dan menghitung, pada setiap piksel, fungsi Gaussian dari jarak pusat piksel dari segmen garis.
Ini berarti menggambar setiap segmen garis dalam grafik sebagai quad yang terpisah, tetapi dalam D3D11 Anda tentu bisa menggunakan shader geometri dan / atau membuat instans untuk menghasilkan paha depan, mengurangi jumlah data yang akan ditransfer ke GPU hanya pada titik data diri. Saya mungkin akan mengatur titik data sebagai StructuredBuffer untuk dibaca oleh vertex / geometri shader, kemudian lakukan draw call yang menentukan jumlah segmen yang akan diambil. Tidak akan ada buffer vertex yang sebenarnya; vertex shader hanya akan menggunakan SV_VertexID atau SV_InstanceID untuk menentukan titik data yang akan dilihat.
sumber
@ Dr.ABT - Permintaan maaf untuk ini adalah pertanyaan, bukan jawaban. Saya tidak menemukan cara untuk menanyakannya dalam jawaban oleh Sam Hocevar di atas.
Bisakah Anda berbagi detail lebih lanjut tentang bagaimana Anda akhirnya menerapkan garis untuk bagan Anda? Saya memiliki kebutuhan yang sama untuk aplikasi WPF. Terima kasih sebelumnya untuk setiap detail atau kode yang dapat Anda bagikan tentang ini.
sumber