@@ -16,7 +16,7 @@
#include "Common/Assert.h"
#include "Common/Atomic.h"
#include "Common/CommonTypes.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLContext.h"
#include "Common/GL/GLUtil.h"
#include "Common/Logging/LogManager.h"
#include "Common/MathUtil.h"
@@ -353,9 +353,10 @@ static void InitDriverInfo()
}

// Init functions
Renderer::Renderer()
: ::Renderer(static_cast<int>(std::max(GLInterface->GetBackBufferWidth(), 1u)),
static_cast<int>(std::max(GLInterface->GetBackBufferHeight(), 1u)))
Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context)
: ::Renderer(static_cast<int>(std::max(main_gl_context->GetBackBufferWidth(), 1u)),
static_cast<int>(std::max(main_gl_context->GetBackBufferHeight(), 1u))),
m_main_gl_context(std::move(main_gl_context))
{
bool bSuccess = true;

@@ -365,7 +366,7 @@ Renderer::Renderer()

InitDriverInfo();

if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
if (!m_main_gl_context->IsGLES())
{
if (!GLExtensions::Supports("GL_ARB_framebuffer_object"))
{
@@ -500,7 +501,7 @@ Renderer::Renderer()
g_Config.backend_info.bSupportsBPTCTextures =
GLExtensions::Supports("GL_ARB_texture_compression_bptc");

if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
if (m_main_gl_context->IsGLES())
{
g_ogl_config.SupportedESPointSize =
GLExtensions::Supports("GL_OES_geometry_point_size") ?
@@ -730,10 +731,9 @@ Renderer::Renderer()

if (!g_ogl_config.bSupportsGLBufferStorage && !g_ogl_config.bSupportsGLPinnedMemory)
{
OSD::AddMessage(
StringFromFormat("Your OpenGL driver does not support %s_buffer_storage.",
GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3 ? "EXT" : "ARB"),
60000);
OSD::AddMessage(StringFromFormat("Your OpenGL driver does not support %s_buffer_storage.",
m_main_gl_context->IsGLES() ? "EXT" : "ARB"),
60000);
OSD::AddMessage("This device's performance will be terrible.", 60000);
OSD::AddMessage("Please ask your device vendor for an updated OpenGL driver.", 60000);
}
@@ -761,7 +761,7 @@ Renderer::Renderer()
// Handle VSync on/off
s_vsync = g_ActiveConfig.IsVSync();
if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
GLInterface->SwapInterval(s_vsync);
m_main_gl_context->SwapInterval(s_vsync);

// Because of the fixed framebuffer size we need to disable the resolution
// options while running
@@ -796,7 +796,7 @@ Renderer::Renderer()
glClearDepthf(1.0f);

if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart)
GLUtil::EnablePrimitiveRestart();
GLUtil::EnablePrimitiveRestart(m_main_gl_context.get());
IndexGenerator::Init();

UpdateActiveConfig();
@@ -805,6 +805,11 @@ Renderer::Renderer()

Renderer::~Renderer() = default;

bool Renderer::IsHeadless() const
{
return m_main_gl_context->IsHeadless();
}

void Renderer::Shutdown()
{
::Renderer::Shutdown();
@@ -1044,7 +1049,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)

std::unique_ptr<u32[]> colorMap(new u32[targetPixelRcWidth * targetPixelRcHeight]);

if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
if (IsGLES())
// XXX: Swap colours
glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth,
targetPixelRcHeight, GL_RGBA, GL_UNSIGNED_BYTE, colorMap.get());
@@ -1351,7 +1356,7 @@ void Renderer::ApplyBlendingState(const BlendingState state, bool force)
GL_XOR, GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE,
GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET};

if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL)
if (IsGLES())
{
// Logic ops aren't available in GLES3
}
@@ -1421,7 +1426,7 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
OSD::DrawMessages();

// Swap the back and front buffers, presenting the image.
GLInterface->Swap();
m_main_gl_context->Swap();
}
else
{
@@ -1466,7 +1471,7 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
{
s_vsync = g_ActiveConfig.IsVSync();
if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
GLInterface->SwapInterval(s_vsync);
m_main_gl_context->SwapInterval(s_vsync);
}

// Clean out old stuff from caches. It's not worth it to clean out the shader caches.
@@ -1500,24 +1505,22 @@ void Renderer::CheckForSurfaceChange()
if (!m_surface_changed.TestAndClear())
return;

m_surface_handle = m_new_surface_handle;
m_main_gl_context->UpdateSurface(m_new_surface_handle);
m_new_surface_handle = nullptr;
GLInterface->UpdateHandle(m_surface_handle);
GLInterface->UpdateSurface();

// With a surface change, the window likely has new dimensions.
m_backbuffer_width = GLInterface->GetBackBufferWidth();
m_backbuffer_height = GLInterface->GetBackBufferHeight();
m_backbuffer_width = m_main_gl_context->GetBackBufferWidth();
m_backbuffer_height = m_main_gl_context->GetBackBufferHeight();
}

void Renderer::CheckForSurfaceResize()
{
if (!m_surface_resized.TestAndClear())
return;

GLInterface->Update();
m_backbuffer_width = m_new_backbuffer_width;
m_backbuffer_height = m_new_backbuffer_height;
m_main_gl_context->Update();
m_backbuffer_width = m_main_gl_context->GetBackBufferWidth();
m_backbuffer_height = m_main_gl_context->GetBackBufferHeight();
}

void Renderer::DrawEFB(GLuint framebuffer, const TargetRectangle& target_rc,
@@ -1538,7 +1541,7 @@ void Renderer::ResetAPIState()
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_BLEND);
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
if (!IsGLES())
glDisable(GL_COLOR_LOGIC_OP);
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
{
@@ -1717,4 +1720,4 @@ std::unique_ptr<VideoCommon::AsyncShaderCompiler> Renderer::CreateAsyncShaderCom
{
return std::make_unique<SharedContextAsyncShaderCompiler>();
}
}
} // namespace OGL
@@ -7,7 +7,8 @@
#include <array>
#include <string>

#include "Common/GL/GLUtil.h"
#include "Common/GL/GLContext.h"
#include "Common/GL/GLExtensions/GLExtensions.h"
#include "VideoCommon/RenderBase.h"

struct XFBSourceBase;
@@ -81,9 +82,11 @@ extern VideoConfig g_ogl_config;
class Renderer : public ::Renderer
{
public:
Renderer();
Renderer(std::unique_ptr<GLContext> main_gl_context);
~Renderer() override;

bool IsHeadless() const override;

void Init();
void Shutdown() override;

@@ -141,6 +144,10 @@ class Renderer : public ::Renderer

std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler() override;

// Only call methods from this on the GPU thread.
GLContext* GetMainGLContext() const { return m_main_gl_context.get(); }
bool IsGLES() const { return m_main_gl_context->IsGLES(); }

private:
void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc,
const TargetRectangle& targetPixelRc, const void* data);
@@ -159,10 +166,11 @@ class Renderer : public ::Renderer
void ApplyDepthState(const DepthState state, bool force = false);
void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size);

std::unique_ptr<GLContext> m_main_gl_context;
std::array<const AbstractTexture*, 8> m_bound_textures{};
const OGLPipeline* m_graphics_pipeline = nullptr;
RasterizationState m_current_rasterization_state = {};
DepthState m_current_depth_state = {};
BlendingState m_current_blend_state = {};
};
}
} // namespace OGL
@@ -3,11 +3,11 @@
// Refer to the license.txt file included.

#include "VideoBackends/OGL/SamplerCache.h"
#include "VideoBackends/OGL/Render.h"

#include <memory>

#include "Common/CommonTypes.h"
#include "Common/GL/GLInterfaceBase.h"
#include "VideoCommon/SamplerCommon.h"
#include "VideoCommon/VideoConfig.h"

@@ -99,7 +99,7 @@ void SamplerCache::SetParameters(GLuint sampler_id, const SamplerState& params)
glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, params.min_lod / 16.f);
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, params.max_lod / 16.f);

if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
if (!static_cast<Renderer*>(g_renderer.get())->IsGLES())
glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, params.lod_bias / 256.f);

if (params.anisotropic_filtering && g_ogl_config.bSupportsAniso)
@@ -117,4 +117,4 @@ void SamplerCache::Clear()
p.second = 0;
m_cache.clear();
}
}
} // namespace OGL
@@ -10,7 +10,6 @@
#include <vector>

#include "Common/Assert.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"

@@ -7,11 +7,13 @@
#include <string>
#include "VideoCommon/VideoBackendBase.h"

class GLContext;

namespace OGL
{
class VideoBackend : public VideoBackendBase
{
bool Initialize(void*) override;
bool Initialize(const WindowSystemInfo& wsi) override;
void Shutdown() override;

std::string GetName() const override;
@@ -20,7 +22,7 @@ class VideoBackend : public VideoBackendBase
void InitBackendInfo() override;

private:
bool InitializeGLExtensions();
bool InitializeGLExtensions(GLContext* context);
bool FillBackendInfo();
};
}
} // namespace OGL
@@ -39,10 +39,12 @@ Make AA apply instantly during gameplay if possible
#include <vector>

#include "Common/Common.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLContext.h"
#include "Common/GL/GLUtil.h"
#include "Common/MsgHandler.h"

#include "Core/Config/GraphicsSettings.h"

#include "VideoBackends/OGL/BoundingBox.h"
#include "VideoBackends/OGL/PerfQuery.h"
#include "VideoBackends/OGL/ProgramShaderCache.h"
@@ -66,7 +68,7 @@ std::string VideoBackend::GetName() const

std::string VideoBackend::GetDisplayName() const
{
if (GLInterface != nullptr && GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
if (g_renderer && static_cast<Renderer*>(g_renderer.get())->IsGLES())
return _trans("OpenGL ES");
else
return _trans("OpenGL");
@@ -108,10 +110,10 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.AAModes = {1, 2, 4, 8};
}

bool VideoBackend::InitializeGLExtensions()
bool VideoBackend::InitializeGLExtensions(GLContext* context)
{
// Init extension support.
if (!GLExtensions::Init())
if (!GLExtensions::Init(context))
{
// OpenGL 2.0 is required for all shader based drawings. There is no way to get this by
// extensions
@@ -157,20 +159,20 @@ bool VideoBackend::FillBackendInfo()
return true;
}

bool VideoBackend::Initialize(void* window_handle)
bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
{
InitializeShared();

GLUtil::InitInterface();
GLInterface->SetMode(GLInterfaceMode::MODE_DETECT);
if (!GLInterface->Create(window_handle, g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer))
std::unique_ptr<GLContext> main_gl_context =
GLContext::Create(wsi, g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer, true, false,
Config::Get(Config::GFX_PREFER_GLES));
if (!main_gl_context)
return false;

GLInterface->MakeCurrent();
if (!InitializeGLExtensions() || !FillBackendInfo())
if (!InitializeGLExtensions(main_gl_context.get()) || !FillBackendInfo())
return false;

g_renderer = std::make_unique<Renderer>();
g_renderer = std::make_unique<Renderer>(std::move(main_gl_context));
g_vertex_manager = std::make_unique<VertexManager>();
g_perf_query = GetPerfQuery();
ProgramShaderCache::Init();
@@ -196,9 +198,6 @@ void VideoBackend::Shutdown()
g_perf_query.reset();
g_vertex_manager.reset();
g_renderer.reset();
GLInterface->ClearCurrent();
GLInterface->Shutdown();
GLInterface.reset();
ShutdownShared();
}
}
} // namespace OGL
@@ -4,52 +4,51 @@

#include <memory>

#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLContext.h"
#include "Common/GL/GLUtil.h"
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"

#include "VideoBackends/Software/SWOGLWindow.h"
#include "VideoBackends/Software/SWTexture.h"

std::unique_ptr<SWOGLWindow> SWOGLWindow::s_instance;
SWOGLWindow::SWOGLWindow() = default;
SWOGLWindow::~SWOGLWindow() = default;

void SWOGLWindow::Init(void* window_handle)
std::unique_ptr<SWOGLWindow> SWOGLWindow::Create(const WindowSystemInfo& wsi)
{
GLUtil::InitInterface();
GLInterface->SetMode(GLInterfaceMode::MODE_DETECT);
if (!GLInterface->Create(window_handle))
std::unique_ptr<SWOGLWindow> window = std::unique_ptr<SWOGLWindow>(new SWOGLWindow());
if (!window->Initialize(wsi))
{
ERROR_LOG(VIDEO, "GLInterface::Create failed.");
PanicAlert("Failed to create OpenGL window");
return nullptr;
}

s_instance.reset(new SWOGLWindow());
return window;
}

void SWOGLWindow::Shutdown()
bool SWOGLWindow::IsHeadless() const
{
GLInterface->Shutdown();
GLInterface.reset();

s_instance.reset();
return m_gl_context->IsHeadless();
}

void SWOGLWindow::Prepare()
bool SWOGLWindow::Initialize(const WindowSystemInfo& wsi)
{
if (m_init)
return;
m_init = true;
m_gl_context = GLContext::Create(wsi);
if (!m_gl_context)
return false;

// Init extension support.
if (!GLExtensions::Init())
if (!GLExtensions::Init(m_gl_context.get()))
{
ERROR_LOG(VIDEO, "GLExtensions::Init failed!Does your video card support OpenGL 2.0?");
return;
return false;
}
else if (GLExtensions::Version() < 310)
{
ERROR_LOG(VIDEO, "OpenGL Version %d detected, but at least 3.1 is required.",
GLExtensions::Version());
return;
return false;
}

std::string frag_shader = "in vec2 TexCoord;\n"
@@ -66,10 +65,9 @@ void SWOGLWindow::Prepare()
" TexCoord = vec2(rawpos.x, -rawpos.y);\n"
"}\n";

std::string header = GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL ?
"#version 140\n" :
"#version 300 es\n"
"precision highp float;\n";
std::string header = m_gl_context->IsGLES() ? "#version 300 es\n"
"precision highp float;\n" :
"#version 140\n";

m_image_program = GLUtil::CompileProgram(header + vertex_shader, header + frag_shader);

@@ -83,6 +81,7 @@ void SWOGLWindow::Prepare()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glGenVertexArrays(1, &m_image_vao);
return true;
}

void SWOGLWindow::PrintText(const std::string& text, int x, int y, u32 color)
@@ -93,10 +92,10 @@ void SWOGLWindow::PrintText(const std::string& text, int x, int y, u32 color)
void SWOGLWindow::ShowImage(AbstractTexture* image, const EFBRectangle& xfb_region)
{
SW::SWTexture* sw_image = static_cast<SW::SWTexture*>(image);
GLInterface->Update(); // just updates the render window position and the backbuffer size
m_gl_context->Update(); // just updates the render window position and the backbuffer size

GLsizei glWidth = (GLsizei)GLInterface->GetBackBufferWidth();
GLsizei glHeight = (GLsizei)GLInterface->GetBackBufferHeight();
GLsizei glWidth = (GLsizei)m_gl_context->GetBackBufferWidth();
GLsizei glHeight = (GLsizei)m_gl_context->GetBackBufferHeight();

glViewport(0, 0, glWidth, glHeight);

@@ -123,10 +122,5 @@ void SWOGLWindow::ShowImage(AbstractTexture* image, const EFBRectangle& xfb_regi
// }
m_text.clear();

GLInterface->Swap();
}

int SWOGLWindow::PeekMessages()
{
return GLInterface->PeekMessages();
m_gl_context->Swap();
}
@@ -11,27 +11,32 @@
#include "Common/CommonTypes.h"
#include "VideoCommon/VideoCommon.h"

class GLContext;

class AbstractTexture;
struct WindowSystemInfo;

class SWOGLWindow
{
public:
static void Init(void* window_handle);
static void Shutdown();
void Prepare();
~SWOGLWindow();

GLContext* GetContext() const { return m_gl_context.get(); }
bool IsHeadless() const;

// Will be printed on the *next* image
void PrintText(const std::string& text, int x, int y, u32 color);

// Image to show, will be swapped immediately
void ShowImage(AbstractTexture* image, const EFBRectangle& xfb_region);

int PeekMessages();

static std::unique_ptr<SWOGLWindow> s_instance;
static std::unique_ptr<SWOGLWindow> Create(const WindowSystemInfo& wsi);

private:
SWOGLWindow() {}
SWOGLWindow();

bool Initialize(const WindowSystemInfo& wsi);

struct TextData
{
std::string text;
@@ -40,7 +45,9 @@ class SWOGLWindow
};
std::vector<TextData> m_text;

bool m_init{false};
u32 m_image_program = 0;
u32 m_image_texture = 0;
u32 m_image_vao = 0;

u32 m_image_program, m_image_texture, m_image_vao;
std::unique_ptr<GLContext> m_gl_context;
};
@@ -7,6 +7,7 @@
#include <string>

#include "Common/CommonTypes.h"
#include "Common/GL/GLContext.h"

#include "Core/Config/GraphicsSettings.h"
#include "Core/HW/Memmap.h"
@@ -23,11 +24,17 @@
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"

SWRenderer::SWRenderer()
: ::Renderer(static_cast<int>(MAX_XFB_WIDTH), static_cast<int>(MAX_XFB_HEIGHT))
SWRenderer::SWRenderer(std::unique_ptr<SWOGLWindow> window)
: ::Renderer(static_cast<int>(MAX_XFB_WIDTH), static_cast<int>(MAX_XFB_HEIGHT)),
m_window(std::move(window))
{
}

bool SWRenderer::IsHeadless() const
{
return m_window->IsHeadless();
}

std::unique_ptr<AbstractTexture> SWRenderer::CreateTexture(const TextureConfig& config)
{
return std::make_unique<SW::SWTexture>(config);
@@ -49,7 +56,7 @@ SWRenderer::CreateFramebuffer(const AbstractTexture* color_attachment,

void SWRenderer::RenderText(const std::string& pstr, int left, int top, u32 color)
{
SWOGLWindow::s_instance->PrintText(pstr, left, top, color);
m_window->PrintText(pstr, left, top, color);
}

class SWShader final : public AbstractShader
@@ -94,7 +101,7 @@ void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_regi
if (!IsHeadless())
{
DrawDebugText();
SWOGLWindow::s_instance->ShowImage(texture, xfb_region);
m_window->ShowImage(texture, xfb_region);
}

UpdateActiveConfig();
@@ -4,14 +4,20 @@

#pragma once

#include <memory>

#include "Common/CommonTypes.h"

#include "VideoCommon/RenderBase.h"

class SWOGLWindow;

class SWRenderer : public Renderer
{
public:
SWRenderer();
SWRenderer(std::unique_ptr<SWOGLWindow> window);

bool IsHeadless() const override;

std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
std::unique_ptr<AbstractStagingTexture>
@@ -40,4 +46,7 @@ class SWRenderer : public Renderer
u32 color, u32 z) override;

void ReinterpretPixelData(unsigned int convtype) override {}

private:
std::unique_ptr<SWOGLWindow> m_window;
};
@@ -9,7 +9,7 @@

#include "Common/Common.h"
#include "Common/CommonTypes.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/GL/GLContext.h"

#include "VideoBackends/Software/Clipper.h"
#include "VideoBackends/Software/DebugUtil.h"
@@ -78,20 +78,19 @@ void VideoSoftware::InitBackendInfo()
g_Config.backend_info.AAModes = {1};
}

bool VideoSoftware::Initialize(void* window_handle)
bool VideoSoftware::Initialize(const WindowSystemInfo& wsi)
{
InitializeShared();

SWOGLWindow::Init(window_handle);
std::unique_ptr<SWOGLWindow> window = SWOGLWindow::Create(wsi);
if (!window)
return false;

Clipper::Init();
Rasterizer::Init();
DebugUtil::Init();

GLInterface->MakeCurrent();
SWOGLWindow::s_instance->Prepare();

g_renderer = std::make_unique<SWRenderer>();
g_renderer = std::make_unique<SWRenderer>(std::move(window));
g_vertex_manager = std::make_unique<SWVertexLoader>();
g_perf_query = std::make_unique<PerfQuery>();
g_texture_cache = std::make_unique<TextureCache>();
@@ -108,12 +107,11 @@ void VideoSoftware::Shutdown()
g_renderer->Shutdown();

DebugUtil::Shutdown();
SWOGLWindow::Shutdown();
g_framebuffer_manager.reset();
g_texture_cache.reset();
g_perf_query.reset();
g_vertex_manager.reset();
g_renderer.reset();
ShutdownShared();
}
}
} // namespace SW
@@ -11,12 +11,12 @@ namespace SW
{
class VideoSoftware : public VideoBackendBase
{
bool Initialize(void* window_handle) override;
bool Initialize(const WindowSystemInfo& wsi) override;
void Shutdown() override;

std::string GetName() const override;
std::string GetDisplayName() const override;

void InitBackendInfo() override;
};
}
} // namespace SW
@@ -70,6 +70,11 @@ Renderer* Renderer::GetInstance()
return static_cast<Renderer*>(g_renderer.get());
}

bool Renderer::IsHeadless() const
{
return m_swap_chain == nullptr;
}

bool Renderer::Initialize()
{
BindEFBToStateTracker();
@@ -860,50 +865,20 @@ void Renderer::BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_r

void Renderer::CheckForSurfaceChange()
{
if (!m_surface_changed.TestAndClear())
if (!m_surface_changed.TestAndClear() || !m_swap_chain)
return;

m_surface_handle = m_new_surface_handle;
m_new_surface_handle = nullptr;

// Submit the current draws up until rendering the XFB.
g_command_buffer_mgr->ExecuteCommandBuffer(false, false);
g_command_buffer_mgr->WaitForGPUIdle();

// Clear the present failed flag, since we don't want to resize after recreating.
g_command_buffer_mgr->CheckLastPresentFail();

// Did we previously have a swap chain?
if (m_swap_chain)
{
if (!m_surface_handle)
{
// If there is no surface now, destroy the swap chain.
m_swap_chain.reset();
}
else
{
// Recreate the surface. If this fails we're in trouble.
if (!m_swap_chain->RecreateSurface(m_surface_handle))
PanicAlert("Failed to recreate Vulkan surface. Cannot continue.");
}
}
else
{
// Previously had no swap chain. So create one.
VkSurfaceKHR surface =
SwapChain::CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), m_surface_handle);
if (surface != VK_NULL_HANDLE)
{
m_swap_chain = SwapChain::Create(m_surface_handle, surface, g_ActiveConfig.IsVSync());
if (!m_swap_chain)
PanicAlert("Failed to create swap chain.");
}
else
{
PanicAlert("Failed to create surface.");
}
}
// Recreate the surface. If this fails we're in trouble.
if (!m_swap_chain->RecreateSurface(m_new_surface_handle))
PanicAlert("Failed to recreate Vulkan surface. Cannot continue.");
m_new_surface_handle = nullptr;

// Handle case where the dimensions are now different.
OnSwapChainResized();
@@ -914,9 +889,6 @@ void Renderer::CheckForSurfaceResize()
if (!m_surface_resized.TestAndClear())
return;

m_backbuffer_width = m_new_backbuffer_width;
m_backbuffer_height = m_new_backbuffer_height;

// If we don't have a surface, how can we resize the swap chain?
// CheckForSurfaceChange should handle this case.
if (!m_swap_chain)
@@ -35,6 +35,8 @@ class Renderer : public ::Renderer

static Renderer* GetInstance();

bool IsHeadless() const override;

std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
std::unique_ptr<AbstractStagingTexture>
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
@@ -25,8 +25,9 @@

namespace Vulkan
{
SwapChain::SwapChain(void* native_handle, VkSurfaceKHR surface, bool vsync)
: m_native_handle(native_handle), m_surface(surface), m_vsync_enabled(vsync)
SwapChain::SwapChain(void* display_handle, void* native_handle, VkSurfaceKHR surface, bool vsync)
: m_display_handle(display_handle), m_native_handle(native_handle), m_surface(surface),
m_vsync_enabled(vsync)
{
}

@@ -37,7 +38,7 @@ SwapChain::~SwapChain()
DestroySurface();
}

VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, void* hwnd)
VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, void* display_handle, void* hwnd)
{
#if defined(VK_USE_PLATFORM_WIN32_KHR)
VkWin32SurfaceCreateInfoKHR surface_create_info = {
@@ -59,15 +60,11 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, void* hwnd)
return surface;

#elif defined(VK_USE_PLATFORM_XLIB_KHR)
// Assuming the display handles are compatible, or shared. This matches what we do in the
// GL backend, but it's not ideal.
Display* display = XOpenDisplay(nullptr);

VkXlibSurfaceCreateInfoKHR surface_create_info = {
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
nullptr, // const void* pNext
0, // VkXlibSurfaceCreateFlagsKHR flags
display, // Display* dpy
static_cast<Display*>(display_handle), // Display* dpy
reinterpret_cast<Window>(hwnd) // Window window
};

@@ -83,8 +80,7 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, void* hwnd)

#elif defined(VK_USE_PLATFORM_XCB_KHR)
// If we ever switch to using xcb, we should pass the display handle as well.
Display* display = XOpenDisplay(nullptr);
xcb_connection_t* connection = XGetXCBConnection(display);
xcb_connection_t* connection = XGetXCBConnection(display_handle);

VkXcbSurfaceCreateInfoKHR surface_create_info = {
VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
@@ -127,10 +123,11 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, void* hwnd)
#endif
}

std::unique_ptr<SwapChain> SwapChain::Create(void* native_handle, VkSurfaceKHR surface, bool vsync)
std::unique_ptr<SwapChain> SwapChain::Create(void* display_handle, void* native_handle,
VkSurfaceKHR surface, bool vsync)
{
std::unique_ptr<SwapChain> swap_chain =
std::make_unique<SwapChain>(native_handle, surface, vsync);
std::make_unique<SwapChain>(display_handle, native_handle, surface, vsync);

if (!swap_chain->CreateSwapChain() || !swap_chain->CreateRenderPass() ||
!swap_chain->SetupSwapChainImages())
@@ -467,7 +464,8 @@ bool SwapChain::RecreateSurface(void* native_handle)

// Re-create the surface with the new native handle
m_native_handle = native_handle;
m_surface = CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), native_handle);
m_surface =
CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), m_display_handle, native_handle);
if (m_surface == VK_NULL_HANDLE)
return false;

@@ -499,4 +497,4 @@ void SwapChain::DestroySurface()
vkDestroySurfaceKHR(g_vulkan_context->GetVulkanInstance(), m_surface, nullptr);
m_surface = VK_NULL_HANDLE;
}
}
} // namespace Vulkan
@@ -19,15 +19,17 @@ class ObjectCache;
class SwapChain
{
public:
SwapChain(void* native_handle, VkSurfaceKHR surface, bool vsync);
SwapChain(void* display_handle, void* native_handle, VkSurfaceKHR surface, bool vsync);
~SwapChain();

// Creates a vulkan-renderable surface for the specified window handle.
static VkSurfaceKHR CreateVulkanSurface(VkInstance instance, void* hwnd);
static VkSurfaceKHR CreateVulkanSurface(VkInstance instance, void* display_handle, void* hwnd);

// Create a new swap chain from a pre-existing surface.
static std::unique_ptr<SwapChain> Create(void* native_handle, VkSurfaceKHR surface, bool vsync);
static std::unique_ptr<SwapChain> Create(void* display_handle, void* native_handle,
VkSurfaceKHR surface, bool vsync);

void* GetDisplayHandle() const { return m_display_handle; }
void* GetNativeHandle() const { return m_native_handle; }
VkSurfaceKHR GetSurface() const { return m_surface; }
VkSurfaceFormatKHR GetSurfaceFormat() const { return m_surface_format; }
@@ -81,6 +83,7 @@ class SwapChain
VkFramebuffer framebuffer;
};

void* m_display_handle;
void* m_native_handle;
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
VkSurfaceFormatKHR m_surface_format = {};
@@ -12,11 +12,11 @@ namespace Vulkan
class VideoBackend : public VideoBackendBase
{
public:
bool Initialize(void* window_handle) override;
bool Initialize(const WindowSystemInfo& wsi) override;
void Shutdown() override;

std::string GetName() const override { return "Vulkan"; }
std::string GetDisplayName() const override { return _trans("Vulkan"); }
void InitBackendInfo() override;
};
}
} // namespace Vulkan
@@ -89,7 +89,7 @@ static bool ShouldEnableDebugReports(bool enable_validation_layers)
return enable_validation_layers || IsHostGPULoggingEnabled();
}

bool VideoBackend::Initialize(void* window_handle)
bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
{
if (!LoadVulkanLibrary())
{
@@ -107,7 +107,7 @@ bool VideoBackend::Initialize(void* window_handle)

// Create Vulkan instance, needed before we can create a surface, or enumerate devices.
// We use this instance to fill in backend info, then re-use it for the actual device.
bool enable_surface = window_handle != nullptr;
bool enable_surface = wsi.render_surface != nullptr;
bool enable_debug_reports = ShouldEnableDebugReports(enable_validation_layer);
VkInstance instance = VulkanContext::CreateVulkanInstance(enable_surface, enable_debug_reports,
enable_validation_layer);
@@ -146,7 +146,7 @@ bool VideoBackend::Initialize(void* window_handle)
VkSurfaceKHR surface = VK_NULL_HANDLE;
if (enable_surface)
{
surface = SwapChain::CreateVulkanSurface(instance, window_handle);
surface = SwapChain::CreateVulkanSurface(instance, wsi.display_connection, wsi.render_surface);
if (surface == VK_NULL_HANDLE)
{
PanicAlert("Failed to create Vulkan surface.");
@@ -209,7 +209,8 @@ bool VideoBackend::Initialize(void* window_handle)
std::unique_ptr<SwapChain> swap_chain;
if (surface != VK_NULL_HANDLE)
{
swap_chain = SwapChain::Create(window_handle, surface, g_Config.IsVSync());
swap_chain =
SwapChain::Create(wsi.display_connection, wsi.render_surface, surface, g_Config.IsVSync());
if (!swap_chain)
{
PanicAlert("Failed to create Vulkan swap chain.");
@@ -271,4 +272,4 @@ void VideoBackend::Shutdown()
ShutdownShared();
UnloadVulkanLibrary();
}
}
} // namespace Vulkan
@@ -35,8 +35,6 @@ const u32 m_os = OS_ALL | OS_LINUX;
const u32 m_os = OS_ALL | OS_FREEBSD;
#elif __OpenBSD__
const u32 m_os = OS_ALL | OS_OPENBSD;
#elif __HAIKU__
const u32 m_os = OS_ALL | OS_HAIKU;
#endif

static API m_api = API_OPENGL;
@@ -27,7 +27,6 @@ enum OS
OS_ANDROID = (1 << 4),
OS_FREEBSD = (1 << 5),
OS_OPENBSD = (1 << 6),
OS_HAIKU = (1 << 7),
};
// Enum of known vendors
// Tegra and Nvidia are separated out due to such substantial differences
@@ -86,7 +86,6 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height)
if (SConfig::GetInstance().bWii)
m_aspect_wide = Config::Get(Config::SYSCONF_WIDESCREEN);

m_surface_handle = Host_GetRenderHandle();
m_last_host_config_bits = ShaderHostConfig::GetCurrent().bits;
m_last_efb_multisamples = g_ActiveConfig.iMultisamples;
}
@@ -408,7 +407,7 @@ float Renderer::CalculateDrawAspectRatio() const

bool Renderer::IsHeadless() const
{
return !m_surface_handle;
return true;
}

void Renderer::ChangeSurface(void* new_surface_handle)
@@ -418,11 +417,9 @@ void Renderer::ChangeSurface(void* new_surface_handle)
m_surface_changed.Set();
}

void Renderer::ResizeSurface(int new_width, int new_height)
void Renderer::ResizeSurface()
{
std::lock_guard<std::mutex> lock(m_swap_mutex);
m_new_backbuffer_width = new_width;
m_new_backbuffer_height = new_height;
m_surface_resized.Set();
}

@@ -77,6 +77,8 @@ class Renderer

using ClearColor = std::array<float, 4>;

virtual bool IsHeadless() const = 0;

virtual void SetPipeline(const AbstractPipeline* pipeline) {}
virtual void SetScissorRect(const MathUtil::Rectangle<int>& rc) {}
virtual void SetTexture(u32 index, const AbstractTexture* texture) {}
@@ -134,7 +136,6 @@ class Renderer

const TargetRectangle& GetTargetRectangle() const { return m_target_rectangle; }
float CalculateDrawAspectRatio() const;
bool IsHeadless() const;

std::tuple<float, float> ScaleToDisplayAspectRatio(int width, int height) const;
void UpdateDrawRectangle();
@@ -182,7 +183,7 @@ class Renderer
// Final surface changing
// This is called when the surface is resized (WX) or the window changes (Android).
void ChangeSurface(void* new_surface_handle);
void ResizeSurface(int new_width, int new_height);
void ResizeSurface();
bool UseVertexDepthRange() const;

virtual std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler();
@@ -228,15 +229,12 @@ class Renderer
// Backbuffer (window) size and render area
int m_backbuffer_width = 0;
int m_backbuffer_height = 0;
int m_new_backbuffer_width = 0;
int m_new_backbuffer_height = 0;
TargetRectangle m_target_rectangle = {};

FPSCounter m_fps_counter;

std::unique_ptr<PostProcessingShaderImplementation> m_post_processor;

void* m_surface_handle = nullptr;
void* m_new_surface_handle = nullptr;
Common::Flag m_surface_changed;
Common::Flag m_surface_resized;
@@ -9,6 +9,7 @@
#include <vector>

#include "Common/CommonTypes.h"
#include "Common/WindowSystemInfo.h"
#include "VideoCommon/PerfQueryBase.h"

namespace MMIO
@@ -35,7 +36,7 @@ class VideoBackendBase
{
public:
virtual ~VideoBackendBase() {}
virtual bool Initialize(void* window_handle) = 0;
virtual bool Initialize(const WindowSystemInfo& wsi) = 0;
virtual void Shutdown() = 0;

virtual std::string GetName() const = 0;
@@ -8,7 +8,6 @@
#include <memory>
#include <string>

#include "Common/GL/GLInterfaceBase.h"
#include "Core/Host.h"

void Host_NotifyMapLoaded()
@@ -20,10 +19,6 @@ void Host_RefreshDSPDebuggerWindow()
void Host_Message(HostMessageID)
{
}
void* Host_GetRenderHandle()
{
return nullptr;
}
void Host_UpdateTitle(const std::string&)
{
}
@@ -54,7 +49,3 @@ void Host_YieldToUI()
void Host_UpdateProgressDialog(const char* caption, int position, int total)
{
}
std::unique_ptr<cInterfaceBase> HostGL_CreateGLInterface()
{
return nullptr;
}