mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-03-12 06:39:14 +01:00
D3D: Support stereoscopic XFB blit to screen.
This commit is contained in:
parent
a845aeeb3d
commit
4a86234a79
@ -6,6 +6,7 @@
|
||||
#include "VideoBackends/D3D/D3DBase.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/VertexShaderCache.h"
|
||||
@ -182,14 +183,6 @@ void FramebufferManager::GetTargetSize(unsigned int *width, unsigned int *height
|
||||
*height = targetSource.bottom - targetSource.top;
|
||||
}
|
||||
|
||||
void XFBSource::Draw(const MathUtil::Rectangle<int> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc) const
|
||||
{
|
||||
D3D::drawShadedTexSubQuad(tex->GetSRV(), &sourcerc,
|
||||
texWidth, texHeight, &drawrc, PixelShaderCache::GetColorCopyProgram(false),
|
||||
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
|
||||
}
|
||||
|
||||
void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
// DX11's XFB decoder does not use this function.
|
||||
|
@ -48,8 +48,6 @@ struct XFBSource : public XFBSourceBase
|
||||
XFBSource(D3DTexture2D *_tex, int slices) : tex(_tex), m_slices(slices) {}
|
||||
~XFBSource() { tex->Release(); }
|
||||
|
||||
void Draw(const MathUtil::Rectangle<int> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc) const override;
|
||||
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override;
|
||||
void CopyEFB(float Gamma) override;
|
||||
|
||||
|
@ -709,23 +709,8 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
|
||||
|
||||
// Prepare to copy the XFBs to our backbuffer
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
TargetRectangle targetRc = GetTargetRectangle();
|
||||
|
||||
int X = GetTargetRectangle().left;
|
||||
int Y = GetTargetRectangle().top;
|
||||
int Width = GetTargetRectangle().right - GetTargetRectangle().left;
|
||||
int Height = GetTargetRectangle().bottom - GetTargetRectangle().top;
|
||||
|
||||
// TODO: Redundant checks...
|
||||
if (X < 0) X = 0;
|
||||
if (Y < 0) Y = 0;
|
||||
if (X > s_backbuffer_width) X = s_backbuffer_width;
|
||||
if (Y > s_backbuffer_height) Y = s_backbuffer_height;
|
||||
if (Width < 0) Width = 0;
|
||||
if (Height < 0) Height = 0;
|
||||
if (Width > (s_backbuffer_width - X)) Width = s_backbuffer_width - X;
|
||||
if (Height > (s_backbuffer_height - Y)) Height = s_backbuffer_height - Y;
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)X, (float)Y, (float)Width, (float)Height);
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr);
|
||||
|
||||
float ClearColor[4] = { 0.f, 0.f, 0.f, 1.f };
|
||||
@ -737,32 +722,26 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
|
||||
if (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB)
|
||||
{
|
||||
// TODO: Television should be used to render Virtual XFB mode as well.
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, (float)targetRc.GetWidth(), (float)targetRc.GetHeight());
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
|
||||
s_television.Submit(xfbAddr, fbStride, fbWidth, fbHeight);
|
||||
s_television.Render();
|
||||
}
|
||||
else if (g_ActiveConfig.bUseXFB)
|
||||
{
|
||||
const XFBSourceBase* xfbSource;
|
||||
const XFBSource* xfbSource;
|
||||
|
||||
// draw each xfb source
|
||||
for (u32 i = 0; i < xfbCount; ++i)
|
||||
{
|
||||
xfbSource = xfbSourceList[i];
|
||||
MathUtil::Rectangle<int> sourceRc;
|
||||
xfbSource = (const XFBSource*)xfbSourceList[i];
|
||||
|
||||
sourceRc.left = 0;
|
||||
sourceRc.top = 0;
|
||||
sourceRc.right = (int)xfbSource->texWidth;
|
||||
sourceRc.bottom = (int)xfbSource->texHeight;
|
||||
|
||||
MathUtil::Rectangle<float> drawRc;
|
||||
TargetRectangle drawRc;
|
||||
|
||||
if (g_ActiveConfig.bUseRealXFB)
|
||||
{
|
||||
drawRc.top = 1;
|
||||
drawRc.bottom = -1;
|
||||
drawRc.left = -1;
|
||||
drawRc.right = 1;
|
||||
drawRc = targetRc;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -771,10 +750,10 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
|
||||
int xfbWidth = xfbSource->srcWidth;
|
||||
int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbStride * 2);
|
||||
|
||||
drawRc.top = 1.0f - (2.0f * (hOffset) / (float)fbHeight);
|
||||
drawRc.bottom = 1.0f - (2.0f * (hOffset + xfbHeight) / (float)fbHeight);
|
||||
drawRc.left = -(xfbWidth / (float)fbStride);
|
||||
drawRc.right = (xfbWidth / (float)fbStride);
|
||||
drawRc.top = targetRc.bottom - (hOffset + xfbHeight) * targetRc.GetHeight() / fbHeight;
|
||||
drawRc.bottom = targetRc.bottom - hOffset * targetRc.GetHeight() / fbHeight;
|
||||
drawRc.left = targetRc.left + (targetRc.GetWidth() - xfbWidth * targetRc.GetWidth() / fbStride) / 2;
|
||||
drawRc.right = targetRc.left + (targetRc.GetWidth() + xfbWidth * targetRc.GetWidth() / fbStride) / 2;
|
||||
|
||||
// The following code disables auto stretch. Kept for reference.
|
||||
// scale draw area for a 1 to 1 pixel mapping with the draw target
|
||||
@ -786,61 +765,19 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
|
||||
//drawRc.right *= hScale;
|
||||
}
|
||||
|
||||
xfbSource->Draw(sourceRc, drawRc);
|
||||
TargetRectangle sourceRc = xfbSource->sourceRc;
|
||||
sourceRc.right -= fbStride - fbWidth;
|
||||
|
||||
BlitScreen(sourceRc, drawRc, xfbSource->tex, xfbSource->texWidth, xfbSource->texHeight, Gamma);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc);
|
||||
TargetRectangle sourceRc = Renderer::ConvertEFBRectangle(rc);
|
||||
|
||||
// TODO: Improve sampling algorithm for the pixel shader so that we can use the multisampled EFB texture as source
|
||||
D3DTexture2D* read_texture = FramebufferManager::GetResolvedEFBColorTexture();
|
||||
|
||||
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);
|
||||
}
|
||||
BlitScreen(sourceRc, targetRc, read_texture, GetTargetWidth(), GetTargetHeight(), Gamma);
|
||||
}
|
||||
|
||||
// done with drawing the game stuff, good moment to save a screenshot
|
||||
@ -911,7 +848,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
|
||||
}
|
||||
|
||||
// Reset viewport for drawing text
|
||||
vp = CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetBackbufferWidth(), (float)GetBackbufferHeight());
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetBackbufferWidth(), (float)GetBackbufferHeight());
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
|
||||
Renderer::DrawDebugText();
|
||||
@ -1279,4 +1216,53 @@ void Renderer::BBoxWrite(int index, u16 _value)
|
||||
BBox::Set(index, value);
|
||||
}
|
||||
|
||||
void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, u32 src_width, u32 src_height, float Gamma)
|
||||
{
|
||||
if (g_ActiveConfig.iStereoMode == STEREO_SBS || g_ActiveConfig.iStereoMode == STEREO_TAB)
|
||||
{
|
||||
TargetRectangle leftRc, rightRc;
|
||||
ConvertStereoRectangle(dst, 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(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0);
|
||||
|
||||
D3D::context->RSSetViewports(1, &rightVp);
|
||||
D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1);
|
||||
}
|
||||
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)dst.left, (float)dst.top, (float)dst.GetWidth(), (float)dst.GetHeight());
|
||||
D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)(dst.left + s_backbuffer_width), (float)dst.top, (float)dst.GetWidth(), (float)dst.GetHeight());
|
||||
|
||||
// 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(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0);
|
||||
|
||||
D3D::context->RSSetViewports(1, &rightVp);
|
||||
D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, 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);
|
||||
|
||||
// Restore render target to backbuffer
|
||||
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(), (float)dst.GetHeight());
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, (g_Config.iStereoMode == STEREO_ANAGLYPH) ? PixelShaderCache::GetAnaglyphProgram() : PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
|
@ -52,6 +52,9 @@ public:
|
||||
static bool CheckForResize();
|
||||
|
||||
int GetMaxTextureSize() override;
|
||||
|
||||
private:
|
||||
void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, u32 src_width, u32 src_height, float Gamma);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -66,7 +66,6 @@ const XFBSourceBase* const* FramebufferManagerBase::GetRealXFBSource(u32 xfbAddr
|
||||
m_realXFBSource->texWidth = fbWidth;
|
||||
m_realXFBSource->texHeight = fbHeight;
|
||||
|
||||
// TODO: stuff only used by OGL... :/
|
||||
// OpenGL texture coordinates originate at the lower left, which is why
|
||||
// sourceRc.top = fbHeight and sourceRc.bottom = 0.
|
||||
m_realXFBSource->sourceRc.left = 0;
|
||||
|
@ -13,9 +13,6 @@ struct XFBSourceBase
|
||||
{
|
||||
virtual ~XFBSourceBase() {}
|
||||
|
||||
virtual void Draw(const MathUtil::Rectangle<int> &sourcerc,
|
||||
const MathUtil::Rectangle<float> &drawrc) const {};
|
||||
|
||||
virtual void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) = 0;
|
||||
|
||||
virtual void CopyEFB(float Gamma) = 0;
|
||||
@ -27,7 +24,6 @@ struct XFBSourceBase
|
||||
unsigned int texWidth;
|
||||
unsigned int texHeight;
|
||||
|
||||
// TODO: only used by OGL
|
||||
TargetRectangle sourceRc;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user