Mangled OpenGL рендеринг на некоторых платформах - PullRequest
0 голосов
/ 11 октября 2019

Я экспериментировал с пакетным рендерингом спрайтов, и у меня есть решение, которое хорошо работает на моем настольном ПК. Однако, пробуя это на моем интегрированном ноутбуке Intel UHD 620, я получаю следующие предупреждения о производительности:

[21:42:03   error] OpenGL: API - Performance - Recompiling fragment shader for program 27
[21:42:03   error] OpenGL: API - Performance -   multisampled FBO 0->1

Предположительно, из-за источника этих предупреждений о производительности, кадров, которые занимают 1-2 миллисекунды на моей выделенной машине с видеокартойпримерно 100 миллисекунд на моем ноутбуке.

Вот мой код рендерера:

BatchedSpriteRenderer::BatchedSpriteRenderer(ResourceManager &resource_manager)
    : resource_manager(&resource_manager), 
      max_sprites(100000),
      vertex_array(std::make_unique<VertexArray>()),
      vertex_buffer(std::make_unique<VertexBuffer>())
{
    resource_manager.load_shader("batched_texture",
                                 "shaders/texture_batched.vert",
                                 "shaders/texture.frag");

    std::vector<unsigned int> sprite_indices;
    for (int i = 0; i < max_sprites; ++i)
    {
        unsigned int sprite_number = i * 4;
        sprite_indices.push_back(0 + sprite_number);
        sprite_indices.push_back(1 + sprite_number);
        sprite_indices.push_back(2 + sprite_number);
        sprite_indices.push_back(2 + sprite_number);
        sprite_indices.push_back(3 + sprite_number);
        sprite_indices.push_back(0 + sprite_number);
    }
    element_buffer = std::make_unique<ElementBuffer>(sprite_indices.data(), max_sprites * 6);

    VertexBufferLayout layout;
    layout.push<float>(2);
    layout.push<float>(2);
    layout.push<float>(4);
    vertex_array->add_buffer(*vertex_buffer, layout);
}

void BatchedSpriteRenderer::draw(const std::string &texture,
                                 const std::vector<glm::mat4> &transforms,
                                 const glm::mat4 &view)
{
    vertex_array->bind();

    auto shader = resource_manager->shader_store.get("batched_texture");
    shader->bind();

    std::vector<SpriteVertex> vertices;
    vertices.reserve(transforms.size() * 4);
    for (const auto &transform : transforms)
    {
        glm::vec4 transformed_position = transform * glm::vec4(0.0, 1.0, 1.0, 1.0);
        vertices.push_back({glm::vec2(transformed_position.x, transformed_position.y),
                            glm::vec2(0.0, 1.0),
                            glm::vec4(1.0, 1.0, 1.0, 1.0)});
        transformed_position = transform * glm::vec4(0.0, 0.0, 1.0, 1.0);
        vertices.push_back({glm::vec2(transformed_position.x, transformed_position.y),
                            glm::vec2(0.0, 0.0),
                            glm::vec4(1.0, 1.0, 1.0, 1.0)});
        transformed_position = transform * glm::vec4(1.0, 0.0, 1.0, 1.0);
        vertices.push_back({glm::vec2(transformed_position.x, transformed_position.y),
                            glm::vec2(1.0, 0.0),
                            glm::vec4(1.0, 1.0, 1.0, 1.0)});
        transformed_position = transform * glm::vec4(1.0, 1.0, 1.0, 1.0);
        vertices.push_back({glm::vec2(transformed_position.x, transformed_position.y),
                            glm::vec2(1.0, 1.0),
                            glm::vec4(1.0, 1.0, 1.0, 1.0)});
    }
    vertex_buffer->add_data(vertices.data(),
                            sizeof(SpriteVertex) * vertices.size(),
                            GL_DYNAMIC_DRAW);

    shader->set_uniform_mat4f("u_view", view);
    shader->set_uniform_1i("u_texture", 0);

    resource_manager->texture_store.get(texture)->bind();

    glDrawElements(GL_TRIANGLES, transforms.size() * 6, GL_UNSIGNED_INT, 0);
}

Надеюсь, мои абстракции должны быть достаточно понятны. Каждый из классов абстракции (VertexArray, VertexBuffer, ElementBuffer, VertexBufferLayout) управляет временем жизни своего эквивалентного объекта OpenGL.

Вот используемые шейдеры: texture_batched.vert

#version 430 core

layout(location = 0)in vec2 v_position; 
layout(location = 1)in vec2 v_tex_coord; 
layout(location = 2)in vec4 v_color; 

out vec4 color; 
out vec2 tex_coord; 

uniform mat4 u_view;

void main()
 {
    tex_coord = v_tex_coord;
    gl_Position = u_view * vec4(v_position, 0.0, 1.0);
    color = v_color;
}

texture.frag

#version 430 core

in vec4 color; 
in vec2 tex_coord; 

out vec4 frag_color; 

uniform sampler2D u_texture; 

void main()
 {
    frag_color = texture(u_texture, tex_coord);
    frag_color *= color;
}

Что вызывает эти проблемы с производительностью и как их можно исправить?

РЕДАКТИРОВАТЬ: я совершенно забыл упомянуть, что фактическое изображение отображается сэто полностью запутано, я попытаюсь получить скриншот, где он работает правильно, когда доберусь до настольного компьютера, но вот как выглядит сломанная версия: Mangled rendering

Это должна быть аккуратная сетка из 200х200 белых кружков.

РЕДАКТИРОВАТЬ 2: Я пробовал на другом компьютере, на этот раз с GTX 1050 Ti, и он также сломан. Нет сообщений об ошибках или предупреждений на этот раз. Предупреждение может быть не связано.

1 Ответ

0 голосов
/ 13 октября 2019

Насколько я могу судить, он оказался не связанным с OpenGL.

В функции рисования я создаю вектор с именем vertices, а затем помещаю в него все вершины. По какой-то причине, когда я воссоздаю этот вектор в каждом кадре, следующие push_back вызовы не добавляются в вектор должным образом. Члены SpriteVertex структур были перепутаны. Таким образом, вместо правильного макета:

pos tex_coord color
pos tex_coord color
pos tex_coord color
pos tex_coord color

Он заполнялся следующим макетом:

pos tex_coord color
tex_coord pos color
tex_coord pos color
tex_coord pos color

Или что-то в этом роде, по крайней мере.

Я изменил его так, чтобы вектор vertices был членом класса BatchedSpriteRenderer, зарезервировав пространство для максимально возможного числа вершин.

void BatchedSpriteRenderer::draw(const std::string &texture,
                                 const std::vector<glm::mat4> &transforms,
                                 const glm::mat4 &view)
{
    vertex_array->bind();

    auto shader = resource_manager->shader_store.get("batched_texture");
    shader->bind();

    for (unsigned int i = 0; i < transforms.size(); ++i)
    {
        const auto &transform = transforms[i];

        glm::vec4 transformed_position = transform * glm::vec4(0.0, 1.0, 1.0, 1.0);
        vertices[i * 4] = {glm::vec2(transformed_position.x,
                                     transformed_position.y),
                           glm::vec2(0.0, 1.0),
                           glm::vec4(1.0, 1.0, 1.0, 1.0)};

        transformed_position = transform * glm::vec4(0.0, 0.0, 1.0, 1.0);
        vertices[i * 4 + 1] = {glm::vec2(transformed_position.x,
                                         transformed_position.y),
                               glm::vec2(0.0, 0.0),
                               glm::vec4(1.0, 1.0, 1.0, 1.0)};

        transformed_position = transform * glm::vec4(1.0, 0.0, 1.0, 1.0);
        vertices[i * 4 + 2] = {glm::vec2(transformed_position.x,
                                         transformed_position.y),
                               glm::vec2(1.0, 0.0),
                               glm::vec4(1.0, 1.0, 1.0, 1.0)};

        transformed_position = transform * glm::vec4(1.0, 1.0, 1.0, 1.0);
        vertices[i * 4 + 3] = {glm::vec2(transformed_position.x,
                                         transformed_position.y),
                               glm::vec2(1.0, 1.0),
                               glm::vec4(1.0, 1.0, 1.0, 1.0)};
    }

    vertex_buffer->add_data(vertices.data(),
                            sizeof(SpriteVertex) * (transforms.size() * 4),
                            GL_DYNAMIC_DRAW);

    shader->set_uniform_mat4f("u_view", view);
    shader->set_uniform_1i("u_texture", 0);

    resource_manager->texture_store.get(texture)->bind();

    glDrawElements(GL_TRIANGLES, transforms.size() * 6, GL_UNSIGNED_INT, 0);
}
...