diff --git a/Source/Core/Common/GL/GLInterface/AGL.h b/Source/Core/Common/GL/GLInterface/AGL.h index f3c3bd47cf..5f9a138282 100644 --- a/Source/Core/Common/GL/GLInterface/AGL.h +++ b/Source/Core/Common/GL/GLInterface/AGL.h @@ -17,7 +17,7 @@ class cInterfaceAGL : public cInterfaceBase { public: void Swap() override; - bool Create(void* window_handle, bool core) override; + bool Create(void* window_handle, bool stereo, bool core) override; bool MakeCurrent() override; bool ClearCurrent() override; void Shutdown() override; diff --git a/Source/Core/Common/GL/GLInterface/AGL.mm b/Source/Core/Common/GL/GLInterface/AGL.mm index 37fec99440..bdae829cbc 100644 --- a/Source/Core/Common/GL/GLInterface/AGL.mm +++ b/Source/Core/Common/GL/GLInterface/AGL.mm @@ -51,12 +51,15 @@ void cInterfaceAGL::Swap() // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool cInterfaceAGL::Create(void* window_handle, bool core) +bool cInterfaceAGL::Create(void* window_handle, bool stereo, bool core) { - NSOpenGLPixelFormatAttribute attr[] = {NSOpenGLPFADoubleBuffer, NSOpenGLPFAOpenGLProfile, - core ? NSOpenGLProfileVersion3_2Core : - NSOpenGLProfileVersionLegacy, - NSOpenGLPFAAccelerated, 0}; + NSOpenGLPixelFormatAttribute attr[] = { + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAOpenGLProfile, + core ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy, + NSOpenGLPFAAccelerated, + stereo ? NSOpenGLPFAStereo : static_cast(0), + 0}; NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; if (fmt == nil) { diff --git a/Source/Core/Common/GL/GLInterface/BGL.cpp b/Source/Core/Common/GL/GLInterface/BGL.cpp index 7cc9070a49..ed2670efc5 100644 --- a/Source/Core/Common/GL/GLInterface/BGL.cpp +++ b/Source/Core/Common/GL/GLInterface/BGL.cpp @@ -13,7 +13,7 @@ void cInterfaceBGL::Swap() m_gl->SwapBuffers(); } -bool cInterfaceBGL::Create(void* window_handle, bool core) +bool cInterfaceBGL::Create(void* window_handle, bool stereo, bool core) { m_window = static_cast(window_handle); diff --git a/Source/Core/Common/GL/GLInterface/BGL.h b/Source/Core/Common/GL/GLInterface/BGL.h index aeb678f804..b26e5e3fc8 100644 --- a/Source/Core/Common/GL/GLInterface/BGL.h +++ b/Source/Core/Common/GL/GLInterface/BGL.h @@ -14,7 +14,7 @@ class cInterfaceBGL final : public cInterfaceBase public: void Swap() override; void* GetFuncAddress(const std::string& name) override; - bool Create(void* window_handle, bool core) override; + bool Create(void* window_handle, bool stereo, bool core) override; bool MakeCurrent() override; bool ClearCurrent() override; void Shutdown() override; diff --git a/Source/Core/Common/GL/GLInterface/EGL.cpp b/Source/Core/Common/GL/GLInterface/EGL.cpp index 9deb4f20e7..32cd705d73 100644 --- a/Source/Core/Common/GL/GLInterface/EGL.cpp +++ b/Source/Core/Common/GL/GLInterface/EGL.cpp @@ -111,7 +111,7 @@ void cInterfaceEGL::DetectMode() // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool cInterfaceEGL::Create(void* window_handle, bool core) +bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core) { EGLint egl_major, egl_minor; bool supports_core_profile = false; diff --git a/Source/Core/Common/GL/GLInterface/EGL.h b/Source/Core/Common/GL/GLInterface/EGL.h index 2352f9b646..69a351851f 100644 --- a/Source/Core/Common/GL/GLInterface/EGL.h +++ b/Source/Core/Common/GL/GLInterface/EGL.h @@ -38,7 +38,7 @@ public: void SwapInterval(int interval) override; void SetMode(GLInterfaceMode mode) override { s_opengl_mode = mode; } void* GetFuncAddress(const std::string& name) override; - bool Create(void* window_handle, bool core) override; + bool Create(void* window_handle, bool stereo, bool core) override; bool Create(cInterfaceBase* main_context) override; bool MakeCurrent() override; bool ClearCurrent() override; diff --git a/Source/Core/Common/GL/GLInterface/GLX.cpp b/Source/Core/Common/GL/GLInterface/GLX.cpp index d3550c688f..f6fea067ef 100644 --- a/Source/Core/Common/GL/GLInterface/GLX.cpp +++ b/Source/Core/Common/GL/GLInterface/GLX.cpp @@ -43,7 +43,7 @@ void cInterfaceGLX::Swap() // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool cInterfaceGLX::Create(void* window_handle, bool core) +bool cInterfaceGLX::Create(void* window_handle, bool stereo, bool core) { dpy = XOpenDisplay(nullptr); int screen = DefaultScreen(dpy); @@ -87,6 +87,8 @@ bool cInterfaceGLX::Create(void* window_handle, bool core) 0, GLX_DOUBLEBUFFER, True, + GLX_STEREO, + stereo ? True : False, None}; int fbcount = 0; GLXFBConfig* fbc = glXChooseFBConfig(dpy, screen, visual_attribs, &fbcount); diff --git a/Source/Core/Common/GL/GLInterface/GLX.h b/Source/Core/Common/GL/GLInterface/GLX.h index 20feba27e0..ae019ccbf9 100644 --- a/Source/Core/Common/GL/GLInterface/GLX.h +++ b/Source/Core/Common/GL/GLInterface/GLX.h @@ -24,7 +24,7 @@ public: void SwapInterval(int Interval) override; void Swap() override; void* GetFuncAddress(const std::string& name) override; - bool Create(void* window_handle, bool core) override; + bool Create(void* window_handle, bool stereo, bool core) override; bool MakeCurrent() override; bool ClearCurrent() override; void Shutdown() override; diff --git a/Source/Core/Common/GL/GLInterface/WGL.cpp b/Source/Core/Common/GL/GLInterface/WGL.cpp index 3e500f5866..4d4647e838 100644 --- a/Source/Core/Common/GL/GLInterface/WGL.cpp +++ b/Source/Core/Common/GL/GLInterface/WGL.cpp @@ -200,7 +200,7 @@ bool cInterfaceWGL::PeekMessages() // Create rendering window. // Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() -bool cInterfaceWGL::Create(void* window_handle, bool core) +bool cInterfaceWGL::Create(void* window_handle, bool stereo, bool core) { if (!window_handle) return false; @@ -219,12 +219,14 @@ bool cInterfaceWGL::Create(void* window_handle, bool core) s_backbuffer_width = twidth; s_backbuffer_height = theight; - static constexpr PIXELFORMATDESCRIPTOR pfd = { + const DWORD stereo_flag = stereo ? PFD_STEREO : 0; + static const PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor 1, // Version Number PFD_DRAW_TO_WINDOW | // Format Must Support Window PFD_SUPPORT_OPENGL | // Format Must Support OpenGL - PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_DOUBLEBUFFER | // Must Support Double Buffering + stereo_flag, // Could Support Quad Buffering PFD_TYPE_RGBA, // Request An RGBA Format 32, // Select Our Color Depth 0, diff --git a/Source/Core/Common/GL/GLInterface/WGL.h b/Source/Core/Common/GL/GLInterface/WGL.h index e6f0ff3c66..efa9655713 100644 --- a/Source/Core/Common/GL/GLInterface/WGL.h +++ b/Source/Core/Common/GL/GLInterface/WGL.h @@ -14,7 +14,7 @@ public: void SwapInterval(int interval) override; void Swap() override; void* GetFuncAddress(const std::string& name) override; - bool Create(void* window_handle, bool core) override; + bool Create(void* window_handle, bool stereo, bool core) override; bool Create(cInterfaceBase* main_context) override; bool MakeCurrent() override; bool ClearCurrent() override; diff --git a/Source/Core/Common/GL/GLInterfaceBase.h b/Source/Core/Common/GL/GLInterfaceBase.h index b19f5698bc..4ffb7f5f53 100644 --- a/Source/Core/Common/GL/GLInterfaceBase.h +++ b/Source/Core/Common/GL/GLInterfaceBase.h @@ -34,7 +34,7 @@ public: virtual void SetMode(GLInterfaceMode mode) { s_opengl_mode = GLInterfaceMode::MODE_OPENGL; } virtual GLInterfaceMode GetMode() { return s_opengl_mode; } virtual void* GetFuncAddress(const std::string& name) { return nullptr; } - virtual bool Create(void* window_handle, bool core = true) { return true; } + virtual bool Create(void* window_handle, bool stereo = false, bool core = true) { return true; } virtual bool Create(cInterfaceBase* main_context) { return true; } virtual bool MakeCurrent() { return true; } virtual bool ClearCurrent() { return true; } diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index 2dc76ae456..30e93a6ff4 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -277,8 +277,9 @@ static wxString cache_efb_copies_desc = static wxString stereo_3d_desc = wxTRANSLATE("Selects the stereoscopic 3D mode. Stereoscopy allows you to get a better feeling " "of depth if you have the necessary hardware.\nSide-by-Side and Top-and-Bottom are " - "used by most 3D TVs.\nAnaglyph is used for Red-Cyan colored glasses.\nHeavily " - "decreases emulation speed and sometimes causes issues.\n\nIf unsure, select Off."); + "used by most 3D TVs.\nAnaglyph is used for Red-Cyan colored glasses.\nHDMI 3D is " + "used when your monitor supports 3D display resolutions.\nHeavily decreases " + "emulation speed and sometimes causes issues.\n\nIf unsure, select Off."); static wxString stereo_depth_desc = wxTRANSLATE("Controls the separation distance between the virtual cameras.\nA higher value " "creates a stronger feeling of depth while a lower value is more comfortable."); @@ -622,8 +623,8 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title) szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Stereoscopic 3D Mode:")), 0, wxALIGN_CENTER_VERTICAL); - const wxString stereo_choices[] = {_("Off"), _("Side-by-Side"), _("Top-and-Bottom"), - _("Anaglyph"), _("Nvidia 3D Vision")}; + const wxString stereo_choices[] = {_("Off"), _("Side-by-Side"), _("Top-and-Bottom"), + _("Anaglyph"), _("HDMI 3D"), _("Nvidia 3D Vision")}; wxChoice* stereo_choice = CreateChoice(page_enh, Config::GFX_STEREO_MODE, wxGetTranslation(stereo_3d_desc), vconfig.backend_info.bSupports3DVision ? ArraySize(stereo_choices) : diff --git a/Source/Core/VideoBackends/D3D/D3DBase.cpp b/Source/Core/VideoBackends/D3D/D3DBase.cpp index 327fece109..ad989f4188 100644 --- a/Source/Core/VideoBackends/D3D/D3DBase.cpp +++ b/Source/Core/VideoBackends/D3D/D3DBase.cpp @@ -26,13 +26,7 @@ CREATEDXGIFACTORY PCreateDXGIFactory = nullptr; HINSTANCE hDXGIDll = nullptr; int dxgi_dll_ref = 0; -typedef HRESULT(WINAPI* D3D11CREATEDEVICEANDSWAPCHAIN)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, - UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, - CONST DXGI_SWAP_CHAIN_DESC*, - IDXGISwapChain**, ID3D11Device**, - D3D_FEATURE_LEVEL*, ID3D11DeviceContext**); static D3D11CREATEDEVICE PD3D11CreateDevice = nullptr; -D3D11CREATEDEVICEANDSWAPCHAIN PD3D11CreateDeviceAndSwapChain = nullptr; HINSTANCE hD3DDll = nullptr; int d3d_dll_ref = 0; @@ -40,7 +34,7 @@ namespace D3D { ID3D11Device* device = nullptr; ID3D11DeviceContext* context = nullptr; -static IDXGISwapChain* swapchain = nullptr; +static IDXGISwapChain1* swapchain = nullptr; static ID3D11Debug* debug = nullptr; D3D_FEATURE_LEVEL featlevel; D3DTexture2D* backbuf = nullptr; @@ -58,6 +52,8 @@ unsigned int xres, yres; bool bFrameInProgress = false; +#define NUM_SWAPCHAIN_BUFFERS 2 + HRESULT LoadDXGI() { if (dxgi_dll_ref++ > 0) @@ -99,12 +95,6 @@ HRESULT LoadD3D() MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDevice!", "Critical error", MB_OK | MB_ICONERROR); - PD3D11CreateDeviceAndSwapChain = - (D3D11CREATEDEVICEANDSWAPCHAIN)GetProcAddress(hD3DDll, "D3D11CreateDeviceAndSwapChain"); - if (PD3D11CreateDeviceAndSwapChain == nullptr) - MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDeviceAndSwapChain!", - "Critical error", MB_OK | MB_ICONERROR); - return S_OK; } @@ -172,7 +162,6 @@ void UnloadD3D() FreeLibrary(hD3DDll); hD3DDll = nullptr; PD3D11CreateDevice = nullptr; - PD3D11CreateDeviceAndSwapChain = nullptr; } void UnloadD3DCompiler() @@ -276,14 +265,13 @@ HRESULT Create(HWND wnd) return hr; } - IDXGIFactory* factory; - IDXGIAdapter* adapter; - IDXGIOutput* output; + IDXGIFactory2* factory; hr = PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory); if (FAILED(hr)) MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); + IDXGIAdapter* adapter; hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter); if (FAILED(hr)) { @@ -294,25 +282,6 @@ HRESULT Create(HWND wnd) MB_OK | MB_ICONERROR); } - // TODO: Make this configurable - hr = adapter->EnumOutputs(0, &output); - if (FAILED(hr)) - { - // try using the first one - IDXGIAdapter* firstadapter; - hr = factory->EnumAdapters(0, &firstadapter); - if (!FAILED(hr)) - hr = firstadapter->EnumOutputs(0, &output); - if (FAILED(hr)) - MessageBox(wnd, _T("Failed to enumerate outputs!\n") - _T("This usually happens when you've set your video adapter to the Nvidia ") - _T("GPU in an Optimus-equipped system.\n") - _T("Set Dolphin to use the high-performance graphics in Nvidia's drivers ") - _T("instead and leave Dolphin's video adapter set to the Intel GPU."), - _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); - SAFE_RELEASE(firstadapter); - } - // get supported AA modes aa_modes = EnumAAModes(adapter); @@ -324,45 +293,34 @@ HRESULT Create(HWND wnd) UpdateActiveConfig(); } - DXGI_SWAP_CHAIN_DESC swap_chain_desc = {}; - swap_chain_desc.BufferCount = 1; + DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {}; + swap_chain_desc.BufferCount = NUM_SWAPCHAIN_BUFFERS; swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.OutputWindow = wnd; swap_chain_desc.SampleDesc.Count = 1; swap_chain_desc.SampleDesc.Quality = 0; - swap_chain_desc.Windowed = - !SConfig::GetInstance().bFullscreen || g_ActiveConfig.bBorderlessFullscreen; + swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swap_chain_desc.Scaling = DXGI_SCALING_STRETCH; + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swap_chain_desc.Width = xres; + swap_chain_desc.Height = yres; - DXGI_OUTPUT_DESC out_desc = {}; - output->GetDesc(&out_desc); - - DXGI_MODE_DESC mode_desc = {}; - mode_desc.Width = out_desc.DesktopCoordinates.right - out_desc.DesktopCoordinates.left; - mode_desc.Height = out_desc.DesktopCoordinates.bottom - out_desc.DesktopCoordinates.top; - mode_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - mode_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - hr = output->FindClosestMatchingMode(&mode_desc, &swap_chain_desc.BufferDesc, nullptr); - if (FAILED(hr)) - MessageBox(wnd, _T("Failed to find a supported video mode"), _T("Dolphin Direct3D 11 backend"), - MB_OK | MB_ICONERROR); - - if (swap_chain_desc.Windowed) - { - // forcing buffer resolution to xres and yres.. - // this is not a problem as long as we're in windowed mode - swap_chain_desc.BufferDesc.Width = xres; - swap_chain_desc.BufferDesc.Height = yres; - } + // By always creating a stereo swapchain we can toggle Quad-Buffered stereoscopy + // while the game is running. + swap_chain_desc.Stereo = TRUE; #if defined(_DEBUG) || defined(DEBUGFAST) // Creating debug devices can sometimes fail if the user doesn't have the correct // version of the DirectX SDK. If it does, simply fallback to a non-debug device. { - hr = PD3D11CreateDeviceAndSwapChain( - adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, - D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG, supported_feature_levels, - NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device, - &featlevel, &context); + hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, + D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG, + supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, + D3D11_SDK_VERSION, &device, &featlevel, &context); + + if (SUCCEEDED(hr)) + hr = factory->CreateSwapChainForHwnd(device, hWnd, &swap_chain_desc, nullptr, nullptr, + &swapchain); + // Debugbreak on D3D error if (SUCCEEDED(hr) && SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), (void**)&debug))) { @@ -386,10 +344,14 @@ HRESULT Create(HWND wnd) if (FAILED(hr)) #endif { - hr = PD3D11CreateDeviceAndSwapChain( - adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED, - supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &swap_chain_desc, - &swapchain, &device, &featlevel, &context); + hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, + D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels, + NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &device, &featlevel, + &context); + + if (SUCCEEDED(hr)) + hr = factory->CreateSwapChainForHwnd(device, hWnd, &swap_chain_desc, nullptr, nullptr, + &swapchain); } if (FAILED(hr)) @@ -414,7 +376,6 @@ HRESULT Create(HWND wnd) SetDebugObjectName((ID3D11DeviceChild*)context, "device context"); SAFE_RELEASE(factory); - SAFE_RELEASE(output); SAFE_RELEASE(adapter); ID3D11Texture2D* buf; @@ -574,7 +535,7 @@ void Reset() GetClientRect(hWnd, &client); xres = client.right - client.left; yres = client.bottom - client.top; - D3D::swapchain->ResizeBuffers(1, xres, yres, DXGI_FORMAT_R8G8B8A8_UNORM, 0); + D3D::swapchain->ResizeBuffers(NUM_SWAPCHAIN_BUFFERS, xres, yres, DXGI_FORMAT_R8G8B8A8_UNORM, 0); // recreate back buffer texture ID3D11Texture2D* buf; @@ -618,8 +579,11 @@ void EndFrame() void Present() { + UINT present_flags = + g_ActiveConfig.iStereoMode != STEREO_QUADBUFFER ? DXGI_PRESENT_STEREO_TEMPORARY_MONO : 0; + // TODO: Is 1 the correct value for vsyncing? - swapchain->Present((UINT)g_ActiveConfig.IsVSync(), 0); + swapchain->Present((UINT)g_ActiveConfig.IsVSync(), present_flags); } HRESULT SetFullscreenState(bool enable_fullscreen) diff --git a/Source/Core/VideoBackends/D3D/D3DBase.h b/Source/Core/VideoBackends/D3D/D3DBase.h index dec8d5206f..288be59a9f 100644 --- a/Source/Core/VideoBackends/D3D/D3DBase.h +++ b/Source/Core/VideoBackends/D3D/D3DBase.h @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include "Common/Common.h" diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 3fef05973b..027c3611c0 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -1220,12 +1220,16 @@ void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(), (float)dst.GetHeight()); D3D::context->RSSetViewports(1, &vp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, - (g_Config.iStereoMode == STEREO_ANAGLYPH) ? - PixelShaderCache::GetAnaglyphProgram() : - PixelShaderCache::GetColorCopyProgram(false), + + ID3D11PixelShader* pixelShader = (g_Config.iStereoMode == STEREO_ANAGLYPH) ? + PixelShaderCache::GetAnaglyphProgram() : + PixelShaderCache::GetColorCopyProgram(false); + ID3D11GeometryShader* geomShader = (g_ActiveConfig.iStereoMode == STEREO_QUADBUFFER) ? + GeometryShaderCache::GetCopyGeometryShader() : + nullptr; + D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, pixelShader, VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma); + VertexShaderCache::GetSimpleInputLayout(), geomShader, Gamma); } } diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 494a478501..3282489369 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1196,6 +1196,16 @@ void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, GLuint src_t post_processor->BlitFromTexture(src, leftRc, src_texture, src_width, src_height, 0); post_processor->BlitFromTexture(src, rightRc, src_texture, src_width, src_height, 1); } + else if (g_ActiveConfig.iStereoMode == STEREO_QUADBUFFER) + { + glDrawBuffer(GL_BACK_LEFT); + post_processor->BlitFromTexture(src, dst, src_texture, src_width, src_height, 0); + + glDrawBuffer(GL_BACK_RIGHT); + post_processor->BlitFromTexture(src, dst, src_texture, src_width, src_height, 1); + + glDrawBuffer(GL_BACK); + } else { post_processor->BlitFromTexture(src, dst, src_texture, src_width, src_height, 0); diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp index f9bf7c069e..c00782ee70 100644 --- a/Source/Core/VideoBackends/OGL/main.cpp +++ b/Source/Core/VideoBackends/OGL/main.cpp @@ -167,7 +167,7 @@ bool VideoBackend::Initialize(void* window_handle) InitInterface(); GLInterface->SetMode(GLInterfaceMode::MODE_DETECT); - if (!GLInterface->Create(window_handle)) + if (!GLInterface->Create(window_handle, g_ActiveConfig.iStereoMode == STEREO_QUADBUFFER)) return false; return true; diff --git a/Source/Core/VideoBackends/Vulkan/PostProcessing.cpp b/Source/Core/VideoBackends/Vulkan/PostProcessing.cpp index db8da49499..971de51180 100644 --- a/Source/Core/VideoBackends/Vulkan/PostProcessing.cpp +++ b/Source/Core/VideoBackends/Vulkan/PostProcessing.cpp @@ -41,11 +41,14 @@ void VulkanPostProcessing::BlitFromTexture(const TargetRectangle& dst, const Tar const Texture2D* src_tex, int src_layer, VkRenderPass render_pass) { + // If the source layer is negative we simply copy all available layers. + VkShaderModule geometry_shader = + src_layer < 0 ? g_object_cache->GetPassthroughGeometryShader() : VK_NULL_HANDLE; VkShaderModule fragment_shader = m_fragment_shader != VK_NULL_HANDLE ? m_fragment_shader : m_default_fragment_shader; UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), render_pass, - g_object_cache->GetPassthroughVertexShader(), VK_NULL_HANDLE, + g_object_cache->GetPassthroughVertexShader(), geometry_shader, fragment_shader); // Source is always bound. diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 4800d99424..9a26df8548 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -949,6 +949,10 @@ void Renderer::BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_r post_processor->BlitFromTexture(left_rect, src_rect, src_tex, 0, render_pass); post_processor->BlitFromTexture(right_rect, src_rect, src_tex, 1, render_pass); } + else if (g_ActiveConfig.iStereoMode == STEREO_QUADBUFFER) + { + post_processor->BlitFromTexture(dst_rect, src_rect, src_tex, -1, render_pass); + } else { post_processor->BlitFromTexture(dst_rect, src_rect, src_tex, 0, render_pass); @@ -1186,6 +1190,11 @@ void Renderer::CheckForConfigChanges() m_swap_chain->SetVSync(g_ActiveConfig.IsVSync()); } + // For quad-buffered stereo we need to change the layer count, so recreate the swap chain. + if (m_swap_chain && + (g_ActiveConfig.iStereoMode == STEREO_QUADBUFFER) != m_swap_chain->IsStereoEnabled()) + ResizeSwapChain(); + // Wipe sampler cache if force texture filtering or anisotropy changes. if (anisotropy_changed || force_texture_filtering_changed) ResetSamplerStates(); diff --git a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp index d43a0e4499..21009510bb 100644 --- a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp +++ b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp @@ -320,6 +320,9 @@ bool SwapChain::CreateSwapChain() return false; } + // Select the number of image layers for Quad-Buffered stereoscopy + uint32_t image_layers = g_ActiveConfig.iStereoMode == STEREO_QUADBUFFER ? 2 : 1; + // Store the old/current swap chain when recreating for resize VkSwapchainKHR old_swap_chain = m_swap_chain; @@ -333,7 +336,7 @@ bool SwapChain::CreateSwapChain() m_surface_format.format, m_surface_format.colorSpace, size, - 1, + image_layers, image_usage, VK_SHARING_MODE_EXCLUSIVE, 0, @@ -359,6 +362,7 @@ bool SwapChain::CreateSwapChain() m_width = size.width; m_height = size.height; + m_layers = image_layers; return true; } @@ -400,7 +404,7 @@ bool SwapChain::SetupSwapChainImages() &view, m_width, m_height, - 1}; + m_layers}; res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, &image.framebuffer); diff --git a/Source/Core/VideoBackends/Vulkan/SwapChain.h b/Source/Core/VideoBackends/Vulkan/SwapChain.h index 0ff480d64c..37c3460796 100644 --- a/Source/Core/VideoBackends/Vulkan/SwapChain.h +++ b/Source/Core/VideoBackends/Vulkan/SwapChain.h @@ -32,6 +32,7 @@ public: VkSurfaceKHR GetSurface() const { return m_surface; } VkSurfaceFormatKHR GetSurfaceFormat() const { return m_surface_format; } bool IsVSyncEnabled() const { return m_vsync_enabled; } + bool IsStereoEnabled() const { return m_layers == 2; } VkSwapchainKHR GetSwapChain() const { return m_swap_chain; } VkRenderPass GetRenderPass() const { return m_render_pass; } u32 GetWidth() const { return m_width; } @@ -94,6 +95,7 @@ private: u32 m_width = 0; u32 m_height = 0; + u32 m_layers = 0; }; } // namespace Vulkan diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index 335c180b30..cec2c5183d 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -606,6 +606,8 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa), uid_data->genMode_numtexgens + 2); } + out.Write(",\n in float clipDist0 : SV_ClipDistance0\n"); + out.Write(",\n in float clipDist1 : SV_ClipDistance1\n"); if (uid_data->stereo) out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n"); out.Write(" ) {\n"); diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index ef4c33fa43..e706cea1c3 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -47,6 +47,7 @@ enum StereoMode STEREO_SBS, STEREO_TAB, STEREO_ANAGLYPH, + STEREO_QUADBUFFER, STEREO_3DVISION };