SFML เร็วแค่ไหน?

Aug 31 2020

ฉันต้องการวาดกราฟิกใน c ++ ทีละพิกเซลบนหน้าต่าง ในการดำเนินการนี้ฉันสร้างหน้าต่าง SFML สไปรท์และพื้นผิว ฉันวาดกราฟิกที่ต้องการลงในอาร์เรย์ uint8_t จากนั้นอัปเดตพื้นผิวและสไปรท์ด้วย กระบวนการนี้จะใช้เวลาประมาณ2500 เรา วาดรูปสามเหลี่ยมสองรูปที่กรอกหน้าต่างทั้งหมดใช้เวลาเพียง10 ดอลลาร์สหรัฐ ความแตกต่างขนาดใหญ่นี้เป็นไปได้อย่างไร? ฉันได้ลองใช้การวาดภาพแบบพิกเซลต่อพิกเซลแบบมัลติเธรดแล้ว แต่ความแตกต่างของลำดับความสำคัญสองลำดับยังคงอยู่ ฉันได้ลองวาดพิกเซลโดยใช้แผนที่จุดโดยไม่มีการปรับปรุง ฉันเข้าใจว่า SFML ใช้การเร่งความเร็วของ GPU ในพื้นหลัง แต่การวนซ้ำและกำหนดค่าให้กับอาร์เรย์พิกเซลก็ใช้เวลาหลายร้อยไมโครวินาทีแล้ว

มีใครรู้วิธีที่มีประสิทธิภาพมากขึ้นในการกำหนดค่าของพิกเซลในหน้าต่างหรือไม่?

นี่คือตัวอย่างของรหัสที่ฉันใช้เพื่อเปรียบเทียบความเร็วของรูปสามเหลี่ยมและการวาดแบบพิกเซลต่อพิกเซล:

#include <SFML/Graphics.hpp>
#include <chrono>
using namespace std::chrono;
#include <iostream>
#include<cmath>

uint8_t* pixels;

int main(int, char const**)
{
    const unsigned int width=1200;
    const unsigned int height=1200;
    sf::RenderWindow window(sf::VideoMode(width, height), "MA: Rasterization Test");
    pixels = new uint8_t[width*height*4];
    sf::Texture pixels_texture;
    pixels_texture.create(width, height);
    sf::Sprite pixels_sprite(pixels_texture);
    sf::Clock clock;
    sf::VertexArray triangle(sf::Triangles, 3);

    triangle[0].position = sf::Vector2f(0, height);
    triangle[1].position = sf::Vector2f(width, height);
    triangle[2].position = sf::Vector2f(width/2, height-std::sqrt(std::pow(width,2)-std::pow(width/2,2)));
    triangle[0].color = sf::Color::Red;
    triangle[1].color = sf::Color::Blue;
    triangle[2].color = sf::Color::Green;
    
    
    while (window.isOpen()){
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }
            if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) {
                window.close();
            }
        }

        window.clear(sf::Color(255,255,255,255));

        // Pixel-by-pixel
        int us = duration_cast< microseconds >(system_clock::now().time_since_epoch()).count();
        for(int i=0;i!=width*height*4;++i){
            pixels[i]=255;
        }
        pixels_texture.update(pixels);
        window.draw(pixels_sprite);
        int duration=duration_cast< microseconds >(system_clock::now().time_since_epoch()).count()-us;
        std::cout<<"Background: "<<duration<<" us\n";

        // Triangle
        us = duration_cast< microseconds >(system_clock::now().time_since_epoch()).count();
        window.draw(triangle);
         duration=duration_cast< microseconds >(system_clock::now().time_since_epoch()).count()-us;
        std::cout<<"Triangle: "<<duration<<" us\n";

        window.display();
    }
    return EXIT_SUCCESS;
}

คำตอบ

5 Noname Aug 31 2020 at 22:00

การวาดภาพกราฟิกในอุปกรณ์สมัยใหม่โดยใช้กราฟิกการ์ดและความเร็วในการวาดขึ้นอยู่กับจำนวนสามเหลี่ยมในข้อมูลที่คุณส่งไปยังหน่วยความจำกราฟิก นั่นเป็นเหตุผลว่าทำไมแค่วาดสามเหลี่ยมสองอันก็เร็วแล้ว

ดังที่คุณได้กล่าวถึงเกี่ยวกับมัลติเธรดหากคุณใช้ OpenGL (ฉันจำไม่ได้ว่า SFML ใช้อะไร แต่น่าจะเหมือนกัน) สิ่งที่คุณคิดว่าคุณกำลังวาดคือการส่งคำสั่งและข้อมูลไปยังกราฟิกการ์ดโดยทั่วไปดังนั้นมัลติเธรดที่นี่จึงไม่มีประโยชน์มากนัก การ์ดแสดงผลมีเธรดของตัวเองเพื่อทำสิ่งนี้

ถ้าคุณอยากรู้เกี่ยวกับการทำงานของการ์ดวิธีกราฟิกนี้กวดวิชาเป็นหนังสือที่คุณควรอ่าน

ป.ล. ในขณะที่คุณแก้ไขคำถามของคุณฉันเดาว่าระยะเวลา 2500us เทียบกับ 10us เป็นเพราะคุณสร้างพื้นผิวสำหรับการวนซ้ำ (แม้ว่าพื้นผิวจะเป็นพื้นหลังสีขาวล้วนก็ตาม) (และสำหรับลูปคุณอาจต้องเริ่มนับหลังจากวนซ้ำ) และการส่งพื้นผิวไปยังกราฟิกการ์ดต้องใช้เวลาในขณะที่รูปสามเหลี่ยมส่งได้หลายจุดเท่านั้น ถึงกระนั้นฉันขอแนะนำให้อ่านบทช่วยสอนการสร้างพิกเซลพื้นผิวทีละพิกเซลอาจพิสูจน์ได้ว่าพลาดความเข้าใจเกี่ยวกับการทำงานของ GPU