Bagaimana cara CPU dan GPU berinteraksi dalam menampilkan grafik komputer?

58

Di sini Anda dapat melihat tangkapan layar program C ++ kecil yang disebut Triangle.exe dengan segitiga berputar berdasarkan OpenGL API.

masukkan deskripsi gambar di sini

Memang contoh yang sangat mendasar tetapi saya pikir itu berlaku untuk operasi kartu grafis lainnya.

Saya hanya ingin tahu dan ingin mengetahui seluruh proses dari mengklik ganda pada Triangle.exe di bawah Windows XP sampai saya dapat melihat segitiga berputar pada monitor. Apa yang terjadi, bagaimana cara CPU (yang pertama menangani .exe) dan GPU (yang akhirnya menampilkan segitiga di layar) berinteraksi?

Saya kira terlibat dalam menampilkan rotating triangle ini terutama perangkat keras / lunak berikut:

Perangkat keras

  • HDD
  • Memori Sistem (RAM)
  • CPU
  • Memori video
  • GPU
  • layar LCD

Perangkat lunak

  • Sistem operasi
  • API DirectX / OpenGL
  • Driver Nvidia

Adakah yang bisa menjelaskan prosesnya, mungkin dengan semacam diagram alur untuk ilustrasi?

Seharusnya bukan penjelasan yang rumit yang mencakup setiap langkah (tebakan yang akan melampaui ruang lingkup), tetapi penjelasan yang bisa diikuti oleh seorang perantara TI.

Saya cukup yakin banyak orang yang bahkan menyebut diri mereka profesional TI tidak dapat menggambarkan proses ini dengan benar.

JohnnyFromBF
sumber
Dilema Anda akan berakhir jika Anda bisa menganggap GPU sebagai perpanjangan dari CPU!
KawaiKx

Jawaban:

55

Saya memutuskan untuk menulis sedikit tentang aspek pemrograman dan bagaimana komponen saling berbicara. Mungkin itu akan menjelaskan beberapa area tertentu.

Presentasi

Apa yang diperlukan bahkan untuk memiliki satu gambar itu, yang Anda poskan di pertanyaan Anda, digambar di layar?

Ada banyak cara untuk menggambar segitiga di layar. Untuk mempermudah, mari kita asumsikan tidak ada buffer vertex yang digunakan. (A buffer vertex adalah area memori di mana Anda menyimpan koordinat.) Mari kita asumsikan program hanya memberi tahu pipa pemrosesan grafis tentang setiap vertex tunggal (sebuah vertex hanya koordinat dalam ruang) dalam satu baris.

Tapi , sebelum kita bisa menggambar apa pun, pertama-tama kita harus menjalankan beberapa perancah. Kita akan lihat alasannya nanti:

// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

// Reset The Current Modelview Matrix
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity();

// Drawing Using Triangles
glBegin(GL_TRIANGLES);

  // Red
  glColor3f(1.0f,0.0f,0.0f);
  // Top Of Triangle (Front)
  glVertex3f( 0.0f, 1.0f, 0.0f);

  // Green
  glColor3f(0.0f,1.0f,0.0f);
  // Left Of Triangle (Front)
  glVertex3f(-1.0f,-1.0f, 1.0f);

  // Blue
  glColor3f(0.0f,0.0f,1.0f);
  // Right Of Triangle (Front)
  glVertex3f( 1.0f,-1.0f, 1.0f);

// Done Drawing
glEnd();

Jadi apa yang dilakukannya?

Saat Anda menulis sebuah program yang ingin menggunakan kartu grafis, biasanya Anda akan memilih semacam antarmuka untuk driver. Beberapa antarmuka yang terkenal untuk driver adalah:

  • OpenGL
  • Direct3D
  • CUDA

Untuk contoh ini kita akan tetap menggunakan OpenGL. Sekarang, antarmuka Anda ke driver adalah apa yang memberi Anda semua alat yang Anda butuhkan untuk membuat program Anda berbicara dengan kartu grafis (atau driver, yang kemudian berbicara ke kartu).

Antarmuka ini terikat untuk memberi Anda alat tertentu . Alat-alat ini berbentuk API yang dapat Anda hubungi dari program Anda.

API itulah yang kami lihat digunakan dalam contoh di atas. Mari kita lihat lebih dekat.

Perancah

Sebelum Anda benar-benar dapat melakukan gambar yang sebenarnya, Anda harus melakukan pengaturan . Anda harus menentukan viewport Anda (area yang benar-benar akan ditampilkan), perspektif Anda ( kamera ke dunia Anda), apa anti-aliasing yang akan Anda gunakan (untuk menghaluskan tepi segitiga Anda) ...

Tapi kita tidak akan melihat itu. Kami hanya akan mengintip hal-hal yang harus Anda lakukan setiap frame . Suka:

Menghapus layar

Pipa grafis tidak akan menghapus layar untuk Anda setiap frame. Anda harus mengatakannya. Mengapa? Ini sebabnya:

masukkan deskripsi gambar di sini

Jika Anda tidak menghapus layar, Anda hanya akan menggambar setiap frame. Itu sebabnya kami memanggil glCleardengan GL_COLOR_BUFFER_BITset. Bit lainnya ( GL_DEPTH_BUFFER_BIT) memberitahu OpenGL untuk menghapus buffer kedalaman . Buffer ini digunakan untuk menentukan piksel mana yang berada di depan (atau di belakang) piksel lainnya.

Transformasi

masukkan deskripsi gambar di sini
Sumber gambar

Transformasi adalah bagian di mana kita mengambil semua koordinat input (simpul segitiga kami) dan menerapkan matriks ModelView kami. Ini adalah matriks yang menjelaskan bagaimana model kami (simpul) diputar, diskalakan, dan diterjemahkan (dipindahkan).

Selanjutnya, kami menerapkan matriks Proyeksi kami. Ini memindahkan semua koordinat sehingga mereka menghadap kamera kami dengan benar.

Sekarang kita mengubah sekali lagi, dengan matriks Viewport kami. Kami melakukan ini untuk menskalakan model kami dengan ukuran monitor kami. Sekarang kita memiliki seperangkat simpul yang siap untuk dirender!

Kami akan kembali ke transformasi sedikit kemudian.

Gambar

Untuk menggambar sebuah segitiga, kita hanya bisa mengatakan OpenGL untuk memulai baru daftar segitiga dengan memanggil glBegindengan GL_TRIANGLESkonstan.
Ada juga formulir lain yang bisa Anda gambar. Seperti strip segitiga atau kipas segitiga . Ini terutama adalah optimasi, karena mereka membutuhkan lebih sedikit komunikasi antara CPU dan GPU untuk menggambar jumlah segitiga yang sama.

Setelah itu, kami dapat menyediakan daftar set 3 simpul yang harus membentuk setiap segitiga. Setiap segitiga menggunakan 3 koordinat (karena kita berada dalam ruang 3D). Selain itu, saya juga memberikan warna untuk setiap titik, dengan menelepon glColor3f sebelum memanggil glVertex3f.

Bayangan antara 3 simpul (3 sudut segitiga) dihitung oleh OpenGL secara otomatis . Ini akan menginterpolasi warna di seluruh wajah poligon.

Interaksi

Sekarang, ketika Anda mengklik jendela. Aplikasi hanya perlu menangkap pesan jendela yang menandakan klik. Kemudian Anda dapat menjalankan tindakan apa pun di program yang Anda inginkan.

Ini menjadi jauh lebih sulit setelah Anda ingin mulai berinteraksi dengan adegan 3D Anda.

Pertama-tama Anda harus mengetahui dengan jelas piksel mana yang diklik pengguna. Kemudian, dengan mempertimbangkan perspektif Anda, Anda dapat menghitung arah sinar, dari titik klik mouse ke adegan Anda. Anda kemudian dapat menghitung jika ada objek di adegan Anda bersinggungan dengan sinar itu . Sekarang Anda tahu jika pengguna mengklik suatu objek.

Jadi, bagaimana Anda membuatnya berputar?

Transformasi

Saya mengetahui dua jenis transformasi yang umumnya diterapkan:

  • Transformasi berbasis matriks
  • Transformasi berbasis tulang

Perbedaannya adalah bahwa tulang memengaruhi simpul tunggal . Matriks selalu mempengaruhi semua simpul yang ditarik dengan cara yang sama. Mari kita lihat sebuah contoh.

Contoh

Sebelumnya, kami memuat matriks identitas kami sebelum menggambar segitiga kami. Matriks identitas adalah matriks yang sama sekali tidak menyediakan transformasi sama sekali. Jadi, apa pun yang saya gambar, hanya dipengaruhi oleh perspektif saya. Jadi, segitiga tidak akan diputar sama sekali.

Jika saya ingin memutarnya sekarang, saya bisa melakukan matematika sendiri (pada CPU) dan cukup menelepon glVertex3fdengan koordinat lain (yang diputar). Atau saya bisa membiarkan GPU melakukan semua pekerjaan, dengan menelepon glRotatefsebelum menggambar:

// Rotate The Triangle On The Y axis
glRotatef(amount,0.0f,1.0f,0.0f);               

amounttentu saja hanyalah nilai tetap. Jika Anda ingin menghidupkan , Anda harus melacak amountdan meningkatkannya setiap frame.

Jadi, tunggu, apa yang terjadi pada semua pembicaraan matriks sebelumnya?

Dalam contoh sederhana ini, kita tidak perlu peduli dengan matriks. Kami cukup menelepon glRotatefdan mengurus semua itu untuk kami.

glRotatemenghasilkan rotasi anglederajat di sekitar vektor xyz. Matriks saat ini (lihat glMatrixMode ) dikalikan dengan matriks rotasi dengan produk yang menggantikan matriks saat ini, seolah-olah glMultMatrix dipanggil dengan matriks berikut sebagai argumennya:

x 2 ⁡ 1 - c + cx ⁢ y ⁡ 1 - c - z ⁢ sx ⁢ z ⁡ 1 - c + y ⁢ s 0 y ⁢ x ⁡ 1 - c + z ⁢ sy 2 ⁡ 1 - c + cy ⁢ z ⁡ 1 - c - x ⁢ s 0 x ⁢ z ⁡ 1 - c - y ⁢ sy ⁢ z ⁡ 1 - c + x ⁢ sz 2 ⁡ 1 - c + c 0 0 0 0 1 1

Terima kasih untuk itu!

Kesimpulan

Yang menjadi jelas adalah, ada banyak pembicaraan dengan OpenGL. Tapi itu tidak memberi tahu kita apa-apa. Di mana komunikasinya?

Satu-satunya hal yang dikatakan OpenGL dalam contoh ini adalah ketika selesai . Setiap operasi akan memakan waktu tertentu. Beberapa operasi memakan waktu sangat lama, yang lain sangat cepat.

Mengirim simpul ke GPU akan sangat cepat, saya bahkan tidak tahu bagaimana mengekspresikannya. Mengirim ribuan simpul dari CPU ke GPU, setiap frame tunggal, kemungkinan besar, tidak ada masalah sama sekali.

Membersihkan layar bisa memakan waktu milidetik atau lebih buruk (perlu diingat, Anda biasanya hanya memiliki waktu sekitar 16 milidetik untuk menggambar setiap frame), tergantung pada seberapa besar viewport Anda. Untuk menghapusnya, OpenGL harus menggambar setiap piksel dalam warna yang ingin Anda hapus, yang bisa jutaan piksel.

Selain itu, kami hanya dapat menanyakan OpenGL tentang kemampuan adaptor grafis kami (resolusi maks, anti-aliasing maks, kedalaman warna maks, ...).

Tetapi kita juga dapat mengisi tekstur dengan piksel yang masing-masing memiliki warna tertentu. Setiap piksel memiliki nilai dan teksturnya adalah "file" raksasa yang diisi dengan data. Kita dapat memuatnya ke kartu grafis (dengan membuat buffer tekstur), kemudian memuat shader , memberi tahu shader itu untuk menggunakan tekstur kita sebagai input dan menjalankan beberapa perhitungan yang sangat berat pada "file" kita.

Kami kemudian dapat "membuat" hasil perhitungan kami (dalam bentuk warna baru) ke dalam tekstur baru.

Itulah cara Anda membuat GPU berfungsi untuk Anda dengan cara lain. Saya menganggap CUDA melakukan hal yang mirip dengan aspek itu, tetapi saya tidak pernah memiliki kesempatan untuk bekerja dengannya.

Kami benar-benar hanya sedikit menyentuh keseluruhan subjek. Pemrograman grafis 3D adalah binatang buas.

masukkan deskripsi gambar di sini
Sumber Gambar

Der Hochstapler
sumber
38

Sulit untuk memahami apa yang sebenarnya tidak Anda mengerti.

GPU memiliki serangkaian register yang dipetakan oleh BIOS. Ini memungkinkan CPU untuk mengakses memori GPU dan memerintahkan GPU untuk melakukan operasi. CPU menghubungkan nilai ke register tersebut untuk memetakan sebagian memori GPU sehingga CPU dapat mengaksesnya. Kemudian memuat instruksi ke dalam memori itu. Itu kemudian menulis nilai ke register yang memberitahu GPU untuk menjalankan instruksi CPU dimuat ke dalam memorinya.

Informasi terdiri dari perangkat lunak yang perlu dijalankan GPU. Perangkat lunak ini dibundel dengan driver dan kemudian driver menangani pembagian tanggung jawab antara CPU dan GPU (dengan menjalankan bagian-bagian dari kodenya pada kedua perangkat).

Pengemudi kemudian mengelola serangkaian "windows" ke dalam memori GPU yang dapat dibaca dan ditulis oleh CPU. Secara umum, pola akses melibatkan instruksi penulisan CPU atau informasi ke dalam memori GPU yang dipetakan dan kemudian menginstruksikan GPU, melalui register, untuk menjalankan instruksi tersebut atau memproses informasi tersebut. Informasi tersebut mencakup logika shader, tekstur, dan sebagainya.

David Schwartz
sumber
1
Terima kasih atas penjelasan anda Pada dasarnya yang saya tidak mengerti adalah bagaimana set instruksi CPU berkomunikasi dengan set instruksi GPU, tetapi jelas itu adalah driver yang melakukan bagian itu. Itulah yang saya maksud dengan lapisan abstraksi.
JohnnyFromBF
2
Tidak ada set instruksi CPU yang terlibat. Driver & runtime mengkompilasi CUDA, OpenGL, Direct3D, dll. Anda ke program / kernel GPU asli, yang kemudian juga diunggah ke memori perangkat. Perintah buffer kemudian merujuk pada yang seperti sumber daya lainnya.
Axel Gneiting
2
Saya tidak yakin program apa yang Anda maksud (yang dijalankan pada GPU dan disertakan dengan driver). GPU sebagian besar adalah perangkat keras fungsi tetap, dan satu-satunya program yang akan dijalankan adalah shader, yang disediakan oleh aplikasi, bukan driver. Pengemudi hanya mengkompilasi program-program ini, dan kemudian memuatnya ke dalam memori gpu.
Ben Richards
1
@ sidran32: Misalnya, dalam arsitektur Kepler nVidia, kernel, stream, dan acara dibuat oleh perangkat lunak yang berjalan pada GPU, bukan (biasanya) CPU. Perangkat lunak sisi GPU juga mengelola RDMA. Semua perangkat lunak itu dimuat ke dalam memori GPU oleh pengemudi dan berjalan sebagai "mini-OS" pada GPU yang menangani sisi GPU dari pasangan yang bekerja sama dengan CPU / GPU.
David Schwartz
@ DavidSchwartz Saya memang lupa tentang tugas komputasi GPU. Namun, mereka tetap berperilaku mirip dengan shader, dalam implementasi, toh. Saya tidak akan menyebutnya "mini-OS", karena tidak memiliki fungsi yang sama yang biasanya dikaitkan dengan OS. Ini masih perangkat lunak yang sangat khusus, karena GPU tidak dirancang seperti CPU (untuk alasan yang baik).
Ben Richards
13

Saya hanya ingin tahu dan ingin mengetahui seluruh proses dari mengklik ganda pada Triangle.exe di bawah Windows XP sampai saya dapat melihat segitiga berputar pada monitor. Apa yang terjadi, bagaimana cara CPU (yang pertama menangani .exe) dan GPU (yang akhirnya menampilkan segitiga di layar) berinteraksi?

Mari kita asumsikan Anda benar-benar tahu bagaimana eksekusi dapat dijalankan pada sistem operasi dan bagaimana eksekusi itu dikirim dari GPU Anda ke monitor, tetapi tidak tahu tentang apa yang terjadi di antaranya. Jadi, mari kita lihat dari aspek perangkat keras dan memperluas jawaban aspek programmer ...

Apa antarmuka antara CPU dan GPU?

Menggunakan driver , CPU dapat berbicara melalui fitur motherboard seperti PCI ke kartu grafis dan mengirim perintah kepadanya untuk menjalankan beberapa instruksi GPU, mengakses / memperbarui memori GPU , memuat kode yang akan dieksekusi pada GPU dan banyak lagi ...

Tapi, Anda tidak dapat berbicara langsung dengan perangkat keras atau driver dari kode; jadi, ini harus terjadi melalui API seperti OpenGL, Direct3D, CUDA, HLSL, Cg. Sementara mantan menjalankan instruksi GPU dan / atau memperbarui memori GPU, yang terakhir sebenarnya akan mengeksekusi kode pada GPU karena mereka adalah bahasa fisika / shader.

Mengapa menjalankan kode pada GPU dan bukan pada CPU?

Walaupun CPU bagus dalam menjalankan program workstation dan server harian kami, tidak ada banyak pemikiran tentang semua grafik mengkilap yang Anda lihat dalam game saat ini. Kembali pada hari-hari ada perender perangkat lunak yang melakukan trik dari beberapa hal 2D dan 3D, tetapi mereka sangat membatasi. Jadi, di sinilah GPU berperan.

GPU dioptimalkan untuk salah satu perhitungan terpenting dalam grafis, Manipulasi Matrix . Sementara CPU harus menghitung setiap perkalian dalam manipulasi matriks satu-per-satu (nanti, hal-hal seperti 3DNow! Dan SSE menyusul), GPU dapat melakukan semua perkalian itu sekaligus! Paralelisme.

Tetapi perhitungan paralel bukan satu-satunya alasan, alasan lainnya adalah GPU lebih dekat dengan memori video yang membuatnya lebih cepat daripada harus melakukan bolak-balik melalui CPU, dll ...

Bagaimana instruksi / memori / kode GPU ini menunjukkan grafik?

Ada satu bagian yang hilang untuk membuat ini semua berfungsi, kita perlu sesuatu yang bisa kita tulis yang kemudian bisa kita baca dan kirim ke layar. Kita dapat melakukan ini dengan membuat framebuffer . Apa pun operasi yang Anda lakukan, Anda akhirnya akan memperbarui piksel dalam framebuffer; yang selain lokasi juga menyimpan informasi tentang warna dan kedalaman.

Mari kita beri contoh di mana Anda ingin menggambar sprite darah (gambar) di suatu tempat; pertama, tekstur pohon itu sendiri dimuat ke dalam memori GPU yang membuatnya mudah untuk menggambar ulang sesuai keinginan. Selanjutnya, untuk benar-benar menggambar sprite di suatu tempat, kita dapat menerjemahkan sprite menggunakan vertex (meletakkannya di posisi yang tepat), rasterisasi (mengubahnya dari objek 3D menjadi piksel) dan memperbarui framebuffer. Untuk mendapatkan ide yang lebih baik, berikut adalah bagan alur pipa OpenGL dari Wikipedia:

Ini adalah inti utama dari seluruh ide grafis, penelitian lebih lanjut adalah pekerjaan rumah bagi pembaca.

Tamara Wijsman
sumber
7

Untuk menjaga hal-hal sederhana kita dapat menggambarkannya seperti ini. Beberapa alamat memori dicadangkan (oleh BIOS dan / atau sistem operasi) bukan untuk RAM tetapi untuk kartu video. Setiap data yang ditulis pada nilai-nilai tersebut (pointer) masuk ke kartu. Jadi secara teori, program apa pun dapat menulis langsung ke kartu video hanya dengan mengetahui kisaran alamat dan ini persis seperti yang dilakukan di masa lalu. Dalam praktiknya dengan OS modern ini dikelola oleh driver video dan / atau perpustakaan grafik di atas (DirectX, OpenGL dll.).

AZ.
sumber
1
-1 dia bertanya bagaimana panggilan DirectX API dari CPU dapat berkomunikasi dengan GPU, dan jawaban Anda adalah "dikelola oleh pengemudi dan / atau DirectX" ? Ini juga tidak menjelaskan bagaimana kode khusus (ala CUDA) dapat dijalankan.
BlueRaja - Danny Pflughoeft
3
tolong belajar membaca. Saya katakan dengan menulis ke alamat memori tertentu yang dicadangkan untuk GPU, bukan RAM. Dan ini menjelaskan bagaimana Anda dapat menjalankan semuanya. Rentang memori terdaftar untuk kartu. Semua yang Anda tulis dalam rentang itu menuju GPU yang menjalankan pemrosesan vertex, CUDA, apa pun.
AZ.
5

GPU biasanya digerakkan oleh buffer DMA. Artinya, driver mengkompilasi perintah yang diterimanya dari program ruang pengguna menjadi aliran instruksi (alihkan keadaan, gambarkan ini dengan cara itu, alihkan konteks, dll.), Yang kemudian disalin ke memori perangkat. Kemudian menginstruksikan GPU untuk menjalankan buffer perintah ini melalui register PCI atau metode serupa.

Jadi pada setiap undian, dll. Yang terjadi adalah driver ruang pengguna akan mengkompilasi perintah, yang kemudian memanggil driver ruang kernel melalui interupsi dan yang akhirnya mengirimkan buffer perintah ke memori perangkat dan memerintahkan GPU untuk mulai rendering.

Pada konsol Anda bahkan dapat bersenang-senang melakukan semua itu sendiri, terutama di PS3.

Axel Gneiting
sumber
0

Saya pikir CPU mengirimkan data video ke GPU melalui bus dan kemudian GPU menampilkannya. Jadi GPU yang lebih cepat dapat menangani lebih banyak data dari CPU. Dengan cara ini beberapa pemrosesan cpuoffload menjadi GPU. Karenanya Anda mendapatkan kecepatan lebih cepat dalam permainan.

Ini seperti RAM tempat CPU menyimpan barang sehingga dapat dimuat dan diproses dengan cepat. Keduanya membuat game lebih cepat.

Atau kartu suara atau kartu net berfungsi dengan prinsip yang sama, yaitu mengambil data dan mengeluarkan beberapa pekerjaan CPU.

pengguna583641
sumber
Ini menggandakan jawaban lain dan tidak menambahkan konten baru. Tolong jangan memposting jawaban kecuali Anda benar-benar memiliki sesuatu yang baru untuk disumbangkan.
DavidPostill
0

Saya pikir op tidak yakin apa yang sebenarnya diminta CPU untuk dilakukan oleh kartu grafis dan mengapa perintah terkait grafis (seperti perintah opengl atau direct3d) tidak dikirim langsung ke GPU.

CPU hanya memberi tahu GPU apa yang harus dirender. Semua instruksi terlebih dahulu melalui CPU di mana mereka mendapatkan pengaturan / diinisialisasi untuk GPU untuk benar-benar melakukan rendering.

dave
sumber