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 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 unsigned int g_VboHandle = 0, g_VaoHandle = 0, g_ElementsHandle = 0;
static bool g_IsGLES = false; static bool g_IsGLES = false;
static bool g_IsGLES2 = false;
// Forward Declarations // Forward Declarations
static void ImGui_ImplOpenGL3_InitPlatformInterface(); 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) 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. // 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 (GLAD_GL_ES_VERSION_3_0)
{
if (glsl_version == NULL)
glsl_version = "#version 100";
g_IsGLES = true;
}
else if (GLAD_GL_ES_VERSION_3_0)
{ {
if (glsl_version == NULL) if (glsl_version == NULL)
glsl_version = "#version 300 es"; glsl_version = "#version 300 es";
g_IsGLES = true; 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 else
{ {
if (glsl_version == NULL) if (glsl_version == NULL)
glsl_version = "#version 130"; glsl_version = "#version 130";
g_IsGLES = false; g_IsGLES = false;
g_IsGLES2 = false;
} }
if (!g_IsGLES) if (!g_IsGLES)
@ -179,11 +183,24 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
glUseProgram(g_ShaderHandle); glUseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0); glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][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
glBindVertexArray(g_VaoHandle); 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_ARRAY_BUFFER, g_VboHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); 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() bool ImGui_ImplOpenGL3_CreateFontsTexture()
@ -499,27 +529,30 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
glBufferData(GL_ARRAY_BUFFER, sizeof(ImDrawVert), nullptr, GL_STREAM_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(ImDrawVert), nullptr, GL_STREAM_DRAW);
glGenVertexArrays(1, &g_VaoHandle);
glBindVertexArray(g_VaoHandle);
glEnableVertexAttribArray(g_AttribLocationVtxPos); if (!g_IsGLES2)
glEnableVertexAttribArray(g_AttribLocationVtxUV); {
glEnableVertexAttribArray(g_AttribLocationVtxColor); glGenVertexArrays(1, &g_VaoHandle);
glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), glBindVertexArray(g_VaoHandle);
(GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), glEnableVertexAttribArray(g_AttribLocationVtxPos);
(GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); glEnableVertexAttribArray(g_AttribLocationVtxUV);
glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), glEnableVertexAttribArray(g_AttribLocationVtxColor);
(GLvoid*)IM_OFFSETOF(ImDrawVert, col)); 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));
}
ImGui_ImplOpenGL3_CreateFontsTexture(); ImGui_ImplOpenGL3_CreateFontsTexture();
// Restore modified GL state // Restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture); glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
#ifndef IMGUI_IMPL_OPENGL_ES2 if (!g_IsGLES2)
glBindVertexArray(last_vertex_array); glBindVertexArray(last_vertex_array);
#endif
return true; return true;
} }

View file

@ -466,7 +466,10 @@ void OpenGLHostDisplay::DestroyImGuiContext()
bool OpenGLHostDisplay::CreateResources() bool OpenGLHostDisplay::CreateResources()
{ {
static constexpr char fullscreen_quad_vertex_shader[] = R"( 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; uniform vec4 u_src_rect;
out vec2 v_tex0; out vec2 v_tex0;
@ -478,7 +481,7 @@ void main()
} }
)"; )";
static constexpr char display_fragment_shader[] = R"( static constexpr char display_fragment_shader[] = R"(
uniform sampler2D samp0; uniform sampler2D samp0;
in vec2 v_tex0; in vec2 v_tex0;
@ -490,7 +493,7 @@ void main()
} }
)"; )";
static constexpr char cursor_fragment_shader[] = R"( static constexpr char cursor_fragment_shader[] = R"(
uniform sampler2D samp0; uniform sampler2D samp0;
in vec2 v_tex0; in vec2 v_tex0;
@ -502,46 +505,114 @@ void main()
} }
)"; )";
if (!m_display_program.Compile(GetGLSLVersionHeader() + fullscreen_quad_vertex_shader, {}, if (!m_display_program.Compile(GetGLSLVersionHeader() + fullscreen_quad_vertex_shader, {},
GetGLSLVersionHeader() + display_fragment_shader) || GetGLSLVersionHeader() + display_fragment_shader) ||
!m_cursor_program.Compile(GetGLSLVersionHeader() + fullscreen_quad_vertex_shader, {}, !m_cursor_program.Compile(GetGLSLVersionHeader() + fullscreen_quad_vertex_shader, {},
GetGLSLVersionHeader() + cursor_fragment_shader)) GetGLSLVersionHeader() + cursor_fragment_shader))
{ {
Log_ErrorPrintf("Failed to compile display shaders"); Log_ErrorPrintf("Failed to compile display shaders");
return false; return false;
}
if (GetRenderAPI() != RenderAPI::OpenGLES)
{
m_display_program.BindFragData(0, "o_col0");
m_cursor_program.BindFragData(0, "o_col0");
}
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("u_src_rect");
m_display_program.RegisterUniform("samp0");
m_display_program.Uniform1i(1, 0);
m_cursor_program.Bind();
m_cursor_program.RegisterUniform("u_src_rect");
m_cursor_program.RegisterUniform("samp0");
m_cursor_program.Uniform1i(1, 0);
glGenVertexArrays(1, &m_display_vao);
// samplers
glGenSamplers(1, &m_display_nearest_sampler);
glSamplerParameteri(m_display_nearest_sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(m_display_nearest_sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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
if (GetRenderAPI() != RenderAPI::OpenGLES)
{ {
m_display_program.BindFragData(0, "o_col0"); static constexpr char fullscreen_quad_vertex_shader[] = R"(
m_cursor_program.BindFragData(0, "o_col0"); #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);
} }
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("u_src_rect");
m_display_program.RegisterUniform("samp0");
m_display_program.Uniform1i(1, 0);
m_cursor_program.Bind();
m_cursor_program.RegisterUniform("u_src_rect");
m_cursor_program.RegisterUniform("samp0");
m_cursor_program.Uniform1i(1, 0);
glGenVertexArrays(1, &m_display_vao);
// samplers
glGenSamplers(1, &m_display_nearest_sampler);
glSamplerParameteri(m_display_nearest_sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(m_display_nearest_sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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);
return true; return true;
} }
@ -561,11 +632,20 @@ void OpenGLHostDisplay::DestroyResources()
} }
if (m_display_vao != 0) if (m_display_vao != 0)
{
glDeleteVertexArrays(1, &m_display_vao); glDeleteVertexArrays(1, &m_display_vao);
m_display_vao = 0;
}
if (m_display_linear_sampler != 0) if (m_display_linear_sampler != 0)
{
glDeleteSamplers(1, &m_display_linear_sampler); glDeleteSamplers(1, &m_display_linear_sampler);
m_display_linear_sampler = 0;
}
if (m_display_nearest_sampler != 0) if (m_display_nearest_sampler != 0)
{
glDeleteSamplers(1, &m_display_nearest_sampler); glDeleteSamplers(1, &m_display_nearest_sampler);
m_display_nearest_sampler = 0;
}
m_cursor_program.Destroy(); m_cursor_program.Destroy();
m_display_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); 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, 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, 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) s32 texture_view_width, s32 texture_view_height, bool linear_filter)
@ -651,16 +755,25 @@ void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 heigh
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
m_display_program.Bind();
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))); 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); m_display_program.Bind();
glBindVertexArray(m_display_vao);
glDrawArrays(GL_TRIANGLES, 0, 3); if (!m_use_gles2_draw_path)
glBindSampler(0, 0); {
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));
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() void OpenGLHostDisplay::RenderSoftwareCursor()
@ -684,12 +797,22 @@ void OpenGLHostDisplay::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s3
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
m_cursor_program.Bind(); 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()); glBindTexture(GL_TEXTURE_2D, static_cast<OpenGLHostDisplayTexture*>(texture_handle)->GetGLID());
glBindSampler(0, m_display_linear_sampler);
glBindVertexArray(m_display_vao); if (!m_use_gles2_draw_path)
glDrawArrays(GL_TRIANGLES, 0, 3); {
glBindSampler(0, 0); 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 #ifndef LIBRETRO

View file

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