OpenGL में "तत्काल मोड" का क्या अर्थ है?


82

"तत्काल मोड" क्या है? एक कोड उदाहरण दें।

मुझे रिटेन किए गए मोड के बजाय तत्काल मोड का उपयोग कब करना है? प्रत्येक विधि का उपयोग करने के पेशेवरों और विपक्ष क्या हैं?

जवाबों:


143

"तत्काल मोड" का एक उदाहरण उपयोग कर रहा है glBeginऔर glEndसाथ glVertexउन दोनों के बीच में। "तत्काल मोड" का एक और उदाहरण का उपयोग करने के लिए है glDrawArraysएक ग्राहक शिखर सरणी (यानी के साथ नहीं एक शीर्ष बफर वस्तु)।

आप आमतौर पर तत्काल मोड (शायद अपने पहले "हैलो वर्ल्ड" प्रोग्राम को छोड़कर) का उपयोग नहीं करना चाहेंगे, क्योंकि यह पदावनत कार्यक्षमता है और इष्टतम प्रदर्शन की पेशकश नहीं करता है।

तत्काल मोड इष्टतम नहीं होने का कारण यह है कि ग्राफिक कार्ड सीधे आपके प्रोग्राम के प्रवाह के साथ जुड़ा हुआ है। ड्राइवर GPU को पहले रेंडर करना शुरू करने के लिए नहीं कह सकता है glEnd, क्योंकि यह नहीं पता है कि आपको डेटा सबमिट करना कब समाप्त होगा, और इसे उस डेटा को भी ट्रांसफर करने की आवश्यकता है (जो कि यह केवल उसके बाद कर सकता है glEnd)।
इसी तरह, क्लाइंट वर्टेक्स ऐरे के साथ, ड्राइवर केवल आपके एरे की एक कॉपी खींच सकता है जिसे आप कॉल करते हैं glDrawArrays, और उसे आपके एप्लिकेशन को ब्लॉक करना चाहिए। कारण यह है कि अन्यथा आप ड्राइवर को कैप्चर करने से पहले सरणी की मेमोरी को संशोधित (या मुफ्त) कर सकते हैं। यह उस ऑपरेशन को पहले या बाद में शेड्यूल नहीं कर सकता है, क्योंकि यह केवल यह जानता है कि डेटा एक समय में बिल्कुल मान्य है।

इसके विपरीत, यदि आप उदाहरण के लिए एक वर्टेक्स बफर ऑब्जेक्ट का उपयोग करते हैं, तो आप डेटा के साथ एक बफर भरते हैं और इसे ओपनजीएल को सौंप देते हैं। आपकी प्रक्रिया अब इस डेटा का स्वामी नहीं है और इसलिए अब इसे संशोधित नहीं किया जा सकता है। ड्राइवर इस तथ्य पर भरोसा कर सकता है और जब भी बस खाली होती है, तब भी डेटा अपलोड कर सकता है।
आपका कोई भी बाद glDrawArraysया glDrawElementsकॉल बस एक काम कतार में जाएगा और तुरंत (वास्तव में खत्म होने से पहले!) वापस आ जाएगा, इसलिए आपका कार्यक्रम एक ही समय में कमांड जमा करता रहता है जबकि ड्राइवर एक-एक करके काम करता है। उन्होंने यह भी कहा कि डेटा के आने की प्रतीक्षा करने की आवश्यकता नहीं होगी, क्योंकि ड्राइवर पहले से ही ऐसा कर सकता है।
इस प्रकार, थ्रेड और जीपीयू को अतुल्यकालिक रूप से चलाएं, हर घटक हर समय व्यस्त रहता है, जो बेहतर प्रदर्शन देता है।

तत्काल मोड का उपयोग करने के लिए मृत सरल होने का फायदा होता है, लेकिन फिर एक गैर-पदावनत तरीके से ओपनजीएल का सही तरीके से उपयोग करना ठीक से रॉकेट साइंस भी नहीं है - यह केवल बहुत कम अतिरिक्त काम करता है।

यहाँ तत्काल मोड में विशिष्ट OpenGL "हैलो वर्ल्ड" कोड है:

संपादित करें:
सामान्य अनुरोध के अनुसार, अनुरक्षित मोड में एक ही चीज कुछ इस तरह दिखाई देगी:


1
बहुत बहुत धन्यवाद, बहुत दिलचस्प तुलना। यह मेरे लिए बहुत अधिक जटिल दिखता है, लेकिन मुझे लगता है कि एक बार जब मैं पाइपलाइन को ठीक से समझ
पाऊंगा

6
@ मल्मर्डज़: आधुनिक ओपनजीएल के साथ कुछ भी करना बहुत कठिन है , लेकिन प्रारंभिक बाधा (और, बहुत तेज़ी से) खत्म होने के बाद यह वास्तव में आसान है। तत्काल मोड अच्छा है क्योंकि प्रवेश बाधा बेहद कम है। मेरा उदाहरण अभी भी वर्टेक्स और फ्रेग्मेंट शेड्स को याद कर रहा है, जिसकी आपको आपूर्ति करना होगा (साथ ही बहुत ही बुनियादी)। किसी चीज का पूर्ण रूप से चलने वाला उदाहरण जो वास्तव में संकलित करता है और काम करता है, काफी लंबा है। :-)
डेमोन

19

चल-चलकर बनाए गए उदाहरण

डेमन ने प्रमुख भागों को प्रदान किया है, लेकिन मेरे जैसे नए लोग एक पूर्ण रूप से चलने योग्य उदाहरण की तलाश में होंगे।

यहाँ छवि विवरण दर्ज करें

main.c

#include <stdio.h>
#include <stdlib.h>

#define GLEW_STATIC
#include <GL/glew.h>

#include <GLFW/glfw3.h>

#define INFOLOG_LEN 512

static const GLuint WIDTH = 512, HEIGHT = 512;
/* vertex data is passed as input to this shader
 * ourColor is passed as input to the to the fragment shader. */
static const GLchar* vertexShaderSource =
    "#version 330 core\n"
    "layout (location = 0) in vec3 position;\n"
    "layout (location = 1) in vec3 color;\n"
    "out vec3 ourColor;\n"
    "void main() {\n"
    "    gl_Position = vec4(position, 1.0f);\n"
    "    ourColor = color;\n"
    "}\n";
static const GLchar* fragmentShaderSource =
    "#version 330 core\n"
    "in vec3 ourColor;\n"
    "out vec4 color;\n"
    "void main() {\n"
    "    color = vec4(ourColor, 1.0f);\n"
    "}\n";
GLfloat vertices[] = {
/*   Positions            Colors */
     0.5f, -0.5f, 0.0f,   1.0f, 0.0f, 0.0f,
    -0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,
     0.0f,  0.5f, 0.0f,   0.0f, 0.0f, 1.0f
};

int main(int argc, char **argv) {
    int immediate = (argc > 1) && argv[1][0] == '1';

    /* Used in !immediate only. */
    GLuint vao, vbo;
    GLint shaderProgram;

    glfwInit();
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, __FILE__, NULL, NULL);
    glfwMakeContextCurrent(window);
    glewExperimental = GL_TRUE;
    glewInit();
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glViewport(0, 0, WIDTH, HEIGHT);
    if (immediate) {
        float ratio;
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        ratio = width / (float) height;
        glClear(GL_COLOR_BUFFER_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glBegin(GL_TRIANGLES);
        glColor3f(  1.0f,  0.0f, 0.0f);
        glVertex3f(-0.5f, -0.5f, 0.0f);
        glColor3f(  0.0f,  1.0f, 0.0f);
        glVertex3f( 0.5f, -0.5f, 0.0f);
        glColor3f(  0.0f,  0.0f, 1.0f);
        glVertex3f( 0.0f,  0.5f, 0.0f);
        glEnd();
    } else {
        /* Build and compile shader program. */
        /* Vertex shader */
        GLint vertexShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
        glCompileShader(vertexShader);
        GLint success;
        GLchar infoLog[INFOLOG_LEN];
        glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
        if (!success) {
            glGetShaderInfoLog(vertexShader, INFOLOG_LEN, NULL, infoLog);
            printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog);
        }
        /* Fragment shader */
        GLint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
        glCompileShader(fragmentShader);
        glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
        if (!success) {
            glGetShaderInfoLog(fragmentShader, INFOLOG_LEN, NULL, infoLog);
            printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog);
        }
        /* Link shaders */
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram, vertexShader);
        glAttachShader(shaderProgram, fragmentShader);
        glLinkProgram(shaderProgram);
        glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
        if (!success) {
            glGetProgramInfoLog(shaderProgram, INFOLOG_LEN, NULL, infoLog);
            printf("ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", infoLog);
        }
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);

        glGenVertexArrays(1, &vao);
        glGenBuffers(1, &vbo);
        glBindVertexArray(vao);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
        /* Position attribute */
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
        glEnableVertexAttribArray(0);
        /* Color attribute */
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
        glEnableVertexAttribArray(1);
        glBindVertexArray(0);
        glUseProgram(shaderProgram);
        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glBindVertexArray(0);
    }
    glfwSwapBuffers(window);

    /* Main loop. */
    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
    }

    if (!immediate) {
        glDeleteVertexArrays(1, &vao);
        glDeleteBuffers(1, &vbo);
        glDeleteProgram(shaderProgram);
    }
    glfwTerminate();
    return EXIT_SUCCESS;
}

ओपन जीआईजीएल से अनुकूलित , मेरा गिटहब अपस्ट्रीम

संकलन और Ubuntu 20.04 पर चलाएं:

sudo apt install libglew-dev libglfw3-dev
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c -lGL -lGLEW -lglfw
# Shader
./main.out
# Immediate
./main.out 1

इससे हम देखते हैं कि:

शेड का उपयोग करते समय:

  • सीपीयू पर चलने वाले नियमित सी प्रोग्राम के अंदर जीएलएसएल भाषा ( vertexShaderSourceऔर fragmentShaderSource) युक्त सी-स्टाइल स्ट्रिंग्स के रूप में वर्टेक्स और टुकड़ा shader कार्यक्रमों का प्रतिनिधित्व किया जा रहा है

  • यह C प्रोग्राम OpenGL कॉल करता है जो उन तारों को GPU कोड में संकलित करता है, जैसे:

    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    
  • shader उनके अपेक्षित इनपुट को परिभाषित करता है, और C प्रोग्राम उन्हें GPU कोड को मेमोरी में पॉइंटर के माध्यम से प्रदान करता है। उदाहरण के लिए, टुकड़ा shader शीर्ष पदों और रंगों की एक सरणी के रूप में अपने अपेक्षित इनपुट को परिभाषित करता है:

    "layout (location = 0) in vec3 position;\n"
    "layout (location = 1) in vec3 color;\n"
    "out vec3 ourColor;\n"
    

    और इसके एक आउटपुट ourColorको रंगों की एक सरणी के रूप में भी परिभाषित करता है , जो तब टुकड़े टुकड़े करने वाले के लिए एक इनपुट बन जाता है:

    static const GLchar* fragmentShaderSource =
        "#version 330 core\n"
        "in vec3 ourColor;\n"
    

    C प्रोग्राम तब CPU से GPU तक वर्टेक्स पोजिशंस और कलर्स युक्त एरी प्रदान करता है

        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    

हालांकि, तत्काल नॉन-शेडर उदाहरण पर, हम देखते हैं कि मैजिक एपीआई कॉल किए जाते हैं जो स्पष्ट रूप से स्थिति और रंग देते हैं:

glColor3f(  1.0f,  0.0f, 0.0f);
glVertex3f(-0.5f, -0.5f, 0.0f);

इसलिए हम समझते हैं कि यह एक बहुत अधिक प्रतिबंधित मॉडल का प्रतिनिधित्व करता है, क्योंकि स्थिति और रंग अब स्मृति में उपयोगकर्ता-परिभाषित सरणियों नहीं हैं, बल्कि केवल एक फोंग जैसे मॉडल के लिए इनपुट करते हैं।

दोनों मामलों में, प्रदान किया गया आउटपुट सामान्य रूप से सीपीयू के माध्यम से वापस जाने के बिना, सीधे वीडियो में चला जाता है, हालांकि सीपीयू को पढ़ना संभव है, जैसे यदि आप उन्हें एक फ़ाइल में सहेजना चाहते हैं: रेंडर करने के लिए GLUT / OpenGL का उपयोग कैसे करें एक पंक्ति?

अधिकांश "आधुनिक" ओपनजीएल ट्यूटोरियल सामान्य रूप से बनाए रखा गया मोड और GLFW, आपको कई उदाहरण मिलेंगे


1
मेरे पास एक रिपोर्ट है कि अगर आपको कोई त्रुटि मिलती है ERROR::SHADER::VERTEX::COMPILATION_FAILEDतो आप इसे ठीक कर सकते हैं glfwWindowHintजैसा कि दिखाया गया है: stackoverflow.com/questions/52592309/… फिर भी मैं पुन: पेश नहीं कर सकता।
सीरो सेंटिल्ली 郝海东 冠状 iro i 法轮功 '

1
मैंने सिर्फ export MESA_GL_VERSION_OVERRIDE=3.3main.out (डेबियन 8) चलाने से पहले कमांड को चलाकर समस्या का हल किया क्योंकि एक उत्तर उसी पोस्ट पर इंगित करता है जिसे आपने साझा किया था।
इवानजिन्हो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.