W jaki sposób używać bufforów i shaderów stworzonych przez klasy pointer w innym wątku?

Odpowiedz Nowy wątek
2019-01-01 15:56
0

Witam,
chciałbym żeby moje renderowanie było na osobnym wątku.

Okno oraz kontekst tworzę przy pomocy biblioteki SDL2, a za funkcje opengl odpowiada glew

SDL_Init(SDL_INIT_EVERYTHING);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);

window = SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL);
glContext = SDL_GL_CreateContext(window);
initContext = SDL_GL_CreateContext(window);

glewExperimental = true;
glewInit();

w taki sposób chciałbym wykonać to renderowanie w wątku

void mainloop()
{
    std::thread* thread = nullptr;
    std::mutex mutex;

    Cube cube;

    std::lock_guard<std::mutex> guard(mutex);
    thread = new std::thread([&]() {
        while (!quit) {
            SDL_GL_MakeCurrent(window, glContext);

            glCall(glClearColor(0, 0, static_cast<float>(15) / 255, 1));
            glCall(glClear(GL_COLOR_BUFFER_BIT));

            cube.Render({ 1280.0f, 720.0f });

            SDL_GL_SwapWindow(window);
        }
    });
}

buffory są tworzone przez klasę Buffor, która jest matką klasy GLBuffor i metodę Create(), która zwraca stworzony pointer

Buffor* vbo = nullptr;

Cube()
{
    vbo = vbo->Create();
}

                                   //rodzaj bufora, czy to array, czy to element array | sposób użycia - static draw, dynamic draw, copy itd.
Buffer* Buffer::Create(BUFFOR buffor,                                                       USAGE usage)
{
    //Konstruktor GLBuffor wywołuje glGenBuffers i glBindBuffer dla odpowiedniego buffora
    retrun new GLBuffor(buffor, usage);
}

shader działa bardzo podobnie:

class Shader
{
public:
    Shader* Create()
    {
        //ctor GLShadera wywołuje Begin()
        return new GLShader();
    }
    //klasa GLShader nadpisuje Begin() i wywołuje w tej metodzie glCreateProgram(...)
    virtual void Begin() {}
    //tworzy shader o podanym typie - wywołuje glCreateShader, glShaderSource, glCompileShader i glAttachShader
    //wynik końcowy chcemy zapisać do tablicy, razem na przykład z shaderem fragmentów, którą potem podamy do metody End
    virtual int ShaderFromSource(const char* shader, SHADER type) {}
    //Bierze tablice z shaderami i wywołuje - glLinkProgram
    virtual void End(const int* shaders, int count) {}
}

Shadery oraz buffory są tworzone w konstruktorze klasy Cube, konstruktor jest wywoływany w głównym wątku (czyli nie w tym renderującym).
metoda Cube::Render(...) potrzebuje mieć dostęp do tych buforów i shaderów stworzonych w konstruktorze - żeby użyć takich rzeczy jak Shader::UseProgram() - czyli proste glUseProgram(...), Shader::UniformXXX(....) czy nawet DrawArrays(...) czy DrawElements(...).

Gdy wywołuje Cube::Render(...) w wątku renderującym, wyskakuje mi

screenshot-20190101154920.png

dokładnie klasa Cube wygląda tak

class Cube
{                                                                           
public:
    Cube();
    ~Cube();

    void Render(const Vector2& windowSize);

    VertexArray* vao = nullptr,
                  * lightVao = nullptr;
    Buffer* vbo = nullptr;
    Shader* shader = nullptr;

    Camera camera; 
};
Cube::Cube()
{
    float vertices[] = {
        -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
         0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
         0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
         0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
        -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,

        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
         0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
        -0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,

        -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,

         0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
         0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
         0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
         0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
         0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
         0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,

        -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
         0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
         0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
         0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,

        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
         0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,                                 
         0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
        -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f
    };

    vao = vao->Create();

    vbo = vbo->Create(Array_Buffer, Static_Draw);
    vbo->AddData(sizeof(vertices), vertices);
    vbo->AddAttribute(0, 3, FLOAT, false, 6 * sizeof(float), (const void*)(0));
    vbo->AddAttribute(1, 3, FLOAT, false, 6 * sizeof(float), (const void*)(3 * sizeof(float)));

    lightVao = lightVao->Create();                                                                               
    vbo->BindBuffer();
    vbo->AddAttribute(0, 3, FLOAT, false, 6 * sizeof(float), 0);

    shader = shader->Create();
    const int shaders[2] = {
       shader->ShaderFromSource(vs, VERTEX),                                             
       shader->ShaderFromSource(fs, FRAGMENT)
    };
    shader->End(shaders, 2);    
}
void Cube::Render(const Vector2& windowSize)                                                                            
{                                                                       
    struct Material
    {
        Vector3 ambient{ 1.0f, 0.5f, 0.31f }, diffuse{ 1.0f, 0.5f, 0.31f }, specular = 0.5f;
        int shininess = 32;
    } static material;

    struct Light {
        Vector3 ambient = 0.2f, diffuse = 0.5f, specular = 1.0f;
    } static light;

            shader->UseProgram();

            Vector3 lightPosition{ 0.0f, 0.0f, 0.0f };
            shader->Uniform3fv("lightPosition", 1, &lightPosition.x);
            Vector3 viewPosition = 0.0f;
            shader->Uniform3fv("viewPosition", 1, &camera->Position.x);
            Vector3 objectColor{ 1.0f, 0.5f, 0.31f };
            shader->Uniform3fv("objectColor", 1, &objectColor.x);
            Vector3 lightColor{ 1.0f, 1.0f, 1.0f };
            shader->Uniform3fv("lightColor", 1, &lightColor.x);

            shader->Uniform3fv("material.ambient", 1, &material.ambient.x);
            shader->Uniform3fv("material.diffuse", 1, &material.diffuse.x);
            shader->Uniform3fv("material.specular", 1, &material.specular.x);
            shader->Uniform1f("material.shininess", static_cast<float>(material.shininess));

            shader->Uniform3fv("light.ambient", 1, &light.ambient.x);
            shader->Uniform3fv("light.diffuse", 1, &light.diffuse.x);
            shader->Uniform3fv("light.specular", 1, &light.specular.x);

            Mat4 projection = Mat4(1.0f);
            projection = glm::perspective(45.0f, ratio, 0.001f, 1000.0f);

            Mat4 view = Mat4(1.0f);
            view = camera->GetViewMatrix();

            Mat4 model = Mat4(1.0f);
            {
                Mat4 rotate = Rotate(-(SDL_GetTicks() / 100.0f), Vector3(0.0f, 1.0f, 0.0f));
                model = rotate;
            }

            Mat4 mvp = Mat4(1.0f);
            mvp = projection * view * model;

            shader->UniformMatrix4fv("u_camera", mvp);
            shader->UniformMatrix4fv("u_model", model);
            shader->UniformMatrix4fv("u_normalModel", glm::transpose(glm::inverse(model)));
            shader->Uniform1i("index", 0);
            vao->DrawArrays(Triangles, 0, 36);

            model = Mat4(1.0f);
            {
                Mat4 traslate = Translate(lightPosition);
                Mat4 scale = Scale(Vector3(0.2f));
                model = traslate * scale;
            }
            mvp = projection * view * model;
            shader->UniformMatrix4fv("u_camera", mvp);
            shader->Uniform1i("index", 1);
            lightVao->DrawArrays(Triangles, 0, 36);
}

Dlaczego tak się dzieje? W jaki sposób mogę to naprawić?

Pozostało 580 znaków

2019-01-01 16:54
0

Shadery oraz buffory są tworzone w konstruktorze klasy Cube, konstruktor jest wywoływany w głównym wątku (czyli nie w tym renderującym).

Jesteś pewien że nie próbujesz używać tych obiektów zanim nie zostaną stworzone?

Tworzenie obiektów ściśle związanych z renderowaniem w innym wątku niż renderujący nie brzmi jak dobry pomysł…

edytowany 1x, ostatnio: Azarien, 2019-01-01 16:55

Pozostało 580 znaków

2019-01-01 17:15
0

Jesteś pewien że nie próbujesz używać tych obiektów zanim nie zostaną stworzone?

Nie wydaje mi się. Najpierw tworze obiekt Cube - w tym tworzone są buffory i dodawane dane do nich, potem dopiero jest tworzony wątek w którym jest używany shader i rysowana kostka. No chyba, że tworzenie wątków kompilator jakoś traktuje specjalnie i przepisuje wątek nad tworzenie obiektu, ale nie wydaje mi się, że tak jest.

Tworzenie obiektów ściśle związanych z renderowaniem w innym wątku niż renderujący nie brzmi jak dobry pomysł…

Gdy tworze obiekt w wątku to pokazuje mi się taki komunikat
screenshot-20190101171520.png

Pozostało 580 znaków

2019-01-02 16:57

Odkryłem, że ten drugi błąd jest przez spdlog - jest to biblioteka do logowania (logowałem błędy opengl tym). Gdy użyłem zwykłego cout to okazało się, że glGenVertexArrays i glBindVertexArray dają 1282 error, co oznacza GL_INVALID_OPERATION. Najzabawniejsze jest to, że jest to zwracane dla glGenVertexArrays a na stronie https://www.khronos.org/regis[...]/html/glGenVertexArrays.xhtml nie ma w ogóle opisanego takiego błędu. Jakieś pomysły?

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0