HostDisplay: Support rotation
This commit is contained in:
parent
537f833658
commit
e2b77d17d8
|
@ -40,6 +40,7 @@ public:
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
int RegisterUniform(const char* name);
|
int RegisterUniform(const char* name);
|
||||||
|
GLint GetUniformLocation(int index) const { return m_uniform_locations[index]; }
|
||||||
void Uniform1ui(int index, u32 x) const;
|
void Uniform1ui(int index, u32 x) const;
|
||||||
void Uniform2ui(int index, u32 x, u32 y) const;
|
void Uniform2ui(int index, u32 x, u32 y) const;
|
||||||
void Uniform3ui(int index, u32 x, u32 y, u32 z) const;
|
void Uniform3ui(int index, u32 x, u32 y, u32 z) const;
|
||||||
|
@ -97,6 +98,6 @@ private:
|
||||||
GLuint m_fragment_shader_id = 0;
|
GLuint m_fragment_shader_id = 0;
|
||||||
|
|
||||||
std::vector<GLint> m_uniform_locations;
|
std::vector<GLint> m_uniform_locations;
|
||||||
};
|
}; // namespace GL
|
||||||
|
|
||||||
} // namespace GL
|
} // namespace GL
|
|
@ -91,6 +91,11 @@ bool HostDisplay::GetHostRefreshRate(float* refresh_rate)
|
||||||
return g_host_interface->GetMainDisplayRefreshRate(refresh_rate);
|
return g_host_interface->GetMainDisplayRefreshRate(refresh_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HostDisplay::SetDisplayRotation(Rotation rotation)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void HostDisplay::SetSoftwareCursor(std::unique_ptr<HostDisplayTexture> texture, float scale /*= 1.0f*/)
|
void HostDisplay::SetSoftwareCursor(std::unique_ptr<HostDisplayTexture> texture, float scale /*= 1.0f*/)
|
||||||
{
|
{
|
||||||
m_cursor_texture = std::move(texture);
|
m_cursor_texture = std::move(texture);
|
||||||
|
|
|
@ -52,6 +52,15 @@ public:
|
||||||
RightOrBottom
|
RightOrBottom
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class Rotation
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
R90Degrees,
|
||||||
|
R180Degrees,
|
||||||
|
R270Degrees,
|
||||||
|
Count
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~HostDisplay();
|
virtual ~HostDisplay();
|
||||||
|
|
||||||
ALWAYS_INLINE s32 GetWindowWidth() const { return static_cast<s32>(m_window_info.surface_width); }
|
ALWAYS_INLINE s32 GetWindowWidth() const { return static_cast<s32>(m_window_info.surface_width); }
|
||||||
|
@ -182,6 +191,7 @@ public:
|
||||||
virtual bool SetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, const void* buffer, u32 pitch);
|
virtual bool SetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, const void* buffer, u32 pitch);
|
||||||
|
|
||||||
virtual bool GetHostRefreshRate(float* refresh_rate);
|
virtual bool GetHostRefreshRate(float* refresh_rate);
|
||||||
|
virtual bool SetDisplayRotation(Rotation rotation);
|
||||||
|
|
||||||
void SetDisplayLinearFiltering(bool enabled) { m_display_linear_filtering = enabled; }
|
void SetDisplayLinearFiltering(bool enabled) { m_display_linear_filtering = enabled; }
|
||||||
void SetDisplayTopMargin(s32 height) { m_display_top_margin = height; }
|
void SetDisplayTopMargin(s32 height) { m_display_top_margin = height; }
|
||||||
|
@ -260,6 +270,7 @@ protected:
|
||||||
|
|
||||||
s32 m_display_top_margin = 0;
|
s32 m_display_top_margin = 0;
|
||||||
Alignment m_display_alignment = Alignment::Center;
|
Alignment m_display_alignment = Alignment::Center;
|
||||||
|
Rotation m_display_rotation = Rotation::None;
|
||||||
|
|
||||||
std::unique_ptr<HostDisplayTexture> m_cursor_texture;
|
std::unique_ptr<HostDisplayTexture> m_cursor_texture;
|
||||||
float m_cursor_texture_scale = 1.0f;
|
float m_cursor_texture_scale = 1.0f;
|
||||||
|
|
|
@ -185,6 +185,77 @@ void OpenGLHostDisplay::UpdateDisplayPixelsTextureFilter()
|
||||||
m_display_texture_is_linear_filtered = m_display_linear_filtering;
|
m_display_texture_is_linear_filtered = m_display_linear_filtering;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OpenGLHostDisplay::SetDisplayRotation(Rotation rotation)
|
||||||
|
{
|
||||||
|
m_display_rotation = rotation;
|
||||||
|
UpdateDisplayRotationFramebuffer();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLHostDisplay::UpdateDisplayRotationFramebuffer()
|
||||||
|
{
|
||||||
|
m_window_info.surface_width = m_gl_context->GetSurfaceWidth();
|
||||||
|
m_window_info.surface_height = m_gl_context->GetSurfaceHeight();
|
||||||
|
|
||||||
|
if (m_display_rotation_framebuffer_fbo != 0)
|
||||||
|
{
|
||||||
|
glDeleteFramebuffers(1, &m_display_rotation_framebuffer_fbo);
|
||||||
|
m_display_rotation_framebuffer_fbo = 0;
|
||||||
|
glDeleteTextures(1, &m_display_rotation_framebuffer_texture);
|
||||||
|
m_display_rotation_framebuffer_texture = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_display_rotation != Rotation::None)
|
||||||
|
{
|
||||||
|
if (m_display_rotation_framebuffer_texture == 0)
|
||||||
|
glGenTextures(1, &m_display_rotation_framebuffer_texture);
|
||||||
|
if (m_display_rotation_framebuffer_fbo == 0)
|
||||||
|
glGenFramebuffers(1, &m_display_rotation_framebuffer_fbo);
|
||||||
|
|
||||||
|
if (m_display_rotation == Rotation::R90Degrees || m_display_rotation == Rotation::R270Degrees)
|
||||||
|
std::swap(m_window_info.surface_width, m_window_info.surface_height);
|
||||||
|
|
||||||
|
GLint old_texture;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_display_rotation_framebuffer_texture);
|
||||||
|
|
||||||
|
if (GLAD_GL_ARB_texture_storage || GLAD_GL_ES_VERSION_3_1)
|
||||||
|
{
|
||||||
|
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, m_window_info.surface_width, m_window_info.surface_height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_window_info.surface_width, m_window_info.surface_height, 0, GL_RGBA,
|
||||||
|
GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
|
||||||
|
|
||||||
|
const GLenum framebuffer_binding = m_use_gles2_draw_path ? GL_FRAMEBUFFER : GL_DRAW_FRAMEBUFFER;
|
||||||
|
GLint old_framebuffer;
|
||||||
|
glGetIntegerv(m_use_gles2_draw_path ? GL_FRAMEBUFFER_BINDING : GL_DRAW_FRAMEBUFFER_BINDING, &old_framebuffer);
|
||||||
|
|
||||||
|
glBindFramebuffer(framebuffer_binding, m_display_rotation_framebuffer_fbo);
|
||||||
|
glFramebufferTexture2D(framebuffer_binding, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||||
|
m_display_rotation_framebuffer_texture, 0);
|
||||||
|
Assert(glCheckFramebufferStatus(framebuffer_binding) == GL_FRAMEBUFFER_COMPLETE);
|
||||||
|
|
||||||
|
glBindFramebuffer(framebuffer_binding, old_framebuffer);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, old_texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::GetCurrentContext())
|
||||||
|
{
|
||||||
|
ImGui::GetIO().DisplaySize =
|
||||||
|
ImVec2(static_cast<float>(m_window_info.surface_width), static_cast<float>(m_window_info.surface_height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool OpenGLHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const
|
bool OpenGLHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const
|
||||||
{
|
{
|
||||||
return (std::get<0>(s_display_pixel_format_mapping[static_cast<u32>(format)]) != static_cast<GLenum>(0));
|
return (std::get<0>(s_display_pixel_format_mapping[static_cast<u32>(format)]) != static_cast<GLenum>(0));
|
||||||
|
@ -417,7 +488,7 @@ bool OpenGLHostDisplay::InitializeRenderDevice(std::string_view shader_cache_dir
|
||||||
glDebugMessageCallback(GLDebugCallback, nullptr);
|
glDebugMessageCallback(GLDebugCallback, nullptr);
|
||||||
|
|
||||||
glEnable(GL_DEBUG_OUTPUT);
|
glEnable(GL_DEBUG_OUTPUT);
|
||||||
// glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CreateResources())
|
if (!CreateResources())
|
||||||
|
@ -476,6 +547,7 @@ bool OpenGLHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateDisplayRotationFramebuffer();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,6 +565,8 @@ void OpenGLHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_
|
||||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
||||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateDisplayRotationFramebuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLHostDisplay::SupportsFullscreen() const
|
bool OpenGLHostDisplay::SupportsFullscreen() const
|
||||||
|
@ -544,12 +618,17 @@ bool OpenGLHostDisplay::CreateResources()
|
||||||
{
|
{
|
||||||
static constexpr char fullscreen_quad_vertex_shader[] = R"(
|
static constexpr char fullscreen_quad_vertex_shader[] = R"(
|
||||||
uniform vec4 u_src_rect;
|
uniform vec4 u_src_rect;
|
||||||
|
uniform mat2 u_rotation_matrix;
|
||||||
out vec2 v_tex0;
|
out vec2 v_tex0;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec2 pos = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
|
vec2 pos = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
|
||||||
v_tex0 = u_src_rect.xy + pos * u_src_rect.zw;
|
v_tex0 = (u_src_rect.xy + pos * u_src_rect.zw);
|
||||||
|
|
||||||
|
vec2 center = vec2(0.5, 0.5);
|
||||||
|
v_tex0 = center + (u_rotation_matrix * (v_tex0 - center));
|
||||||
|
|
||||||
gl_Position = vec4(pos * vec2(2.0f, -2.0f) + vec2(-1.0f, 1.0f), 0.0f, 1.0f);
|
gl_Position = vec4(pos * vec2(2.0f, -2.0f) + vec2(-1.0f, 1.0f), 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
@ -601,12 +680,14 @@ void main()
|
||||||
|
|
||||||
m_display_program.Bind();
|
m_display_program.Bind();
|
||||||
m_display_program.RegisterUniform("u_src_rect");
|
m_display_program.RegisterUniform("u_src_rect");
|
||||||
|
m_display_program.RegisterUniform("u_rotation_matrix");
|
||||||
m_display_program.RegisterUniform("samp0");
|
m_display_program.RegisterUniform("samp0");
|
||||||
m_display_program.Uniform1i(1, 0);
|
m_display_program.Uniform1i(2, 0);
|
||||||
m_cursor_program.Bind();
|
m_cursor_program.Bind();
|
||||||
m_cursor_program.RegisterUniform("u_src_rect");
|
m_cursor_program.RegisterUniform("u_src_rect");
|
||||||
|
m_cursor_program.RegisterUniform("u_rotation_matrix");
|
||||||
m_cursor_program.RegisterUniform("samp0");
|
m_cursor_program.RegisterUniform("samp0");
|
||||||
m_cursor_program.Uniform1i(1, 0);
|
m_cursor_program.Uniform1i(2, 0);
|
||||||
|
|
||||||
glGenVertexArrays(1, &m_display_vao);
|
glGenVertexArrays(1, &m_display_vao);
|
||||||
|
|
||||||
|
@ -733,7 +814,7 @@ bool OpenGLHostDisplay::Render()
|
||||||
}
|
}
|
||||||
|
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_display_rotation_framebuffer_fbo);
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
@ -744,6 +825,12 @@ bool OpenGLHostDisplay::Render()
|
||||||
|
|
||||||
RenderSoftwareCursor();
|
RenderSoftwareCursor();
|
||||||
|
|
||||||
|
if (m_display_rotation_framebuffer_fbo != 0)
|
||||||
|
{
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
RenderRotatedFramebuffer();
|
||||||
|
}
|
||||||
|
|
||||||
m_gl_context->SwapBuffers();
|
m_gl_context->SwapBuffers();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -775,6 +862,13 @@ 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 const std::array<std::array<float, 4>, static_cast<u32>(HostDisplay::Rotation::Count)> s_rotation_matrices = {{
|
||||||
|
{{1.0f, 0.0f, 0.0f, 1.0f}},
|
||||||
|
{{0.0f, 1.0f, 1.0f, 0.0f}},
|
||||||
|
{{-1.0f, 0.0f, 0.0f, 1.0f}},
|
||||||
|
{{0.0f, -1.0f, -1.0f, 0.0f}},
|
||||||
|
}};
|
||||||
|
|
||||||
static void DrawFullscreenQuadES2(s32 tex_view_x, s32 tex_view_y, s32 tex_view_width, s32 tex_view_height,
|
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)
|
s32 tex_width, s32 tex_height)
|
||||||
{
|
{
|
||||||
|
@ -822,6 +916,8 @@ void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 heigh
|
||||||
(static_cast<float>(texture_view_y) + (position_adjust * flip_adjust)) / static_cast<float>(texture_height),
|
(static_cast<float>(texture_view_y) + (position_adjust * flip_adjust)) / static_cast<float>(texture_height),
|
||||||
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture_width),
|
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture_width),
|
||||||
(static_cast<float>(texture_view_height) - (size_adjust * flip_adjust)) / static_cast<float>(texture_height));
|
(static_cast<float>(texture_view_height) - (size_adjust * flip_adjust)) / static_cast<float>(texture_height));
|
||||||
|
glUniformMatrix2fv(m_display_program.GetUniformLocation(1), 1, GL_TRUE,
|
||||||
|
s_rotation_matrices[static_cast<u32>(HostDisplay::Rotation::None)].data());
|
||||||
glBindSampler(0, linear_filter ? m_display_linear_sampler : m_display_nearest_sampler);
|
glBindSampler(0, linear_filter ? m_display_linear_sampler : m_display_nearest_sampler);
|
||||||
glBindVertexArray(m_display_vao);
|
glBindVertexArray(m_display_vao);
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||||
|
@ -837,6 +933,30 @@ void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 heigh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLHostDisplay::RenderRotatedFramebuffer()
|
||||||
|
{
|
||||||
|
const u32 width = m_gl_context->GetSurfaceWidth();
|
||||||
|
const u32 height = m_gl_context->GetSurfaceHeight();
|
||||||
|
|
||||||
|
glViewport(0, 0, width, height);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
m_display_program.Bind();
|
||||||
|
m_display_program.Uniform4f(0, 0.0f, 0.0f, 1.0f, 1.0f);
|
||||||
|
glUniformMatrix2fv(m_display_program.GetUniformLocation(1), 1, GL_TRUE,
|
||||||
|
s_rotation_matrices[static_cast<u32>(m_display_rotation)].data());
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_display_rotation_framebuffer_texture);
|
||||||
|
|
||||||
|
glBindVertexArray(m_display_vao);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLHostDisplay::RenderSoftwareCursor()
|
void OpenGLHostDisplay::RenderSoftwareCursor()
|
||||||
{
|
{
|
||||||
if (!HasSoftwareCursor())
|
if (!HasSoftwareCursor())
|
||||||
|
|
|
@ -48,6 +48,8 @@ public:
|
||||||
|
|
||||||
virtual bool SetPostProcessingChain(const std::string_view& config) override;
|
virtual bool SetPostProcessingChain(const std::string_view& config) override;
|
||||||
|
|
||||||
|
bool SetDisplayRotation(Rotation rotation) override;
|
||||||
|
|
||||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
HostDisplayPixelFormat format, const void* data, u32 data_stride,
|
HostDisplayPixelFormat format, const void* data, u32 data_stride,
|
||||||
bool dynamic = false) override;
|
bool dynamic = false) override;
|
||||||
|
@ -78,6 +80,8 @@ protected:
|
||||||
|
|
||||||
void BindDisplayPixelsTexture();
|
void BindDisplayPixelsTexture();
|
||||||
void UpdateDisplayPixelsTextureFilter();
|
void UpdateDisplayPixelsTextureFilter();
|
||||||
|
void UpdateDisplayRotationFramebuffer();
|
||||||
|
void RenderRotatedFramebuffer();
|
||||||
|
|
||||||
void RenderDisplay();
|
void RenderDisplay();
|
||||||
void RenderImGui();
|
void RenderImGui();
|
||||||
|
@ -115,6 +119,9 @@ protected:
|
||||||
u32 m_display_pixels_texture_pbo_map_size = 0;
|
u32 m_display_pixels_texture_pbo_map_size = 0;
|
||||||
std::vector<u8> m_gles_pixels_repack_buffer;
|
std::vector<u8> m_gles_pixels_repack_buffer;
|
||||||
|
|
||||||
|
GLuint m_display_rotation_framebuffer_texture = 0;
|
||||||
|
GLuint m_display_rotation_framebuffer_fbo = 0;
|
||||||
|
|
||||||
PostProcessingChain m_post_processing_chain;
|
PostProcessingChain m_post_processing_chain;
|
||||||
GL::Texture m_post_processing_input_texture;
|
GL::Texture m_post_processing_input_texture;
|
||||||
std::unique_ptr<GL::StreamBuffer> m_post_processing_ubo;
|
std::unique_ptr<GL::StreamBuffer> m_post_processing_ubo;
|
||||||
|
|
Loading…
Reference in New Issue