Я реализую рендеринг сетки в opengl, где ячейки должны менять цвет при наведении на них курсора. Код работал, и теперь я начал очищать код и уменьшать вмешательства в шейдер.
Теперь, удалив только одно матричное умножение в геометрическом шейдере, вывод останавливается через несколько кадров.
В качестве обходного пути я добавил this_thread :: sleep_for, чтобы ограничить частоту кадров до ~ 60fps, хотя это не решение. Запуск моего приложения с renderdoc также предотвращает возникновение этой ошибки.
Я должен отметить, что я генерирую контекст opengl в другом потоке, отличном от потока, выполняющего цикл PeekMessage, так что это может быть связано с проблемами синхронизации между потоками? (То, что время кадра влияет на это поведение, кажется индикатором того, что мне не хватает синхронизации)
Как только происходит блокировка, поток окна все еще получает сообщения, но мой поток opengl блокирует в SwapBuffers.
В следующем шейдере я объединил matVP и matTransform в один, что приводит к строке:
mat4 m = matVP;
и настоящая проблема начинает происходить.
layout(points) in;
layout(triangle_strip, max_vertices = 6) out;
uniform mat4 matVP;
uniform mat4 matTransform;
uniform int gridDimensions;
layout(binding=0, r8ui) uniform readonly uimage2D tileMap;
out vec2 uv;
out vec2 pos;
void main()
{
int x = gl_PrimitiveIDIn % gridDimensions;
int y = gl_PrimitiveIDIn / gridDimensions;
uvec4 tileData = imageLoad(tileMap, ivec2(x, y));
// if(tileData.r == 0) return;
mat4 m = matVP;
vec4 startPosition = vec4(float(x), float(y), 0.0, 1.0);
vec4 xp = vec4(1.0, 0.0, 0.0,0.0);
vec4 yp = vec4(0.0, 1.0, 0.0, 0.0);
gl_Position = m * startPosition;
uv = vec2(0.0, 0.0);
pos = vec2(x, y);
EmitVertex();
gl_Position = m * (startPosition + xp);
uv = vec2(1.0, 0.0);
pos = vec2(x + 1, y);
EmitVertex();
gl_Position = m * (startPosition + yp);
uv = vec2(0.0, 1.0);
pos = vec2(x, y + 1);
EmitVertex();
EndPrimitive();
gl_Position = m * (startPosition + xp);
uv = vec2(1.0, 0.0);
pos = vec2(x + 1, y);
EmitVertex();
gl_Position = m * (startPosition + xp + yp);
uv = vec2(1.0, 1.0);
pos = vec2(x + 1, y + 1);
EmitVertex();
gl_Position = m * (startPosition + yp);
uv = vec2(0.0, 1.0);
pos = vec2(x, y + 1);
EmitVertex();
EndPrimitive();
}
Я использую видеокарту Vega 8, я попытаюсь воспроизвести проблему на другой машине с NVIDIA.
Мой основной поток и поток opengl никоим образом не разделяют контекст opengl, что заставляет меня думать, что это может быть ошибка, связанная с драйвером.
Основной поток проходит через этот код:
done = false;
while (!done)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
{
done = true;
m_isOpen = false;
}
else
{
if (m_inputSystem->isKeyPressed(VK_ESCAPE))
{
done = true;
m_isOpen = false;
}
}
}
}
И код для отображения сетки вызывает следующее:
void TileGrid::render(const Camera* cam)
{
const auto matMVP = cam->getVP();
glUseProgram(m_renderGridProgram);
glUniformMatrix4fv(m_matVPLoc, 1, GL_FALSE, &((matMVP)[0][0]));
glUniformMatrix4fv(m_matTransformLocation, 1, GL_FALSE, &(m_transform[0][0]));
glUniform1i(m_GridDimensionsLoc, m_gridDimensions);
glBindVertexArray(m_vao);
glBindImageTexture(0, m_gridTexture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8UI);
[...] // calculating "intersect", no gl involved
glUniform2f(m_cursorPosLocation, intersect.x, intersect.y);
glDrawArrays(GL_POINTS, 0, m_gridDimensions * m_gridDimensions);
}
Затем следует
glFinish();
auto frameTime = std::chrono::high_resolution_clock::now() - frameStart;
// the following line "solves" the problem
std::this_thread::sleep_for(std::chrono::milliseconds(16) - frameTime);
m_window->swapBuffers();
Задача ещё не решена.
Других решений пока нет …