D3D: Support stereoscopic XFB blit to screen.

This commit is contained in:
Jules Blok 2014-12-20 18:20:49 +01:00
parent a845aeeb3d
commit 4a86234a79
6 changed files with 72 additions and 97 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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);
};
}

View File

@ -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;

View File

@ -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;
};