Merge pull request #5697 from Armada651/quad-buffer

Implement Quad-Buffered stereoscopy support
This commit is contained in:
Jules Blok 2017-07-06 01:26:06 +02:00 committed by GitHub
commit 29cc009706
23 changed files with 111 additions and 104 deletions

View File

@ -17,7 +17,7 @@ class cInterfaceAGL : public cInterfaceBase
{ {
public: public:
void Swap() override; 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 MakeCurrent() override;
bool ClearCurrent() override; bool ClearCurrent() override;
void Shutdown() override; void Shutdown() override;

View File

@ -51,12 +51,15 @@ void cInterfaceAGL::Swap()
// Create rendering window. // Create rendering window.
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() // 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, NSOpenGLPixelFormatAttribute attr[] = {
core ? NSOpenGLProfileVersion3_2Core : NSOpenGLPFADoubleBuffer,
NSOpenGLProfileVersionLegacy, NSOpenGLPFAOpenGLProfile,
NSOpenGLPFAAccelerated, 0}; core ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy,
NSOpenGLPFAAccelerated,
stereo ? NSOpenGLPFAStereo : static_cast<NSOpenGLPixelFormatAttribute>(0),
0};
NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
if (fmt == nil) if (fmt == nil)
{ {

View File

@ -13,7 +13,7 @@ void cInterfaceBGL::Swap()
m_gl->SwapBuffers(); 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<BWindow*>(window_handle); m_window = static_cast<BWindow*>(window_handle);

View File

@ -14,7 +14,7 @@ class cInterfaceBGL final : public cInterfaceBase
public: public:
void Swap() override; void Swap() override;
void* GetFuncAddress(const std::string& name) 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 MakeCurrent() override;
bool ClearCurrent() override; bool ClearCurrent() override;
void Shutdown() override; void Shutdown() override;

View File

@ -111,7 +111,7 @@ void cInterfaceEGL::DetectMode()
// Create rendering window. // Create rendering window.
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() // 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; EGLint egl_major, egl_minor;
bool supports_core_profile = false; bool supports_core_profile = false;

View File

@ -38,7 +38,7 @@ public:
void SwapInterval(int interval) override; void SwapInterval(int interval) override;
void SetMode(GLInterfaceMode mode) override { s_opengl_mode = mode; } void SetMode(GLInterfaceMode mode) override { s_opengl_mode = mode; }
void* GetFuncAddress(const std::string& name) 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 Create(cInterfaceBase* main_context) override;
bool MakeCurrent() override; bool MakeCurrent() override;
bool ClearCurrent() override; bool ClearCurrent() override;

View File

@ -43,7 +43,7 @@ void cInterfaceGLX::Swap()
// Create rendering window. // Create rendering window.
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() // 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); dpy = XOpenDisplay(nullptr);
int screen = DefaultScreen(dpy); int screen = DefaultScreen(dpy);
@ -87,6 +87,8 @@ bool cInterfaceGLX::Create(void* window_handle, bool core)
0, 0,
GLX_DOUBLEBUFFER, GLX_DOUBLEBUFFER,
True, True,
GLX_STEREO,
stereo ? True : False,
None}; None};
int fbcount = 0; int fbcount = 0;
GLXFBConfig* fbc = glXChooseFBConfig(dpy, screen, visual_attribs, &fbcount); GLXFBConfig* fbc = glXChooseFBConfig(dpy, screen, visual_attribs, &fbcount);

View File

@ -24,7 +24,7 @@ public:
void SwapInterval(int Interval) override; void SwapInterval(int Interval) override;
void Swap() override; void Swap() override;
void* GetFuncAddress(const std::string& name) 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 MakeCurrent() override;
bool ClearCurrent() override; bool ClearCurrent() override;
void Shutdown() override; void Shutdown() override;

View File

@ -200,7 +200,7 @@ bool cInterfaceWGL::PeekMessages()
// Create rendering window. // Create rendering window.
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() // 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) if (!window_handle)
return false; return false;
@ -219,12 +219,14 @@ bool cInterfaceWGL::Create(void* window_handle, bool core)
s_backbuffer_width = twidth; s_backbuffer_width = twidth;
s_backbuffer_height = theight; 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 sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number 1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL 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 PFD_TYPE_RGBA, // Request An RGBA Format
32, // Select Our Color Depth 32, // Select Our Color Depth
0, 0,

View File

@ -14,7 +14,7 @@ public:
void SwapInterval(int interval) override; void SwapInterval(int interval) override;
void Swap() override; void Swap() override;
void* GetFuncAddress(const std::string& name) 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 Create(cInterfaceBase* main_context) override;
bool MakeCurrent() override; bool MakeCurrent() override;
bool ClearCurrent() override; bool ClearCurrent() override;

View File

@ -34,7 +34,7 @@ public:
virtual void SetMode(GLInterfaceMode mode) { s_opengl_mode = GLInterfaceMode::MODE_OPENGL; } virtual void SetMode(GLInterfaceMode mode) { s_opengl_mode = GLInterfaceMode::MODE_OPENGL; }
virtual GLInterfaceMode GetMode() { return s_opengl_mode; } virtual GLInterfaceMode GetMode() { return s_opengl_mode; }
virtual void* GetFuncAddress(const std::string& name) { return nullptr; } 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 Create(cInterfaceBase* main_context) { return true; }
virtual bool MakeCurrent() { return true; } virtual bool MakeCurrent() { return true; }
virtual bool ClearCurrent() { return true; } virtual bool ClearCurrent() { return true; }

View File

@ -277,8 +277,9 @@ static wxString cache_efb_copies_desc =
static wxString stereo_3d_desc = static wxString stereo_3d_desc =
wxTRANSLATE("Selects the stereoscopic 3D mode. Stereoscopy allows you to get a better feeling " 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 " "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 " "used by most 3D TVs.\nAnaglyph is used for Red-Cyan colored glasses.\nHDMI 3D is "
"decreases emulation speed and sometimes causes issues.\n\nIf unsure, select Off."); "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 = static wxString stereo_depth_desc =
wxTRANSLATE("Controls the separation distance between the virtual cameras.\nA higher value " 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."); "creates a stronger feeling of depth while a lower value is more comfortable.");
@ -623,7 +624,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
wxALIGN_CENTER_VERTICAL); wxALIGN_CENTER_VERTICAL);
const wxString stereo_choices[] = {_("Off"), _("Side-by-Side"), _("Top-and-Bottom"), const wxString stereo_choices[] = {_("Off"), _("Side-by-Side"), _("Top-and-Bottom"),
_("Anaglyph"), _("Nvidia 3D Vision")}; _("Anaglyph"), _("HDMI 3D"), _("Nvidia 3D Vision")};
wxChoice* stereo_choice = wxChoice* stereo_choice =
CreateChoice(page_enh, Config::GFX_STEREO_MODE, wxGetTranslation(stereo_3d_desc), CreateChoice(page_enh, Config::GFX_STEREO_MODE, wxGetTranslation(stereo_3d_desc),
vconfig.backend_info.bSupports3DVision ? ArraySize(stereo_choices) : vconfig.backend_info.bSupports3DVision ? ArraySize(stereo_choices) :

View File

@ -26,13 +26,7 @@ CREATEDXGIFACTORY PCreateDXGIFactory = nullptr;
HINSTANCE hDXGIDll = nullptr; HINSTANCE hDXGIDll = nullptr;
int dxgi_dll_ref = 0; 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; static D3D11CREATEDEVICE PD3D11CreateDevice = nullptr;
D3D11CREATEDEVICEANDSWAPCHAIN PD3D11CreateDeviceAndSwapChain = nullptr;
HINSTANCE hD3DDll = nullptr; HINSTANCE hD3DDll = nullptr;
int d3d_dll_ref = 0; int d3d_dll_ref = 0;
@ -40,7 +34,7 @@ namespace D3D
{ {
ID3D11Device* device = nullptr; ID3D11Device* device = nullptr;
ID3D11DeviceContext* context = nullptr; ID3D11DeviceContext* context = nullptr;
static IDXGISwapChain* swapchain = nullptr; static IDXGISwapChain1* swapchain = nullptr;
static ID3D11Debug* debug = nullptr; static ID3D11Debug* debug = nullptr;
D3D_FEATURE_LEVEL featlevel; D3D_FEATURE_LEVEL featlevel;
D3DTexture2D* backbuf = nullptr; D3DTexture2D* backbuf = nullptr;
@ -58,6 +52,8 @@ unsigned int xres, yres;
bool bFrameInProgress = false; bool bFrameInProgress = false;
#define NUM_SWAPCHAIN_BUFFERS 2
HRESULT LoadDXGI() HRESULT LoadDXGI()
{ {
if (dxgi_dll_ref++ > 0) if (dxgi_dll_ref++ > 0)
@ -99,12 +95,6 @@ HRESULT LoadD3D()
MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDevice!", "Critical error", MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDevice!", "Critical error",
MB_OK | MB_ICONERROR); 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; return S_OK;
} }
@ -172,7 +162,6 @@ void UnloadD3D()
FreeLibrary(hD3DDll); FreeLibrary(hD3DDll);
hD3DDll = nullptr; hD3DDll = nullptr;
PD3D11CreateDevice = nullptr; PD3D11CreateDevice = nullptr;
PD3D11CreateDeviceAndSwapChain = nullptr;
} }
void UnloadD3DCompiler() void UnloadD3DCompiler()
@ -276,14 +265,13 @@ HRESULT Create(HWND wnd)
return hr; return hr;
} }
IDXGIFactory* factory; IDXGIFactory2* factory;
IDXGIAdapter* adapter;
IDXGIOutput* output;
hr = PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory); hr = PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
if (FAILED(hr)) if (FAILED(hr))
MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 backend"), MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 backend"),
MB_OK | MB_ICONERROR); MB_OK | MB_ICONERROR);
IDXGIAdapter* adapter;
hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter); hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter);
if (FAILED(hr)) if (FAILED(hr))
{ {
@ -294,25 +282,6 @@ HRESULT Create(HWND wnd)
MB_OK | MB_ICONERROR); 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 // get supported AA modes
aa_modes = EnumAAModes(adapter); aa_modes = EnumAAModes(adapter);
@ -324,45 +293,34 @@ HRESULT Create(HWND wnd)
UpdateActiveConfig(); UpdateActiveConfig();
} }
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {}; DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {};
swap_chain_desc.BufferCount = 1; swap_chain_desc.BufferCount = NUM_SWAPCHAIN_BUFFERS;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.OutputWindow = wnd;
swap_chain_desc.SampleDesc.Count = 1; swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.SampleDesc.Quality = 0; swap_chain_desc.SampleDesc.Quality = 0;
swap_chain_desc.Windowed = swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
!SConfig::GetInstance().bFullscreen || g_ActiveConfig.bBorderlessFullscreen; 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 = {}; // By always creating a stereo swapchain we can toggle Quad-Buffered stereoscopy
output->GetDesc(&out_desc); // while the game is running.
swap_chain_desc.Stereo = TRUE;
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;
}
#if defined(_DEBUG) || defined(DEBUGFAST) #if defined(_DEBUG) || defined(DEBUGFAST)
// Creating debug devices can sometimes fail if the user doesn't have the correct // 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. // version of the DirectX SDK. If it does, simply fallback to a non-debug device.
{ {
hr = PD3D11CreateDeviceAndSwapChain( hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG,
D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG, supported_feature_levels, supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS,
NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device, D3D11_SDK_VERSION, &device, &featlevel, &context);
&featlevel, &context);
if (SUCCEEDED(hr))
hr = factory->CreateSwapChainForHwnd(device, hWnd, &swap_chain_desc, nullptr, nullptr,
&swapchain);
// Debugbreak on D3D error // Debugbreak on D3D error
if (SUCCEEDED(hr) && SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), (void**)&debug))) if (SUCCEEDED(hr) && SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), (void**)&debug)))
{ {
@ -386,10 +344,14 @@ HRESULT Create(HWND wnd)
if (FAILED(hr)) if (FAILED(hr))
#endif #endif
{ {
hr = PD3D11CreateDeviceAndSwapChain( hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED, D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels,
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &swap_chain_desc, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &device, &featlevel,
&swapchain, &device, &featlevel, &context); &context);
if (SUCCEEDED(hr))
hr = factory->CreateSwapChainForHwnd(device, hWnd, &swap_chain_desc, nullptr, nullptr,
&swapchain);
} }
if (FAILED(hr)) if (FAILED(hr))
@ -414,7 +376,6 @@ HRESULT Create(HWND wnd)
SetDebugObjectName((ID3D11DeviceChild*)context, "device context"); SetDebugObjectName((ID3D11DeviceChild*)context, "device context");
SAFE_RELEASE(factory); SAFE_RELEASE(factory);
SAFE_RELEASE(output);
SAFE_RELEASE(adapter); SAFE_RELEASE(adapter);
ID3D11Texture2D* buf; ID3D11Texture2D* buf;
@ -574,7 +535,7 @@ void Reset()
GetClientRect(hWnd, &client); GetClientRect(hWnd, &client);
xres = client.right - client.left; xres = client.right - client.left;
yres = client.bottom - client.top; 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 // recreate back buffer texture
ID3D11Texture2D* buf; ID3D11Texture2D* buf;
@ -618,8 +579,11 @@ void EndFrame()
void Present() void Present()
{ {
UINT present_flags =
g_ActiveConfig.iStereoMode != STEREO_QUADBUFFER ? DXGI_PRESENT_STEREO_TEMPORARY_MONO : 0;
// TODO: Is 1 the correct value for vsyncing? // 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) HRESULT SetFullscreenState(bool enable_fullscreen)

View File

@ -6,7 +6,7 @@
#include <d3d11.h> #include <d3d11.h>
#include <d3dcompiler.h> #include <d3dcompiler.h>
#include <dxgi.h> #include <dxgi1_2.h>
#include <vector> #include <vector>
#include "Common/Common.h" #include "Common/Common.h"

View File

@ -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(), D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(),
(float)dst.GetHeight()); (float)dst.GetHeight());
D3D::context->RSSetViewports(1, &vp); D3D::context->RSSetViewports(1, &vp);
D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height,
(g_Config.iStereoMode == STEREO_ANAGLYPH) ? ID3D11PixelShader* pixelShader = (g_Config.iStereoMode == STEREO_ANAGLYPH) ?
PixelShaderCache::GetAnaglyphProgram() : PixelShaderCache::GetAnaglyphProgram() :
PixelShaderCache::GetColorCopyProgram(false), 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::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma); VertexShaderCache::GetSimpleInputLayout(), geomShader, Gamma);
} }
} }

View File

@ -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, leftRc, src_texture, src_width, src_height, 0);
post_processor->BlitFromTexture(src, rightRc, src_texture, src_width, src_height, 1); 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 else
{ {
post_processor->BlitFromTexture(src, dst, src_texture, src_width, src_height, 0); post_processor->BlitFromTexture(src, dst, src_texture, src_width, src_height, 0);

View File

@ -167,7 +167,7 @@ bool VideoBackend::Initialize(void* window_handle)
InitInterface(); InitInterface();
GLInterface->SetMode(GLInterfaceMode::MODE_DETECT); GLInterface->SetMode(GLInterfaceMode::MODE_DETECT);
if (!GLInterface->Create(window_handle)) if (!GLInterface->Create(window_handle, g_ActiveConfig.iStereoMode == STEREO_QUADBUFFER))
return false; return false;
return true; return true;

View File

@ -41,11 +41,14 @@ void VulkanPostProcessing::BlitFromTexture(const TargetRectangle& dst, const Tar
const Texture2D* src_tex, int src_layer, const Texture2D* src_tex, int src_layer,
VkRenderPass render_pass) 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 = VkShaderModule fragment_shader =
m_fragment_shader != VK_NULL_HANDLE ? m_fragment_shader : m_default_fragment_shader; m_fragment_shader != VK_NULL_HANDLE ? m_fragment_shader : m_default_fragment_shader;
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), render_pass, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), render_pass,
g_object_cache->GetPassthroughVertexShader(), VK_NULL_HANDLE, g_object_cache->GetPassthroughVertexShader(), geometry_shader,
fragment_shader); fragment_shader);
// Source is always bound. // Source is always bound.

View File

@ -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(left_rect, src_rect, src_tex, 0, render_pass);
post_processor->BlitFromTexture(right_rect, src_rect, src_tex, 1, 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 else
{ {
post_processor->BlitFromTexture(dst_rect, src_rect, src_tex, 0, render_pass); 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()); 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. // Wipe sampler cache if force texture filtering or anisotropy changes.
if (anisotropy_changed || force_texture_filtering_changed) if (anisotropy_changed || force_texture_filtering_changed)
ResetSamplerStates(); ResetSamplerStates();

View File

@ -320,6 +320,9 @@ bool SwapChain::CreateSwapChain()
return false; 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 // Store the old/current swap chain when recreating for resize
VkSwapchainKHR old_swap_chain = m_swap_chain; VkSwapchainKHR old_swap_chain = m_swap_chain;
@ -333,7 +336,7 @@ bool SwapChain::CreateSwapChain()
m_surface_format.format, m_surface_format.format,
m_surface_format.colorSpace, m_surface_format.colorSpace,
size, size,
1, image_layers,
image_usage, image_usage,
VK_SHARING_MODE_EXCLUSIVE, VK_SHARING_MODE_EXCLUSIVE,
0, 0,
@ -359,6 +362,7 @@ bool SwapChain::CreateSwapChain()
m_width = size.width; m_width = size.width;
m_height = size.height; m_height = size.height;
m_layers = image_layers;
return true; return true;
} }
@ -400,7 +404,7 @@ bool SwapChain::SetupSwapChainImages()
&view, &view,
m_width, m_width,
m_height, m_height,
1}; m_layers};
res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr,
&image.framebuffer); &image.framebuffer);

View File

@ -32,6 +32,7 @@ public:
VkSurfaceKHR GetSurface() const { return m_surface; } VkSurfaceKHR GetSurface() const { return m_surface; }
VkSurfaceFormatKHR GetSurfaceFormat() const { return m_surface_format; } VkSurfaceFormatKHR GetSurfaceFormat() const { return m_surface_format; }
bool IsVSyncEnabled() const { return m_vsync_enabled; } bool IsVSyncEnabled() const { return m_vsync_enabled; }
bool IsStereoEnabled() const { return m_layers == 2; }
VkSwapchainKHR GetSwapChain() const { return m_swap_chain; } VkSwapchainKHR GetSwapChain() const { return m_swap_chain; }
VkRenderPass GetRenderPass() const { return m_render_pass; } VkRenderPass GetRenderPass() const { return m_render_pass; }
u32 GetWidth() const { return m_width; } u32 GetWidth() const { return m_width; }
@ -94,6 +95,7 @@ private:
u32 m_width = 0; u32 m_width = 0;
u32 m_height = 0; u32 m_height = 0;
u32 m_layers = 0;
}; };
} // namespace Vulkan } // namespace Vulkan

View File

@ -606,6 +606,8 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data*
GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa), GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa),
uid_data->genMode_numtexgens + 2); 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) if (uid_data->stereo)
out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n"); out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n");
out.Write(" ) {\n"); out.Write(" ) {\n");

View File

@ -47,6 +47,7 @@ enum StereoMode
STEREO_SBS, STEREO_SBS,
STEREO_TAB, STEREO_TAB,
STEREO_ANAGLYPH, STEREO_ANAGLYPH,
STEREO_QUADBUFFER,
STEREO_3DVISION STEREO_3DVISION
}; };