OpenGLHostDisplay: Add a GLES2 render path

This commit is contained in:
Connor McLaughlin 2020-11-21 18:08:39 +10:00
parent 2595e31575
commit 7f058169b9
3 changed files with 236 additions and 78 deletions

View file

@ -90,6 +90,7 @@ static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;
static int g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
static unsigned int g_VboHandle = 0, g_VaoHandle = 0, g_ElementsHandle = 0;
static bool g_IsGLES = false;
static bool g_IsGLES2 = false;
// Forward Declarations
static void ImGui_ImplOpenGL3_InitPlatformInterface();
@ -104,23 +105,26 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
// Store GLSL version string so we can refer to it later in case we recreate shaders. Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
if (GLAD_GL_ES_VERSION_2_0)
{
if (glsl_version == NULL)
glsl_version = "#version 100";
g_IsGLES = true;
}
else if (GLAD_GL_ES_VERSION_3_0)
if (GLAD_GL_ES_VERSION_3_0)
{
if (glsl_version == NULL)
glsl_version = "#version 300 es";
g_IsGLES = true;
g_IsGLES2 = false;
}
else if (GLAD_GL_ES_VERSION_2_0)
{
if (glsl_version == NULL)
glsl_version = "#version 100";
g_IsGLES = true;
g_IsGLES2 = true;
}
else
{
if (glsl_version == NULL)
glsl_version = "#version 130";
g_IsGLES = false;
g_IsGLES2 = false;
}
if (!g_IsGLES)
@ -179,11 +183,24 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
glUseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
#ifndef IMGUI_IMPL_OPENGL_ES2
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
#endif
if (!g_IsGLES2)
{
glBindVertexArray(g_VaoHandle);
}
else
{
glEnableVertexAttribArray(g_AttribLocationVtxPos);
glEnableVertexAttribArray(g_AttribLocationVtxUV);
glEnableVertexAttribArray(g_AttribLocationVtxColor);
glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert),
(GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert),
(GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert),
(GLvoid*)IM_OFFSETOF(ImDrawVert, col));
}
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
}
@ -250,6 +267,19 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
}
}
}
if (!g_IsGLES2)
{
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
else
{
glDisableVertexAttribArray(g_AttribLocationVtxPos);
glDisableVertexAttribArray(g_AttribLocationVtxUV);
glDisableVertexAttribArray(g_AttribLocationVtxColor);
}
}
bool ImGui_ImplOpenGL3_CreateFontsTexture()
@ -499,6 +529,9 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
glBufferData(GL_ARRAY_BUFFER, sizeof(ImDrawVert), nullptr, GL_STREAM_DRAW);
if (!g_IsGLES2)
{
glGenVertexArrays(1, &g_VaoHandle);
glBindVertexArray(g_VaoHandle);
@ -511,15 +544,15 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
(GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert),
(GLvoid*)IM_OFFSETOF(ImDrawVert, col));
}
ImGui_ImplOpenGL3_CreateFontsTexture();
// Restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
#ifndef IMGUI_IMPL_OPENGL_ES2
if (!g_IsGLES2)
glBindVertexArray(last_vertex_array);
#endif
return true;
}

View file

@ -465,6 +465,9 @@ void OpenGLHostDisplay::DestroyImGuiContext()
}
bool OpenGLHostDisplay::CreateResources()
{
m_use_gles2_draw_path = m_gl_context->IsGLES() && !GLAD_GL_ES_VERSION_3_0;
if (!m_use_gles2_draw_path)
{
static constexpr char fullscreen_quad_vertex_shader[] = R"(
uniform vec4 u_src_rect;
@ -541,6 +544,74 @@ void main()
glGenSamplers(1, &m_display_linear_sampler);
glSamplerParameteri(m_display_linear_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(m_display_linear_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
else
{
static constexpr char fullscreen_quad_vertex_shader[] = R"(
#version 100
attribute highp vec2 a_pos;
attribute highp vec2 a_tex0;
varying highp vec2 v_tex0;
void main()
{
gl_Position = vec4(a_pos, 0.0, 1.0);
v_tex0 = a_tex0;
}
)";
static constexpr char display_fragment_shader[] = R"(
#version 100
uniform highp sampler2D samp0;
varying highp vec2 v_tex0;
void main()
{
gl_FragColor = vec4(texture2D(samp0, v_tex0).rgb, 1.0);
}
)";
static constexpr char cursor_fragment_shader[] = R"(
#version 100
uniform highp sampler2D samp0;
varying highp vec2 v_tex0;
void main()
{
gl_FragColor = texture2D(samp0, v_tex0);
}
)";
if (!m_display_program.Compile(fullscreen_quad_vertex_shader, {}, display_fragment_shader) ||
!m_cursor_program.Compile(fullscreen_quad_vertex_shader, {}, cursor_fragment_shader))
{
Log_ErrorPrintf("Failed to compile display shaders");
return false;
}
m_display_program.BindAttribute(0, "a_pos");
m_display_program.BindAttribute(1, "a_tex0");
m_cursor_program.BindAttribute(0, "a_pos");
m_cursor_program.BindAttribute(1, "a_tex0");
if (!m_display_program.Link() || !m_cursor_program.Link())
{
Log_ErrorPrintf("Failed to link display programs");
return false;
}
m_display_program.Bind();
m_display_program.RegisterUniform("samp0");
m_display_program.Uniform1i(0, 0);
m_cursor_program.Bind();
m_cursor_program.RegisterUniform("samp0");
m_cursor_program.Uniform1i(0, 0);
}
return true;
}
@ -561,11 +632,20 @@ void OpenGLHostDisplay::DestroyResources()
}
if (m_display_vao != 0)
{
glDeleteVertexArrays(1, &m_display_vao);
m_display_vao = 0;
}
if (m_display_linear_sampler != 0)
{
glDeleteSamplers(1, &m_display_linear_sampler);
m_display_linear_sampler = 0;
}
if (m_display_nearest_sampler != 0)
{
glDeleteSamplers(1, &m_display_nearest_sampler);
m_display_nearest_sampler = 0;
}
m_cursor_program.Destroy();
m_display_program.Destroy();
@ -641,6 +721,30 @@ void OpenGLHostDisplay::RenderDisplay()
m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering);
}
static void DrawFullscreenQuadES2(s32 tex_view_x, s32 tex_view_y, s32 tex_view_width, s32 tex_view_height,
s32 tex_width, s32 tex_height)
{
const float tex_left = static_cast<float>(tex_view_x) / static_cast<float>(tex_width);
const float tex_right = tex_left + static_cast<float>(tex_view_width) / static_cast<float>(tex_width);
const float tex_top = static_cast<float>(tex_view_y) / static_cast<float>(tex_height);
const float tex_bottom = tex_top + static_cast<float>(tex_view_height) / static_cast<float>(tex_height);
const std::array<std::array<float, 4>, 4> vertices = {{
{{-1.0f, -1.0f, tex_left, tex_bottom}}, // bottom-left
{{1.0f, -1.0f, tex_right, tex_bottom}}, // bottom-right
{{-1.0f, 1.0f, tex_left, tex_top}}, // top-left
{{1.0f, 1.0f, tex_right, tex_top}}, // top-right
}};
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertices[0]), &vertices[0][0]);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertices[0]), &vertices[0][2]);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
}
void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 height, void* texture_handle,
u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y,
s32 texture_view_width, s32 texture_view_height, bool linear_filter)
@ -651,17 +755,26 @@ void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 heigh
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_FALSE);
glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture_handle)));
m_display_program.Bind();
if (!m_use_gles2_draw_path)
{
m_display_program.Uniform4f(0, static_cast<float>(texture_view_x) / static_cast<float>(texture_width),
static_cast<float>(texture_view_y) / static_cast<float>(texture_height),
(static_cast<float>(texture_view_width) - 0.5f) / static_cast<float>(texture_width),
(static_cast<float>(texture_view_height) + 0.5f) / static_cast<float>(texture_height));
glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(reinterpret_cast<uintptr_t>(texture_handle)));
glBindSampler(0, linear_filter ? m_display_linear_sampler : m_display_nearest_sampler);
glBindVertexArray(m_display_vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindSampler(0, 0);
}
else
{
DrawFullscreenQuadES2(m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_height, m_display_texture_width, m_display_texture_height);
}
}
void OpenGLHostDisplay::RenderSoftwareCursor()
{
@ -684,13 +797,23 @@ void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s3
glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_FALSE);
m_cursor_program.Bind();
m_cursor_program.Uniform4f(0, 0.0f, 0.0f, 1.0f, 1.0f);
glBindTexture(GL_TEXTURE_2D, static_cast<OpenGLHostDisplayTexture*>(texture_handle)->GetGLID());
if (!m_use_gles2_draw_path)
{
m_cursor_program.Uniform4f(0, 0.0f, 0.0f, 1.0f, 1.0f);
glBindSampler(0, m_display_linear_sampler);
glBindVertexArray(m_display_vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindSampler(0, 0);
}
else
{
const s32 tex_width = static_cast<s32>(static_cast<OpenGLHostDisplayTexture*>(texture_handle)->GetWidth());
const s32 tex_height = static_cast<s32>(static_cast<OpenGLHostDisplayTexture*>(texture_handle)->GetHeight());
DrawFullscreenQuadES2(0, 0, tex_width, tex_height, tex_width, tex_height);
}
}
#ifndef LIBRETRO

View file

@ -120,6 +120,8 @@ protected:
std::unique_ptr<GL::StreamBuffer> m_post_processing_ubo;
std::vector<PostProcessingStage> m_post_processing_stages;
#endif
bool m_use_gles2_draw_path = false;
};
} // namespace FrontendCommon