mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
DX11: Add real XFB mode support. May not work perfectly yet. I'm working on a set of fairly big VI-related changes. When I'm done, it should improve animation smoothness for all the backends, especially when virtual or real XFB mode is enabled.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7319 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
a23fb0eef3
commit
6e348a2731
@ -111,6 +111,13 @@ struct Rectangle
|
||||
T right;
|
||||
T bottom;
|
||||
|
||||
Rectangle()
|
||||
{ }
|
||||
|
||||
Rectangle(T theLeft, T theTop, T theRight, T theBottom)
|
||||
: left(theLeft), top(theTop), right(theRight), bottom(theBottom)
|
||||
{ }
|
||||
|
||||
T GetWidth() const { return abs(right - left); }
|
||||
T GetHeight() const { return abs(bottom - top); }
|
||||
|
||||
@ -124,7 +131,7 @@ struct Rectangle
|
||||
if (bottom < y2) bottom = y2;
|
||||
}
|
||||
|
||||
// If the rectangle is in an coordinate system with an upper-left origin,
|
||||
// If the rectangle is in a coordinate system with an upper-left origin,
|
||||
// use this Clamp.
|
||||
void ClampUL(T x1, T y1, T x2, T y2)
|
||||
{
|
||||
|
@ -210,9 +210,11 @@
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\Television.cpp" />
|
||||
<ClCompile Include="Src\TextureCache.cpp" />
|
||||
<ClCompile Include="Src\VertexManager.cpp" />
|
||||
<ClCompile Include="Src\VertexShaderCache.cpp" />
|
||||
<ClCompile Include="Src\XFBEncoder.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\D3DBase.h" />
|
||||
@ -228,11 +230,13 @@
|
||||
<ClInclude Include="Src\PSTextureEncoder.h" />
|
||||
<ClInclude Include="Src\Render.h" />
|
||||
<ClInclude Include="Src\stdafx.h" />
|
||||
<ClInclude Include="Src\Television.h" />
|
||||
<ClInclude Include="Src\TextureCache.h" />
|
||||
<ClInclude Include="Src\TextureEncoder.h" />
|
||||
<ClInclude Include="Src\VertexManager.h" />
|
||||
<ClInclude Include="Src\VertexShaderCache.h" />
|
||||
<ClInclude Include="Src\VideoBackend.h" />
|
||||
<ClInclude Include="Src\XFBEncoder.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -45,6 +45,12 @@
|
||||
<ClCompile Include="Src\PSTextureEncoder.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\XFBEncoder.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\Television.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Src\Globals.h" />
|
||||
@ -93,6 +99,12 @@
|
||||
<ClInclude Include="Src\TextureEncoder.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\XFBEncoder.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\Television.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="D3D">
|
||||
|
@ -587,10 +587,10 @@ void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture,
|
||||
float G = 1.0f / Gamma;
|
||||
|
||||
STSQVertex coords[4] = {
|
||||
{ rDest->left , rDest->bottom, 0.0f, u1, v1, G},
|
||||
{ rDest->right, rDest->bottom, 0.0f, u2, v1, G},
|
||||
{ rDest->left , rDest->top , 0.0f, u1, v2, G},
|
||||
{ rDest->right, rDest->top , 0.0f, u2, v2, G},
|
||||
{ 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},
|
||||
};
|
||||
|
||||
// only upload the data to VRAM if it changed
|
||||
|
@ -23,9 +23,13 @@
|
||||
#include "PixelShaderCache.h"
|
||||
#include "Render.h"
|
||||
#include "VertexShaderCache.h"
|
||||
#include "XFBEncoder.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
namespace DX11 {
|
||||
|
||||
static XFBEncoder s_xfbEncoder;
|
||||
|
||||
FramebufferManager::Efb FramebufferManager::m_efb;
|
||||
|
||||
D3DTexture2D* &FramebufferManager::GetEFBColorTexture() { return m_efb.color_tex; }
|
||||
@ -144,10 +148,14 @@ FramebufferManager::FramebufferManager()
|
||||
m_efb.resolved_color_tex = NULL;
|
||||
m_efb.resolved_depth_tex = NULL;
|
||||
}
|
||||
|
||||
s_xfbEncoder.Init();
|
||||
}
|
||||
|
||||
FramebufferManager::~FramebufferManager()
|
||||
{
|
||||
s_xfbEncoder.Shutdown();
|
||||
|
||||
SAFE_RELEASE(m_efb.color_tex);
|
||||
SAFE_RELEASE(m_efb.color_temp_tex);
|
||||
SAFE_RELEASE(m_efb.color_staging_buf);
|
||||
@ -160,8 +168,8 @@ FramebufferManager::~FramebufferManager()
|
||||
|
||||
void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma)
|
||||
{
|
||||
// TODO
|
||||
PanicAlert("CopyToRealXFB not implemented, yet\n");
|
||||
u8* dst = Memory::GetPointer(xfbAddr);
|
||||
s_xfbEncoder.Encode(dst, fbWidth, fbHeight, sourceRc, Gamma);
|
||||
}
|
||||
|
||||
XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height)
|
||||
@ -197,8 +205,8 @@ void XFBSource::Draw(const MathUtil::Rectangle<float> &sourcerc,
|
||||
|
||||
void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
// TODO:
|
||||
PanicAlert("RealXFB not implemented, yet\n");
|
||||
// DX11's XFB decoder does not use this function.
|
||||
// YUYV data is decoded in Render::Swap.
|
||||
}
|
||||
|
||||
void XFBSource::CopyEFB(float Gamma)
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "VertexShaderCache.h"
|
||||
#include "Core.h"
|
||||
#include "OnFrame.h"
|
||||
#include "Television.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
@ -50,6 +51,8 @@ static u32 s_LastAA = 0;
|
||||
|
||||
static u32 s_blendMode;
|
||||
|
||||
static Television s_television;
|
||||
|
||||
ID3D11Buffer* access_efb_cbuf = NULL;
|
||||
ID3D11BlendState* clearblendstates[4] = {NULL};
|
||||
ID3D11DepthStencilState* cleardepthstates[3] = {NULL};
|
||||
@ -213,6 +216,8 @@ static const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] =
|
||||
|
||||
void SetupDeviceObjects()
|
||||
{
|
||||
s_television.Init();
|
||||
|
||||
g_framebuffer_manager = new FramebufferManager;
|
||||
|
||||
HRESULT hr;
|
||||
@ -307,6 +312,8 @@ void TeardownDeviceObjects()
|
||||
SAFE_RELEASE(resetblendstate);
|
||||
SAFE_RELEASE(resetdepthstate);
|
||||
SAFE_RELEASE(resetraststate);
|
||||
|
||||
s_television.Shutdown();
|
||||
}
|
||||
|
||||
Renderer::Renderer()
|
||||
@ -930,7 +937,6 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
// EFB is copied to XFB. In this way, flickering is reduced in games
|
||||
// and seems to also give more FPS in ZTP
|
||||
|
||||
if (field == FIELD_LOWER) xfbAddr -= fbWidth * 2;
|
||||
u32 xfbCount = 0;
|
||||
const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount);
|
||||
if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB)
|
||||
@ -969,7 +975,13 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
// activate linear filtering for the buffer copies
|
||||
D3D::SetLinearCopySampler();
|
||||
|
||||
if(g_ActiveConfig.bUseXFB)
|
||||
if (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB)
|
||||
{
|
||||
// TODO: Television should be used to render Virtual XFB mode as well.
|
||||
s_television.Submit(xfbAddr, fbWidth, fbHeight);
|
||||
s_television.Render();
|
||||
}
|
||||
else if(g_ActiveConfig.bUseXFB)
|
||||
{
|
||||
const XFBSourceBase* xfbSource;
|
||||
|
||||
@ -993,8 +1005,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
int xfbWidth = xfbSource->srcWidth;
|
||||
int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbWidth * 2);
|
||||
|
||||
drawRc.bottom = 1.0f - (2.0f * (hOffset) / (float)fbHeight);
|
||||
drawRc.top = 1.0f - (2.0f * (hOffset + xfbHeight) / (float)fbHeight);
|
||||
drawRc.top = 1.0f - (2.0f * (hOffset) / (float)fbHeight);
|
||||
drawRc.bottom = 1.0f - (2.0f * (hOffset + xfbHeight) / (float)fbHeight);
|
||||
drawRc.left = -(xfbWidth / (float)fbWidth);
|
||||
drawRc.right = (xfbWidth / (float)fbWidth);
|
||||
|
||||
@ -1009,8 +1021,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
}
|
||||
else
|
||||
{
|
||||
drawRc.top = -1;
|
||||
drawRc.bottom = 1;
|
||||
drawRc.top = 1;
|
||||
drawRc.bottom = -1;
|
||||
drawRc.left = -1;
|
||||
drawRc.right = 1;
|
||||
}
|
||||
@ -1026,6 +1038,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons
|
||||
D3DTexture2D* read_texture = FramebufferManager::GetResolvedEFBColorTexture();
|
||||
D3D::drawShadedTexQuad(read_texture->GetSRV(), targetRc.AsRECT(), Renderer::GetFullTargetWidth(), Renderer::GetFullTargetHeight(), PixelShaderCache::GetColorCopyProgram(false),VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), Gamma);
|
||||
}
|
||||
|
||||
// done with drawing the game stuff, good moment to save a screenshot
|
||||
if (s_bScreenshot)
|
||||
{
|
||||
|
154
Source/Plugins/Plugin_VideoDX11/Src/Television.cpp
Normal file
154
Source/Plugins/Plugin_VideoDX11/Src/Television.cpp
Normal file
@ -0,0 +1,154 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Television.h"
|
||||
|
||||
#include "VideoConfig.h"
|
||||
#include "D3DBase.h"
|
||||
#include "D3DShader.h"
|
||||
#include "D3DUtil.h"
|
||||
#include "VertexShaderCache.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
static const char YUYV_DECODER_PS[] =
|
||||
"// dolphin-emu YUYV decoder pixel shader\n"
|
||||
|
||||
"Texture2D Tex0 : register(t0);\n"
|
||||
"sampler Samp0 : register(s0);\n"
|
||||
|
||||
"static const float3x3 YCBCR_TO_RGB = float3x3(\n"
|
||||
"1.164, 0.000, 1.596,\n"
|
||||
"1.164, -0.392, -0.813,\n"
|
||||
"1.164, 2.017, 0.000\n"
|
||||
");\n"
|
||||
|
||||
"void main(out float4 ocol0 : SV_Target, in float4 pos : SV_Position, in float2 uv0 : TEXCOORD0)\n"
|
||||
"{\n"
|
||||
"float3 sample = Tex0.Sample(Samp0, uv0).rgb;\n"
|
||||
|
||||
// GameCube/Wii XFB data is in YUYV format with ITU-R Rec. BT.601 color
|
||||
// primaries, compressed to the range Y in 16..235, U and V in 16..240.
|
||||
// We want to convert it to RGB format with sRGB color primaries, with
|
||||
// range 0..255.
|
||||
|
||||
// Recover RGB components
|
||||
"float3 yuv_601_sub = sample.grb - float3(16.0/255.0, 128.0/255.0, 128.0/255.0);\n"
|
||||
"float3 rgb_601 = mul(YCBCR_TO_RGB, yuv_601_sub);\n"
|
||||
|
||||
// If we were really obsessed with accuracy, we would correct for the
|
||||
// differing color primaries between BT.601 and sRGB. However, this may not
|
||||
// be worth the trouble because:
|
||||
// - BT.601 defines two sets of primaries: one for NTSC and one for PAL.
|
||||
// - sRGB's color primaries are actually an intermediate between BT.601's
|
||||
// NTSC and PAL primaries.
|
||||
// - If users even noticed any difference at all, they would be confused by
|
||||
// the slightly-different colors in the NTSC and PAL versions of the same
|
||||
// game.
|
||||
// - Even the game designers probably don't pay close attention to this
|
||||
// stuff.
|
||||
// Still, instructions on how to do it can be found at
|
||||
// <http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC20>
|
||||
|
||||
"ocol0 = float4(rgb_601, 1);\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
Television::Television()
|
||||
: m_yuyvTexture(NULL), m_yuyvTextureSRV(NULL), m_pShader(NULL)
|
||||
{ }
|
||||
|
||||
void Television::Init()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
// Create YUYV texture for real XFB mode
|
||||
|
||||
// This texture format is designed for YUYV data.
|
||||
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
|
||||
DXGI_FORMAT_G8R8_G8B8_UNORM, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 1, 1);
|
||||
hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_yuyvTexture);
|
||||
CHECK(SUCCEEDED(hr), "create tv yuyv texture");
|
||||
D3D::SetDebugObjectName(m_yuyvTexture, "tv yuyv texture");
|
||||
|
||||
// Create shader resource view for YUYV texture
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvd = CD3D11_SHADER_RESOURCE_VIEW_DESC(
|
||||
m_yuyvTexture, D3D11_SRV_DIMENSION_TEXTURE2D,
|
||||
DXGI_FORMAT_G8R8_G8B8_UNORM);
|
||||
hr = D3D::device->CreateShaderResourceView(m_yuyvTexture, &srvd, &m_yuyvTextureSRV);
|
||||
CHECK(SUCCEEDED(hr), "create tv yuyv texture srv");
|
||||
D3D::SetDebugObjectName(m_yuyvTextureSRV, "tv yuyv texture srv");
|
||||
|
||||
// Create YUYV-decoding pixel shader
|
||||
|
||||
m_pShader = D3D::CompileAndCreatePixelShader(YUYV_DECODER_PS, sizeof(YUYV_DECODER_PS));
|
||||
CHECK(m_pShader != NULL, "compile and create yuyv decoder pixel shader");
|
||||
D3D::SetDebugObjectName(m_pShader, "yuyv decoder pixel shader");
|
||||
}
|
||||
|
||||
void Television::Shutdown()
|
||||
{
|
||||
SAFE_RELEASE(m_pShader);
|
||||
SAFE_RELEASE(m_yuyvTextureSRV);
|
||||
SAFE_RELEASE(m_yuyvTexture);
|
||||
}
|
||||
|
||||
void Television::Submit(u32 xfbAddr, u32 width, u32 height)
|
||||
{
|
||||
m_curAddr = xfbAddr;
|
||||
m_curWidth = width;
|
||||
m_curHeight = height;
|
||||
|
||||
// Load data from GameCube RAM to YUYV texture
|
||||
u8* yuyvSrc = Memory::GetPointer(xfbAddr);
|
||||
D3D11_BOX box = CD3D11_BOX(0, 0, 0, width, height, 1);
|
||||
D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2*width, 2*width*height);
|
||||
}
|
||||
|
||||
void Television::Render()
|
||||
{
|
||||
if (g_ActiveConfig.bUseRealXFB && g_ActiveConfig.bUseXFB)
|
||||
{
|
||||
// Use real XFB mode
|
||||
// TODO: If this is the lower field, render at a vertical offset of 1
|
||||
// line down. We could even consider implementing a deinterlacing
|
||||
// algorithm.
|
||||
|
||||
MathUtil::Rectangle<float> sourceRc(0.f, 0.f, float(m_curWidth), float(m_curHeight));
|
||||
MathUtil::Rectangle<float> destRc(-1.f, 1.f, 1.f, -1.f);
|
||||
|
||||
D3D::drawShadedTexSubQuad(
|
||||
m_yuyvTextureSRV, &sourceRc,
|
||||
MAX_XFB_WIDTH, MAX_XFB_HEIGHT,
|
||||
&destRc,
|
||||
m_pShader,
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout());
|
||||
}
|
||||
else if (g_ActiveConfig.bUseXFB)
|
||||
{
|
||||
// Use virtual XFB mode
|
||||
|
||||
// TODO: Eventually, Television should render the Virtual XFB mode
|
||||
// display as well.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
65
Source/Plugins/Plugin_VideoDX11/Src/Television.h
Normal file
65
Source/Plugins/Plugin_VideoDX11/Src/Television.h
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _TELEVISION_H
|
||||
#define _TELEVISION_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
struct ID3D11Texture2D;
|
||||
struct ID3D11ShaderResourceView;
|
||||
struct ID3D11PixelShader;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
class Television
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Television();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
// Submit video data to be drawn. This will change the current state of the
|
||||
// TV. xfbAddr points to YUYV data stored in GameCube/Wii RAM, but the XFB
|
||||
// may be virtualized when rendering so the RAM may not actually be read.
|
||||
void Submit(u32 xfbAddr, u32 width, u32 height);
|
||||
|
||||
// Render the current state of the TV.
|
||||
void Render();
|
||||
|
||||
private:
|
||||
|
||||
// Properties of last Submit call
|
||||
u32 m_curAddr;
|
||||
u32 m_curWidth;
|
||||
u32 m_curHeight;
|
||||
|
||||
// Used for real XFB mode
|
||||
|
||||
ID3D11Texture2D* m_yuyvTexture;
|
||||
ID3D11ShaderResourceView* m_yuyvTextureSRV;
|
||||
ID3D11PixelShader* m_pShader;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
387
Source/Plugins/Plugin_VideoDX11/Src/XFBEncoder.cpp
Normal file
387
Source/Plugins/Plugin_VideoDX11/Src/XFBEncoder.cpp
Normal file
@ -0,0 +1,387 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "XFBEncoder.h"
|
||||
|
||||
#include "D3DBase.h"
|
||||
#include "D3DBlob.h"
|
||||
#include "D3DShader.h"
|
||||
#include "Render.h"
|
||||
#include "GfxState.h"
|
||||
#include "FramebufferManager.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
union XFBEncodeParams
|
||||
{
|
||||
struct
|
||||
{
|
||||
FLOAT Width; // Width and height of encoded XFB in luma pixels
|
||||
FLOAT Height;
|
||||
FLOAT TexLeft; // Normalized tex coordinates of XFB source area in EFB texture
|
||||
FLOAT TexTop;
|
||||
FLOAT TexRight;
|
||||
FLOAT TexBottom;
|
||||
FLOAT Gamma;
|
||||
};
|
||||
// Constant buffers must be a multiple of 16 bytes in size
|
||||
u8 pad[32]; // Pad to the next multiple of 16
|
||||
};
|
||||
|
||||
static const char XFB_ENCODE_VS[] =
|
||||
"// dolphin-emu XFB encoder vertex shader\n"
|
||||
|
||||
"cbuffer cbParams : register(b0)\n"
|
||||
"{\n"
|
||||
"struct\n" // Should match XFBEncodeParams above
|
||||
"{\n"
|
||||
"float Width;\n"
|
||||
"float Height;\n"
|
||||
"float TexLeft;\n"
|
||||
"float TexTop;\n"
|
||||
"float TexRight;\n"
|
||||
"float TexBottom;\n"
|
||||
"float Gamma;\n"
|
||||
"} Params;\n"
|
||||
"}\n"
|
||||
|
||||
"struct Output\n"
|
||||
"{\n"
|
||||
"float4 Pos : SV_Position;\n"
|
||||
"float2 Coord : ENCODECOORD;\n"
|
||||
"};\n"
|
||||
|
||||
"Output main(in float2 Pos : POSITION)\n"
|
||||
"{\n"
|
||||
"Output result;\n"
|
||||
"result.Pos = float4(2*Pos.x-1, -2*Pos.y+1, 0, 1);\n"
|
||||
"result.Coord = Pos * float2(floor(Params.Width/2), Params.Height);\n"
|
||||
"return result;\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
static const char XFB_ENCODE_PS[] =
|
||||
"// dolphin-emu XFB encoder pixel shader\n"
|
||||
|
||||
"cbuffer cbParams : register(b0)\n"
|
||||
"{\n"
|
||||
"struct\n" // Should match XFBEncodeParams above
|
||||
"{\n"
|
||||
"float Width;\n"
|
||||
"float Height;\n"
|
||||
"float TexLeft;\n"
|
||||
"float TexTop;\n"
|
||||
"float TexRight;\n"
|
||||
"float TexBottom;\n"
|
||||
"float Gamma;\n"
|
||||
"} Params;\n"
|
||||
"}\n"
|
||||
|
||||
"Texture2D EFBTexture : register(t0);\n"
|
||||
"sampler EFBSampler : register(s0);\n"
|
||||
|
||||
// GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see
|
||||
// <http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion>
|
||||
"static const float3x4 RGB_TO_YCBCR = float3x4(\n"
|
||||
"0.257, 0.504, 0.098, 16.0/255.0,\n"
|
||||
"-0.148, -0.291, 0.439, 128.0/255.0,\n"
|
||||
"0.439, -0.368, -0.071, 128.0/255.0\n"
|
||||
");\n"
|
||||
|
||||
"float3 SampleEFB(float2 coord)\n"
|
||||
"{\n"
|
||||
"float2 texCoord = lerp(float2(Params.TexLeft,Params.TexTop), float2(Params.TexRight,Params.TexBottom), coord / float2(Params.Width,Params.Height));\n"
|
||||
"return EFBTexture.Sample(EFBSampler, texCoord).rgb;\n"
|
||||
"}\n"
|
||||
|
||||
"void main(out float4 ocol0 : SV_Target, in float4 Pos : SV_Position, in float2 Coord : ENCODECOORD)\n"
|
||||
"{\n"
|
||||
"float2 baseCoord = Coord * float2(2,1);\n"
|
||||
// FIXME: Shall we apply gamma here, or apply it below to the Y components?
|
||||
// Be careful if you apply it to Y! The Y components are in the range (16..235) / 255.
|
||||
"float3 sampleL = pow(abs(SampleEFB(baseCoord+float2(-1,0))), Params.Gamma);\n" // Left
|
||||
"float3 sampleM = pow(abs(SampleEFB(baseCoord)), Params.Gamma);\n" // Middle
|
||||
"float3 sampleR = pow(abs(SampleEFB(baseCoord+float2(1,0))), Params.Gamma);\n" // Right
|
||||
|
||||
"float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));\n"
|
||||
"float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,1));\n"
|
||||
"float3 yuvR = mul(RGB_TO_YCBCR, float4(sampleR,1));\n"
|
||||
|
||||
// The Y components correspond to two EFB pixels, while the U and V are
|
||||
// made from a blend of three EFB pixels.
|
||||
"float y0 = yuvM.r;\n"
|
||||
"float y1 = yuvR.r;\n"
|
||||
"float u0 = 0.25*yuvL.g + 0.5*yuvM.g + 0.25*yuvR.g;\n"
|
||||
"float v0 = 0.25*yuvL.b + 0.5*yuvM.b + 0.25*yuvR.b;\n"
|
||||
|
||||
"ocol0 = float4(y0, u0, y1, v0);\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
static const D3D11_INPUT_ELEMENT_DESC QUAD_LAYOUT_DESC[] = {
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
|
||||
};
|
||||
|
||||
static const struct QuadVertex
|
||||
{
|
||||
float posX;
|
||||
float posY;
|
||||
} QUAD_VERTS[4] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
|
||||
|
||||
XFBEncoder::XFBEncoder()
|
||||
: m_out(NULL), m_outRTV(NULL), m_outStage(NULL), m_encodeParams(NULL),
|
||||
m_quad(NULL), m_vShader(NULL), m_quadLayout(NULL), m_pShader(NULL),
|
||||
m_xfbEncodeBlendState(NULL), m_xfbEncodeDepthState(NULL),
|
||||
m_xfbEncodeRastState(NULL), m_efbSampler(NULL)
|
||||
{ }
|
||||
|
||||
void XFBEncoder::Init()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
// Create output texture
|
||||
|
||||
// The pixel shader can generate one YUYV entry per pixel. One YUYV entry
|
||||
// is created for every two EFB pixels.
|
||||
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, MAX_XFB_WIDTH/2, MAX_XFB_HEIGHT, 1, 1,
|
||||
D3D11_BIND_RENDER_TARGET);
|
||||
hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_out);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encoder output texture");
|
||||
D3D::SetDebugObjectName(m_out, "xfb encoder output texture");
|
||||
|
||||
// Create output render target view
|
||||
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(m_out,
|
||||
D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encoder output texture rtv");
|
||||
D3D::SetDebugObjectName(m_outRTV, "xfb encoder output rtv");
|
||||
|
||||
// Create output staging buffer
|
||||
|
||||
t2dd.Usage = D3D11_USAGE_STAGING;
|
||||
t2dd.BindFlags = 0;
|
||||
t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
hr = D3D::device->CreateTexture2D(&t2dd, NULL, &m_outStage);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encoder output staging buffer");
|
||||
D3D::SetDebugObjectName(m_outStage, "xfb encoder output staging buffer");
|
||||
|
||||
// Create constant buffer for uploading params to shaders
|
||||
|
||||
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(XFBEncodeParams),
|
||||
D3D11_BIND_CONSTANT_BUFFER);
|
||||
hr = D3D::device->CreateBuffer(&bd, NULL, &m_encodeParams);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode params buffer");
|
||||
D3D::SetDebugObjectName(m_encodeParams, "xfb encoder params buffer");
|
||||
|
||||
// Create vertex quad
|
||||
|
||||
bd = CD3D11_BUFFER_DESC(sizeof(QUAD_VERTS), D3D11_BIND_VERTEX_BUFFER,
|
||||
D3D11_USAGE_IMMUTABLE);
|
||||
D3D11_SUBRESOURCE_DATA srd = { QUAD_VERTS, 0, 0 };
|
||||
|
||||
hr = D3D::device->CreateBuffer(&bd, &srd, &m_quad);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode quad vertex buffer");
|
||||
D3D::SetDebugObjectName(m_quad, "xfb encoder quad vertex buffer");
|
||||
|
||||
// Create vertex shader
|
||||
|
||||
D3DBlob* bytecode = NULL;
|
||||
if (!D3D::CompileVertexShader(XFB_ENCODE_VS, sizeof(XFB_ENCODE_VS), &bytecode))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "XFB encode vertex shader failed to compile");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = D3D::device->CreateVertexShader(bytecode->Data(), bytecode->Size(), NULL, &m_vShader);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode vertex shader");
|
||||
D3D::SetDebugObjectName(m_vShader, "xfb encoder vertex shader");
|
||||
|
||||
// Create input layout for vertex quad using bytecode from vertex shader
|
||||
|
||||
hr = D3D::device->CreateInputLayout(QUAD_LAYOUT_DESC,
|
||||
sizeof(QUAD_LAYOUT_DESC)/sizeof(D3D11_INPUT_ELEMENT_DESC),
|
||||
bytecode->Data(), bytecode->Size(), &m_quadLayout);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode quad vertex layout");
|
||||
D3D::SetDebugObjectName(m_quadLayout, "xfb encoder quad layout");
|
||||
|
||||
bytecode->Release();
|
||||
|
||||
// Create pixel shader
|
||||
|
||||
m_pShader = D3D::CompileAndCreatePixelShader(XFB_ENCODE_PS, sizeof(XFB_ENCODE_PS));
|
||||
if (!m_pShader)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "XFB encode pixel shader failed to compile");
|
||||
return;
|
||||
}
|
||||
D3D::SetDebugObjectName(m_pShader, "xfb encoder pixel shader");
|
||||
|
||||
// Create blend state
|
||||
|
||||
D3D11_BLEND_DESC bld = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
|
||||
hr = D3D::device->CreateBlendState(&bld, &m_xfbEncodeBlendState);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode blend state");
|
||||
D3D::SetDebugObjectName(m_xfbEncodeBlendState, "xfb encoder blend state");
|
||||
|
||||
// Create depth state
|
||||
|
||||
D3D11_DEPTH_STENCIL_DESC dsd = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT());
|
||||
dsd.DepthEnable = FALSE;
|
||||
hr = D3D::device->CreateDepthStencilState(&dsd, &m_xfbEncodeDepthState);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode depth state");
|
||||
D3D::SetDebugObjectName(m_xfbEncodeDepthState, "xfb encoder depth state");
|
||||
|
||||
// Create rasterizer state
|
||||
|
||||
D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
|
||||
rd.CullMode = D3D11_CULL_NONE;
|
||||
rd.DepthClipEnable = FALSE;
|
||||
hr = D3D::device->CreateRasterizerState(&rd, &m_xfbEncodeRastState);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode rasterizer state");
|
||||
D3D::SetDebugObjectName(m_xfbEncodeRastState, "xfb encoder rast state");
|
||||
|
||||
// Create EFB texture sampler
|
||||
|
||||
D3D11_SAMPLER_DESC sd = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
|
||||
// FIXME: Should we really use point sampling here?
|
||||
sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
hr = D3D::device->CreateSamplerState(&sd, &m_efbSampler);
|
||||
CHECK(SUCCEEDED(hr), "create xfb encode texture sampler");
|
||||
D3D::SetDebugObjectName(m_efbSampler, "xfb encoder texture sampler");
|
||||
}
|
||||
|
||||
void XFBEncoder::Shutdown()
|
||||
{
|
||||
SAFE_RELEASE(m_efbSampler);
|
||||
SAFE_RELEASE(m_xfbEncodeRastState);
|
||||
SAFE_RELEASE(m_xfbEncodeDepthState);
|
||||
SAFE_RELEASE(m_xfbEncodeBlendState);
|
||||
SAFE_RELEASE(m_pShader);
|
||||
SAFE_RELEASE(m_quadLayout);
|
||||
SAFE_RELEASE(m_vShader);
|
||||
SAFE_RELEASE(m_quad);
|
||||
SAFE_RELEASE(m_encodeParams);
|
||||
SAFE_RELEASE(m_outStage);
|
||||
SAFE_RELEASE(m_outRTV);
|
||||
SAFE_RELEASE(m_out);
|
||||
}
|
||||
|
||||
void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
// Reset API
|
||||
|
||||
g_renderer->ResetAPIState();
|
||||
|
||||
// Set up all the state for XFB encoding
|
||||
|
||||
D3D::context->PSSetShader(m_pShader, NULL, 0);
|
||||
D3D::context->VSSetShader(m_vShader, NULL, 0);
|
||||
|
||||
D3D::stateman->PushBlendState(m_xfbEncodeBlendState);
|
||||
D3D::stateman->PushDepthState(m_xfbEncodeDepthState);
|
||||
D3D::stateman->PushRasterizerState(m_xfbEncodeRastState);
|
||||
D3D::stateman->Apply();
|
||||
|
||||
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width/2), FLOAT(height));
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
|
||||
D3D::context->IASetInputLayout(m_quadLayout);
|
||||
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
UINT stride = sizeof(QuadVertex);
|
||||
UINT offset = 0;
|
||||
D3D::context->IASetVertexBuffers(0, 1, &m_quad, &stride, &offset);
|
||||
|
||||
TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect);
|
||||
|
||||
XFBEncodeParams params = { 0 };
|
||||
params.Width = FLOAT(width);
|
||||
params.Height = FLOAT(height);
|
||||
params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetFullTargetWidth();
|
||||
params.TexTop = FLOAT(targetRect.top) / g_renderer->GetFullTargetHeight();
|
||||
params.TexRight = FLOAT(targetRect.right) / g_renderer->GetFullTargetWidth();
|
||||
params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetFullTargetHeight();
|
||||
params.Gamma = gamma;
|
||||
D3D::context->UpdateSubresource(m_encodeParams, 0, NULL, ¶ms, 0, 0);
|
||||
|
||||
D3D::context->VSSetConstantBuffers(0, 1, &m_encodeParams);
|
||||
|
||||
D3D::context->OMSetRenderTargets(1, &m_outRTV, NULL);
|
||||
|
||||
ID3D11ShaderResourceView* pEFB = FramebufferManager::GetEFBColorTexture()->GetSRV();
|
||||
|
||||
D3D::context->PSSetConstantBuffers(0, 1, &m_encodeParams);
|
||||
D3D::context->PSSetShaderResources(0, 1, &pEFB);
|
||||
D3D::context->PSSetSamplers(0, 1, &m_efbSampler);
|
||||
|
||||
// Encode!
|
||||
|
||||
D3D::context->Draw(4, 0);
|
||||
|
||||
// Copy to staging buffer
|
||||
|
||||
D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, width/2, height, 1);
|
||||
D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox);
|
||||
|
||||
// Clean up state
|
||||
|
||||
IUnknown* nullDummy = NULL;
|
||||
|
||||
D3D::context->PSSetSamplers(0, 1, (ID3D11SamplerState**)&nullDummy);
|
||||
D3D::context->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&nullDummy);
|
||||
D3D::context->PSSetConstantBuffers(0, 1, (ID3D11Buffer**)&nullDummy);
|
||||
|
||||
D3D::context->OMSetRenderTargets(0, NULL, NULL);
|
||||
|
||||
D3D::context->VSSetConstantBuffers(0, 1, (ID3D11Buffer**)&nullDummy);
|
||||
|
||||
D3D::stateman->PopRasterizerState();
|
||||
D3D::stateman->PopDepthState();
|
||||
D3D::stateman->PopBlendState();
|
||||
|
||||
D3D::context->PSSetShader(NULL, NULL, 0);
|
||||
D3D::context->VSSetShader(NULL, NULL, 0);
|
||||
|
||||
// Transfer staging buffer to GameCube/Wii RAM
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE map = { 0 };
|
||||
hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map);
|
||||
CHECK(SUCCEEDED(hr), "map staging buffer");
|
||||
|
||||
u8* src = (u8*)map.pData;
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
memcpy(dst, src, 2*width);
|
||||
dst += bpmem.copyMipMapStrideChannels*32;
|
||||
src += map.RowPitch;
|
||||
}
|
||||
|
||||
D3D::context->Unmap(m_outStage, 0);
|
||||
|
||||
// Restore API
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
D3D::context->OMSetRenderTargets(1,
|
||||
&FramebufferManager::GetEFBColorTexture()->GetRTV(),
|
||||
FramebufferManager::GetEFBDepthTexture()->GetDSV());
|
||||
}
|
||||
|
||||
}
|
68
Source/Plugins/Plugin_VideoDX11/Src/XFBEncoder.h
Normal file
68
Source/Plugins/Plugin_VideoDX11/Src/XFBEncoder.h
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _XFBENCODER_H
|
||||
#define _XFBENCODER_H
|
||||
|
||||
#include "VideoCommon.h"
|
||||
|
||||
struct ID3D11Texture2D;
|
||||
struct ID3D11RenderTargetView;
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11VertexShader;
|
||||
struct ID3D11PixelShader;
|
||||
struct ID3D11InputLayout;
|
||||
struct ID3D11BlendState;
|
||||
struct ID3D11DepthStencilState;
|
||||
struct ID3D11RasterizerState;
|
||||
struct ID3D11SamplerState;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
|
||||
class XFBEncoder
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
XFBEncoder();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma);
|
||||
|
||||
private:
|
||||
|
||||
ID3D11Texture2D* m_out;
|
||||
ID3D11RenderTargetView* m_outRTV;
|
||||
ID3D11Texture2D* m_outStage;
|
||||
ID3D11Buffer* m_encodeParams;
|
||||
ID3D11Buffer* m_quad;
|
||||
ID3D11VertexShader* m_vShader;
|
||||
ID3D11InputLayout* m_quadLayout;
|
||||
ID3D11PixelShader* m_pShader;
|
||||
ID3D11BlendState* m_xfbEncodeBlendState;
|
||||
ID3D11DepthStencilState* m_xfbEncodeDepthState;
|
||||
ID3D11RasterizerState* m_xfbEncodeRastState;
|
||||
ID3D11SamplerState* m_efbSampler;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -82,7 +82,7 @@ void InitBackendInfo()
|
||||
g_Config.backend_info.APIType = API_D3D11;
|
||||
g_Config.backend_info.bUseRGBATextures = true; // the GX formats barely match any D3D11 formats
|
||||
g_Config.backend_info.bSupportsEFBToRAM = true;
|
||||
g_Config.backend_info.bSupportsRealXFB = false;
|
||||
g_Config.backend_info.bSupportsRealXFB = true;
|
||||
g_Config.backend_info.bSupports3DVision = false;
|
||||
g_Config.backend_info.bAllowSignedBytes = true;
|
||||
g_Config.backend_info.bSupportsDualSourceBlend = true;
|
||||
|
Loading…
Reference in New Issue
Block a user