diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index d8cfb12e59..6ccba4251d 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -453,9 +453,9 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con { wxFlexGridSizer* const szr_stereo = new wxFlexGridSizer(2, 5, 5); - const wxString stereo_choices[] = { "Off", "Side-by-Side", "Top-and-Bottom", "Anaglyph" }; + const wxString stereo_choices[] = { "Off", "Side-by-Side", "Top-and-Bottom", "Anaglyph", "Nvidia 3D Vision" }; szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Stereoscopic 3D Mode:")), 1, wxALIGN_CENTER_VERTICAL, 0); - szr_stereo->Add(CreateChoice(page_enh, vconfig.iStereoMode, wxGetTranslation(stereo_3d_desc), 4, stereo_choices)); + szr_stereo->Add(CreateChoice(page_enh, vconfig.iStereoMode, wxGetTranslation(stereo_3d_desc), vconfig.backend_info.bSupports3DVision ? 5 : 4, stereo_choices)); wxSlider* const sep_slider = new wxSlider(page_enh, wxID_ANY, vconfig.iStereoSeparation, 0, 100, wxDefaultPosition, wxDefaultSize); sep_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_StereoSep, this); diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj b/Source/Core/VideoBackends/D3D/D3D.vcxproj index 7ea9e09d07..f70efea502 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj @@ -43,6 +43,7 @@ + @@ -66,6 +67,7 @@ + diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters index c0158038b2..a83db06c6a 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters @@ -30,6 +30,9 @@ Render + + Render + Render @@ -93,6 +96,9 @@ Render + + Render + Render diff --git a/Source/Core/VideoBackends/D3D/D3DTexture.cpp b/Source/Core/VideoBackends/D3D/D3DTexture.cpp index e1c94d5974..8c23a4bd2c 100644 --- a/Source/Core/VideoBackends/D3D/D3DTexture.cpp +++ b/Source/Core/VideoBackends/D3D/D3DTexture.cpp @@ -37,7 +37,7 @@ void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned } // namespace -D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels) +D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels, unsigned int slices, D3D11_SUBRESOURCE_DATA* data) { ID3D11Texture2D* pTexture = nullptr; HRESULT hr; @@ -49,8 +49,8 @@ D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D1 cpuflags = D3D11_CPU_ACCESS_WRITE; else cpuflags = (D3D11_CPU_ACCESS_FLAG)0; - D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(fmt, width, height, 1, levels, bind, usage, cpuflags); - hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture); + D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(fmt, width, height, slices, levels, bind, usage, cpuflags); + hr = D3D::device->CreateTexture2D(&texdesc, data, &pTexture); if (FAILED(hr)) { PanicAlert("Failed to create texture at %s, line %d: hr=%#x\n", __FILE__, __LINE__, hr); @@ -87,9 +87,9 @@ D3DTexture2D::D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format, bool multisampled) : ref(1), tex(texptr), srv(nullptr), rtv(nullptr), dsv(nullptr) { - D3D11_SRV_DIMENSION srv_dim = multisampled ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D; - D3D11_DSV_DIMENSION dsv_dim = multisampled ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D; - D3D11_RTV_DIMENSION rtv_dim = multisampled ? D3D11_RTV_DIMENSION_TEXTURE2DMS : D3D11_RTV_DIMENSION_TEXTURE2D; + D3D11_SRV_DIMENSION srv_dim = multisampled ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + D3D11_DSV_DIMENSION dsv_dim = multisampled ? D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + D3D11_RTV_DIMENSION rtv_dim = multisampled ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D11_RTV_DIMENSION_TEXTURE2DARRAY; D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(srv_dim, srv_format); D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = CD3D11_DEPTH_STENCIL_VIEW_DESC(dsv_dim, dsv_format); D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = CD3D11_RENDER_TARGET_VIEW_DESC(rtv_dim, rtv_format); diff --git a/Source/Core/VideoBackends/D3D/D3DTexture.h b/Source/Core/VideoBackends/D3D/D3DTexture.h index 5c2aa57f4a..6be15b6102 100644 --- a/Source/Core/VideoBackends/D3D/D3DTexture.h +++ b/Source/Core/VideoBackends/D3D/D3DTexture.h @@ -22,7 +22,7 @@ public: // or let the texture automatically be created by D3DTexture2D::Create D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN, bool multisampled = false); - static D3DTexture2D* Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT, unsigned int levels = 1); + static D3DTexture2D* Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT, unsigned int levels = 1, unsigned int slices = 1, D3D11_SUBRESOURCE_DATA* data = nullptr); // reference counting, use AddRef() when creating a new reference and Release() it when you don't need it anymore void AddRef(); diff --git a/Source/Core/VideoBackends/D3D/D3DUtil.cpp b/Source/Core/VideoBackends/D3D/D3DUtil.cpp index 57524a49d3..50eac8665b 100644 --- a/Source/Core/VideoBackends/D3D/D3DUtil.cpp +++ b/Source/Core/VideoBackends/D3D/D3DUtil.cpp @@ -10,6 +10,7 @@ #include "VideoBackends/D3D/D3DShader.h" #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DUtil.h" +#include "VideoBackends/D3D/GeometryShaderCache.h" #include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/VertexShaderCache.h" @@ -422,20 +423,20 @@ int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dw ID3D11SamplerState* linear_copy_sampler = nullptr; ID3D11SamplerState* point_copy_sampler = nullptr; -struct STQVertex { float x, y, z, u, v, w; }; -struct STSQVertex { float x, y, z, u, v, w; }; +struct STQVertex { float x, y, z, u, v, w, g; }; +struct STSQVertex { float x, y, z, u, v, w, g; }; struct ClearVertex { float x, y, z; u32 col; }; struct ColVertex { float x, y, z; u32 col; }; struct { - float u1, v1, u2, v2, G; + float u1, v1, u2, v2, S, G; } tex_quad_data; struct { MathUtil::Rectangle rdest; - float u1, v1, u2, v2, G; + float u1, v1, u2, v2, S, G; } tex_sub_quad_data; struct @@ -510,9 +511,11 @@ void drawShadedTexQuad(ID3D11ShaderResourceView* texture, int SourceWidth, int SourceHeight, ID3D11PixelShader* PShader, - ID3D11VertexShader* Vshader, + ID3D11VertexShader* VShader, ID3D11InputLayout* layout, - float Gamma) + ID3D11GeometryShader* GShader, + float Gamma, + u32 slice) { float sw = 1.0f /(float) SourceWidth; float sh = 1.0f /(float) SourceHeight; @@ -520,19 +523,21 @@ void drawShadedTexQuad(ID3D11ShaderResourceView* texture, float u2 = ((float)rSource->right) * sw; float v1 = ((float)rSource->top) * sh; float v2 = ((float)rSource->bottom) * sh; + float S = (float)slice; float G = 1.0f / Gamma; STQVertex coords[4] = { - {-1.0f, 1.0f, 0.0f, u1, v1, G}, - { 1.0f, 1.0f, 0.0f, u2, v1, G}, - {-1.0f,-1.0f, 0.0f, u1, v2, G}, - { 1.0f,-1.0f, 0.0f, u2, v2, G}, + {-1.0f, 1.0f, 0.0f, u1, v1, S, G}, + { 1.0f, 1.0f, 0.0f, u2, v1, S, G}, + {-1.0f,-1.0f, 0.0f, u1, v2, S, G}, + { 1.0f,-1.0f, 0.0f, u2, v2, S, G}, }; // only upload the data to VRAM if it changed if (stq_observer || tex_quad_data.u1 != u1 || tex_quad_data.v1 != v1 || - tex_quad_data.u2 != u2 || tex_quad_data.v2 != v2 || tex_quad_data.G != G) + tex_quad_data.u2 != u2 || tex_quad_data.v2 != v2 || + tex_quad_data.S != S || tex_quad_data.G != G) { stq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(STQVertex)); stq_observer = false; @@ -541,7 +546,8 @@ void drawShadedTexQuad(ID3D11ShaderResourceView* texture, tex_quad_data.v1 = v1; tex_quad_data.u2 = u2; tex_quad_data.v2 = v2; - tex_quad_data.G = G; + tex_quad_data.S = S; + tex_quad_data.G = G; } UINT stride = sizeof(STQVertex); UINT offset = 0; @@ -551,13 +557,16 @@ void drawShadedTexQuad(ID3D11ShaderResourceView* texture, D3D::stateman->SetVertexBuffer(util_vbuf->GetBuffer(), stride, offset); D3D::stateman->SetPixelShader(PShader); D3D::stateman->SetTexture(0, texture); - D3D::stateman->SetVertexShader(Vshader); + D3D::stateman->SetVertexShader(VShader); + D3D::stateman->SetGeometryShader(GShader); D3D::stateman->Apply(); D3D::context->Draw(4, stq_offset); D3D::stateman->SetTexture(0, nullptr); // immediately unbind the texture D3D::stateman->Apply(); + + D3D::stateman->SetGeometryShader(nullptr); } void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture, @@ -566,9 +575,11 @@ void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture, int SourceHeight, const MathUtil::Rectangle* rDest, ID3D11PixelShader* PShader, - ID3D11VertexShader* Vshader, + ID3D11VertexShader* VShader, ID3D11InputLayout* layout, - float Gamma) + ID3D11GeometryShader* GShader, + float Gamma, + u32 slice) { float sw = 1.0f /(float) SourceWidth; float sh = 1.0f /(float) SourceHeight; @@ -576,20 +587,22 @@ void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture, float u2 = (rSource->right ) * sw; float v1 = (rSource->top ) * sh; float v2 = (rSource->bottom) * sh; + float S = (float)slice; float G = 1.0f / Gamma; STSQVertex coords[4] = { - { rDest->left , rDest->bottom, 0.0f, u1, v2, G}, - { rDest->right, rDest->bottom, 0.0f, u2, v2, G}, - { rDest->left , rDest->top , 0.0f, u1, v1, G}, - { rDest->right, rDest->top , 0.0f, u2, v1, G}, + { rDest->left , rDest->bottom, 0.0f, u1, v2, S, G}, + { rDest->right, rDest->bottom, 0.0f, u2, v2, S, G}, + { rDest->left , rDest->top , 0.0f, u1, v1, S, G}, + { rDest->right, rDest->top , 0.0f, u2, v1, S, G}, }; // only upload the data to VRAM if it changed if (stsq_observer || memcmp(rDest, &tex_sub_quad_data.rdest, sizeof(*rDest)) != 0 || tex_sub_quad_data.u1 != u1 || tex_sub_quad_data.v1 != v1 || - tex_sub_quad_data.u2 != u2 || tex_sub_quad_data.v2 != v2 || tex_sub_quad_data.G != G) + tex_sub_quad_data.u2 != u2 || tex_sub_quad_data.v2 != v2 || + tex_sub_quad_data.S != S || tex_sub_quad_data.G != G) { stsq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(STSQVertex)); stsq_observer = false; @@ -598,6 +611,7 @@ void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture, tex_sub_quad_data.v1 = v1; tex_sub_quad_data.u2 = u2; tex_sub_quad_data.v2 = v2; + tex_sub_quad_data.S = S; tex_sub_quad_data.G = G; memcpy(&tex_sub_quad_data.rdest, &rDest, sizeof(rDest)); } @@ -609,13 +623,16 @@ void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture, stateman->SetInputLayout(layout); stateman->SetTexture(0, texture); stateman->SetPixelShader(PShader); - stateman->SetVertexShader(Vshader); + stateman->SetVertexShader(VShader); + stateman->SetGeometryShader(GShader); stateman->Apply(); context->Draw(4, stsq_offset); stateman->SetTexture(0, nullptr); // immediately unbind the texture stateman->Apply(); + + stateman->SetGeometryShader(nullptr); } // Fills a certain area of the current render target with the specified color @@ -645,6 +662,7 @@ void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2) } stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader()); + stateman->SetGeometryShader(g_ActiveConfig.iStereoMode > 0 ? GeometryShaderCache::GetClearGeometryShader() : nullptr); stateman->SetPixelShader(PixelShaderCache::GetClearProgram()); stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout()); @@ -655,9 +673,11 @@ void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2) stateman->Apply(); context->Draw(4, cq_offset); + + stateman->SetGeometryShader(nullptr); } -void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout) +void drawClearQuad(u32 Color, float z) { ClearVertex coords[4] = { {-1.0f, 1.0f, z, Color}, @@ -675,9 +695,10 @@ void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexS clear_quad_data.z = z; } - stateman->SetVertexShader(Vshader); - stateman->SetPixelShader(PShader); - stateman->SetInputLayout(layout); + stateman->SetVertexShader(VertexShaderCache::GetClearVertexShader()); + stateman->SetGeometryShader(g_ActiveConfig.iStereoMode > 0 ? GeometryShaderCache::GetClearGeometryShader() : nullptr); + stateman->SetPixelShader(PixelShaderCache::GetClearProgram()); + stateman->SetInputLayout(VertexShaderCache::GetClearInputLayout()); UINT stride = sizeof(ClearVertex); UINT offset = 0; @@ -686,6 +707,8 @@ void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexS stateman->Apply(); context->Draw(4, clearq_offset); + + stateman->SetGeometryShader(nullptr); } } // namespace D3D diff --git a/Source/Core/VideoBackends/D3D/D3DUtil.h b/Source/Core/VideoBackends/D3D/D3DUtil.h index bd47d9ff0e..883f232b28 100644 --- a/Source/Core/VideoBackends/D3D/D3DUtil.h +++ b/Source/Core/VideoBackends/D3D/D3DUtil.h @@ -62,17 +62,21 @@ namespace D3D ID3D11PixelShader* PShader, ID3D11VertexShader* VShader, ID3D11InputLayout* layout, - float Gamma = 1.0f); + ID3D11GeometryShader* GShader = nullptr, + float Gamma = 1.0f, + u32 slice = 0); void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture, const MathUtil::Rectangle* rSource, int SourceWidth, int SourceHeight, const MathUtil::Rectangle* rDest, ID3D11PixelShader* PShader, - ID3D11VertexShader* Vshader, + ID3D11VertexShader* VShader, ID3D11InputLayout* layout, - float Gamma = 1.0f); - void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout); + ID3D11GeometryShader* GShader = nullptr, + float Gamma = 1.0f, + u32 slice = 0); + void drawClearQuad(u32 Color, float z); void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2); } diff --git a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp index aeaaf6b8e8..a1b66dc3e7 100644 --- a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp @@ -57,8 +57,10 @@ FramebufferManager::FramebufferManager() D3D11_TEXTURE2D_DESC texdesc; HRESULT hr; + m_EFBLayers = m_efb.slices = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1; + // EFB color texture - primary render target - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, target_width, target_height, 1, 1, D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, target_width, target_height, m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); CHECK(hr==S_OK, "create EFB color texture (size: %dx%d; hr=%#x)", target_width, target_height, hr); m_efb.color_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET), DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1)); @@ -69,7 +71,7 @@ FramebufferManager::FramebufferManager() D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetRTV(), "EFB color texture render target view"); // Temporary EFB color texture - used in ReinterpretPixelData - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, target_width, target_height, 1, 1, D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, target_width, target_height, m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); CHECK(hr==S_OK, "create EFB color temp texture (size: %dx%d; hr=%#x)", target_width, target_height, hr); m_efb.color_temp_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET), DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1)); @@ -80,13 +82,13 @@ FramebufferManager::FramebufferManager() D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetRTV(), "EFB color temp texture render target view"); // AccessEFB - Sysmem buffer used to retrieve the pixel data from color_tex - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ); + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, m_efb.slices, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ); hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &m_efb.color_staging_buf); CHECK(hr==S_OK, "create EFB color staging buffer (hr=%#x)", hr); D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_staging_buf, "EFB color staging texture (used for Renderer::AccessEFB)"); // EFB depth buffer - primary depth buffer - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R24G8_TYPELESS, target_width, target_height, 1, 1, D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R24G8_TYPELESS, target_width, target_height, m_efb.slices, 1, D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0, sample_desc.Count, sample_desc.Quality); hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); CHECK(hr==S_OK, "create EFB depth texture (size: %dx%d; hr=%#x)", target_width, target_height, hr); m_efb.depth_tex = new D3DTexture2D(buf, (D3D11_BIND_FLAG)(D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE), DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, (sample_desc.Count > 1)); @@ -96,7 +98,7 @@ FramebufferManager::FramebufferManager() D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetSRV(), "EFB depth texture shader resource view"); // Render buffer for AccessEFB (depth data) - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET); + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, m_efb.slices, 1, D3D11_BIND_RENDER_TARGET); hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); CHECK(hr==S_OK, "create EFB depth read texture (hr=%#x)", hr); m_efb.depth_read_texture = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET); @@ -105,7 +107,7 @@ FramebufferManager::FramebufferManager() D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetRTV(), "EFB depth read texture render target view (used in Renderer::AccessEFB)"); // AccessEFB - Sysmem buffer used to retrieve the pixel data from depth_read_texture - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ); + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 1, 1, m_efb.slices, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ); hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &m_efb.depth_staging_buf); CHECK(hr==S_OK, "create EFB depth staging buffer (hr=%#x)", hr); D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_staging_buf, "EFB depth staging texture (used for Renderer::AccessEFB)"); @@ -113,7 +115,7 @@ FramebufferManager::FramebufferManager() if (g_ActiveConfig.iMultisampleMode) { // Framebuffer resolve textures (color+depth) - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, target_width, target_height, 1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0, 1); + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, target_width, target_height, m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0, 1); hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); m_efb.resolved_color_tex = new D3DTexture2D(buf, D3D11_BIND_SHADER_RESOURCE, DXGI_FORMAT_R8G8B8A8_UNORM); CHECK(m_efb.resolved_color_tex!=nullptr, "create EFB color resolve texture (size: %dx%d)", target_width, target_height); @@ -121,7 +123,7 @@ FramebufferManager::FramebufferManager() D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_color_tex->GetTex(), "EFB color resolve texture"); D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_color_tex->GetSRV(), "EFB color resolve texture shader resource view"); - texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R24G8_TYPELESS, target_width, target_height, 1, 1, D3D11_BIND_SHADER_RESOURCE); + texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R24G8_TYPELESS, target_width, target_height, m_efb.slices, 1, D3D11_BIND_SHADER_RESOURCE); hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &buf); CHECK(hr==S_OK, "create EFB depth resolve texture (size: %dx%d; hr=%#x)", target_width, target_height, hr); m_efb.resolved_depth_tex = new D3DTexture2D(buf, D3D11_BIND_SHADER_RESOURCE, DXGI_FORMAT_R24_UNORM_X8_TYPELESS); @@ -162,7 +164,7 @@ XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, un { return new XFBSource(D3DTexture2D::Create(target_width, target_height, (D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE), - D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM)); + D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, FramebufferManager::GetEFBLayers()), FramebufferManager::GetEFBLayers()); } void FramebufferManager::GetTargetSize(unsigned int *width, unsigned int *height, const EFBRectangle& sourceRc) @@ -206,7 +208,7 @@ void XFBSource::CopyEFB(float Gamma) D3D::drawShadedTexQuad(FramebufferManager::GetEFBColorTexture()->GetSRV(), sourceRc.AsRECT(), Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), PixelShaderCache::GetColorCopyProgram(true), VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout(),Gamma); + VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma); D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); diff --git a/Source/Core/VideoBackends/D3D/FramebufferManager.h b/Source/Core/VideoBackends/D3D/FramebufferManager.h index 45f43f7357..d7961cb9b8 100644 --- a/Source/Core/VideoBackends/D3D/FramebufferManager.h +++ b/Source/Core/VideoBackends/D3D/FramebufferManager.h @@ -45,7 +45,7 @@ namespace DX11 { struct XFBSource : public XFBSourceBase { - XFBSource(D3DTexture2D *_tex) : tex(_tex) {} + XFBSource(D3DTexture2D *_tex, int slices) : tex(_tex), m_slices(slices) {} ~XFBSource() { tex->Release(); } void Draw(const MathUtil::Rectangle &sourcerc, @@ -54,6 +54,7 @@ struct XFBSource : public XFBSourceBase void CopyEFB(float Gamma) override; D3DTexture2D* const tex; + const int m_slices; }; class FramebufferManager : public FramebufferManagerBase @@ -99,6 +100,8 @@ private: D3DTexture2D* resolved_color_tex; D3DTexture2D* resolved_depth_tex; + + int slices; } m_efb; }; diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp new file mode 100644 index 0000000000..29172f91a1 --- /dev/null +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp @@ -0,0 +1,243 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#include "Common/FileUtil.h" +#include "Common/LinearDiskCache.h" +#include "Common/StringUtil.h" + +#include "Core/ConfigManager.h" + +#include "VideoBackends/D3D/D3DBase.h" +#include "VideoBackends/D3D/D3DShader.h" +#include "VideoBackends/D3D/GeometryShaderCache.h" +#include "VideoBackends/D3D/Globals.h" + +#include "VideoCommon/Debugger.h" +#include "VideoCommon/GeometryShaderGen.h" +#include "VideoCommon/VideoConfig.h" + +namespace DX11 +{ + +GeometryShaderCache::GSCache GeometryShaderCache::GeometryShaders; +const GeometryShaderCache::GSCacheEntry* GeometryShaderCache::last_entry; +GeometryShaderUid GeometryShaderCache::last_uid; +UidChecker GeometryShaderCache::geometry_uid_checker; + +ID3D11GeometryShader* ClearGeometryShader = nullptr; +ID3D11GeometryShader* CopyGeometryShader = nullptr; + +LinearDiskCache g_gs_disk_cache; + +ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader() { return ClearGeometryShader; } +ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader() { return CopyGeometryShader; } + +ID3D11Buffer* gscbuf = nullptr; + +// this class will load the precompiled shaders into our cache +class GeometryShaderCacheInserter : public LinearDiskCacheReader +{ +public: + void Read(const GeometryShaderUid &key, const u8* value, u32 value_size) + { + GeometryShaderCache::InsertByteCode(key, value, value_size); + } +}; + +const char clear_shader_code[] = { + "struct VSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float4 vColor0 : COLOR0;\n" + "};\n" + "struct GSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float4 vColor0 : COLOR0;\n" + "uint slice : SV_RenderTargetArrayIndex;\n" + "};\n" + "[maxvertexcount(6)]\n" + "void main(triangle VSOUTPUT o[3], inout TriangleStream Output)\n" + "{\n" + "for(int slice = 0; slice < 2; slice++)\n" + "{\n" + "for(int i = 0; i < 3; i++)\n" + "{\n" + "GSOUTPUT OUT;\n" + "OUT.vPosition = o[i].vPosition;\n" + "OUT.vColor0 = o[i].vColor0;\n" + "OUT.slice = slice;\n" + "Output.Append(OUT);\n" + "}\n" + "Output.RestartStrip();\n" + "}\n" + "}\n" +}; + +const char copy_shader_code[] = { + "struct VSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float3 vTexCoord : TEXCOORD0;\n" + "float vTexCoord1 : TEXCOORD1;\n" + "};\n" + "struct GSOUTPUT\n" + "{\n" + "float4 vPosition : POSITION;\n" + "float3 vTexCoord : TEXCOORD0;\n" + "float vTexCoord1 : TEXCOORD1;\n" + "uint slice : SV_RenderTargetArrayIndex;\n" + "};\n" + "[maxvertexcount(6)]\n" + "void main(triangle VSOUTPUT o[3], inout TriangleStream Output)\n" + "{\n" + "for(int slice = 0; slice < 2; slice++)\n" + "{\n" + "for(int i = 0; i < 3; i++)\n" + "{\n" + "GSOUTPUT OUT;\n" + "OUT.vPosition = o[i].vPosition;\n" + "OUT.vTexCoord = o[i].vTexCoord;\n" + "OUT.vTexCoord.z = slice;\n" + "OUT.vTexCoord1 = o[i].vTexCoord1;\n" + "OUT.slice = slice;\n" + "Output.Append(OUT);\n" + "}\n" + "Output.RestartStrip();\n" + "}\n" + "}\n" +}; + +void GeometryShaderCache::Init() +{ + // used when drawing clear quads + ClearGeometryShader = D3D::CompileAndCreateGeometryShader(clear_shader_code); + CHECK(ClearGeometryShader != nullptr, "Create clear geometry shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearGeometryShader, "clear geometry shader"); + + // used for buffer copy + CopyGeometryShader = D3D::CompileAndCreateGeometryShader(copy_shader_code); + CHECK(CopyGeometryShader != nullptr, "Create copy geometry shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)CopyGeometryShader, "copy geometry shader"); + + Clear(); + + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + + std::string cache_filename = StringFromFormat("%sdx11-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), + SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str()); + GeometryShaderCacheInserter inserter; + g_gs_disk_cache.OpenAndRead(cache_filename, inserter); + + if (g_Config.bEnableShaderDebugging) + Clear(); + + last_entry = nullptr; +} + +// ONLY to be used during shutdown. +void GeometryShaderCache::Clear() +{ + for (auto& iter : GeometryShaders) + iter.second.Destroy(); + GeometryShaders.clear(); + geometry_uid_checker.Invalidate(); + + last_entry = nullptr; +} + +void GeometryShaderCache::Shutdown() +{ + SAFE_RELEASE(ClearGeometryShader); + SAFE_RELEASE(CopyGeometryShader); + + Clear(); + g_gs_disk_cache.Sync(); + g_gs_disk_cache.Close(); +} + +bool GeometryShaderCache::SetShader(u32 components) +{ + GeometryShaderUid uid; + GetGeometryShaderUid(uid, components, API_D3D); + if (g_ActiveConfig.bEnableShaderDebugging) + { + ShaderCode code; + GenerateGeometryShaderCode(code, components, API_D3D); + geometry_uid_checker.AddToIndexAndCheck(code, uid, "Geometry", "g"); + } + + // Check if the shader is already set + if (last_entry) + { + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); + return (last_entry->shader != nullptr); + } + } + + last_uid = uid; + + // Check if the shader is already in the cache + GSCache::iterator iter; + iter = GeometryShaders.find(uid); + if (iter != GeometryShaders.end()) + { + const GSCacheEntry &entry = iter->second; + last_entry = &entry; + + return (entry.shader != nullptr); + } + + // Need to compile a new shader + ShaderCode code; + GenerateGeometryShaderCode(code, components, API_D3D); + + D3DBlob* pbytecode; + if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode)) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); + return false; + } + + // Insert the bytecode into the caches + g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); + + bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); + pbytecode->Release(); + + if (g_ActiveConfig.bEnableShaderDebugging && success) + { + GeometryShaders[uid].code = code.GetBuffer(); + } + + return success; +} + +bool GeometryShaderCache::InsertByteCode(const GeometryShaderUid &uid, const void* bytecode, unsigned int bytecodelen) +{ + ID3D11GeometryShader* shader = D3D::CreateGeometryShaderFromByteCode(bytecode, bytecodelen); + if (shader == nullptr) + return false; + + // TODO: Somehow make the debug name a bit more specific + D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of GeometryShaderCache"); + + // Make an entry in the table + GSCacheEntry newentry; + newentry.shader = shader; + GeometryShaders[uid] = newentry; + last_entry = &GeometryShaders[uid]; + + if (!shader) + return false; + + return true; +} + +} // DX11 diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.h b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h new file mode 100644 index 0000000000..9d38922d04 --- /dev/null +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h @@ -0,0 +1,49 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "VideoCommon/GeometryShaderGen.h" + +namespace DX11 +{ + +class GeometryShaderCache +{ +public: + static void Init(); + static void Clear(); + static void Shutdown(); + static bool SetShader(u32 components); // TODO: Should be renamed to LoadShader + static bool InsertByteCode(const GeometryShaderUid &uid, const void* bytecode, unsigned int bytecodelen); + + static ID3D11GeometryShader* GeometryShaderCache::GetClearGeometryShader(); + static ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader(); + + static ID3D11GeometryShader* GetActiveShader() { return last_entry->shader; } + +private: + struct GSCacheEntry + { + ID3D11GeometryShader* shader; + + std::string code; + + GSCacheEntry() : shader(nullptr) {} + void Destroy() { SAFE_RELEASE(shader); } + }; + + typedef std::map GSCache; + + static GSCache GeometryShaders; + static const GSCacheEntry* last_entry; + static GeometryShaderUid last_uid; + + static UidChecker geometry_uid_checker; +}; + +} // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/LineGeometryShader.cpp b/Source/Core/VideoBackends/D3D/LineGeometryShader.cpp index cd2b11e2b3..7fcb02ff8d 100644 --- a/Source/Core/VideoBackends/D3D/LineGeometryShader.cpp +++ b/Source/Core/VideoBackends/D3D/LineGeometryShader.cpp @@ -173,7 +173,7 @@ bool LineGeometryShader::SetShader(u32 components, float lineWidth, static char buffer[16384]; ShaderCode code; code.SetBuffer(buffer); - GenerateVSOutputStruct(code, API_D3D); + GenerateVSOutputStruct(code, API_D3D); code.Write("\n%s", LINE_GS_COMMON); std::stringstream numTexCoordsStream; diff --git a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp index 09f124ecc6..fcc40cc9e5 100644 --- a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp @@ -100,7 +100,7 @@ static const char EFB_ENCODE_PS[] = "} Params;\n" "}\n" -"Texture2D EFBTexture : register(t0);\n" +"Texture2DArray EFBTexture : register(t0);\n" "sampler EFBSampler : register(s0);\n" // Constants @@ -183,7 +183,7 @@ static const char EFB_ENCODE_PS[] = "float4 Fetch_0(float2 coord)\n" "{\n" "float2 texCoord = CalcTexCoord(coord);\n" - "float4 result = EFBTexture.Sample(EFBSampler, texCoord);\n" + "float4 result = EFBTexture.Sample(EFBSampler, float3(texCoord.xy, 0.0));\n" "result.a = 1.0;\n" "return result;\n" "}\n" @@ -191,13 +191,13 @@ static const char EFB_ENCODE_PS[] = "float4 Fetch_1(float2 coord)\n" "{\n" "float2 texCoord = CalcTexCoord(coord);\n" - "return EFBTexture.Sample(EFBSampler, texCoord);\n" + "return EFBTexture.Sample(EFBSampler, float3(texCoord.xy, 0.0));\n" "}\n" "float4 Fetch_2(float2 coord)\n" "{\n" "float2 texCoord = CalcTexCoord(coord);\n" - "float4 result = EFBTexture.Sample(EFBSampler, texCoord);\n" + "float4 result = EFBTexture.Sample(EFBSampler, float3(texCoord.xy, 0.0));\n" "result.a = 1.0;\n" "return result;\n" "}\n" @@ -206,7 +206,7 @@ static const char EFB_ENCODE_PS[] = "{\n" "float2 texCoord = CalcTexCoord(coord);\n" - "uint depth24 = 0xFFFFFF * EFBTexture.Sample(EFBSampler, texCoord).r;\n" + "uint depth24 = 0xFFFFFF * EFBTexture.Sample(EFBSampler, float3(texCoord.xy, 0.0)).r;\n" "uint4 bytes = uint4(\n" "(depth24 >> 16) & 0xFF,\n" // r "(depth24 >> 8) & 0xFF,\n" // g diff --git a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp index a42d1a4103..d8fbd62158 100644 --- a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp @@ -35,6 +35,7 @@ ID3D11PixelShader* s_ColorMatrixProgram[2] = {nullptr}; ID3D11PixelShader* s_ColorCopyProgram[2] = {nullptr}; ID3D11PixelShader* s_DepthMatrixProgram[2] = {nullptr}; ID3D11PixelShader* s_ClearProgram = nullptr; +ID3D11PixelShader* s_AnaglyphProgram = nullptr; ID3D11PixelShader* s_rgba6_to_rgb8[2] = {nullptr}; ID3D11PixelShader* s_rgb8_to_rgba6[2] = {nullptr}; ID3D11Buffer* pscbuf = nullptr; @@ -51,40 +52,53 @@ const char clear_program_code[] = { // TODO: Find some way to avoid having separate shaders for non-MSAA and MSAA... const char color_copy_program_code[] = { "sampler samp0 : register(s0);\n" - "Texture2D Tex0 : register(t0);\n" + "Texture2DArray Tex0 : register(t0);\n" "void main(\n" "out float4 ocol0 : SV_Target,\n" "in float4 pos : SV_Position,\n" - "in float2 uv0 : TEXCOORD0){\n" + "in float3 uv0 : TEXCOORD0){\n" "ocol0 = Tex0.Sample(samp0,uv0);\n" "}\n" }; +const char anaglyph_program_code[] = { + "sampler samp0 : register(s0);\n" + "Texture2DArray Tex0 : register(t0);\n" + "void main(\n" + "out float4 ocol0 : SV_Target,\n" + "in float4 pos : SV_Position,\n" + "in float3 uv0 : TEXCOORD0){\n" + "float4 c0 = Tex0.Sample(samp0, float3(uv0.xy, 0.0));\n" + "float4 c1 = Tex0.Sample(samp0, float3(uv0.xy, 1));\n" + "ocol0 = float4(pow(0.7 * c0.g + 0.3 * c0.b, 1.5), c1.gba);" + "}\n" +}; + // TODO: Improve sampling algorithm! const char color_copy_program_code_msaa[] = { "sampler samp0 : register(s0);\n" - "Texture2DMS Tex0 : register(t0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" "void main(\n" "out float4 ocol0 : SV_Target,\n" "in float4 pos : SV_Position,\n" - "in float2 uv0 : TEXCOORD0){\n" - "int width, height, samples;\n" - "Tex0.GetDimensions(width, height, samples);\n" + "in float3 uv0 : TEXCOORD0){\n" + "int width, height, slices, samples;\n" + "Tex0.GetDimensions(width, height, slices, samples);\n" "ocol0 = 0;\n" "for(int i = 0; i < samples; ++i)\n" - " ocol0 += Tex0.Load(int2(uv0.x*(width), uv0.y*(height)), i);\n" + " ocol0 += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" "ocol0 /= samples;\n" "}\n" }; const char color_matrix_program_code[] = { "sampler samp0 : register(s0);\n" - "Texture2D Tex0 : register(t0);\n" + "Texture2DArray Tex0 : register(t0);\n" "uniform float4 cColMatrix[7] : register(c0);\n" "void main(\n" "out float4 ocol0 : SV_Target,\n" "in float4 pos : SV_Position,\n" - " in float2 uv0 : TEXCOORD0){\n" + "in float3 uv0 : TEXCOORD0){\n" "float4 texcol = Tex0.Sample(samp0,uv0);\n" "texcol = round(texcol * cColMatrix[5])*cColMatrix[6];\n" "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" @@ -93,17 +107,17 @@ const char color_matrix_program_code[] = { const char color_matrix_program_code_msaa[] = { "sampler samp0 : register(s0);\n" - "Texture2DMS Tex0 : register(t0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" "uniform float4 cColMatrix[7] : register(c0);\n" "void main(\n" "out float4 ocol0 : SV_Target,\n" "in float4 pos : SV_Position,\n" - " in float2 uv0 : TEXCOORD0){\n" - "int width, height, samples;\n" - "Tex0.GetDimensions(width, height, samples);\n" + "in float3 uv0 : TEXCOORD0){\n" + "int width, height, slices, samples;\n" + "Tex0.GetDimensions(width, height, slices, samples);\n" "float4 texcol = 0;\n" "for(int i = 0; i < samples; ++i)\n" - " texcol += Tex0.Load(int2(uv0.x*(width), uv0.y*(height)), i);\n" + " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" "texcol /= samples;\n" "texcol = round(texcol * cColMatrix[5])*cColMatrix[6];\n" "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n" @@ -112,12 +126,12 @@ const char color_matrix_program_code_msaa[] = { const char depth_matrix_program[] = { "sampler samp0 : register(s0);\n" - "Texture2D Tex0 : register(t0);\n" + "Texture2DArray Tex0 : register(t0);\n" "uniform float4 cColMatrix[7] : register(c0);\n" "void main(\n" "out float4 ocol0 : SV_Target,\n" " in float4 pos : SV_Position,\n" - " in float2 uv0 : TEXCOORD0){\n" + " in float3 uv0 : TEXCOORD0){\n" " float4 texcol = Tex0.Sample(samp0,uv0);\n" // 255.99998474121 = 16777215/16777216*256 @@ -147,17 +161,17 @@ const char depth_matrix_program[] = { const char depth_matrix_program_msaa[] = { "sampler samp0 : register(s0);\n" - "Texture2DMS Tex0 : register(t0);\n" + "Texture2DMSArray Tex0 : register(t0);\n" "uniform float4 cColMatrix[7] : register(c0);\n" "void main(\n" "out float4 ocol0 : SV_Target,\n" " in float4 pos : SV_Position,\n" - " in float2 uv0 : TEXCOORD0){\n" - " int width, height, samples;\n" - " Tex0.GetDimensions(width, height, samples);\n" + " in float3 uv0 : TEXCOORD0){\n" + " int width, height, slices, samples;\n" + " Tex0.GetDimensions(width, height, slices, samples);\n" " float4 texcol = 0;\n" " for(int i = 0; i < samples; ++i)\n" - " texcol += Tex0.Load(int2(uv0.x*(width), uv0.y*(height)), i);\n" + " texcol += Tex0.Load(int3(uv0.x*(width), uv0.y*(height), uv0.z), i);\n" " texcol /= samples;\n" // 255.99998474121 = 16777215/16777216*256 @@ -385,6 +399,11 @@ ID3D11PixelShader* PixelShaderCache::GetClearProgram() return s_ClearProgram; } +ID3D11PixelShader* PixelShaderCache::GetAnaglyphProgram() +{ + return s_AnaglyphProgram; +} + ID3D11Buffer* &PixelShaderCache::GetConstantBuffer() { // TODO: divide the global variables of the generated shaders into about 5 constant buffers to speed this up @@ -405,7 +424,7 @@ ID3D11Buffer* &PixelShaderCache::GetConstantBuffer() class PixelShaderCacheInserter : public LinearDiskCacheReader { public: - void Read(const PixelShaderUid &key, const u8 *value, u32 value_size) + void Read(const PixelShaderUid &key, const u8* value, u32 value_size) { PixelShaderCache::InsertByteCode(key, value, value_size); } @@ -424,6 +443,11 @@ void PixelShaderCache::Init() CHECK(s_ClearProgram!=nullptr, "Create clear pixel shader"); D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "clear pixel shader"); + // used for anaglyph stereoscopy + s_AnaglyphProgram = D3D::CompileAndCreatePixelShader(anaglyph_program_code); + CHECK(s_AnaglyphProgram != nullptr, "Create anaglyph pixel shader"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_AnaglyphProgram, "anaglyph pixel shader"); + // used when copying/resolving the color buffer s_ColorCopyProgram[0] = D3D::CompileAndCreatePixelShader(color_copy_program_code); CHECK(s_ColorCopyProgram[0]!=nullptr, "Create color copy pixel shader"); @@ -484,6 +508,7 @@ void PixelShaderCache::Shutdown() SAFE_RELEASE(pscbuf); SAFE_RELEASE(s_ClearProgram); + SAFE_RELEASE(s_AnaglyphProgram); for (int i = 0; i < 2; ++i) { SAFE_RELEASE(s_ColorCopyProgram[i]); diff --git a/Source/Core/VideoBackends/D3D/PixelShaderCache.h b/Source/Core/VideoBackends/D3D/PixelShaderCache.h index 55a31379e3..413a7c31a4 100644 --- a/Source/Core/VideoBackends/D3D/PixelShaderCache.h +++ b/Source/Core/VideoBackends/D3D/PixelShaderCache.h @@ -30,6 +30,7 @@ public: static ID3D11PixelShader* GetColorCopyProgram(bool multisampled); static ID3D11PixelShader* GetDepthMatrixProgram(bool multisampled); static ID3D11PixelShader* GetClearProgram(); + static ID3D11PixelShader* GetAnaglyphProgram(); static ID3D11PixelShader* ReinterpRGBA6ToRGB8(bool multisampled); static ID3D11PixelShader* ReinterpRGB8ToRGBA6(bool multisampled); diff --git a/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp b/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp index cfaca95cf3..3f874b3915 100644 --- a/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp +++ b/Source/Core/VideoBackends/D3D/PointGeometryShader.cpp @@ -167,7 +167,7 @@ bool PointGeometryShader::SetShader(u32 components, float pointSize, static char buffer[16384]; ShaderCode code; code.SetBuffer(buffer); - GenerateVSOutputStruct(code, API_D3D); + GenerateVSOutputStruct(code, API_D3D); code.Write("\n%s", POINT_GS_COMMON); std::stringstream numTexCoordsStream; diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 9d5802ebd8..86f93fc9ad 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -21,6 +21,7 @@ #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DUtil.h" #include "VideoBackends/D3D/FramebufferManager.h" +#include "VideoBackends/D3D/GeometryShaderCache.h" #include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/Render.h" #include "VideoBackends/D3D/Television.h" @@ -46,6 +47,7 @@ static u32 s_LastAA = 0; static Television s_television; static bool s_last_fullscreen_mode = false; +static bool s_LastStereo = 0; ID3D11Buffer* access_efb_cbuf = nullptr; ID3D11BlendState* clearblendstates[4] = {nullptr}; @@ -55,6 +57,19 @@ ID3D11DepthStencilState* resetdepthstate = nullptr; ID3D11RasterizerState* resetraststate = nullptr; static ID3D11Texture2D* s_screenshot_texture = nullptr; +static D3DTexture2D* s_3d_vision_texture = nullptr; + +// Nvidia stereo blitting struct defined in "nvstereo.h" from the Nvidia SDK +typedef struct _Nv_Stereo_Image_Header +{ + unsigned int dwSignature; + unsigned int dwWidth; + unsigned int dwHeight; + unsigned int dwBPP; + unsigned int dwFlags; +} NVSTEREOIMAGEHEADER, *LPNVSTEREOIMAGEHEADER; + +#define NVSTEREO_IMAGE_SIGNATURE 0x4433564e // GX pipeline state struct @@ -169,6 +184,7 @@ void TeardownDeviceObjects() SAFE_RELEASE(resetdepthstate); SAFE_RELEASE(resetraststate); SAFE_RELEASE(s_screenshot_texture); + SAFE_RELEASE(s_3d_vision_texture); s_television.Shutdown(); @@ -183,6 +199,24 @@ void CreateScreenshotTexture(const TargetRectangle& rc) D3D::SetDebugObjectName((ID3D11DeviceChild*)s_screenshot_texture, "staging screenshot texture"); } +void Create3DVisionTexture(int width, int height) +{ + // Create a staging texture for 3D vision with signature information in the last row. + // Nvidia 3D Vision supports full SBS, so there is no loss in resolution during this process. + D3D11_SUBRESOURCE_DATA sysData; + sysData.SysMemPitch = 4 * width * 2; + sysData.pSysMem = new u8[(height + 1) * sysData.SysMemPitch]; + LPNVSTEREOIMAGEHEADER header = (LPNVSTEREOIMAGEHEADER)((u8*)sysData.pSysMem + height * sysData.SysMemPitch); + header->dwSignature = NVSTEREO_IMAGE_SIGNATURE; + header->dwWidth = width * 2; + header->dwHeight = height + 1; + header->dwBPP = 32; + header->dwFlags = 0; + + s_3d_vision_texture = D3DTexture2D::Create(width * 2, height + 1, D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, &sysData); + delete[] sysData.pSysMem; +} + Renderer::Renderer(void *&window_handle) { D3D::Create((HWND)window_handle); @@ -198,6 +232,7 @@ Renderer::Renderer(void *&window_handle) s_LastAA = g_ActiveConfig.iMultisampleMode; s_LastEFBScale = g_ActiveConfig.iEFBScale; s_last_fullscreen_mode = g_ActiveConfig.bFullscreen; + s_LastStereo = g_ActiveConfig.iStereoMode > 0; CalculateTargetSize(s_backbuffer_width, s_backbuffer_height); SetupDeviceObjects(); @@ -514,7 +549,7 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE // Color is passed in bgra mode so we need to convert it to rgba u32 rgbaColor = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000); - D3D::drawClearQuad(rgbaColor, (z & 0xFFFFFF) / float(0xFFFFFF), PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader(), VertexShaderCache::GetClearInputLayout()); + D3D::drawClearQuad(rgbaColor, (z & 0xFFFFFF) / float(0xFFFFFF)); D3D::stateman->PopDepthState(); D3D::stateman->PopBlendState(); @@ -761,7 +796,52 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co // TODO: Improve sampling algorithm for the pixel shader so that we can use the multisampled EFB texture as source D3DTexture2D* read_texture = FramebufferManager::GetResolvedEFBColorTexture(); - D3D::drawShadedTexQuad(read_texture->GetSRV(), targetRc.AsRECT(), Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), PixelShaderCache::GetColorCopyProgram(false),VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), Gamma); + + if (g_ActiveConfig.iStereoMode == STEREO_SBS || g_ActiveConfig.iStereoMode == STEREO_TAB) + { + TargetRectangle leftRc, rightRc; + ConvertStereoRectangle(GetTargetRectangle(), leftRc, rightRc); + + D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT((float)leftRc.left, (float)leftRc.top, (float)leftRc.GetWidth(), (float)leftRc.GetHeight()); + D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)rightRc.left, (float)rightRc.top, (float)rightRc.GetWidth(), (float)rightRc.GetHeight()); + + D3D::context->RSSetViewports(1, &leftVp); + D3D::drawShadedTexQuad(read_texture->GetSRV(), targetRc.AsRECT(), Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0); + + D3D::context->RSSetViewports(1, &rightVp); + D3D::drawShadedTexQuad(read_texture->GetSRV(), targetRc.AsRECT(), Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1); + + D3D::context->RSSetViewports(1, &vp); + } + else if (g_ActiveConfig.iStereoMode == STEREO_3DVISION) + { + if (!s_3d_vision_texture) + Create3DVisionTexture(s_backbuffer_width, s_backbuffer_height); + + D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT((float)X, (float)Y, (float)Width, (float)Height); + D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)(X + s_backbuffer_width), (float)Y, (float)Width, (float)Height); + + // Render to staging texture which is double the width of the backbuffer + D3D::context->OMSetRenderTargets(1, &s_3d_vision_texture->GetRTV(), nullptr); + + D3D::context->RSSetViewports(1, &leftVp); + D3D::drawShadedTexQuad(read_texture->GetSRV(), targetRc.AsRECT(), Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0); + + D3D::context->RSSetViewports(1, &rightVp); + D3D::drawShadedTexQuad(read_texture->GetSRV(), targetRc.AsRECT(), Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1); + + // Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should + // recognize the signature and automatically include the right eye frame. + D3D11_BOX box = CD3D11_BOX(0, 0, 0, s_backbuffer_width, s_backbuffer_height, 1); + D3D::context->CopySubresourceRegion(D3D::GetBackBuffer()->GetTex(), 0, 0, 0, 0, s_3d_vision_texture->GetTex(), 0, &box); + + D3D::context->RSSetViewports(1, &vp); + D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); + } + else + { + D3D::drawShadedTexQuad(read_texture->GetSRV(), targetRc.AsRECT(), Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), (g_Config.iStereoMode == STEREO_ANAGLYPH) ? PixelShaderCache::GetAnaglyphProgram() : PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma); + } } // done with drawing the game stuff, good moment to save a screenshot @@ -931,7 +1011,8 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co windowResized || fullscreen_changed || s_LastEFBScale != g_ActiveConfig.iEFBScale || - s_LastAA != g_ActiveConfig.iMultisampleMode) + s_LastAA != g_ActiveConfig.iMultisampleMode || + s_LastStereo != (g_ActiveConfig.iStereoMode > 0)) { s_LastAA = g_ActiveConfig.iMultisampleMode; PixelShaderCache::InvalidateMSAAShaders(); @@ -954,6 +1035,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co // TODO: Aren't we still holding a reference to the back buffer right now? D3D::Reset(); SAFE_RELEASE(s_screenshot_texture); + SAFE_RELEASE(s_3d_vision_texture); s_backbuffer_width = D3D::GetBackBufferWidth(); s_backbuffer_height = D3D::GetBackBufferHeight(); } @@ -961,6 +1043,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); s_LastEFBScale = g_ActiveConfig.iEFBScale; + s_LastStereo = g_ActiveConfig.iStereoMode > 0; CalculateTargetSize(s_backbuffer_width, s_backbuffer_height); D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp index 4ed4d6045f..bef632e4fd 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp @@ -7,6 +7,7 @@ #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/D3DUtil.h" #include "VideoBackends/D3D/FramebufferManager.h" +#include "VideoBackends/D3D/GeometryShaderCache.h" #include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/PSTextureEncoder.h" #include "VideoBackends/D3D/TextureCache.h" @@ -163,7 +164,8 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo (srcFormat == PEControl::Z24) ? FramebufferManager::GetEFBDepthTexture()->GetSRV() : FramebufferManager::GetEFBColorTexture()->GetSRV(), &sourcerect, Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), (srcFormat == PEControl::Z24) ? PixelShaderCache::GetDepthMatrixProgram(true) : PixelShaderCache::GetColorMatrixProgram(true), - VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout()); + VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), + (g_Config.iStereoMode > 0) ? GeometryShaderCache::GetCopyGeometryShader() : nullptr); D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); @@ -192,7 +194,7 @@ TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture( { return new TCacheEntry(D3DTexture2D::Create(scaled_tex_w, scaled_tex_h, (D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | (int)D3D11_BIND_SHADER_RESOURCE), - D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM)); + D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, FramebufferManager::GetEFBLayers())); } TextureCache::TextureCache() diff --git a/Source/Core/VideoBackends/D3D/VertexManager.cpp b/Source/Core/VideoBackends/D3D/VertexManager.cpp index 7ab4f950bc..abc7f18e33 100644 --- a/Source/Core/VideoBackends/D3D/VertexManager.cpp +++ b/Source/Core/VideoBackends/D3D/VertexManager.cpp @@ -5,6 +5,7 @@ #include "VideoBackends/D3D/BoundingBox.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" +#include "VideoBackends/D3D/GeometryShaderCache.h" #include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/Render.h" #include "VideoBackends/D3D/VertexManager.h" @@ -139,11 +140,15 @@ void VertexManager::Draw(u32 stride) if (current_primitive_type == PRIMITIVE_TRIANGLES) { D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + D3D::stateman->SetGeometryConstants(VertexShaderCache::GetConstantBuffer()); + D3D::stateman->SetGeometryShader(g_ActiveConfig.iStereoMode > 0 ? GeometryShaderCache::GetActiveShader() : nullptr); D3D::stateman->Apply(); D3D::context->DrawIndexed(indices, startIndex, baseVertex); INCSTAT(stats.thisFrame.numDrawCalls); + + D3D::stateman->SetGeometryShader(nullptr); } else if (current_primitive_type == PRIMITIVE_LINES) { @@ -213,10 +218,21 @@ void VertexManager::vFlush(bool useDstAlpha) GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");}); return; } + + if (g_ActiveConfig.iStereoMode > 0) + { + if (!GeometryShaderCache::SetShader(components)) + { + GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR, true, { printf("Fail to set pixel shader\n"); }); + return; + } + } + if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active) { D3D::context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, 2, 1, &BBox::GetUAV(), nullptr); } + u32 stride = VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride(); PrepareDrawBuffers(stride); diff --git a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp index d565d50c03..9dfd87691e 100644 --- a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp @@ -60,7 +60,7 @@ ID3D11Buffer* &VertexShaderCache::GetConstantBuffer() class VertexShaderCacheInserter : public LinearDiskCacheReader { public: - void Read(const VertexShaderUid &key, const u8 *value, u32 value_size) + void Read(const VertexShaderUid &key, const u8* value, u32 value_size) { D3DBlob* blob = new D3DBlob(value_size, value); VertexShaderCache::InsertByteCode(key, blob); @@ -73,15 +73,15 @@ const char simple_shader_code[] = { "struct VSOUTPUT\n" "{\n" "float4 vPosition : POSITION;\n" - "float2 vTexCoord : TEXCOORD0;\n" + "float3 vTexCoord : TEXCOORD0;\n" "float vTexCoord1 : TEXCOORD1;\n" "};\n" - "VSOUTPUT main(float4 inPosition : POSITION,float3 inTEX0 : TEXCOORD0)\n" + "VSOUTPUT main(float4 inPosition : POSITION,float4 inTEX0 : TEXCOORD0)\n" "{\n" "VSOUTPUT OUT;\n" "OUT.vPosition = inPosition;\n" - "OUT.vTexCoord = inTEX0.xy;\n" - "OUT.vTexCoord1 = inTEX0.z;\n" + "OUT.vTexCoord = inTEX0.xyz;\n" + "OUT.vTexCoord1 = inTEX0.w;\n" "return OUT;\n" "}\n" }; diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index 34a11d493f..22782cc41c 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -16,6 +16,7 @@ #include "VideoBackends/D3D/BoundingBox.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DUtil.h" +#include "VideoBackends/D3D/GeometryShaderCache.h" #include "VideoBackends/D3D/Globals.h" #include "VideoBackends/D3D/PerfQuery.h" #include "VideoBackends/D3D/PixelShaderCache.h" @@ -78,7 +79,8 @@ void InitBackendInfo() g_Config.backend_info.bSupportsDualSourceBlend = true; g_Config.backend_info.bSupportsPrimitiveRestart = true; g_Config.backend_info.bSupportsOversizedViewports = false; - g_Config.backend_info.bSupportsStereoscopy = false; // TODO: not implemented + g_Config.backend_info.bSupportsStereoscopy = true; + g_Config.backend_info.bSupports3DVision = true; IDXGIFactory* factory; IDXGIAdapter* ad; @@ -112,11 +114,17 @@ void InitBackendInfo() g_Config.backend_info.AAModes.push_back(samples); } + bool shader_model_5_supported = (DX11::D3D::GetFeatureLevel(ad) >= D3D_FEATURE_LEVEL_11_0); + // Requires the earlydepthstencil attribute (only available in shader model 5) g_Config.backend_info.bSupportsEarlyZ = shader_model_5_supported; + // Requires full UAV functionality (only available in shader model 5) g_Config.backend_info.bSupportsBBox = shader_model_5_supported; + + // Requires the instance attribute (only available in shader model 5) + g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported; } g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description)); ad->Release(); @@ -168,6 +176,7 @@ void VideoBackend::Video_Prepare() g_perf_query = new PerfQuery; VertexShaderCache::Init(); PixelShaderCache::Init(); + GeometryShaderCache::Init(); D3D::InitUtils(); // VideoCommon @@ -205,6 +214,7 @@ void VideoBackend::Shutdown() D3D::ShutdownUtils(); PixelShaderCache::Shutdown(); VertexShaderCache::Shutdown(); + GeometryShaderCache::Shutdown(); BBox::Shutdown(); delete g_perf_query; diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp index 0fb36ab8d1..eb486c811b 100644 --- a/Source/Core/VideoBackends/OGL/main.cpp +++ b/Source/Core/VideoBackends/OGL/main.cpp @@ -139,6 +139,7 @@ static void InitBackendInfo() //g_Config.backend_info.bSupportsEarlyZ = true; // is gpu dependent and must be set in renderer g_Config.backend_info.bSupportsOversizedViewports = true; g_Config.backend_info.bSupportsStereoscopy = true; + g_Config.backend_info.bSupports3DVision = false; g_Config.backend_info.Adapters.clear(); diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index f9a8704269..57009aedaa 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -52,25 +52,62 @@ static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiTy uid_data->numTexGens = xfmem.numTexGen.numTexGens; uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting; - GenerateVSOutputStruct(out, ApiType); + GenerateVSOutputStruct(out, ApiType); - out.Write("centroid in VS_OUTPUT o[3];\n"); - out.Write("centroid out VS_OUTPUT f;\n"); + if (ApiType == API_OPENGL) + { + out.Write("centroid in VS_OUTPUT o[3];\n"); + out.Write("centroid out VS_OUTPUT vs;\n"); + out.Write("flat out int layer;\n"); - out.Write("flat out int layer;\n"); + out.Write("void main()\n{\n"); + } + else // D3D + { + out.Write("struct GS_OUTPUT {\n"); + out.Write("\tVS_OUTPUT vs;\n"); + out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n"); + out.Write("};\n"); - out.Write("void main()\n{\n"); + if (g_ActiveConfig.backend_info.bSupportsGSInstancing) + { + out.Write("[maxvertexcount(3)]\n[instance(%d)]\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1); + out.Write("void main(triangle VS_OUTPUT o[3], inout TriangleStream Output, in uint InstanceID : SV_GSInstanceID)\n{\n"); + } + else + { + out.Write("[maxvertexcount(6)]\n"); + out.Write("void main(triangle VS_OUTPUT o[3], inout TriangleStream Output)\n{\n"); + } + + out.Write("\tGS_OUTPUT gs;\n"); + } + + out.Write("\tVS_OUTPUT f;\n"); // If the GPU supports invocation we don't need a for loop and can simply use the // invocation identifier to determine which layer we're rendering. if (g_ActiveConfig.backend_info.bSupportsGSInstancing) - out.Write("\tint l = gl_InvocationID;\n"); + { + if (ApiType == API_OPENGL) + out.Write("\tint eye = gl_InvocationID;\n"); + else + out.Write("\tint eye = InstanceID;\n"); + } else - out.Write("\tfor (int l = 0; l < %d; ++l) {\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1); + out.Write("\tfor (int eye = 0; eye < %d; ++eye) {\n", g_ActiveConfig.iStereoMode > 0 ? 2 : 1); out.Write("\tfor (int i = 0; i < 3; ++i) {\n"); - out.Write("\t\tlayer = l;\n"); - out.Write("\t\tgl_Layer = l;\n"); + + // Select the output layer + if (ApiType == API_OPENGL) + { + out.Write("\t\tgl_Layer = eye;\n"); + out.Write("\t\tlayer = eye;\n"); + } + else + out.Write("\t\tgs.layer = eye;\n"); + out.Write("\t\tf = o[i];\n"); out.Write("\t\tfloat4 pos = o[i].pos;\n"); @@ -83,15 +120,28 @@ static inline void GenerateGeometryShader(T& out, u32 components, API_TYPE ApiTy // the depth value. This results in objects at a distance smaller than the convergence // distance to seemingly appear in front of the screen. // This formula is based on page 13 of the "Nvidia 3D Vision Automatic, Best Practices Guide" - out.Write("\t\tf.clipPos.x = o[i].clipPos.x + " I_STEREOPARAMS"[l] * (o[i].clipPos.w - " I_STEREOPARAMS"[2]);\n"); - out.Write("\t\tpos.x = o[i].pos.x + " I_STEREOPARAMS"[l] * (o[i].pos.w - " I_STEREOPARAMS"[2]);\n"); + out.Write("\t\tf.clipPos.x = o[i].clipPos.x + " I_STEREOPARAMS"[eye] * (o[i].clipPos.w - " I_STEREOPARAMS"[2]);\n"); + out.Write("\t\tpos.x = o[i].pos.x + " I_STEREOPARAMS"[eye] * (o[i].pos.w - " I_STEREOPARAMS"[2]);\n"); } out.Write("\t\tf.pos.x = pos.x;\n"); - out.Write("\t\tgl_Position = pos;\n"); - out.Write("\t\tEmitVertex();\n"); + + if (ApiType == API_OPENGL) + out.Write("\t\tgl_Position = pos;\n"); + + out.Write("\t\t%s = f;\n", (ApiType == API_OPENGL) ? "vs" : "gs.vs"); + + if (ApiType == API_OPENGL) + out.Write("\t\tEmitVertex();\n"); + else + out.Write("\t\tOutput.Append(gs);\n"); + out.Write("\t}\n"); - out.Write("\tEndPrimitive();\n"); + + if (ApiType == API_OPENGL) + out.Write("\tEndPrimitive();\n"); + else + out.Write("\tOutput.RestartStrip();\n"); if (!g_ActiveConfig.backend_info.bSupportsGSInstancing) out.Write("\t}\n"); diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index 0e0e9d214c..48cd5b8fec 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -205,7 +205,7 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T out.Write("\n"); for (int i = 0; i < 8; ++i) - out.Write("Texture2D Tex%d : register(t%d);\n", i, i); + out.Write("Texture2DArray Tex%d : register(t%d);\n", i, i); } out.Write("\n"); @@ -264,7 +264,7 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T } } - GenerateVSOutputStruct(out, ApiType); + GenerateVSOutputStruct(out, ApiType); const bool forced_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED); const bool per_pixel_depth = (bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) || (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !forced_early_z); @@ -319,7 +319,7 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T uid_data->stereo = g_ActiveConfig.iStereoMode > 0; if (g_ActiveConfig.iStereoMode > 0) { - out.Write("centroid in VS_OUTPUT f;\n"); + out.Write("centroid in VS_OUTPUT vs;\n"); out.Write("flat in int layer;\n"); } else @@ -348,19 +348,19 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T // Let's set up attributes for (unsigned int i = 0; i < numTexgen; ++i) { - out.Write("\tfloat3 uv%d = f.tex%d;\n", i, i); + out.Write("\tfloat3 uv%d = vs.tex%d;\n", i, i); } - out.Write("\tfloat4 clipPos = f.clipPos;\n"); + out.Write("\tfloat4 clipPos = vs.clipPos;\n"); if (g_ActiveConfig.bEnablePixelLighting) { - out.Write("\tfloat4 Normal = f.Normal;\n"); + out.Write("\tfloat4 Normal = vs.Normal;\n"); } } // On Mali, global variables must be initialized as constants. // This is why we initialize these variables locally instead. - out.Write("\tfloat4 colors_0 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "f.colors_0" : "colors_02"); - out.Write("\tfloat4 colors_1 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "f.colors_1" : "colors_12"); + out.Write("\tfloat4 colors_0 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "vs.colors_0" : "colors_02"); + out.Write("\tfloat4 colors_1 = %s;\n", (g_ActiveConfig.iStereoMode > 0) ? "vs.colors_1" : "colors_12"); out.Write("\tfloat4 rawpos = gl_FragCoord;\n"); } @@ -372,7 +372,7 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T per_pixel_depth ? "\n out float depth : SV_Depth," : ""); out.Write(" in centroid float4 colors_0 : COLOR0,\n"); - out.Write(" in centroid float4 colors_1 : COLOR1"); + out.Write(" in centroid float4 colors_1 : COLOR1\n"); // compute window position if needed because binding semantic WPOS is not widely supported for (unsigned int i = 0; i < numTexgen; ++i) @@ -380,6 +380,9 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T out.Write(",\n in centroid float4 clipPos : TEXCOORD%d", numTexgen); if (g_ActiveConfig.bEnablePixelLighting) out.Write(",\n in centroid float4 Normal : TEXCOORD%d", numTexgen + 1); + uid_data->stereo = g_ActiveConfig.iStereoMode > 0; + if (g_ActiveConfig.iStereoMode > 0) + out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n"); out.Write(" ) {\n"); } @@ -938,7 +941,7 @@ static inline void SampleTexture(T& out, const char *texcoords, const char *texs out.SetConstantsUsed(C_TEXDIMS+texmap,C_TEXDIMS+texmap); if (ApiType == API_D3D) - out.Write("iround(255.0 * Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS"[%d].xy)).%s;\n", texmap,texmap, texcoords, texmap, texswap); + out.Write("iround(255.0 * Tex%d.Sample(samp%d, float3(%s.xy * " I_TEXDIMS"[%d].xy, %s))).%s;\n", texmap, texmap, texcoords, texmap, g_ActiveConfig.iStereoMode > 0 ? "layer" : "0.0", texswap); else out.Write("iround(255.0 * texture(samp%d, float3(%s.xy * " I_TEXDIMS"[%d].xy, %s))).%s;\n", texmap, texcoords, texmap, g_ActiveConfig.iStereoMode > 0 ? "layer" : "0.0", texswap); } diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index 4d22048ee6..618d262374 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -14,6 +14,8 @@ #include "Common/CommonTypes.h" #include "Common/StringUtil.h" #include "VideoCommon/VideoCommon.h" +#include "VideoCommon/VideoConfig.h" +#include "VideoCommon/XFMemory.h" /** * Common interface for classes that need to go through the shader generation path (GenerateVertexShader, GeneratePixelShader) @@ -218,6 +220,44 @@ private: std::vector m_uids; }; +template +static void DefineOutputStructMember(T& object, API_TYPE api_type, const char* type, const char* name, int var_index, const char* semantic = "", int semantic_index = -1) +{ + object.Write(" %s %s", type, name); + if (var_index != -1) + object.Write("%d", var_index); + + if (api_type == API_D3D && strlen(semantic) > 0) + { + if (semantic_index != -1) + object.Write(" : %s%d", semantic, semantic_index); + else + object.Write(" : %s", semantic); + } + + object.Write(";\n"); +} + +template +static inline void GenerateVSOutputStruct(T& object, API_TYPE api_type) +{ + object.Write("struct VS_OUTPUT {\n"); + + DefineOutputStructMember(object, api_type, "float4", "pos", -1, "POSITION"); + DefineOutputStructMember(object, api_type, "float4", "colors_", 0, "COLOR", 0); + DefineOutputStructMember(object, api_type, "float4", "colors_", 1, "COLOR", 1); + + for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) + DefineOutputStructMember(object, api_type, "float3", "tex", i, "TEXCOORD", i); + + DefineOutputStructMember(object, api_type, "float4", "clipPos", -1, "TEXCOORD", xfmem.numTexGen.numTexGens); + + if (g_ActiveConfig.bEnablePixelLighting) + DefineOutputStructMember(object, api_type, "float4", "Normal", -1, "TEXCOORD", xfmem.numTexGen.numTexGens + 1); + + object.Write("};\n"); +} + // Constant variable names #define I_COLORS "color" #define I_KCOLORS "k" diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 6ce3a453b9..00db2b0f02 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -14,43 +14,6 @@ static char text[16768]; -template -static void DefineVSOutputStructMember(T& object, API_TYPE api_type, const char* type, const char* name, int var_index, const char* semantic, int semantic_index = -1) -{ - object.Write(" %s %s", type, name); - if (var_index != -1) - object.Write("%d", var_index); - - if (api_type == API_OPENGL) - object.Write(";\n"); - else // D3D - { - if (semantic_index != -1) - object.Write(" : %s%d;\n", semantic, semantic_index); - else - object.Write(" : %s;\n", semantic); - } -} - -template -static inline void GenerateVSOutputStruct(T& object, API_TYPE api_type) -{ - object.Write("struct VS_OUTPUT {\n"); - DefineVSOutputStructMember(object, api_type, "float4", "pos", -1, "POSITION"); - DefineVSOutputStructMember(object, api_type, "float4", "colors_", 0, "COLOR", 0); - DefineVSOutputStructMember(object, api_type, "float4", "colors_", 1, "COLOR", 1); - - for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) - DefineVSOutputStructMember(object, api_type, "float3", "tex", i, "TEXCOORD", i); - - DefineVSOutputStructMember(object, api_type, "float4", "clipPos", -1, "TEXCOORD", xfmem.numTexGen.numTexGens); - - if (g_ActiveConfig.bEnablePixelLighting) - DefineVSOutputStructMember(object, api_type, "float4", "Normal", -1, "TEXCOORD", xfmem.numTexGen.numTexGens + 1); - - object.Write("};\n"); -} - template static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) { @@ -79,7 +42,7 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ out.Write(s_shader_uniforms); out.Write("};\n"); - GenerateVSOutputStruct(out, api_type); + GenerateVSOutputStruct(out, api_type); uid_data->numTexGens = xfmem.numTexGen.numTexGens; uid_data->components = components; @@ -464,13 +427,3 @@ void GenerateVertexShaderCode(VertexShaderCode& object, u32 components, API_TYPE { GenerateVertexShader(object, components, api_type); } - -void GenerateVSOutputStruct(ShaderCode& object, API_TYPE api_type) -{ - GenerateVSOutputStruct(object, api_type); -} - -void GenerateVSOutputStruct(ShaderGeneratorInterface& object, API_TYPE api_type) -{ - // Ignore unknown types -} diff --git a/Source/Core/VideoCommon/VertexShaderGen.h b/Source/Core/VideoCommon/VertexShaderGen.h index b5e9e33f29..1f08c1963a 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.h +++ b/Source/Core/VideoCommon/VertexShaderGen.h @@ -7,7 +7,6 @@ #include "VideoCommon/LightingShaderGen.h" #include "VideoCommon/ShaderGenCommon.h" #include "VideoCommon/VideoCommon.h" -#include "VideoCommon/XFMemory.h" // TODO should be reordered #define SHADER_POSITION_ATTRIB 0 @@ -64,5 +63,3 @@ typedef ShaderCode VertexShaderCode; // TODO: Obsolete.. void GetVertexShaderUid(VertexShaderUid& object, u32 components, API_TYPE api_type); void GenerateVertexShaderCode(VertexShaderCode& object, u32 components, API_TYPE api_type); -void GenerateVSOutputStruct(ShaderCode& object, API_TYPE api_type); -void GenerateVSOutputStruct(ShaderGeneratorInterface& object, API_TYPE api_type); diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index c825f8ec53..fa5a52772b 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -49,7 +49,8 @@ enum StereoMode STEREO_OFF = 0, STEREO_SBS, STEREO_TAB, - STEREO_ANAGLYPH + STEREO_ANAGLYPH, + STEREO_3DVISION }; // NEVER inherit from this class. @@ -151,6 +152,7 @@ struct VideoConfig final bool bSupportsPrimitiveRestart; bool bSupportsOversizedViewports; bool bSupportsStereoscopy; + bool bSupports3DVision; bool bSupportsEarlyZ; // needed by PixelShaderGen, so must stay in VideoCommon bool bSupportsBindingLayout; // Needed by ShaderGen, so must stay in VideoCommon bool bSupportsBBox;