Put Plugins/ in Core/, rename to VideoBackends

This commit is contained in:
Jasper St. Pierre
2013-09-10 23:12:54 -04:00
parent d6f0ecebb4
commit a7c7208103
145 changed files with 25 additions and 41 deletions

View File

@ -0,0 +1,243 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="DebugFast|Win32">
<Configuration>DebugFast</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="DebugFast|x64">
<Configuration>DebugFast</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9A4C733C-BADE-4AC6-B58A-6E274395E90E}</ProjectGuid>
<RootNamespace>VideoD3D</RootNamespace>
<ProjectName>VideoD3D</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\VSProps\Base.props" />
<Import Project="..\..\VSProps\PrecompiledHeader.props" />
<Import Project="..\..\VSProps\CodeGen_Debug.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\VSProps\Base.props" />
<Import Project="..\..\VSProps\PrecompiledHeader.props" />
<Import Project="..\..\VSProps\CodeGen_Debug.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\VSProps\Base.props" />
<Import Project="..\..\VSProps\CodeGen_Release.props" />
<Import Project="..\..\VSProps\PrecompiledHeader.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\VSProps\Base.props" />
<Import Project="..\..\VSProps\CodeGen_DebugFast.props" />
<Import Project="..\..\VSProps\PrecompiledHeader.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\VSProps\Base.props" />
<Import Project="..\..\VSProps\CodeGen_Release.props" />
<Import Project="..\..\VSProps\PrecompiledHeader.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\VSProps\Base.props" />
<Import Project="..\..\VSProps\CodeGen_DebugFast.props" />
<Import Project="..\..\VSProps\PrecompiledHeader.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
<ClCompile>
<AdditionalIncludeDirectories>..\..\Core\Common\Src;..\..\Core\Core\Src;..\..\Core\VideoCommon\Src;..\..\Core\DolphinWX\Src;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="..\..\Core\VideoCommon\VideoCommon.vcxproj">
<Project>{3e5c4e02-1ba9-4776-bdbe-e3f91ffa34cf}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Src\D3DBase.cpp" />
<ClCompile Include="Src\D3DBlob.cpp" />
<ClCompile Include="Src\D3DShader.cpp" />
<ClCompile Include="Src\D3DTexture.cpp" />
<ClCompile Include="Src\D3DUtil.cpp" />
<ClCompile Include="Src\FramebufferManager.cpp" />
<ClCompile Include="Src\GfxState.cpp" />
<ClCompile Include="Src\LineGeometryShader.cpp" />
<ClCompile Include="Src\main.cpp" />
<ClCompile Include="Src\NativeVertexFormat.cpp" />
<ClCompile Include="Src\PerfQuery.cpp" />
<ClCompile Include="Src\PixelShaderCache.cpp" />
<ClCompile Include="Src\PointGeometryShader.cpp" />
<ClCompile Include="Src\PSTextureEncoder.cpp" />
<ClCompile Include="Src\Render.cpp" />
<ClCompile Include="Src\stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">Create</PrecompiledHeader>
<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" />
<ClInclude Include="Src\D3DBlob.h" />
<ClInclude Include="Src\D3DShader.h" />
<ClInclude Include="Src\D3DTexture.h" />
<ClInclude Include="Src\D3DUtil.h" />
<ClInclude Include="Src\FramebufferManager.h" />
<ClInclude Include="Src\GfxState.h" />
<ClInclude Include="Src\Globals.h" />
<ClInclude Include="Src\LineGeometryShader.h" />
<ClInclude Include="Src\main.h" />
<ClInclude Include="Src\PerfQuery.h" />
<ClInclude Include="Src\PixelShaderCache.h" />
<ClInclude Include="Src\PointGeometryShader.h" />
<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">
</ImportGroup>
</Project>

View File

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="Src\main.cpp" />
<ClCompile Include="Src\stdafx.cpp" />
<ClCompile Include="Src\D3DBase.cpp">
<Filter>D3D</Filter>
</ClCompile>
<ClCompile Include="Src\D3DBlob.cpp">
<Filter>D3D</Filter>
</ClCompile>
<ClCompile Include="Src\D3DShader.cpp">
<Filter>D3D</Filter>
</ClCompile>
<ClCompile Include="Src\D3DTexture.cpp">
<Filter>D3D</Filter>
</ClCompile>
<ClCompile Include="Src\D3DUtil.cpp">
<Filter>D3D</Filter>
</ClCompile>
<ClCompile Include="Src\GfxState.cpp">
<Filter>D3D</Filter>
</ClCompile>
<ClCompile Include="Src\FramebufferManager.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\NativeVertexFormat.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\PixelShaderCache.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\Render.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\TextureCache.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\VertexManager.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\VertexShaderCache.cpp">
<Filter>Render</Filter>
</ClCompile>
<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>
<ClCompile Include="Src\LineGeometryShader.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\PointGeometryShader.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Src\PerfQuery.cpp">
<Filter>Render</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Src\Globals.h" />
<ClInclude Include="Src\main.h" />
<ClInclude Include="Src\stdafx.h" />
<ClInclude Include="Src\VideoBackend.h" />
<ClInclude Include="Src\D3DUtil.h">
<Filter>D3D</Filter>
</ClInclude>
<ClInclude Include="Src\D3DBase.h">
<Filter>D3D</Filter>
</ClInclude>
<ClInclude Include="Src\D3DBlob.h">
<Filter>D3D</Filter>
</ClInclude>
<ClInclude Include="Src\D3DShader.h">
<Filter>D3D</Filter>
</ClInclude>
<ClInclude Include="Src\D3DTexture.h">
<Filter>D3D</Filter>
</ClInclude>
<ClInclude Include="Src\GfxState.h">
<Filter>D3D</Filter>
</ClInclude>
<ClInclude Include="Src\FramebufferManager.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\Render.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\PixelShaderCache.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\VertexShaderCache.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\TextureCache.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\VertexManager.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\PSTextureEncoder.h">
<Filter>Render</Filter>
</ClInclude>
<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>
<ClInclude Include="Src\LineGeometryShader.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\PointGeometryShader.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Src\PerfQuery.h">
<Filter>Render</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="D3D">
<UniqueIdentifier>{8dda993d-a0ed-4c2e-9651-c13c743e3e27}</UniqueIdentifier>
</Filter>
<Filter Include="Render">
<UniqueIdentifier>{41d3f9d1-16f3-4a48-a486-292b1593dc92}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View File

@ -0,0 +1,534 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "StringUtil.h"
#include "VideoConfig.h"
#include "D3DBase.h"
#include "D3DTexture.h"
#include "GfxState.h"
namespace DX11
{
HINSTANCE hD3DCompilerDll = NULL;
D3DREFLECT PD3DReflect = NULL;
int d3dcompiler_dll_ref = 0;
HINSTANCE hD3DXDll = NULL;
D3DX11COMPILEFROMMEMORYTYPE PD3DX11CompileFromMemory = NULL;
D3DX11FILTERTEXTURETYPE PD3DX11FilterTexture = NULL;
D3DX11SAVETEXTURETOFILEATYPE PD3DX11SaveTextureToFileA = NULL;
D3DX11SAVETEXTURETOFILEWTYPE PD3DX11SaveTextureToFileW = NULL;
int d3dx_dll_ref = 0;
CREATEDXGIFACTORY PCreateDXGIFactory = NULL;
HINSTANCE hDXGIDll = NULL;
int dxgi_dll_ref = 0;
typedef HRESULT (WINAPI* D3D11CREATEDEVICEANDSWAPCHAIN)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, CONST DXGI_SWAP_CHAIN_DESC*, IDXGISwapChain**, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext**);
D3D11CREATEDEVICE PD3D11CreateDevice = NULL;
D3D11CREATEDEVICEANDSWAPCHAIN PD3D11CreateDeviceAndSwapChain = NULL;
HINSTANCE hD3DDll = NULL;
int d3d_dll_ref = 0;
namespace D3D
{
ID3D11Device* device = NULL;
ID3D11DeviceContext* context = NULL;
IDXGISwapChain* swapchain = NULL;
D3D_FEATURE_LEVEL featlevel;
D3DTexture2D* backbuf = NULL;
HWND hWnd;
std::vector<DXGI_SAMPLE_DESC> aa_modes; // supported AA modes of the current adapter
bool bgra_textures_supported;
#define NUM_SUPPORTED_FEATURE_LEVELS 3
const D3D_FEATURE_LEVEL supported_feature_levels[NUM_SUPPORTED_FEATURE_LEVELS] = {
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0
};
unsigned int xres, yres;
bool bFrameInProgress = false;
HRESULT LoadDXGI()
{
if (dxgi_dll_ref++ > 0) return S_OK;
if (hDXGIDll) return S_OK;
hDXGIDll = LoadLibraryA("dxgi.dll");
if (!hDXGIDll)
{
MessageBoxA(NULL, "Failed to load dxgi.dll", "Critical error", MB_OK | MB_ICONERROR);
--dxgi_dll_ref;
return E_FAIL;
}
PCreateDXGIFactory = (CREATEDXGIFACTORY)GetProcAddress(hDXGIDll, "CreateDXGIFactory");
if (PCreateDXGIFactory == NULL) MessageBoxA(NULL, "GetProcAddress failed for CreateDXGIFactory!", "Critical error", MB_OK | MB_ICONERROR);
return S_OK;
}
HRESULT LoadD3D()
{
if (d3d_dll_ref++ > 0) return S_OK;
if (hD3DDll) return S_OK;
hD3DDll = LoadLibraryA("d3d11.dll");
if (!hD3DDll)
{
MessageBoxA(NULL, "Failed to load d3d11.dll", "Critical error", MB_OK | MB_ICONERROR);
--d3d_dll_ref;
return E_FAIL;
}
PD3D11CreateDevice = (D3D11CREATEDEVICE)GetProcAddress(hD3DDll, "D3D11CreateDevice");
if (PD3D11CreateDevice == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3D11CreateDevice!", "Critical error", MB_OK | MB_ICONERROR);
PD3D11CreateDeviceAndSwapChain = (D3D11CREATEDEVICEANDSWAPCHAIN)GetProcAddress(hD3DDll, "D3D11CreateDeviceAndSwapChain");
if (PD3D11CreateDeviceAndSwapChain == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3D11CreateDeviceAndSwapChain!", "Critical error", MB_OK | MB_ICONERROR);
return S_OK;
}
HRESULT LoadD3DX()
{
if (d3dx_dll_ref++ > 0) return S_OK;
if (hD3DXDll) return S_OK;
// try to load D3DX11 first to check whether we have proper runtime support
// try to use the dll the backend was compiled against first - don't bother about debug runtimes
hD3DXDll = LoadLibraryA(D3DX11_DLL_A);
if (!hD3DXDll)
{
// if that fails, use the dll which should be available in every SDK which officially supports DX11.
hD3DXDll = LoadLibraryA("d3dx11_42.dll");
if (!hD3DXDll)
{
MessageBoxA(NULL, "Failed to load d3dx11_42.dll, update your DX11 runtime, please", "Critical error", MB_OK | MB_ICONERROR);
return E_FAIL;
}
else
{
NOTICE_LOG(VIDEO, "Successfully loaded d3dx11_42.dll. If you're having trouble, try updating your DX runtime first.");
}
}
PD3DX11CompileFromMemory = (D3DX11COMPILEFROMMEMORYTYPE)GetProcAddress(hD3DXDll, "D3DX11CompileFromMemory");
if (PD3DX11CompileFromMemory == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11CompileFromMemory!", "Critical error", MB_OK | MB_ICONERROR);
PD3DX11FilterTexture = (D3DX11FILTERTEXTURETYPE)GetProcAddress(hD3DXDll, "D3DX11FilterTexture");
if (PD3DX11FilterTexture == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11FilterTexture!", "Critical error", MB_OK | MB_ICONERROR);
PD3DX11SaveTextureToFileA = (D3DX11SAVETEXTURETOFILEATYPE)GetProcAddress(hD3DXDll, "D3DX11SaveTextureToFileA");
if (PD3DX11SaveTextureToFileA == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11SaveTextureToFileA!", "Critical error", MB_OK | MB_ICONERROR);
PD3DX11SaveTextureToFileW = (D3DX11SAVETEXTURETOFILEWTYPE)GetProcAddress(hD3DXDll, "D3DX11SaveTextureToFileW");
if (PD3DX11SaveTextureToFileW == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DX11SaveTextureToFileW!", "Critical error", MB_OK | MB_ICONERROR);
return S_OK;
}
HRESULT LoadD3DCompiler()
{
if (d3dcompiler_dll_ref++ > 0) return S_OK;
if (hD3DCompilerDll) return S_OK;
// try to load D3DCompiler first to check whether we have proper runtime support
// try to use the dll the backend was compiled against first - don't bother about debug runtimes
hD3DCompilerDll = LoadLibraryA(D3DCOMPILER_DLL_A);
if (!hD3DCompilerDll)
{
// if that fails, use the dll which should be available in every SDK which officially supports DX11.
hD3DCompilerDll = LoadLibraryA("D3DCompiler_42.dll");
if (!hD3DCompilerDll)
{
MessageBoxA(NULL, "Failed to load D3DCompiler_42.dll, update your DX11 runtime, please", "Critical error", MB_OK | MB_ICONERROR);
return E_FAIL;
}
else
{
NOTICE_LOG(VIDEO, "Successfully loaded D3DCompiler_42.dll. If you're having trouble, try updating your DX runtime first.");
}
}
PD3DReflect = (D3DREFLECT)GetProcAddress(hD3DCompilerDll, "D3DReflect");
if (PD3DReflect == NULL) MessageBoxA(NULL, "GetProcAddress failed for D3DReflect!", "Critical error", MB_OK | MB_ICONERROR);
return S_OK;
}
void UnloadDXGI()
{
if (!dxgi_dll_ref) return;
if (--dxgi_dll_ref != 0) return;
if(hDXGIDll) FreeLibrary(hDXGIDll);
hDXGIDll = NULL;
PCreateDXGIFactory = NULL;
}
void UnloadD3DX()
{
if (!d3dx_dll_ref) return;
if (--d3dx_dll_ref != 0) return;
if(hD3DXDll) FreeLibrary(hD3DXDll);
hD3DXDll = NULL;
PD3DX11FilterTexture = NULL;
PD3DX11SaveTextureToFileA = NULL;
PD3DX11SaveTextureToFileW = NULL;
}
void UnloadD3D()
{
if (!d3d_dll_ref) return;
if (--d3d_dll_ref != 0) return;
if(hD3DDll) FreeLibrary(hD3DDll);
hD3DDll = NULL;
PD3D11CreateDevice = NULL;
PD3D11CreateDeviceAndSwapChain = NULL;
}
void UnloadD3DCompiler()
{
if (!d3dcompiler_dll_ref) return;
if (--d3dcompiler_dll_ref != 0) return;
if (hD3DCompilerDll) FreeLibrary(hD3DCompilerDll);
hD3DCompilerDll = NULL;
PD3DReflect = NULL;
}
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter)
{
std::vector<DXGI_SAMPLE_DESC> aa_modes;
// NOTE: D3D 10.0 doesn't support multisampled resources which are bound as depth buffers AND shader resources.
// Thus, we can't have MSAA with 10.0 level hardware.
ID3D11Device* device;
ID3D11DeviceContext* context;
D3D_FEATURE_LEVEL feat_level;
HRESULT hr = PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, &device, &feat_level, &context);
if (FAILED(hr) || feat_level == D3D_FEATURE_LEVEL_10_0)
{
DXGI_SAMPLE_DESC desc;
desc.Count = 1;
desc.Quality = 0;
aa_modes.push_back(desc);
SAFE_RELEASE(context);
SAFE_RELEASE(device);
}
else
{
for (int samples = 0; samples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples)
{
UINT quality_levels = 0;
device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, samples, &quality_levels);
if (quality_levels > 0) {
DXGI_SAMPLE_DESC desc;
desc.Count = samples;
for (desc.Quality = 0; desc.Quality < quality_levels; ++desc.Quality)
aa_modes.push_back(desc);
}
}
context->Release();
device->Release();
}
return aa_modes;
}
D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter)
{
D3D_FEATURE_LEVEL feat_level = D3D_FEATURE_LEVEL_9_1;
PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, NULL, &feat_level, NULL);
return feat_level;
}
DXGI_SAMPLE_DESC GetAAMode(int index)
{
return aa_modes[index];
}
HRESULT Create(HWND wnd)
{
hWnd = wnd;
HRESULT hr;
RECT client;
GetClientRect(hWnd, &client);
xres = client.right - client.left;
yres = client.bottom - client.top;
hr = LoadDXGI();
if (SUCCEEDED(hr)) hr = LoadD3D();
if (SUCCEEDED(hr)) hr = LoadD3DX();
if (SUCCEEDED(hr)) hr = LoadD3DCompiler();
if (FAILED(hr))
{
UnloadDXGI();
UnloadD3D();
UnloadD3DX();
UnloadD3DCompiler();
return hr;
}
IDXGIFactory* factory;
IDXGIAdapter* adapter;
IDXGIOutput* output;
hr = PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
if (FAILED(hr)) MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter);
if (FAILED(hr))
{
// try using the first one
hr = factory->EnumAdapters(0, &adapter);
if (FAILED(hr)) MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
}
// TODO: Make this configurable
hr = adapter->EnumOutputs(0, &output);
if (FAILED(hr))
{
// try using the first one
hr = adapter->EnumOutputs(0, &output);
if (FAILED(hr)) MessageBox(wnd, _T("Failed to enumerate outputs"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
}
// get supported AA modes
aa_modes = EnumAAModes(adapter);
if (g_Config.iMultisampleMode >= (int)aa_modes.size())
{
g_Config.iMultisampleMode = 0;
UpdateActiveConfig();
}
DXGI_SWAP_CHAIN_DESC swap_chain_desc;
memset(&swap_chain_desc, 0, sizeof(swap_chain_desc));
swap_chain_desc.BufferCount = 1;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.OutputWindow = wnd;
swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.SampleDesc.Quality = 0;
swap_chain_desc.Windowed = TRUE;
DXGI_MODE_DESC mode_desc;
memset(&mode_desc, 0, sizeof(mode_desc));
mode_desc.Width = xres;
mode_desc.Height = yres;
mode_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
mode_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
hr = output->FindClosestMatchingMode(&mode_desc, &swap_chain_desc.BufferDesc, NULL);
if (FAILED(hr)) MessageBox(wnd, _T("Failed to find a supported video mode"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
// forcing buffer resolution to xres and yres.. TODO: The new video mode might not actually be supported!
swap_chain_desc.BufferDesc.Width = xres;
swap_chain_desc.BufferDesc.Height = yres;
#if defined(_DEBUG) || defined(DEBUGFAST)
// Creating debug devices can sometimes fail if the user doesn't have the correct
// version of the DirectX SDK. If it does, simply fallback to a non-debug device.
{
hr = PD3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL,
D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_DEBUG,
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS,
D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device,
&featlevel, &context);
}
if (FAILED(hr))
#endif
{
hr = PD3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL,
D3D11_CREATE_DEVICE_SINGLETHREADED,
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS,
D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device,
&featlevel, &context);
}
if (FAILED(hr))
{
MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
SAFE_RELEASE(device);
SAFE_RELEASE(context);
SAFE_RELEASE(swapchain);
return E_FAIL;
}
SetDebugObjectName((ID3D11DeviceChild*)context, "device context");
SAFE_RELEASE(factory);
SAFE_RELEASE(output);
SAFE_RELEASE(adapter);
ID3D11Texture2D* buf;
hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf);
if (FAILED(hr))
{
MessageBox(wnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
SAFE_RELEASE(device);
SAFE_RELEASE(context);
SAFE_RELEASE(swapchain);
return E_FAIL;
}
backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
SAFE_RELEASE(buf);
CHECK(backbuf!=NULL, "Create back buffer texture");
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture");
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view");
context->OMSetRenderTargets(1, &backbuf->GetRTV(), NULL);
// BGRA textures are easier to deal with in TextureCache, but might not be supported by the hardware
UINT format_support;
device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &format_support);
bgra_textures_supported = (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
stateman = new StateManager;
return S_OK;
}
void Close()
{
// release all bound resources
context->ClearState();
SAFE_RELEASE(backbuf);
SAFE_RELEASE(swapchain);
SAFE_DELETE(stateman);
context->Flush(); // immediately destroy device objects
SAFE_RELEASE(context);
ULONG references = device->Release();
if (references)
{
ERROR_LOG(VIDEO, "Unreleased references: %i.", references);
}
else
{
NOTICE_LOG(VIDEO, "Successfully released all device references!");
}
device = NULL;
// unload DLLs
UnloadD3DX();
UnloadD3D();
UnloadDXGI();
}
const char* VertexShaderVersionString()
{
if(featlevel == D3D_FEATURE_LEVEL_11_0) return "vs_5_0";
else if(featlevel == D3D_FEATURE_LEVEL_10_1) return "vs_4_1";
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "vs_4_0";
}
const char* GeometryShaderVersionString()
{
if(featlevel == D3D_FEATURE_LEVEL_11_0) return "gs_5_0";
else if(featlevel == D3D_FEATURE_LEVEL_10_1) return "gs_4_1";
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "gs_4_0";
}
const char* PixelShaderVersionString()
{
if(featlevel == D3D_FEATURE_LEVEL_11_0) return "ps_5_0";
else if(featlevel == D3D_FEATURE_LEVEL_10_1) return "ps_4_1";
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ return "ps_4_0";
}
D3DTexture2D* &GetBackBuffer() { return backbuf; }
unsigned int GetBackBufferWidth() { return xres; }
unsigned int GetBackBufferHeight() { return yres; }
bool BGRATexturesSupported() { return bgra_textures_supported; }
// Returns the maximum width/height of a texture. This value only depends upon the feature level in DX11
unsigned int GetMaxTextureSize()
{
switch (featlevel)
{
case D3D_FEATURE_LEVEL_11_0:
return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0:
return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
case D3D_FEATURE_LEVEL_9_3:
return 4096;
case D3D_FEATURE_LEVEL_9_2:
case D3D_FEATURE_LEVEL_9_1:
return 2048;
default:
return 0;
}
}
void Reset()
{
// release all back buffer references
SAFE_RELEASE(backbuf);
// resize swapchain buffers
RECT client;
GetClientRect(hWnd, &client);
xres = client.right - client.left;
yres = client.bottom - client.top;
D3D::swapchain->ResizeBuffers(1, xres, yres, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
// recreate back buffer texture
ID3D11Texture2D* buf;
HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&buf);
if (FAILED(hr))
{
MessageBox(hWnd, _T("Failed to get swapchain buffer"), _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR);
SAFE_RELEASE(device);
SAFE_RELEASE(context);
SAFE_RELEASE(swapchain);
return;
}
backbuf = new D3DTexture2D(buf, D3D11_BIND_RENDER_TARGET);
SAFE_RELEASE(buf);
CHECK(backbuf!=NULL, "Create back buffer texture");
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetTex(), "backbuffer texture");
SetDebugObjectName((ID3D11DeviceChild*)backbuf->GetRTV(), "backbuffer render target view");
}
bool BeginFrame()
{
if (bFrameInProgress)
{
PanicAlert("BeginFrame called although a frame is already in progress");
return false;
}
bFrameInProgress = true;
return (device != NULL);
}
void EndFrame()
{
if (!bFrameInProgress)
{
PanicAlert("EndFrame called although no frame is in progress");
return;
}
bFrameInProgress = false;
}
void Present()
{
// TODO: Is 1 the correct value for vsyncing?
swapchain->Present((UINT)g_ActiveConfig.IsVSync(), 0);
}
} // namespace D3D
} // namespace DX11

View File

@ -0,0 +1,106 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include <D3DX11.h>
#include <D3Dcompiler.h>
#include "Common.h"
#include <vector>
namespace DX11
{
#define SAFE_RELEASE(x) { if (x) (x)->Release(); (x) = NULL; }
#define SAFE_DELETE(x) { delete (x); (x) = NULL; }
#define SAFE_DELETE_ARRAY(x) { delete[] (x); (x) = NULL; }
#define CHECK(cond, Message, ...) if (!(cond)) { PanicAlert(__FUNCTION__ "Failed in %s at line %d: " Message, __FILE__, __LINE__, __VA_ARGS__); }
class D3DTexture2D;
namespace D3D
{
HRESULT LoadDXGI();
HRESULT LoadD3D();
HRESULT LoadD3DX();
HRESULT LoadD3DCompiler();
void UnloadDXGI();
void UnloadD3D();
void UnloadD3DX();
void UnloadD3DCompiler();
D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter);
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter);
DXGI_SAMPLE_DESC GetAAMode(int index);
HRESULT Create(HWND wnd);
void Close();
extern ID3D11Device* device;
extern ID3D11DeviceContext* context;
extern IDXGISwapChain* swapchain;
extern bool bFrameInProgress;
void Reset();
bool BeginFrame();
void EndFrame();
void Present();
unsigned int GetBackBufferWidth();
unsigned int GetBackBufferHeight();
D3DTexture2D* &GetBackBuffer();
const char* PixelShaderVersionString();
const char* GeometryShaderVersionString();
const char* VertexShaderVersionString();
bool BGRATexturesSupported();
unsigned int GetMaxTextureSize();
// Ihis function will assign a name to the given resource.
// The DirectX debug layer will make it easier to identify resources that way,
// e.g. when listing up all resources who have unreleased references.
template <typename T>
void SetDebugObjectName(T resource, const char* name)
{
static_assert(std::is_convertible<T, ID3D11DeviceChild*>::value,
"resource must be convertible to ID3D11DeviceChild*");
#if defined(_DEBUG) || defined(DEBUGFAST)
resource->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)strlen(name), name);
#endif
}
} // namespace
// Used to not require the SDK and runtime versions to match:
// Linking with d3dx11.lib makes the most recent d3dx11_xx.dll of the
// compiler's SDK a requirement, but this backend works with DX11 runtimes
// back to August 2009 even if the backend was built with June 2010.
// Add any d3dx11 functions which you want to use here and load them in Create()
typedef HRESULT (WINAPI* D3DX11COMPILEFROMMEMORYTYPE)(LPCSTR, SIZE_T, LPCSTR, const D3D10_SHADER_MACRO*, LPD3D10INCLUDE, LPCSTR, LPCSTR, UINT, UINT, ID3DX11ThreadPump*, ID3D10Blob**, ID3D10Blob**, HRESULT*);
typedef HRESULT (WINAPI* D3DX11FILTERTEXTURETYPE)(ID3D11DeviceContext*, ID3D11Resource*, UINT, UINT);
typedef HRESULT (WINAPI* D3DX11SAVETEXTURETOFILEATYPE)(ID3D11DeviceContext*, ID3D11Resource*, D3DX11_IMAGE_FILE_FORMAT, LPCSTR);
typedef HRESULT (WINAPI* D3DX11SAVETEXTURETOFILEWTYPE)(ID3D11DeviceContext*, ID3D11Resource*, D3DX11_IMAGE_FILE_FORMAT, LPCWSTR);
extern D3DX11COMPILEFROMMEMORYTYPE PD3DX11CompileFromMemory;
extern D3DX11FILTERTEXTURETYPE PD3DX11FilterTexture;
extern D3DX11SAVETEXTURETOFILEATYPE PD3DX11SaveTextureToFileA;
extern D3DX11SAVETEXTURETOFILEWTYPE PD3DX11SaveTextureToFileW;
#ifdef UNICODE
#define PD3DX11SaveTextureToFile PD3DX11SaveTextureToFileW
#else
#define PD3DX11SaveTextureToFile PD3DX11SaveTextureToFileA
#endif
typedef HRESULT (WINAPI* CREATEDXGIFACTORY)(REFIID, void**);
extern CREATEDXGIFACTORY PCreateDXGIFactory;
typedef HRESULT (WINAPI* D3D11CREATEDEVICE)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext**);
extern D3D11CREATEDEVICE PD3D11CreateDevice;
typedef HRESULT (WINAPI *D3DREFLECT)(LPCVOID, SIZE_T, REFIID, void**);
extern D3DREFLECT PD3DReflect;
} // namespace DX11

View File

@ -0,0 +1,56 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <d3d11.h>
#include "D3DBlob.h"
namespace DX11
{
D3DBlob::D3DBlob(unsigned int blob_size, const u8* init_data) : ref(1), size(blob_size), blob(NULL)
{
data = new u8[blob_size];
if (init_data) memcpy(data, init_data, size);
}
D3DBlob::D3DBlob(ID3D10Blob* d3dblob) : ref(1)
{
blob = d3dblob;
data = (u8*)blob->GetBufferPointer();
size = (unsigned int)blob->GetBufferSize();
d3dblob->AddRef();
}
D3DBlob::~D3DBlob()
{
if (blob) blob->Release();
else delete[] data;
}
void D3DBlob::AddRef()
{
++ref;
}
unsigned int D3DBlob::Release()
{
if (--ref == 0)
{
delete this;
return 0;
}
return ref;
}
unsigned int D3DBlob::Size()
{
return size;
}
u8* D3DBlob::Data()
{
return data;
}
} // namespace DX11

View File

@ -0,0 +1,40 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include "CommonTypes.h"
struct ID3D10Blob;
namespace DX11
{
// use this class instead ID3D10Blob or ID3D11Blob whenever possible
class D3DBlob
{
public:
// memory will be copied into an own buffer
D3DBlob(unsigned int blob_size, const u8* init_data = NULL);
// d3dblob will be AddRef'd
D3DBlob(ID3D10Blob* d3dblob);
void AddRef();
unsigned int Release();
unsigned int Size();
u8* Data();
private:
~D3DBlob();
unsigned int ref;
unsigned int size;
u8* data;
ID3D10Blob* blob;
};
} // namespace

View File

@ -0,0 +1,236 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <string>
#include "VideoConfig.h"
#include "D3DBase.h"
#include "D3DShader.h"
namespace DX11
{
namespace D3D
{
// bytecode->shader
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len)
{
ID3D11VertexShader* v_shader;
HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, NULL, &v_shader);
if (FAILED(hr))
return NULL;
return v_shader;
}
// code->bytecode
bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob)
{
ID3D10Blob* shaderBuffer = NULL;
ID3D10Blob* errorBuffer = NULL;
#if defined(_DEBUG) || defined(DEBUGFAST)
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS;
#else
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_OPTIMIZATION_LEVEL3|D3D10_SHADER_SKIP_VALIDATION;
#endif
HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, NULL, NULL, "main", D3D::VertexShaderVersionString(),
flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL);
if (errorBuffer)
{
INFO_LOG(VIDEO, "Vertex shader compiler messages:\n%s\n",
(const char*)errorBuffer->GetBufferPointer());
}
if (FAILED(hr))
{
static int num_failures = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%sbad_vs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file;
OpenFStream(file, szTemp, std::ios_base::out);
file << code;
file.close();
PanicAlert("Failed to compile vertex shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s",
szTemp,
D3D::VertexShaderVersionString(),
(char*)errorBuffer->GetBufferPointer());
*blob = NULL;
errorBuffer->Release();
}
else
{
*blob = new D3DBlob(shaderBuffer);
shaderBuffer->Release();
}
return SUCCEEDED(hr);
}
// bytecode->shader
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len)
{
ID3D11GeometryShader* g_shader;
HRESULT hr = D3D::device->CreateGeometryShader(bytecode, len, NULL, &g_shader);
if (FAILED(hr))
return NULL;
return g_shader;
}
// code->bytecode
bool CompileGeometryShader(const char* code, unsigned int len, D3DBlob** blob,
const D3D_SHADER_MACRO* pDefines)
{
ID3D10Blob* shaderBuffer = NULL;
ID3D10Blob* errorBuffer = NULL;
#if defined(_DEBUG) || defined(DEBUGFAST)
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS;
#else
UINT flags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY|D3D10_SHADER_OPTIMIZATION_LEVEL3|D3D10_SHADER_SKIP_VALIDATION;
#endif
HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, pDefines, NULL, "main", D3D::GeometryShaderVersionString(),
flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL);
if (errorBuffer)
{
INFO_LOG(VIDEO, "Geometry shader compiler messages:\n%s\n",
(const char*)errorBuffer->GetBufferPointer());
}
if (FAILED(hr))
{
static int num_failures = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%sbad_gs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file;
OpenFStream(file, szTemp, std::ios_base::out);
file << code;
file.close();
PanicAlert("Failed to compile geometry shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s",
szTemp,
D3D::GeometryShaderVersionString(),
(char*)errorBuffer->GetBufferPointer());
*blob = NULL;
errorBuffer->Release();
}
else
{
*blob = new D3DBlob(shaderBuffer);
shaderBuffer->Release();
}
return SUCCEEDED(hr);
}
// bytecode->shader
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len)
{
ID3D11PixelShader* p_shader;
HRESULT hr = D3D::device->CreatePixelShader(bytecode, len, NULL, &p_shader);
if (FAILED(hr))
{
PanicAlert("CreatePixelShaderFromByteCode failed at %s %d\n", __FILE__, __LINE__);
p_shader = NULL;
}
return p_shader;
}
// code->bytecode
bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob,
const D3D_SHADER_MACRO* pDefines)
{
ID3D10Blob* shaderBuffer = NULL;
ID3D10Blob* errorBuffer = NULL;
#if defined(_DEBUG) || defined(DEBUGFAST)
UINT flags = D3D10_SHADER_DEBUG|D3D10_SHADER_WARNINGS_ARE_ERRORS;
#else
UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3;
#endif
HRESULT hr = PD3DX11CompileFromMemory(code, len, NULL, pDefines, NULL, "main", D3D::PixelShaderVersionString(),
flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL);
if (errorBuffer)
{
INFO_LOG(VIDEO, "Pixel shader compiler messages:\n%s",
(const char*)errorBuffer->GetBufferPointer());
}
if (FAILED(hr))
{
static int num_failures = 0;
char szTemp[MAX_PATH];
sprintf(szTemp, "%sbad_ps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
std::ofstream file;
OpenFStream(file, szTemp, std::ios_base::out);
file << code;
file.close();
PanicAlert("Failed to compile pixel shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s",
szTemp,
D3D::PixelShaderVersionString(),
(char*)errorBuffer->GetBufferPointer());
*blob = NULL;
errorBuffer->Release();
}
else
{
*blob = new D3DBlob(shaderBuffer);
shaderBuffer->Release();
}
return SUCCEEDED(hr);
}
ID3D11VertexShader* CompileAndCreateVertexShader(const char* code,
unsigned int len)
{
D3DBlob* blob = NULL;
if (CompileVertexShader(code, len, &blob))
{
ID3D11VertexShader* v_shader = CreateVertexShaderFromByteCode(blob);
blob->Release();
return v_shader;
}
return NULL;
}
ID3D11GeometryShader* CompileAndCreateGeometryShader(const char* code,
unsigned int len, const D3D_SHADER_MACRO* pDefines)
{
D3DBlob* blob = NULL;
if (CompileGeometryShader(code, len, &blob, pDefines))
{
ID3D11GeometryShader* g_shader = CreateGeometryShaderFromByteCode(blob);
blob->Release();
return g_shader;
}
return NULL;
}
ID3D11PixelShader* CompileAndCreatePixelShader(const char* code,
unsigned int len)
{
D3DBlob* blob = NULL;
CompilePixelShader(code, len, &blob);
if (blob)
{
ID3D11PixelShader* p_shader = CreatePixelShaderFromByteCode(blob);
blob->Release();
return p_shader;
}
return NULL;
}
} // namespace
} // namespace DX11

View File

@ -0,0 +1,53 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include "D3DBase.h"
#include "D3DBlob.h"
struct ID3D11PixelShader;
struct ID3D11VertexShader;
namespace DX11
{
namespace D3D
{
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, unsigned int len);
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, unsigned int len);
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, unsigned int len);
// The returned bytecode buffers should be Release()d.
bool CompileVertexShader(const char* code, unsigned int len,
D3DBlob** blob);
bool CompileGeometryShader(const char* code, unsigned int len,
D3DBlob** blob, const D3D_SHADER_MACRO* pDefines = NULL);
bool CompilePixelShader(const char* code, unsigned int len,
D3DBlob** blob, const D3D_SHADER_MACRO* pDefines = NULL);
// Utility functions
ID3D11VertexShader* CompileAndCreateVertexShader(const char* code,
unsigned int len);
ID3D11GeometryShader* CompileAndCreateGeometryShader(const char* code,
unsigned int len, const D3D_SHADER_MACRO* pDefines = NULL);
ID3D11PixelShader* CompileAndCreatePixelShader(const char* code,
unsigned int len);
inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode)
{ return CreateVertexShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
inline ID3D11GeometryShader* CreateGeometryShaderFromByteCode(D3DBlob* bytecode)
{ return CreateGeometryShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
inline ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode)
{ return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size()); }
inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code)
{ return CompileAndCreateVertexShader((const char*)code->Data(), code->Size()); }
inline ID3D11GeometryShader* CompileAndCreateGeometryShader(D3DBlob* code, const D3D_SHADER_MACRO* pDefines = NULL)
{ return CompileAndCreateGeometryShader((const char*)code->Data(), code->Size(), pDefines); }
inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code)
{ return CompileAndCreatePixelShader((const char*)code->Data(), code->Size()); }
}
} // namespace DX11

View File

@ -0,0 +1,107 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "D3DBase.h"
#include "D3DTexture.h"
namespace DX11
{
namespace D3D
{
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage)
{
if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING)
{
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (4 * pitch == map.RowPitch)
{
memcpy(map.pData, buffer, map.RowPitch * height);
}
else
{
for (unsigned int y = 0; y < height; ++y)
memcpy((u8*)map.pData + y * map.RowPitch, (u32*)buffer + y * pitch, 4 * pitch);
}
D3D::context->Unmap(pTexture, level);
}
else
{
D3D11_BOX dest_region = CD3D11_BOX(0, 0, 0, width, height, 1);
D3D::context->UpdateSubresource(pTexture, level, &dest_region, buffer, 4*pitch, 4*pitch*height);
}
}
} // namespace
D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels)
{
ID3D11Texture2D* pTexture = NULL;
HRESULT hr;
D3D11_CPU_ACCESS_FLAG cpuflags;
if (usage == D3D11_USAGE_STAGING) cpuflags = (D3D11_CPU_ACCESS_FLAG)((int)D3D11_CPU_ACCESS_WRITE|(int)D3D11_CPU_ACCESS_READ);
else if (usage == D3D11_USAGE_DYNAMIC) 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, NULL, &pTexture);
if (FAILED(hr))
{
PanicAlert("Failed to create texture at %s, line %d: hr=%#x\n", __FILE__, __LINE__, hr);
return NULL;
}
D3DTexture2D* ret = new D3DTexture2D(pTexture, bind);
SAFE_RELEASE(pTexture);
return ret;
}
void D3DTexture2D::AddRef()
{
++ref;
}
UINT D3DTexture2D::Release()
{
--ref;
if (ref == 0)
{
delete this;
return 0;
}
return ref;
}
ID3D11Texture2D* &D3DTexture2D::GetTex() { return tex; }
ID3D11ShaderResourceView* &D3DTexture2D::GetSRV() { return srv; }
ID3D11RenderTargetView* &D3DTexture2D::GetRTV() { return rtv; }
ID3D11DepthStencilView* &D3DTexture2D::GetDSV() { return dsv; }
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(NULL), rtv(NULL), dsv(NULL)
{
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_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);
if (bind & D3D11_BIND_SHADER_RESOURCE) D3D::device->CreateShaderResourceView(tex, &srv_desc, &srv);
if (bind & D3D11_BIND_RENDER_TARGET) D3D::device->CreateRenderTargetView(tex, &rtv_desc, &rtv);
if (bind & D3D11_BIND_DEPTH_STENCIL) D3D::device->CreateDepthStencilView(tex, &dsv_desc, &dsv);
tex->AddRef();
}
D3DTexture2D::~D3DTexture2D()
{
SAFE_RELEASE(srv);
SAFE_RELEASE(rtv);
SAFE_RELEASE(dsv);
SAFE_RELEASE(tex);
}
} // namespace DX11

View File

@ -0,0 +1,47 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include <d3d11.h>
namespace DX11
{
namespace D3D
{
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage);
}
class D3DTexture2D
{
public:
// there are two ways to create a D3DTexture2D object:
// either create an ID3D11Texture2D object, pass it to the constructor and specify what views to create
// 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);
// reference counting, use AddRef() when creating a new reference and Release() it when you don't need it anymore
void AddRef();
UINT Release();
ID3D11Texture2D* &GetTex();
ID3D11ShaderResourceView* &GetSRV();
ID3D11RenderTargetView* &GetRTV();
ID3D11DepthStencilView* &GetDSV();
private:
~D3DTexture2D();
ID3D11Texture2D* tex;
ID3D11ShaderResourceView* srv;
ID3D11RenderTargetView* rtv;
ID3D11DepthStencilView* dsv;
D3D11_BIND_FLAG bindflags;
UINT ref;
};
} // namespace DX11

View File

@ -0,0 +1,685 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <list>
#include "D3DBase.h"
#include "D3DUtil.h"
#include "PixelShaderCache.h"
#include "VertexShaderCache.h"
#include "D3DShader.h"
#include "GfxState.h"
namespace DX11
{
namespace D3D
{
// Ring buffer class, shared between the draw* functions
class UtilVertexBuffer
{
public:
UtilVertexBuffer(int size) : buf(NULL), offset(0), max_size(size)
{
D3D11_BUFFER_DESC desc = CD3D11_BUFFER_DESC(max_size, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
device->CreateBuffer(&desc, NULL, &buf);
}
~UtilVertexBuffer()
{
buf->Release();
}
// returns vertex offset to the new data
int AppendData(void* data, int size, int vertex_size)
{
D3D11_MAPPED_SUBRESOURCE map;
if(offset + size >= max_size)
{
// wrap buffer around and notify observers
offset = 0;
context->Map(buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
for(std::list<bool*>::iterator it = observers.begin(); it != observers.end(); ++it)
**it = true;
}
else
{
context->Map(buf, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map);
}
offset = ((offset+vertex_size-1)/vertex_size)*vertex_size; // align offset to vertex_size bytes
memcpy((u8*)map.pData + offset, data, size);
context->Unmap(buf, 0);
offset += size;
return (offset - size) / vertex_size;
}
void AddWrapObserver(bool* observer)
{
observers.push_back(observer);
}
inline ID3D11Buffer* &GetBuffer() { return buf; }
private:
ID3D11Buffer* buf;
int offset;
int max_size;
std::list<bool*> observers;
};
CD3DFont font;
UtilVertexBuffer* util_vbuf = NULL;
#define MAX_NUM_VERTICES 50*6
struct FONT2DVERTEX {
float x,y,z;
float col[4];
float tu, tv;
};
inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv)
{
FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.tu = tu; v.tv = tv;
v.col[0] = ((float)((color >> 16) & 0xFF)) / 255.f;
v.col[1] = ((float)((color >> 8) & 0xFF)) / 255.f;
v.col[2] = ((float)((color >> 0) & 0xFF)) / 255.f;
v.col[3] = ((float)((color >> 24) & 0xFF)) / 255.f;
return v;
}
CD3DFont::CD3DFont() : m_dwTexWidth(512), m_dwTexHeight(512)
{
m_pTexture = NULL;
m_pVB = NULL;
m_InputLayout = NULL;
m_pshader = NULL;
m_vshader = NULL;
}
const char fontpixshader[] = {
"Texture2D tex2D;\n"
"SamplerState linearSampler\n"
"{\n"
" Filter = MIN_MAG_MIP_LINEAR;\n"
" AddressU = D3D11_TEXTURE_ADDRESS_BORDER;\n"
" AddressV = D3D11_TEXTURE_ADDRESS_BORDER;\n"
" BorderColor = float4(0.f, 0.f, 0.f, 0.f);\n"
"};\n"
"struct PS_INPUT\n"
"{\n"
" float4 pos : SV_POSITION;\n"
" float4 col : COLOR;\n"
" float2 tex : TEXCOORD;\n"
"};\n"
"float4 main( PS_INPUT input ) : SV_Target\n"
"{\n"
" return tex2D.Sample( linearSampler, input.tex ) * input.col;\n"
"};\n"
};
const char fontvertshader[] = {
"struct VS_INPUT\n"
"{\n"
" float4 pos : POSITION;\n"
" float4 col : COLOR;\n"
" float2 tex : TEXCOORD;\n"
"};\n"
"struct PS_INPUT\n"
"{\n"
" float4 pos : SV_POSITION;\n"
" float4 col : COLOR;\n"
" float2 tex : TEXCOORD;\n"
"};\n"
"PS_INPUT main( VS_INPUT input )\n"
"{\n"
" PS_INPUT output;\n"
" output.pos = input.pos;\n"
" output.col = input.col;\n"
" output.tex = input.tex;\n"
" return output;\n"
"};\n"
};
int CD3DFont::Init()
{
// Create vertex buffer for the letters
HRESULT hr;
// Prepare to create a bitmap
unsigned int* pBitmapBits;
BITMAPINFO bmi;
ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = (int)m_dwTexWidth;
bmi.bmiHeader.biHeight = -(int)m_dwTexHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biBitCount = 32;
// Create a DC and a bitmap for the font
HDC hDC = CreateCompatibleDC(NULL);
HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pBitmapBits, NULL, 0);
SetMapMode(hDC, MM_TEXT);
// create a GDI font
HFONT hFont = CreateFont(24, 0, 0, 0, FW_NORMAL, FALSE,
FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
VARIABLE_PITCH, _T("Tahoma"));
if (NULL == hFont) return E_FAIL;
HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap);
HGDIOBJ hOldFont = SelectObject(hDC, hFont);
// Set text properties
SetTextColor(hDC, 0xFFFFFF);
SetBkColor (hDC, 0);
SetTextAlign(hDC, TA_TOP);
TEXTMETRICW tm;
GetTextMetricsW(hDC, &tm);
m_LineHeight = tm.tmHeight;
// Loop through all printable characters and output them to the bitmap
// Meanwhile, keep track of the corresponding tex coords for each character.
int x = 0, y = 0;
char str[2] = "\0";
for (int c = 0; c < 127 - 32; c++)
{
str[0] = c + 32;
SIZE size;
GetTextExtentPoint32A(hDC, str, 1, &size);
if ((int)(x+size.cx+1) > m_dwTexWidth)
{
x = 0;
y += m_LineHeight;
}
ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, NULL, str, 1, NULL);
m_fTexCoords[c][0] = ((float)(x+0))/m_dwTexWidth;
m_fTexCoords[c][1] = ((float)(y+0))/m_dwTexHeight;
m_fTexCoords[c][2] = ((float)(x+0+size.cx))/m_dwTexWidth;
m_fTexCoords[c][3] = ((float)(y+0+size.cy))/m_dwTexHeight;
x += size.cx + 3; // 3 to work around annoying ij conflict (part of the j ends up with the i)
}
// Create a new texture for the font
// possible optimization: store the converted data in a buffer and fill the texture on creation.
// That way, we can use a static texture
ID3D11Texture2D* buftex;
D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, m_dwTexWidth, m_dwTexHeight,
1, 1, D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DYNAMIC,
D3D11_CPU_ACCESS_WRITE);
hr = device->CreateTexture2D(&texdesc, NULL, &buftex);
if (FAILED(hr))
{
PanicAlert("Failed to create font texture");
return hr;
}
D3D::SetDebugObjectName((ID3D11DeviceChild*)buftex, "texture of a CD3DFont object");
// Lock the surface and write the alpha values for the set pixels
D3D11_MAPPED_SUBRESOURCE texmap;
hr = context->Map(buftex, 0, D3D11_MAP_WRITE_DISCARD, 0, &texmap);
if (FAILED(hr)) PanicAlert("Failed to map a texture at %s %d\n", __FILE__, __LINE__);
for (y = 0; y < m_dwTexHeight; y++)
{
u32* pDst32 = (u32*)((u8*)texmap.pData + y * texmap.RowPitch);
for (x = 0; x < m_dwTexWidth; x++)
{
const u8 bAlpha = (pBitmapBits[m_dwTexWidth * y + x] & 0xff);
*pDst32++ = (((bAlpha << 4) | bAlpha) << 24) | 0xFFFFFF;
}
}
// Done updating texture, so clean up used objects
context->Unmap(buftex, 0);
hr = D3D::device->CreateShaderResourceView(buftex, NULL, &m_pTexture);
if (FAILED(hr)) PanicAlert("Failed to create shader resource view at %s %d\n", __FILE__, __LINE__);
SAFE_RELEASE(buftex);
SelectObject(hDC, hOldbmBitmap);
DeleteObject(hbmBitmap);
SelectObject(hDC, hOldFont);
DeleteObject(hFont);
// setup device objects for drawing
m_pshader = D3D::CompileAndCreatePixelShader(fontpixshader, sizeof(fontpixshader));
if (m_pshader == NULL) PanicAlert("Failed to create pixel shader, %s %d\n", __FILE__, __LINE__);
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pshader, "pixel shader of a CD3DFont object");
D3DBlob* vsbytecode;
D3D::CompileVertexShader(fontvertshader, sizeof(fontvertshader), &vsbytecode);
if (vsbytecode == NULL) PanicAlert("Failed to compile vertex shader, %s %d\n", __FILE__, __LINE__);
m_vshader = D3D::CreateVertexShaderFromByteCode(vsbytecode);
if (m_vshader == NULL) PanicAlert("Failed to create vertex shader, %s %d\n", __FILE__, __LINE__);
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_vshader, "vertex shader of a CD3DFont object");
const D3D11_INPUT_ELEMENT_DESC desc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
hr = D3D::device->CreateInputLayout(desc, 3, vsbytecode->Data(), vsbytecode->Size(), &m_InputLayout);
if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
SAFE_RELEASE(vsbytecode);
D3D11_BLEND_DESC blenddesc;
blenddesc.AlphaToCoverageEnable = FALSE;
blenddesc.IndependentBlendEnable = FALSE;
blenddesc.RenderTarget[0].BlendEnable = TRUE;
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
hr = D3D::device->CreateBlendState(&blenddesc, &m_blendstate);
CHECK(hr==S_OK, "Create font blend state");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_blendstate, "blend state of a CD3DFont object");
D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0.f, false, false, false, false);
hr = D3D::device->CreateRasterizerState(&rastdesc, &m_raststate);
CHECK(hr==S_OK, "Create font rasterizer state");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_raststate, "rasterizer state of a CD3DFont object");
D3D11_BUFFER_DESC vbdesc = CD3D11_BUFFER_DESC(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
if (FAILED(hr = device->CreateBuffer(&vbdesc, NULL, &m_pVB)))
{
PanicAlert("Failed to create font vertex buffer at %s, line %d\n", __FILE__, __LINE__);
return hr;
}
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_pVB, "vertex buffer of a CD3DFont object");
return S_OK;
}
int CD3DFont::Shutdown()
{
SAFE_RELEASE(m_pVB);
SAFE_RELEASE(m_pTexture);
SAFE_RELEASE(m_InputLayout);
SAFE_RELEASE(m_pshader);
SAFE_RELEASE(m_vshader);
SAFE_RELEASE(m_blendstate);
SAFE_RELEASE(m_raststate);
return S_OK;
}
int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dwColor, const char* strText)
{
if (!m_pVB)
return 0;
UINT stride = sizeof(FONT2DVERTEX);
UINT bufoffset = 0;
float scalex = 1 / (float)D3D::GetBackBufferWidth() * 2.f;
float scaley = 1 / (float)D3D::GetBackBufferHeight() * 2.f;
float sizeratio = size / (float)m_LineHeight;
// translate starting positions
float sx = x * scalex - 1.f;
float sy = 1.f - y * scaley;
char c;
// Fill vertex buffer
FONT2DVERTEX* pVertices;
int dwNumTriangles = 0L;
D3D11_MAPPED_SUBRESOURCE vbmap;
HRESULT hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap);
if (FAILED(hr)) PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__);
pVertices = (D3D::FONT2DVERTEX*)vbmap.pData;
// set general pipeline state
D3D::stateman->PushBlendState(m_blendstate);
D3D::stateman->PushRasterizerState(m_raststate);
D3D::stateman->Apply();
D3D::context->PSSetShader(m_pshader, NULL, 0);
D3D::context->VSSetShader(m_vshader, NULL, 0);
D3D::context->IASetInputLayout(m_InputLayout);
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
D3D::context->PSSetShaderResources(0, 1, &m_pTexture);
float fStartX = sx;
while (c = *strText++)
{
if (c == ('\n'))
{
sx = fStartX;
sy -= scaley * size;
}
if (c < (' '))
continue;
c -= 32;
float tx1 = m_fTexCoords[c][0];
float ty1 = m_fTexCoords[c][1];
float tx2 = m_fTexCoords[c][2];
float ty2 = m_fTexCoords[c][3];
float w = (float)(tx2-tx1) * m_dwTexWidth * scalex * sizeratio;
float h = (float)(ty1-ty2) * m_dwTexHeight * scaley * sizeratio;
FONT2DVERTEX v[6];
v[0] = InitFont2DVertex(sx, sy+h, dwColor, tx1, ty2);
v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1);
v[2] = InitFont2DVertex(sx+w, sy+h, dwColor, tx2, ty2);
v[3] = InitFont2DVertex(sx+w, sy, dwColor, tx2, ty1);
v[4] = v[2];
v[5] = v[1];
memcpy(pVertices, v, 6*sizeof(FONT2DVERTEX));
pVertices+=6;
dwNumTriangles += 2;
if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6))
{
context->Unmap(m_pVB, 0);
D3D::context->IASetVertexBuffers(0, 1, &m_pVB, &stride, &bufoffset);
D3D::context->Draw(3 * dwNumTriangles, 0);
dwNumTriangles = 0;
D3D11_MAPPED_SUBRESOURCE vbmap;
hr = context->Map(m_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vbmap);
if (FAILED(hr)) PanicAlert("Mapping vertex buffer failed, %s %d\n", __FILE__, __LINE__);
pVertices = (D3D::FONT2DVERTEX*)vbmap.pData;
}
sx += w + spacing * scalex * size;
}
// Unlock and render the vertex buffer
context->Unmap(m_pVB, 0);
if (dwNumTriangles > 0)
{
D3D::context->IASetVertexBuffers(0, 1, &m_pVB, &stride, &bufoffset);
D3D::context->Draw(3 * dwNumTriangles, 0);
}
D3D::stateman->PopBlendState();
D3D::stateman->PopRasterizerState();
return S_OK;
}
ID3D11SamplerState* linear_copy_sampler = NULL;
ID3D11SamplerState* point_copy_sampler = NULL;
typedef struct { float x,y,z,u,v,w; } STQVertex;
typedef struct { float x,y,z,u,v,w; } STSQVertex;
typedef struct { float x,y,z; u32 col; } ClearVertex;
typedef struct { float x,y,z; u32 col; } ColVertex;
struct
{
float u1, v1, u2, v2, G;
} tex_quad_data;
struct
{
MathUtil::Rectangle<float> rdest;
float u1, v1, u2, v2, G;
} tex_sub_quad_data;
struct
{
float x1, y1, x2, y2;
u32 col;
} draw_quad_data;
struct
{
u32 col;
float z;
} clear_quad_data;
// ring buffer offsets
int stq_offset, stsq_offset, cq_offset, clearq_offset;
// observer variables for ring buffer wraps
bool stq_observer, stsq_observer, cq_observer, clearq_observer;
void InitUtils()
{
util_vbuf = new UtilVertexBuffer(0x4000);
float border[4] = { 0.f, 0.f, 0.f, 0.f };
D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f);
HRESULT hr = D3D::device->CreateSamplerState(&samDesc, &point_copy_sampler);
if (FAILED(hr)) PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__);
else SetDebugObjectName((ID3D11DeviceChild*)point_copy_sampler, "point copy sampler state");
samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f);
hr = D3D::device->CreateSamplerState(&samDesc, &linear_copy_sampler);
if (FAILED(hr)) PanicAlert("Failed to create sampler state at %s %d\n", __FILE__, __LINE__);
else SetDebugObjectName((ID3D11DeviceChild*)linear_copy_sampler, "linear copy sampler state");
// cached data used to avoid unnecessarily reloading the vertex buffers
memset(&tex_quad_data, 0, sizeof(tex_quad_data));
memset(&tex_sub_quad_data, 0, sizeof(tex_sub_quad_data));
memset(&draw_quad_data, 0, sizeof(draw_quad_data));
memset(&clear_quad_data, 0, sizeof(clear_quad_data));
// make sure to properly load the vertex data whenever the corresponding functions get called the first time
stq_observer = stsq_observer = cq_observer = clearq_observer = true;
util_vbuf->AddWrapObserver(&stq_observer);
util_vbuf->AddWrapObserver(&stsq_observer);
util_vbuf->AddWrapObserver(&cq_observer);
util_vbuf->AddWrapObserver(&clearq_observer);
font.Init();
}
void ShutdownUtils()
{
font.Shutdown();
SAFE_RELEASE(point_copy_sampler);
SAFE_RELEASE(linear_copy_sampler);
SAFE_DELETE(util_vbuf);
}
void SetPointCopySampler()
{
D3D::context->PSSetSamplers(0, 1, &point_copy_sampler);
}
void SetLinearCopySampler()
{
D3D::context->PSSetSamplers(0, 1, &linear_copy_sampler);
}
void drawShadedTexQuad(ID3D11ShaderResourceView* texture,
const D3D11_RECT* rSource,
int SourceWidth,
int SourceHeight,
ID3D11PixelShader* PShader,
ID3D11VertexShader* Vshader,
ID3D11InputLayout* layout,
float Gamma)
{
float sw = 1.0f /(float) SourceWidth;
float sh = 1.0f /(float) SourceHeight;
float u1 = ((float)rSource->left) * sw;
float u2 = ((float)rSource->right) * sw;
float v1 = ((float)rSource->top) * sh;
float v2 = ((float)rSource->bottom) * sh;
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},
};
// 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)
{
stq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(STQVertex));
stq_observer = false;
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;
}
UINT stride = sizeof(STQVertex);
UINT offset = 0;
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
D3D::context->IASetInputLayout(layout);
D3D::context->IASetVertexBuffers(0, 1, &util_vbuf->GetBuffer(), &stride, &offset);
D3D::context->PSSetShader(PShader, NULL, 0);
D3D::context->PSSetShaderResources(0, 1, &texture);
D3D::context->VSSetShader(Vshader, NULL, 0);
D3D::stateman->Apply();
D3D::context->Draw(4, stq_offset);
ID3D11ShaderResourceView* texres = NULL;
context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture
}
void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture,
const MathUtil::Rectangle<float>* rSource,
int SourceWidth,
int SourceHeight,
const MathUtil::Rectangle<float>* rDest,
ID3D11PixelShader* PShader,
ID3D11VertexShader* Vshader,
ID3D11InputLayout* layout,
float Gamma)
{
float sw = 1.0f /(float) SourceWidth;
float sh = 1.0f /(float) SourceHeight;
float u1 = (rSource->left ) * sw;
float u2 = (rSource->right ) * sw;
float v1 = (rSource->top ) * sh;
float v2 = (rSource->bottom) * sh;
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},
};
// 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)
{
stsq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(STSQVertex));
stsq_observer = false;
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;
memcpy(&tex_sub_quad_data.rdest, &rDest, sizeof(rDest));
}
UINT stride = sizeof(STSQVertex);
UINT offset = 0;
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
context->IASetVertexBuffers(0, 1, &util_vbuf->GetBuffer(), &stride, &offset);
context->IASetInputLayout(layout);
context->PSSetShaderResources(0, 1, &texture);
context->PSSetShader(PShader, NULL, 0);
context->VSSetShader(Vshader, NULL, 0);
stateman->Apply();
context->Draw(4, stsq_offset);
ID3D11ShaderResourceView* texres = NULL;
context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture
}
// Fills a certain area of the current render target with the specified color
// destination coordinates normalized to (-1;1)
void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2)
{
ColVertex coords[4] = {
{ x1, y2, 0.f, Color },
{ x2, y2, 0.f, Color },
{ x1, y1, 0.f, Color },
{ x2, y1, 0.f, Color },
};
if(cq_observer ||
draw_quad_data.x1 != x1 || draw_quad_data.y1 != y1 ||
draw_quad_data.x2 != x2 || draw_quad_data.y2 != y2 ||
draw_quad_data.col != Color)
{
cq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(ColVertex));
cq_observer = false;
draw_quad_data.x1 = x1;
draw_quad_data.y1 = y1;
draw_quad_data.x2 = x2;
draw_quad_data.y2 = y2;
draw_quad_data.col = Color;
}
context->VSSetShader(VertexShaderCache::GetClearVertexShader(), NULL, 0);
context->PSSetShader(PixelShaderCache::GetClearProgram(), NULL, 0);
context->IASetInputLayout(VertexShaderCache::GetClearInputLayout());
UINT stride = sizeof(ColVertex);
UINT offset = 0;
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
context->IASetVertexBuffers(0, 1, &util_vbuf->GetBuffer(), &stride, &offset);
stateman->Apply();
context->Draw(4, cq_offset);
}
void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout)
{
ClearVertex coords[4] = {
{-1.0f, 1.0f, z, Color},
{ 1.0f, 1.0f, z, Color},
{-1.0f, -1.0f, z, Color},
{ 1.0f, -1.0f, z, Color},
};
if (clearq_observer || clear_quad_data.col != Color || clear_quad_data.z != z)
{
clearq_offset = util_vbuf->AppendData(coords, sizeof(coords), sizeof(ClearVertex));
clearq_observer = false;
clear_quad_data.col = Color;
clear_quad_data.z = z;
}
context->VSSetShader(Vshader, NULL, 0);
context->PSSetShader(PShader, NULL, 0);
context->IASetInputLayout(layout);
UINT stride = sizeof(ClearVertex);
UINT offset = 0;
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
context->IASetVertexBuffers(0, 1, &util_vbuf->GetBuffer(), &stride, &offset);
stateman->Apply();
context->Draw(4, clearq_offset);
}
} // namespace D3D
} // namespace DX11

View File

@ -0,0 +1,77 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include <d3d11.h>
#include <MathUtil.h>
namespace DX11
{
namespace D3D
{
// Font creation flags
#define D3DFONT_BOLD 0x0001
#define D3DFONT_ITALIC 0x0002
// Font rendering flags
#define D3DFONT_CENTERED 0x0001
class CD3DFont
{
ID3D11ShaderResourceView* m_pTexture;
ID3D11Buffer* m_pVB;
ID3D11InputLayout* m_InputLayout;
ID3D11PixelShader* m_pshader;
ID3D11VertexShader* m_vshader;
ID3D11BlendState* m_blendstate;
ID3D11RasterizerState* m_raststate;
const int m_dwTexWidth;
const int m_dwTexHeight;
unsigned int m_LineHeight;
float m_fTexCoords[128-32][4];
public:
CD3DFont();
// 2D text drawing function
// Initializing and destroying device-dependent objects
int Init();
int Shutdown();
int DrawTextScaled(float x, float y,
float size,
float spacing, u32 dwColor,
const char* strText);
};
extern CD3DFont font;
void InitUtils();
void ShutdownUtils();
void SetPointCopySampler();
void SetLinearCopySampler();
void drawShadedTexQuad(ID3D11ShaderResourceView* texture,
const D3D11_RECT* rSource,
int SourceWidth,
int SourceHeight,
ID3D11PixelShader* PShader,
ID3D11VertexShader* VShader,
ID3D11InputLayout* layout,
float Gamma = 1.0f);
void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture,
const MathUtil::Rectangle<float>* rSource,
int SourceWidth,
int SourceHeight,
const MathUtil::Rectangle<float>* rDest,
ID3D11PixelShader* PShader,
ID3D11VertexShader* Vshader,
ID3D11InputLayout* layout,
float Gamma = 1.0f);
void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout);
void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2);
}
}

View File

@ -0,0 +1,218 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "VideoConfig.h"
#include "D3DBase.h"
#include "D3DUtil.h"
#include "FramebufferManager.h"
#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; }
ID3D11Texture2D* &FramebufferManager::GetEFBColorStagingBuffer() { return m_efb.color_staging_buf; }
D3DTexture2D* &FramebufferManager::GetEFBDepthTexture() { return m_efb.depth_tex; }
D3DTexture2D* &FramebufferManager::GetEFBDepthReadTexture() { return m_efb.depth_read_texture; }
ID3D11Texture2D* &FramebufferManager::GetEFBDepthStagingBuffer() { return m_efb.depth_staging_buf; }
D3DTexture2D* &FramebufferManager::GetResolvedEFBColorTexture()
{
if (g_ActiveConfig.iMultisampleMode)
{
D3D::context->ResolveSubresource(m_efb.resolved_color_tex->GetTex(), 0, m_efb.color_tex->GetTex(), 0, DXGI_FORMAT_R8G8B8A8_UNORM);
return m_efb.resolved_color_tex;
}
else
return m_efb.color_tex;
}
D3DTexture2D* &FramebufferManager::GetResolvedEFBDepthTexture()
{
if (g_ActiveConfig.iMultisampleMode)
{
D3D::context->ResolveSubresource(m_efb.resolved_color_tex->GetTex(), 0, m_efb.color_tex->GetTex(), 0, DXGI_FORMAT_R8G8B8A8_UNORM);
return m_efb.resolved_color_tex;
}
else
return m_efb.depth_tex;
}
FramebufferManager::FramebufferManager()
{
unsigned int target_width = Renderer::GetTargetWidth();
unsigned int target_height = Renderer::GetTargetHeight();
DXGI_SAMPLE_DESC sample_desc = D3D::GetAAMode(g_ActiveConfig.iMultisampleMode);
ID3D11Texture2D* buf;
D3D11_TEXTURE2D_DESC texdesc;
HRESULT hr;
// 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);
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &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));
CHECK(m_efb.color_tex!=NULL, "create EFB color texture (size: %dx%d)", target_width, target_height);
SAFE_RELEASE(buf);
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetTex(), "EFB color texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetSRV(), "EFB color texture shader resource view");
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);
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &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));
CHECK(m_efb.color_temp_tex!=NULL, "create EFB color temp texture (size: %dx%d)", target_width, target_height);
SAFE_RELEASE(buf);
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetTex(), "EFB color temp texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_temp_tex->GetSRV(), "EFB color temp texture shader resource view");
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);
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &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);
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &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));
SAFE_RELEASE(buf);
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetTex(), "EFB depth texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_tex->GetDSV(), "EFB depth texture depth stencil view");
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);
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &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);
SAFE_RELEASE(buf);
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.depth_read_texture->GetTex(), "EFB depth read texture (used in Renderer::AccessEFB)");
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);
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &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)");
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);
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &buf);
m_efb.resolved_color_tex = new D3DTexture2D(buf, D3D11_BIND_SHADER_RESOURCE, DXGI_FORMAT_R8G8B8A8_UNORM);
CHECK(m_efb.resolved_color_tex!=NULL, "create EFB color resolve texture (size: %dx%d)", target_width, target_height);
SAFE_RELEASE(buf);
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);
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &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);
SAFE_RELEASE(buf);
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_depth_tex->GetTex(), "EFB depth resolve texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.resolved_depth_tex->GetSRV(), "EFB depth resolve texture shader resource view");
}
else
{
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);
SAFE_RELEASE(m_efb.resolved_color_tex);
SAFE_RELEASE(m_efb.depth_tex);
SAFE_RELEASE(m_efb.depth_staging_buf);
SAFE_RELEASE(m_efb.depth_read_texture);
SAFE_RELEASE(m_efb.resolved_depth_tex);
}
void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma)
{
u8* dst = Memory::GetPointer(xfbAddr);
s_xfbEncoder.Encode(dst, fbWidth, fbHeight, sourceRc, Gamma);
}
XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height)
{
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));
}
void FramebufferManager::GetTargetSize(unsigned int *width, unsigned int *height, const EFBRectangle& sourceRc)
{
TargetRectangle targetSource;
targetSource.top = ScaleToVirtualXfbHeight(sourceRc.top, Renderer::GetBackbufferHeight());
targetSource.bottom = ScaleToVirtualXfbHeight(sourceRc.bottom, Renderer::GetBackbufferHeight());
targetSource.left = ScaleToVirtualXfbWidth(sourceRc.left, Renderer::GetBackbufferWidth());
targetSource.right = ScaleToVirtualXfbWidth(sourceRc.right, Renderer::GetBackbufferWidth());
*width = targetSource.right - targetSource.left;
*height = targetSource.bottom - targetSource.top;
}
void XFBSource::Draw(const MathUtil::Rectangle<float> &sourcerc,
const MathUtil::Rectangle<float> &drawrc, int width, int height) 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.
// YUYV data is decoded in Render::Swap.
}
void XFBSource::CopyEFB(float Gamma)
{
g_renderer->ResetAPIState(); // reset any game specific settings
// Copy EFB data to XFB and restore render target again
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)texWidth, (float)texHeight);
D3D::context->RSSetViewports(1, &vp);
D3D::context->OMSetRenderTargets(1, &tex->GetRTV(), NULL);
D3D::SetLinearCopySampler();
D3D::drawShadedTexQuad(FramebufferManager::GetEFBColorTexture()->GetSRV(), sourceRc.AsRECT(),
Renderer::GetTargetWidth(), Renderer::GetTargetHeight(),
PixelShaderCache::GetColorCopyProgram(true), VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(),Gamma);
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
g_renderer->RestoreAPIState();
}
} // namespace DX11

View File

@ -0,0 +1,109 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _FBMANAGER_D3D_H_
#define _FBMANAGER_D3D_H_
#include "d3d11.h"
#include "FramebufferManagerBase.h"
#include "D3DTexture.h"
namespace DX11 {
// On the GameCube, the game sends a request for the graphics processor to
// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM
// called the XFB (External Framebuffer). The size and location of the XFB is
// decided at the time of the copy, and the format is always YUYV. The video
// interface is given a pointer to the XFB, which will be decoded and
// displayed on the TV.
//
// There are two ways for Dolphin to emulate this:
//
// Real XFB mode:
//
// Dolphin will behave like the GameCube and encode the EFB to
// a portion of GameCube RAM. The emulated video interface will decode the data
// for output to the screen.
//
// Advantages: Behaves exactly like the GameCube.
// Disadvantages: Resolution will be limited.
//
// Virtual XFB mode:
//
// When a request is made to copy the EFB to an XFB, Dolphin
// will remember the RAM location and size of the XFB in a Virtual XFB list.
// The video interface will look up the XFB in the list and use the enhanced
// data stored there, if available.
//
// Advantages: Enables high resolution graphics, better than real hardware.
// Disadvantages: If the GameCube CPU writes directly to the XFB (which is
// possible but uncommon), the Virtual XFB will not capture this information.
// There may be multiple XFBs in GameCube RAM. This is the maximum number to
// virtualize.
struct XFBSource : public XFBSourceBase
{
XFBSource(D3DTexture2D *_tex) : tex(_tex) {}
~XFBSource() { tex->Release(); }
void Draw(const MathUtil::Rectangle<float> &sourcerc,
const MathUtil::Rectangle<float> &drawrc, int width, int height) const;
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
void CopyEFB(float Gamma);
D3DTexture2D* const tex;
};
class FramebufferManager : public FramebufferManagerBase
{
public:
FramebufferManager();
~FramebufferManager();
static D3DTexture2D* &GetEFBColorTexture();
static ID3D11Texture2D* &GetEFBColorStagingBuffer();
static D3DTexture2D* &GetEFBDepthTexture();
static D3DTexture2D* &GetEFBDepthReadTexture();
static ID3D11Texture2D* &GetEFBDepthStagingBuffer();
static D3DTexture2D* &GetResolvedEFBColorTexture();
static D3DTexture2D* &GetResolvedEFBDepthTexture();
static D3DTexture2D* &GetEFBColorTempTexture() { return m_efb.color_temp_tex; }
static void SwapReinterpretTexture()
{
D3DTexture2D* swaptex = GetEFBColorTempTexture();
m_efb.color_temp_tex = GetEFBColorTexture();
m_efb.color_tex = swaptex;
}
private:
XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height);
void GetTargetSize(unsigned int *width, unsigned int *height, const EFBRectangle& sourceRc);
void CopyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma);
static struct Efb
{
D3DTexture2D* color_tex;
ID3D11Texture2D* color_staging_buf;
D3DTexture2D* depth_tex;
ID3D11Texture2D* depth_staging_buf;
D3DTexture2D* depth_read_texture;
D3DTexture2D* color_temp_tex;
D3DTexture2D* resolved_color_tex;
D3DTexture2D* resolved_depth_tex;
} m_efb;
};
} // namespace DX11
#endif

View File

@ -0,0 +1,80 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "Log.h"
#include "D3DBase.h"
#include "GfxState.h"
namespace DX11
{
namespace D3D
{
StateManager* stateman;
template<typename T> AutoState<T>::AutoState(const T* object) : state(object)
{
((IUnknown*)state)->AddRef();
}
template<typename T> AutoState<T>::AutoState(const AutoState<T> &source)
{
state = source.GetPtr();
((T*)state)->AddRef();
}
template<typename T> AutoState<T>::~AutoState()
{
if(state) ((T*)state)->Release();
state = NULL;
}
StateManager::StateManager() : cur_blendstate(NULL), cur_depthstate(NULL), cur_raststate(NULL) {}
void StateManager::PushBlendState(const ID3D11BlendState* state) { blendstates.push(AutoBlendState(state)); }
void StateManager::PushDepthState(const ID3D11DepthStencilState* state) { depthstates.push(AutoDepthStencilState(state)); }
void StateManager::PushRasterizerState(const ID3D11RasterizerState* state) { raststates.push(AutoRasterizerState(state)); }
void StateManager::PopBlendState() { blendstates.pop(); }
void StateManager::PopDepthState() { depthstates.pop(); }
void StateManager::PopRasterizerState() { raststates.pop(); }
void StateManager::Apply()
{
if (!blendstates.empty())
{
if (cur_blendstate != blendstates.top().GetPtr())
{
cur_blendstate = (ID3D11BlendState*)blendstates.top().GetPtr();
D3D::context->OMSetBlendState(cur_blendstate, NULL, 0xFFFFFFFF);
}
}
else ERROR_LOG(VIDEO, "Tried to apply without blend state!");
if (!depthstates.empty())
{
if (cur_depthstate != depthstates.top().GetPtr())
{
cur_depthstate = (ID3D11DepthStencilState*)depthstates.top().GetPtr();
D3D::context->OMSetDepthStencilState(cur_depthstate, 0);
}
}
else ERROR_LOG(VIDEO, "Tried to apply without depth state!");
if (!raststates.empty())
{
if (cur_raststate != raststates.top().GetPtr())
{
cur_raststate = (ID3D11RasterizerState*)raststates.top().GetPtr();
D3D::context->RSSetState(cur_raststate);
}
}
else ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!");
}
} // namespace
} // namespace DX11

View File

@ -0,0 +1,67 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include <stack>
struct ID3D11BlendState;
struct ID3D11DepthStencilState;
struct ID3D11RasterizerState;
namespace DX11
{
namespace D3D
{
template<typename T> class AutoState
{
public:
AutoState(const T* object);
AutoState(const AutoState<T> &source);
~AutoState();
const inline T* GetPtr() const { return state; }
private:
const T* state;
};
typedef AutoState<ID3D11BlendState> AutoBlendState;
typedef AutoState<ID3D11DepthStencilState> AutoDepthStencilState;
typedef AutoState<ID3D11RasterizerState> AutoRasterizerState;
class StateManager
{
public:
StateManager();
// call any of these to change the affected states
void PushBlendState(const ID3D11BlendState* state);
void PushDepthState(const ID3D11DepthStencilState* state);
void PushRasterizerState(const ID3D11RasterizerState* state);
// call these after drawing
void PopBlendState();
void PopDepthState();
void PopRasterizerState();
// call this before any drawing operation if states could have changed meanwhile
void Apply();
private:
std::stack<AutoBlendState> blendstates;
std::stack<AutoDepthStencilState> depthstates;
std::stack<AutoRasterizerState> raststates;
ID3D11BlendState* cur_blendstate;
ID3D11DepthStencilState* cur_depthstate;
ID3D11RasterizerState* cur_raststate;
};
extern StateManager* stateman;
} // namespace
} // namespace DX11

View File

@ -0,0 +1,14 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _GLOBALS_H_
#define _GLOBALS_H_
#include "Common.h"
#include "VideoConfig.h"
#include "main.h"
#include "VideoCommon.h"
#endif // _GLOBALS_H_

View File

@ -0,0 +1,238 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "LineGeometryShader.h"
#include <sstream>
#include "D3DBase.h"
#include "D3DShader.h"
#include "VertexShaderGen.h"
namespace DX11
{
struct LineGSParams
{
FLOAT LineWidth; // In units of 1/6 of an EFB pixel
FLOAT TexOffset;
FLOAT VpWidth; // Width and height of the viewport in EFB pixels
FLOAT VpHeight;
FLOAT TexOffsetEnable[8]; // For each tex coordinate, whether to apply offset to it (1 on, 0 off)
};
union LineGSParams_Padded
{
LineGSParams params;
// Constant buffers must be a multiple of 16 bytes in size.
u8 pad[(sizeof(LineGSParams) + 15) & ~15];
};
static const char LINE_GS_COMMON[] =
// The struct VS_OUTPUT used by the vertex shader goes here.
"// dolphin-emu line geometry shader common part\n"
"cbuffer cbParams : register(b0)\n"
"{\n"
"struct\n" // Should match LineGSParams above
"{\n"
"float LineWidth;\n"
"float TexOffset;\n"
"float VpWidth;\n"
"float VpHeight;\n"
"float TexOffsetEnable[8];\n"
"} Params;\n"
"}\n"
"[maxvertexcount(4)]\n"
"void main(line VS_OUTPUT input[2], inout TriangleStream<VS_OUTPUT> outStream)\n"
"{\n"
// Pretend input[0] is on the bottom and input[1] is on top.
// We generate vertices to the left and right.
"VS_OUTPUT l0 = input[0];\n"
"VS_OUTPUT r0 = l0;\n"
"VS_OUTPUT l1 = input[1];\n"
"VS_OUTPUT r1 = l1;\n"
// GameCube/Wii's line drawing algorithm is a little quirky. It does not
// use the correct line caps. Instead, the line caps are vertical or
// horizontal depending the slope of the line.
"float2 offset;\n"
"float2 to = abs(input[1].pos.xy - input[0].pos.xy);\n"
// FIXME: What does real hardware do when line is at a 45-degree angle?
// FIXME: Lines aren't drawn at the correct width. See Twilight Princess map.
"if (Params.VpHeight*to.y > Params.VpWidth*to.x) {\n"
// Line is more tall. Extend geometry left and right.
// Lerp Params.LineWidth/2 from [0..VpWidth] to [-1..1]
"offset = float2(Params.LineWidth/Params.VpWidth, 0);\n"
"} else {\n"
// Line is more wide. Extend geometry up and down.
// Lerp Params.LineWidth/2 from [0..VpHeight] to [1..-1]
"offset = float2(0, -Params.LineWidth/Params.VpHeight);\n"
"}\n"
"l0.pos.xy -= offset * input[0].pos.w;\n"
"r0.pos.xy += offset * input[0].pos.w;\n"
"l1.pos.xy -= offset * input[1].pos.w;\n"
"r1.pos.xy += offset * input[1].pos.w;\n"
"#ifndef NUM_TEXCOORDS\n"
"#error NUM_TEXCOORDS not defined\n"
"#endif\n"
// Apply TexOffset to all tex coordinates in the vertex.
// They can each be enabled seperately.
"#if NUM_TEXCOORDS >= 1\n"
"r0.tex0.x += Params.TexOffset * Params.TexOffsetEnable[0];\n"
"r1.tex0.x += Params.TexOffset * Params.TexOffsetEnable[0];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 2\n"
"r0.tex1.x += Params.TexOffset * Params.TexOffsetEnable[1];\n"
"r1.tex1.x += Params.TexOffset * Params.TexOffsetEnable[1];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 3\n"
"r0.tex2.x += Params.TexOffset * Params.TexOffsetEnable[2];\n"
"r1.tex2.x += Params.TexOffset * Params.TexOffsetEnable[2];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 4\n"
"r0.tex3.x += Params.TexOffset * Params.TexOffsetEnable[3];\n"
"r1.tex3.x += Params.TexOffset * Params.TexOffsetEnable[3];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 5\n"
"r0.tex4.x += Params.TexOffset * Params.TexOffsetEnable[4];\n"
"r1.tex4.x += Params.TexOffset * Params.TexOffsetEnable[4];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 6\n"
"r0.tex5.x += Params.TexOffset * Params.TexOffsetEnable[5];\n"
"r1.tex5.x += Params.TexOffset * Params.TexOffsetEnable[5];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 7\n"
"r0.tex6.x += Params.TexOffset * Params.TexOffsetEnable[6];\n"
"r1.tex6.x += Params.TexOffset * Params.TexOffsetEnable[6];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 8\n"
"r0.tex7.x += Params.TexOffset * Params.TexOffsetEnable[7];\n"
"r1.tex7.x += Params.TexOffset * Params.TexOffsetEnable[7];\n"
"#endif\n"
"outStream.Append(l0);\n"
"outStream.Append(r0);\n"
"outStream.Append(l1);\n"
"outStream.Append(r1);\n"
"}\n"
;
LineGeometryShader::LineGeometryShader()
: m_ready(false), m_paramsBuffer(NULL)
{ }
void LineGeometryShader::Init()
{
m_ready = false;
HRESULT hr;
// Create constant buffer for uploading data to geometry shader
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(LineGSParams_Padded),
D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
hr = D3D::device->CreateBuffer(&bd, NULL, &m_paramsBuffer);
CHECK(SUCCEEDED(hr), "create line geometry shader params buffer");
D3D::SetDebugObjectName(m_paramsBuffer, "line geometry shader params buffer");
m_ready = true;
}
void LineGeometryShader::Shutdown()
{
m_ready = false;
for (ComboMap::iterator it = m_shaders.begin(); it != m_shaders.end(); ++it)
{
SAFE_RELEASE(it->second);
}
m_shaders.clear();
SAFE_RELEASE(m_paramsBuffer);
}
bool LineGeometryShader::SetShader(u32 components, float lineWidth,
float texOffset, float vpWidth, float vpHeight, const bool* texOffsetEnable)
{
if (!m_ready)
return false;
// Make sure geometry shader for "components" is available
ComboMap::iterator shaderIt = m_shaders.find(components);
if (shaderIt == m_shaders.end())
{
// Generate new shader. Warning: not thread-safe.
static char buffer[16384];
ShaderCode code;
code.SetBuffer(buffer);
GenerateVSOutputStructForGS(code, components, API_D3D);
code.Write("\n%s", LINE_GS_COMMON);
std::stringstream numTexCoordsStream;
numTexCoordsStream << xfregs.numTexGen.numTexGens;
INFO_LOG(VIDEO, "Compiling line geometry shader for components 0x%.08X (num texcoords %d)",
components, xfregs.numTexGen.numTexGens);
const std::string& numTexCoordsStr = numTexCoordsStream.str();
D3D_SHADER_MACRO macros[] = {
{ "NUM_TEXCOORDS", numTexCoordsStr.c_str() },
{ NULL, NULL }
};
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code.GetBuffer(), unsigned int(strlen(code.GetBuffer())), macros);
if (!newShader)
{
WARN_LOG(VIDEO, "Line geometry shader for components 0x%.08X failed to compile", components);
// Add dummy shader to prevent trying to compile again
m_shaders[components] = NULL;
return false;
}
shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first;
}
if (shaderIt != m_shaders.end())
{
if (shaderIt->second)
{
D3D11_MAPPED_SUBRESOURCE map;
HRESULT hr = D3D::context->Map(m_paramsBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (SUCCEEDED(hr))
{
LineGSParams* params = (LineGSParams*)map.pData;
params->LineWidth = lineWidth;
params->TexOffset = texOffset;
params->VpWidth = vpWidth;
params->VpHeight = vpHeight;
for (int i = 0; i < 8; ++i)
params->TexOffsetEnable[i] = texOffsetEnable[i] ? 1.f : 0.f;
D3D::context->Unmap(m_paramsBuffer, 0);
}
else
ERROR_LOG(VIDEO, "Failed to map line gs params buffer");
DEBUG_LOG(VIDEO, "Line params: width %f, texOffset %f, vpWidth %f, vpHeight %f",
lineWidth, texOffset, vpWidth, vpHeight);
D3D::context->GSSetShader(shaderIt->second, NULL, 0);
D3D::context->GSSetConstantBuffers(0, 1, &m_paramsBuffer);
return true;
}
else
return false;
}
else
return false;
}
}

View File

@ -0,0 +1,45 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _LINEGEOMETRYSHADER_H
#define _LINEGEOMETRYSHADER_H
#include "VideoCommon.h"
struct ID3D11Buffer;
struct ID3D11GeometryShader;
namespace DX11
{
// This class manages a collection of line geometry shaders, one for each
// vertex format.
class LineGeometryShader
{
public:
LineGeometryShader();
void Init();
void Shutdown();
// Returns true on success, false on failure
bool SetShader(u32 components, float lineWidth, float texOffset,
float vpWidth, float vpHeight, const bool* texOffsetEnable);
private:
bool m_ready;
ID3D11Buffer* m_paramsBuffer;
typedef std::map<u32, ID3D11GeometryShader*> ComboMap;
ComboMap m_shaders;
};
}
#endif

View File

@ -0,0 +1,143 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "D3DBase.h"
#include "D3DBlob.h"
#include "NativeVertexFormat.h"
#include "VertexManager.h"
#include "VertexShaderCache.h"
namespace DX11
{
class D3DVertexFormat : public NativeVertexFormat
{
D3D11_INPUT_ELEMENT_DESC m_elems[32];
UINT m_num_elems;
DX11::D3DBlob* m_vs_bytecode;
ID3D11InputLayout* m_layout;
public:
D3DVertexFormat() : m_num_elems(0), m_vs_bytecode(NULL), m_layout(NULL) {}
~D3DVertexFormat() { SAFE_RELEASE(m_vs_bytecode); SAFE_RELEASE(m_layout); }
void Initialize(const PortableVertexDeclaration &_vtx_decl);
void SetupVertexPointers();
};
NativeVertexFormat* VertexManager::CreateNativeVertexFormat()
{
return new D3DVertexFormat();
}
DXGI_FORMAT VarToD3D(VarType t, int size)
{
DXGI_FORMAT retval = DXGI_FORMAT_UNKNOWN;
static const DXGI_FORMAT lookup1[5] = {
DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R32_FLOAT
};
static const DXGI_FORMAT lookup2[5] = {
DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R32G32_FLOAT
};
static const DXGI_FORMAT lookup3[5] = {
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32_FLOAT
};
static const DXGI_FORMAT lookup4[5] = {
DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R32G32B32A32_FLOAT
};
switch (size)
{
case 1: retval = lookup1[t]; break;
case 2: retval = lookup2[t]; break;
case 3: retval = lookup3[t]; break;
case 4: retval = lookup4[t]; break;
default: break;
}
if (retval == DXGI_FORMAT_UNKNOWN)
{
PanicAlert("VarToD3D: Invalid type/size combo %i , %i", (int)t, size);
}
return retval;
}
void D3DVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
{
vertex_stride = _vtx_decl.stride;
memset(m_elems, 0, sizeof(m_elems));
m_elems[m_num_elems].SemanticName = "POSITION";
m_elems[m_num_elems].AlignedByteOffset = 0;
m_elems[m_num_elems].Format = DXGI_FORMAT_R32G32B32_FLOAT;
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
for (int i = 0; i < 3; i++)
{
if (_vtx_decl.normal_offset[i] > 0)
{
m_elems[m_num_elems].SemanticName = "NORMAL";
m_elems[m_num_elems].SemanticIndex = i;
m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.normal_offset[i];
m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.normal_gl_type, _vtx_decl.normal_gl_size);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
}
for (int i = 0; i < 2; i++)
{
if (_vtx_decl.color_offset[i] > 0)
{
m_elems[m_num_elems].SemanticName = "COLOR";
m_elems[m_num_elems].SemanticIndex = i;
m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.color_offset[i];
m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.color_gl_type, 4);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
}
for (int i = 0; i < 8; i++)
{
if (_vtx_decl.texcoord_offset[i] > 0)
{
m_elems[m_num_elems].SemanticName = "TEXCOORD";
m_elems[m_num_elems].SemanticIndex = i;
m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.texcoord_offset[i];
m_elems[m_num_elems].Format = VarToD3D(_vtx_decl.texcoord_gl_type[i], _vtx_decl.texcoord_size[i]);
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
}
if (_vtx_decl.posmtx_offset != -1)
{
m_elems[m_num_elems].SemanticName = "BLENDINDICES";
m_elems[m_num_elems].AlignedByteOffset = _vtx_decl.posmtx_offset;
m_elems[m_num_elems].Format = DXGI_FORMAT_R8G8B8A8_UNORM;
m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
++m_num_elems;
}
}
void D3DVertexFormat::SetupVertexPointers()
{
if (m_vs_bytecode != DX11::VertexShaderCache::GetActiveShaderBytecode())
{
SAFE_RELEASE(m_vs_bytecode);
SAFE_RELEASE(m_layout);
m_vs_bytecode = DX11::VertexShaderCache::GetActiveShaderBytecode();
m_vs_bytecode->AddRef();
HRESULT hr = DX11::D3D::device->CreateInputLayout(m_elems, m_num_elems, m_vs_bytecode->Data(), m_vs_bytecode->Size(), &m_layout);
if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
DX11::D3D::SetDebugObjectName((ID3D11DeviceChild*)m_layout, "input layout used to emulate the GX pipeline");
}
DX11::D3D::context->IASetInputLayout(m_layout);
}
} // namespace DX11

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,106 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _PSTEXTUREENCODER_H
#define _PSTEXTUREENCODER_H
#include "TextureEncoder.h"
struct ID3D11Texture2D;
struct ID3D11RenderTargetView;
struct ID3D11Buffer;
struct ID3D11InputLayout;
struct ID3D11VertexShader;
struct ID3D11PixelShader;
struct ID3D11ClassLinkage;
struct ID3D11ClassInstance;
struct ID3D11BlendState;
struct ID3D11DepthStencilState;
struct ID3D11RasterizerState;
struct ID3D11SamplerState;
namespace DX11
{
class PSTextureEncoder : public TextureEncoder
{
public:
PSTextureEncoder();
void Init();
void Shutdown();
size_t Encode(u8* dst, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect, bool isIntensity,
bool scaleByHalf);
private:
bool m_ready;
ID3D11Texture2D* m_out;
ID3D11RenderTargetView* m_outRTV;
ID3D11Texture2D* m_outStage;
ID3D11Buffer* m_encodeParams;
ID3D11Buffer* m_quad;
ID3D11VertexShader* m_vShader;
ID3D11InputLayout* m_quadLayout;
ID3D11BlendState* m_efbEncodeBlendState;
ID3D11DepthStencilState* m_efbEncodeDepthState;
ID3D11RasterizerState* m_efbEncodeRastState;
ID3D11SamplerState* m_efbSampler;
// Stuff only used in static-linking mode (SM4.0-compatible)
bool InitStaticMode();
bool SetStaticShader(unsigned int dstFormat, unsigned int srcFormat,
bool isIntensity, bool scaleByHalf);
typedef unsigned int ComboKey; // Key for a shader combination
ComboKey MakeComboKey(unsigned int dstFormat, unsigned int srcFormat,
bool isIntensity, bool scaleByHalf)
{
return (dstFormat << 4) | (srcFormat << 2) | (isIntensity ? (1<<1) : 0)
| (scaleByHalf ? (1<<0) : 0);
}
typedef std::map<ComboKey, ID3D11PixelShader*> ComboMap;
ComboMap m_staticShaders;
// Stuff only used for dynamic-linking mode (SM5.0+, available as soon as
// Microsoft fixes their bloody HLSL compiler)
bool InitDynamicMode();
bool SetDynamicShader(unsigned int dstFormat, unsigned int srcFormat,
bool isIntensity, bool scaleByHalf);
ID3D11PixelShader* m_dynamicShader;
ID3D11ClassLinkage* m_classLinkage;
// Interface slots
UINT m_fetchSlot;
UINT m_scaledFetchSlot;
UINT m_intensitySlot;
UINT m_generatorSlot;
// Class instances
// Fetch: 0 is RGB, 1 is RGBA, 2 is RGB565, 3 is Z
ID3D11ClassInstance* m_fetchClass[4];
// ScaledFetch: 0 is off, 1 is on
ID3D11ClassInstance* m_scaledFetchClass[2];
// Intensity: 0 is off, 1 is on
ID3D11ClassInstance* m_intensityClass[2];
// Generator: one for each dst format, 16 total
ID3D11ClassInstance* m_generatorClass[16];
std::vector<ID3D11ClassInstance*> m_linkageArray;
};
}
#endif

View File

@ -0,0 +1,171 @@
#include "RenderBase.h"
#include "D3DBase.h"
#include "PerfQuery.h"
namespace DX11 {
PerfQuery::PerfQuery()
: m_query_read_pos()
, m_query_count()
{
for (int i = 0; i != ArraySize(m_query_buffer); ++i)
{
D3D11_QUERY_DESC qdesc = CD3D11_QUERY_DESC(D3D11_QUERY_OCCLUSION, 0);
D3D::device->CreateQuery(&qdesc, &m_query_buffer[i].query);
}
ResetQuery();
}
PerfQuery::~PerfQuery()
{
for (int i = 0; i != ArraySize(m_query_buffer); ++i)
{
// TODO: EndQuery?
m_query_buffer[i].query->Release();
}
}
void PerfQuery::EnableQuery(PerfQueryGroup type)
{
if (!ShouldEmulate())
return;
// Is this sane?
if (m_query_count > ArraySize(m_query_buffer) / 2)
WeakFlush();
if (ArraySize(m_query_buffer) == m_query_count)
{
// TODO
FlushOne();
ERROR_LOG(VIDEO, "Flushed query buffer early!");
}
// start query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % ArraySize(m_query_buffer)];
D3D::context->Begin(entry.query);
entry.query_type = type;
++m_query_count;
}
}
void PerfQuery::DisableQuery(PerfQueryGroup type)
{
if (!ShouldEmulate())
return;
// stop query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count + ArraySize(m_query_buffer)-1) % ArraySize(m_query_buffer)];
D3D::context->End(entry.query);
}
}
void PerfQuery::ResetQuery()
{
m_query_count = 0;
std::fill_n(m_results, ArraySize(m_results), 0);
}
u32 PerfQuery::GetQueryResult(PerfQueryType type)
{
if (!ShouldEmulate())
return 0;
u32 result = 0;
if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
{
result = m_results[PQG_ZCOMP_ZCOMPLOC];
}
else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
{
result = m_results[PQG_ZCOMP];
}
else if (type == PQ_BLEND_INPUT)
{
result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC];
}
else if (type == PQ_EFB_COPY_CLOCKS)
{
result = m_results[PQG_EFB_COPY_CLOCKS];
}
return result / 4;
}
void PerfQuery::FlushOne()
{
if (!ShouldEmulate())
return;
auto& entry = m_query_buffer[m_query_read_pos];
UINT64 result = 0;
HRESULT hr = S_FALSE;
while (hr != S_OK)
{
// TODO: Might cause us to be stuck in an infinite loop!
hr = D3D::context->GetData(entry.query, &result, sizeof(result), 0);
}
// NOTE: Reported pixel metrics should be referenced to native resolution
m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight();
m_query_read_pos = (m_query_read_pos + 1) % ArraySize(m_query_buffer);
--m_query_count;
}
// TODO: could selectively flush things, but I don't think that will do much
void PerfQuery::FlushResults()
{
if (!ShouldEmulate())
return;
while (!IsFlushed())
FlushOne();
}
void PerfQuery::WeakFlush()
{
if (!ShouldEmulate())
return;
while (!IsFlushed())
{
auto& entry = m_query_buffer[m_query_read_pos];
UINT64 result = 0;
HRESULT hr = D3D::context->GetData(entry.query, &result, sizeof(result), D3D11_ASYNC_GETDATA_DONOTFLUSH);
if (hr == S_OK)
{
// NOTE: Reported pixel metrics should be referenced to native resolution
m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight();
m_query_read_pos = (m_query_read_pos + 1) % ArraySize(m_query_buffer);
--m_query_count;
}
else
{
break;
}
}
}
bool PerfQuery::IsFlushed() const
{
if (!ShouldEmulate())
return true;
return 0 == m_query_count;
}
} // namespace

View File

@ -0,0 +1,46 @@
#ifndef _PERFQUERY_H_
#define _PERFQUERY_H_
#include "PerfQueryBase.h"
namespace DX11 {
class PerfQuery : public PerfQueryBase
{
public:
PerfQuery();
~PerfQuery();
void EnableQuery(PerfQueryGroup type);
void DisableQuery(PerfQueryGroup type);
void ResetQuery();
u32 GetQueryResult(PerfQueryType type);
void FlushResults();
bool IsFlushed() const;
private:
struct ActiveQuery
{
ID3D11Query* query;
PerfQueryGroup query_type;
};
void WeakFlush();
// Only use when non-empty
void FlushOne();
// when testing in SMS: 64 was too small, 128 was ok
static const int PERF_QUERY_BUFFER_SIZE = 512;
ActiveQuery m_query_buffer[PERF_QUERY_BUFFER_SIZE];
int m_query_read_pos;
// TODO: sloppy
volatile int m_query_count;
volatile u32 m_results[PQG_NUM_MEMBERS];
};
} // namespace
#endif // _PERFQUERY_H_

View File

@ -0,0 +1,585 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "FileUtil.h"
#include "LinearDiskCache.h"
#include "Debugger.h"
#include "Statistics.h"
#include "VideoConfig.h"
#include "D3DBase.h"
#include "D3DShader.h"
#include "Globals.h"
#include "PixelShaderGen.h"
#include "PixelShaderCache.h"
#include "ConfigManager.h"
extern int frameCount;
// See comment near the bottom of this file.
float psconstants[C_PENVCONST_END*4];
bool pscbufchanged = true;
namespace DX11
{
PixelShaderCache::PSCache PixelShaderCache::PixelShaders;
const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry;
PixelShaderUid PixelShaderCache::last_uid;
UidChecker<PixelShaderUid,PixelShaderCode> PixelShaderCache::pixel_uid_checker;
LinearDiskCache<PixelShaderUid, u8> g_ps_disk_cache;
ID3D11PixelShader* s_ColorMatrixProgram[2] = {NULL};
ID3D11PixelShader* s_ColorCopyProgram[2] = {NULL};
ID3D11PixelShader* s_DepthMatrixProgram[2] = {NULL};
ID3D11PixelShader* s_ClearProgram = NULL;
ID3D11PixelShader* s_rgba6_to_rgb8[2] = {NULL};
ID3D11PixelShader* s_rgb8_to_rgba6[2] = {NULL};
ID3D11Buffer* pscbuf = NULL;
const char clear_program_code[] = {
"void main(\n"
"out float4 ocol0 : SV_Target,\n"
"in float4 pos : SV_Position,\n"
"in float4 incol0 : COLOR0){\n"
"ocol0 = incol0;\n"
"}\n"
};
// 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"
"void main(\n"
"out float4 ocol0 : SV_Target,\n"
"in float4 pos : SV_Position,\n"
"in float2 uv0 : TEXCOORD0){\n"
"ocol0 = Tex0.Sample(samp0,uv0);\n"
"}\n"
};
// TODO: Improve sampling algorithm!
const char color_copy_program_code_msaa[] = {
"sampler samp0 : register(s0);\n"
"Texture2DMS<float4, %d> 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"
"ocol0 = 0;\n"
"for(int i = 0; i < samples; ++i)\n"
" ocol0 += Tex0.Load(int2(uv0.x*(width), uv0.y*(height)), i);\n"
"ocol0 /= samples;\n"
"}\n"
};
const char color_matrix_program_code[] = {
"sampler samp0 : register(s0);\n"
"Texture2D 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"
"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"
"}\n"
};
const char color_matrix_program_code_msaa[] = {
"sampler samp0 : register(s0);\n"
"Texture2DMS<float4, %d> 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"
"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 /= 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"
"}\n"
};
const char depth_matrix_program[] = {
"sampler samp0 : register(s0);\n"
"Texture2D 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"
"float4 texcol = Tex0.Sample(samp0,uv0);\n"
"float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,256.0f,256.0f*256.0f,1.0f));\n"
"texcol = round(EncodedDepth * (16777216.0f/16777215.0f) * float4(255.0f,255.0f,255.0f,15.0f)) / float4(255.0f,255.0f,255.0f,15.0f);\n"
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
"}\n"
};
const char depth_matrix_program_msaa[] = {
"sampler samp0 : register(s0);\n"
"Texture2DMS<float4, %d> 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"
"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 /= samples;\n"
"float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,256.0f,256.0f*256.0f,16.0f));\n"
"texcol = round(EncodedDepth * (16777216.0f/16777215.0f) * float4(255.0f,255.0f,255.0f,15.0f)) / float4(255.0f,255.0f,255.0f,15.0f);\n"
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
"}\n"
};
const char reint_rgba6_to_rgb8[] = {
"sampler samp0 : register(s0);\n"
"Texture2D Tex0 : register(t0);\n"
"void main(\n"
" out float4 ocol0 : SV_Target,\n"
" in float4 pos : SV_Position,\n"
" in float2 uv0 : TEXCOORD0)\n"
"{\n"
" int4 src6 = round(Tex0.Sample(samp0,uv0) * 63.f);\n"
" int4 dst8;\n"
" dst8.r = (src6.r << 2) | (src6.g >> 4);\n"
" dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n"
" dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n"
" dst8.a = 255;\n"
" ocol0 = (float4)dst8 / 255.f;\n"
"}"
};
const char reint_rgba6_to_rgb8_msaa[] = {
"sampler samp0 : register(s0);\n"
"Texture2DMS<float4, %d> Tex0 : register(t0);\n"
"void main(\n"
" out float4 ocol0 : SV_Target,\n"
" in float4 pos : SV_Position,\n"
" in float2 uv0 : TEXCOORD0)\n"
"{\n"
" int width, height, samples;\n"
" Tex0.GetDimensions(width, height, 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 /= samples;\n"
" int4 src6 = round(texcol * 63.f);\n"
" int4 dst8;\n"
" dst8.r = (src6.r << 2) | (src6.g >> 4);\n"
" dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n"
" dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n"
" dst8.a = 255;\n"
" ocol0 = (float4)dst8 / 255.f;\n"
"}"
};
const char reint_rgb8_to_rgba6[] = {
"sampler samp0 : register(s0);\n"
"Texture2D Tex0 : register(t0);\n"
"void main(\n"
" out float4 ocol0 : SV_Target,\n"
" in float4 pos : SV_Position,\n"
" in float2 uv0 : TEXCOORD0)\n"
"{\n"
" int4 src8 = round(Tex0.Sample(samp0,uv0) * 255.f);\n"
" int4 dst6;\n"
" dst6.r = src8.r >> 2;\n"
" dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n"
" dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n"
" dst6.a = src8.b & 0x3F;\n"
" ocol0 = (float4)dst6 / 63.f;\n"
"}\n"
};
const char reint_rgb8_to_rgba6_msaa[] = {
"sampler samp0 : register(s0);\n"
"Texture2DMS<float4, %d> Tex0 : register(t0);\n"
"void main(\n"
" out float4 ocol0 : SV_Target,\n"
" in float4 pos : SV_Position,\n"
" in float2 uv0 : TEXCOORD0)\n"
"{\n"
" int width, height, samples;\n"
" Tex0.GetDimensions(width, height, 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 /= samples;\n"
" int4 src8 = round(texcol * 255.f);\n"
" int4 dst6;\n"
" dst6.r = src8.r >> 2;\n"
" dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n"
" dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n"
" dst6.a = src8.b & 0x3F;\n"
" ocol0 = (float4)dst6 / 63.f;\n"
"}\n"
};
ID3D11PixelShader* PixelShaderCache::ReinterpRGBA6ToRGB8(bool multisampled)
{
if (!multisampled || D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count == 1)
{
if (!s_rgba6_to_rgb8[0])
{
s_rgba6_to_rgb8[0] = D3D::CompileAndCreatePixelShader(reint_rgba6_to_rgb8, sizeof(reint_rgba6_to_rgb8));
CHECK(s_rgba6_to_rgb8[0], "Create RGBA6 to RGB8 pixel shader");
D3D::SetDebugObjectName(s_rgba6_to_rgb8[0], "RGBA6 to RGB8 pixel shader");
}
return s_rgba6_to_rgb8[0];
}
else if (!s_rgba6_to_rgb8[1])
{
// create MSAA shader for current AA mode
char buf[1024];
const int l = sprintf_s(buf, 1024, reint_rgba6_to_rgb8_msaa, D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count);
s_rgba6_to_rgb8[1] = D3D::CompileAndCreatePixelShader(buf, l);
CHECK(s_rgba6_to_rgb8[1], "Create RGBA6 to RGB8 MSAA pixel shader");
D3D::SetDebugObjectName(s_rgba6_to_rgb8[1], "RGBA6 to RGB8 MSAA pixel shader");
}
return s_rgba6_to_rgb8[1];
}
ID3D11PixelShader* PixelShaderCache::ReinterpRGB8ToRGBA6(bool multisampled)
{
if (!multisampled || D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count == 1)
{
if (!s_rgb8_to_rgba6[0])
{
s_rgb8_to_rgba6[0] = D3D::CompileAndCreatePixelShader(reint_rgb8_to_rgba6, sizeof(reint_rgb8_to_rgba6));
CHECK(s_rgb8_to_rgba6[0], "Create RGB8 to RGBA6 pixel shader");
D3D::SetDebugObjectName(s_rgb8_to_rgba6[0], "RGB8 to RGBA6 pixel shader");
}
return s_rgb8_to_rgba6[0];
}
else if (!s_rgb8_to_rgba6[1])
{
// create MSAA shader for current AA mode
char buf[1024];
const int l = sprintf_s(buf, 1024, reint_rgb8_to_rgba6_msaa, D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count);
s_rgb8_to_rgba6[1] = D3D::CompileAndCreatePixelShader(buf, l);
CHECK(s_rgb8_to_rgba6[1], "Create RGB8 to RGBA6 MSAA pixel shader");
D3D::SetDebugObjectName(s_rgb8_to_rgba6[1], "RGB8 to RGBA6 MSAA pixel shader");
}
return s_rgb8_to_rgba6[1];
}
ID3D11PixelShader* PixelShaderCache::GetColorCopyProgram(bool multisampled)
{
if (!multisampled || D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count == 1) return s_ColorCopyProgram[0];
else if (s_ColorCopyProgram[1]) return s_ColorCopyProgram[1];
else
{
// create MSAA shader for current AA mode
char buf[1024];
int l = sprintf_s(buf, 1024, color_copy_program_code_msaa, D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count);
s_ColorCopyProgram[1] = D3D::CompileAndCreatePixelShader(buf, l);
CHECK(s_ColorCopyProgram[1]!=NULL, "Create color copy MSAA pixel shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorCopyProgram[1], "color copy MSAA pixel shader");
return s_ColorCopyProgram[1];
}
}
ID3D11PixelShader* PixelShaderCache::GetColorMatrixProgram(bool multisampled)
{
if (!multisampled || D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count == 1) return s_ColorMatrixProgram[0];
else if (s_ColorMatrixProgram[1]) return s_ColorMatrixProgram[1];
else
{
// create MSAA shader for current AA mode
char buf[1024];
int l = sprintf_s(buf, 1024, color_matrix_program_code_msaa, D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count);
s_ColorMatrixProgram[1] = D3D::CompileAndCreatePixelShader(buf, l);
CHECK(s_ColorMatrixProgram[1]!=NULL, "Create color matrix MSAA pixel shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorMatrixProgram[1], "color matrix MSAA pixel shader");
return s_ColorMatrixProgram[1];
}
}
ID3D11PixelShader* PixelShaderCache::GetDepthMatrixProgram(bool multisampled)
{
if (!multisampled || D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count == 1) return s_DepthMatrixProgram[0];
else if (s_DepthMatrixProgram[1]) return s_DepthMatrixProgram[1];
else
{
// create MSAA shader for current AA mode
char buf[1024];
int l = sprintf_s(buf, 1024, depth_matrix_program_msaa, D3D::GetAAMode(g_ActiveConfig.iMultisampleMode).Count);
s_DepthMatrixProgram[1] = D3D::CompileAndCreatePixelShader(buf, l);
CHECK(s_DepthMatrixProgram[1]!=NULL, "Create depth matrix MSAA pixel shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_DepthMatrixProgram[1], "depth matrix MSAA pixel shader");
return s_DepthMatrixProgram[1];
}
}
ID3D11PixelShader* PixelShaderCache::GetClearProgram()
{
return s_ClearProgram;
}
ID3D11Buffer* &PixelShaderCache::GetConstantBuffer()
{
// TODO: divide the global variables of the generated shaders into about 5 constant buffers to speed this up
if (pscbufchanged)
{
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(pscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, psconstants, sizeof(psconstants));
D3D::context->Unmap(pscbuf, 0);
pscbufchanged = false;
ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(psconstants));
}
return pscbuf;
}
// this class will load the precompiled shaders into our cache
class PixelShaderCacheInserter : public LinearDiskCacheReader<PixelShaderUid, u8>
{
public:
void Read(const PixelShaderUid &key, const u8 *value, u32 value_size)
{
PixelShaderCache::InsertByteCode(key, value, value_size);
}
};
void PixelShaderCache::Init()
{
unsigned int cbsize = ((sizeof(psconstants))&(~0xf))+0x10; // must be a multiple of 16
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
D3D::device->CreateBuffer(&cbdesc, NULL, &pscbuf);
CHECK(pscbuf!=NULL, "Create pixel shader constant buffer");
D3D::SetDebugObjectName((ID3D11DeviceChild*)pscbuf, "pixel shader constant buffer used to emulate the GX pipeline");
// used when drawing clear quads
s_ClearProgram = D3D::CompileAndCreatePixelShader(clear_program_code, sizeof(clear_program_code));
CHECK(s_ClearProgram!=NULL, "Create clear pixel shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "clear pixel shader");
// used when copying/resolving the color buffer
s_ColorCopyProgram[0] = D3D::CompileAndCreatePixelShader(color_copy_program_code, sizeof(color_copy_program_code));
CHECK(s_ColorCopyProgram[0]!=NULL, "Create color copy pixel shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorCopyProgram[0], "color copy pixel shader");
// used for color conversion
s_ColorMatrixProgram[0] = D3D::CompileAndCreatePixelShader(color_matrix_program_code, sizeof(color_matrix_program_code));
CHECK(s_ColorMatrixProgram[0]!=NULL, "Create color matrix pixel shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ColorMatrixProgram[0], "color matrix pixel shader");
// used for depth copy
s_DepthMatrixProgram[0] = D3D::CompileAndCreatePixelShader(depth_matrix_program, sizeof(depth_matrix_program));
CHECK(s_DepthMatrixProgram[0]!=NULL, "Create depth matrix pixel shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_DepthMatrixProgram[0], "depth matrix pixel shader");
Clear();
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str());
SETSTAT(stats.numPixelShadersCreated, 0);
SETSTAT(stats.numPixelShadersAlive, 0);
char cache_filename[MAX_PATH];
sprintf(cache_filename, "%sdx11-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
PixelShaderCacheInserter inserter;
g_ps_disk_cache.OpenAndRead(cache_filename, inserter);
if (g_Config.bEnableShaderDebugging)
Clear();
last_entry = NULL;
}
// ONLY to be used during shutdown.
void PixelShaderCache::Clear()
{
for (PSCache::iterator iter = PixelShaders.begin(); iter != PixelShaders.end(); iter++)
iter->second.Destroy();
PixelShaders.clear();
pixel_uid_checker.Invalidate();
last_entry = NULL;
}
// Used in Swap() when AA mode has changed
void PixelShaderCache::InvalidateMSAAShaders()
{
SAFE_RELEASE(s_ColorCopyProgram[1]);
SAFE_RELEASE(s_ColorMatrixProgram[1]);
SAFE_RELEASE(s_DepthMatrixProgram[1]);
SAFE_RELEASE(s_rgb8_to_rgba6[1]);
SAFE_RELEASE(s_rgba6_to_rgb8[1]);
}
void PixelShaderCache::Shutdown()
{
SAFE_RELEASE(pscbuf);
SAFE_RELEASE(s_ClearProgram);
for (int i = 0; i < 2; ++i)
{
SAFE_RELEASE(s_ColorCopyProgram[i]);
SAFE_RELEASE(s_ColorMatrixProgram[i]);
SAFE_RELEASE(s_DepthMatrixProgram[i]);
SAFE_RELEASE(s_rgba6_to_rgb8[i]);
SAFE_RELEASE(s_rgb8_to_rgba6[i]);
}
Clear();
g_ps_disk_cache.Sync();
g_ps_disk_cache.Close();
}
bool PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components)
{
PixelShaderUid uid;
GetPixelShaderUid(uid, dstAlphaMode, API_D3D, components);
if (g_ActiveConfig.bEnableShaderDebugging)
{
PixelShaderCode code;
GeneratePixelShaderCode(code, dstAlphaMode, API_D3D, components);
pixel_uid_checker.AddToIndexAndCheck(code, uid, "Pixel", "p");
}
// 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 != NULL);
}
}
last_uid = uid;
// Check if the shader is already in the cache
PSCache::iterator iter;
iter = PixelShaders.find(uid);
if (iter != PixelShaders.end())
{
const PSCacheEntry &entry = iter->second;
last_entry = &entry;
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true);
return (entry.shader != NULL);
}
// Need to compile a new shader
PixelShaderCode code;
GeneratePixelShaderCode(code, dstAlphaMode, API_D3D, components);
D3DBlob* pbytecode;
if (!D3D::CompilePixelShader(code.GetBuffer(), (unsigned int)strlen(code.GetBuffer()), &pbytecode))
{
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
return false;
}
// Insert the bytecode into the caches
g_ps_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size());
bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size());
pbytecode->Release();
if (g_ActiveConfig.bEnableShaderDebugging && success)
{
PixelShaders[uid].code = code.GetBuffer();
}
GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true);
return success;
}
bool PixelShaderCache::InsertByteCode(const PixelShaderUid &uid, const void* bytecode, unsigned int bytecodelen)
{
ID3D11PixelShader* shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen);
if (shader == NULL)
return false;
// TODO: Somehow make the debug name a bit more specific
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a pixel shader of PixelShaderCache");
// Make an entry in the table
PSCacheEntry newentry;
newentry.shader = shader;
PixelShaders[uid] = newentry;
last_entry = &PixelShaders[uid];
if (!shader) {
// INCSTAT(stats.numPixelShadersFailed);
return false;
}
INCSTAT(stats.numPixelShadersCreated);
SETSTAT(stats.numPixelShadersAlive, PixelShaders.size());
return true;
}
// These are "callbacks" from VideoCommon and thus must be outside namespace DX11.
// This will have to be changed when we merge.
// HACK to avoid some invasive VideoCommon changes
// these values are hardcoded, they depend on internal D3DCompile behavior; TODO: Solve this with D3DReflect or something
// offset given in floats, table index is float4
static const unsigned int ps_constant_offset_table[] = {
0, 4, 8, 12, // C_COLORS, 16
16, 20, 24, 28, // C_KCOLORS, 16
32, // C_ALPHA, 4
36, 40, 44, 48, 52, 56, 60, 64, // C_TEXDIMS, 32
68, 72, // C_ZBIAS, 8
76, 80, // C_INDTEXSCALE, 8
84, 88, 92, 96, 100, 104, // C_INDTEXMTX, 24
108, 112, 116, // C_FOG, 12
120, 124, 128, 132, 136, // C_PLIGHTS0, 20
140, 144, 148, 152, 156, // C_PLIGHTS1, 20
160, 164, 168, 172, 176, // C_PLIGHTS2, 20
180, 184, 188, 192, 196, // C_PLIGHTS3, 20
200, 204, 208, 212, 216, // C_PLIGHTS4, 20
220, 224, 228, 232, 236, // C_PLIGHTS5, 20
240, 244, 248, 252, 256, // C_PLIGHTS6, 20
260, 264, 268, 272, 276, // C_PLIGHTS7, 20
280, 284, 288, 292 // C_PMATERIALS, 16
};
void Renderer::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
{
psconstants[ps_constant_offset_table[const_number] ] = f1;
psconstants[ps_constant_offset_table[const_number]+1] = f2;
psconstants[ps_constant_offset_table[const_number]+2] = f3;
psconstants[ps_constant_offset_table[const_number]+3] = f4;
pscbufchanged = true;
}
void Renderer::SetPSConstant4fv(unsigned int const_number, const float* f)
{
memcpy(&psconstants[ps_constant_offset_table[const_number]], f, sizeof(float)*4);
pscbufchanged = true;
}
void Renderer::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float* f)
{
memcpy(&psconstants[ps_constant_offset_table[const_number]], f, sizeof(float)*4*count);
pscbufchanged = true;
}
} // DX11

View File

@ -0,0 +1,59 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include "PixelShaderGen.h"
#include <d3d11.h>
#include <map>
enum DSTALPHA_MODE;
namespace DX11
{
class PixelShaderCache
{
public:
static void Init();
static void Clear();
static void Shutdown();
static bool SetShader(DSTALPHA_MODE dstAlphaMode, u32 components); // TODO: Should be renamed to LoadShader
static bool InsertByteCode(const PixelShaderUid &uid, const void* bytecode, unsigned int bytecodelen);
static ID3D11PixelShader* GetActiveShader() { return last_entry->shader; }
static ID3D11Buffer* &GetConstantBuffer();
static ID3D11PixelShader* GetColorMatrixProgram(bool multisampled);
static ID3D11PixelShader* GetColorCopyProgram(bool multisampled);
static ID3D11PixelShader* GetDepthMatrixProgram(bool multisampled);
static ID3D11PixelShader* GetClearProgram();
static ID3D11PixelShader* ReinterpRGBA6ToRGB8(bool multisampled);
static ID3D11PixelShader* ReinterpRGB8ToRGBA6(bool multisampled);
static void InvalidateMSAAShaders();
private:
struct PSCacheEntry
{
ID3D11PixelShader* shader;
std::string code;
PSCacheEntry() : shader(NULL) {}
void Destroy() { SAFE_RELEASE(shader); }
};
typedef std::map<PixelShaderUid, PSCacheEntry> PSCache;
static PSCache PixelShaders;
static const PSCacheEntry* last_entry;
static PixelShaderUid last_uid;
static UidChecker<PixelShaderUid,PixelShaderCode> pixel_uid_checker;
};
} // namespace DX11

View File

@ -0,0 +1,232 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "PointGeometryShader.h"
#include <sstream>
#include "D3DBase.h"
#include "D3DShader.h"
#include "VertexShaderGen.h"
namespace DX11
{
struct PointGSParams
{
FLOAT PointSize; // In units of 1/6 of an EFB pixel
FLOAT TexOffset;
FLOAT VpWidth; // Width and height of viewport in EFB pixels
FLOAT VpHeight;
FLOAT TexOffsetEnable[8]; // For each tex coordinate, whether to apply offset to it (1 on, 0 off)
};
union PointGSParams_Padded
{
PointGSParams params;
// Constant buffers must be a multiple of 16 bytes in size.
u8 pad[(sizeof(PointGSParams) + 15) & ~15];
};
static const char POINT_GS_COMMON[] =
// The struct VS_OUTPUT used by the vertex shader goes here.
"// dolphin-emu point geometry shader common part\n"
"cbuffer cbParams : register(b0)\n"
"{\n"
"struct\n" // Should match PointGSParams above
"{\n"
"float PointSize;\n"
"float TexOffset;\n"
"float VpWidth;\n"
"float VpHeight;\n"
"float TexOffsetEnable[8];\n"
"} Params;\n"
"}\n"
"[maxvertexcount(4)]\n"
"void main(point VS_OUTPUT input[1], inout TriangleStream<VS_OUTPUT> outStream)\n"
"{\n"
"VS_OUTPUT ptLL = input[0];\n"
"VS_OUTPUT ptLR = ptLL;\n"
"VS_OUTPUT ptUL = ptLL;\n"
"VS_OUTPUT ptUR = ptLL;\n"
// Offset from center to upper right vertex
// Lerp Params.PointSize/2 from [0,0..VpWidth,VpHeight] to [-1,1..1,-1]
"float2 offset = float2(Params.PointSize/Params.VpWidth, -Params.PointSize/Params.VpHeight) * input[0].pos.w;\n"
"ptLL.pos.xy += float2(-1,-1) * offset;\n"
"ptLR.pos.xy += float2(1,-1) * offset;\n"
"ptUL.pos.xy += float2(-1,1) * offset;\n"
"ptUR.pos.xy += offset;\n"
"float2 texOffset = float2(Params.TexOffset, Params.TexOffset);\n"
"#ifndef NUM_TEXCOORDS\n"
"#error NUM_TEXCOORDS not defined\n"
"#endif\n"
// Apply TexOffset to all tex coordinates in the vertex
// FIXME: The game may be able to enable TexOffset for some coords and
// disable for others, but where is that information stored?
"#if NUM_TEXCOORDS >= 1\n"
"ptLL.tex0.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[0];\n"
"ptLR.tex0.xy += texOffset * Params.TexOffsetEnable[0];\n"
"ptUR.tex0.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[0];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 2\n"
"ptLL.tex1.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[1];\n"
"ptLR.tex1.xy += texOffset * Params.TexOffsetEnable[1];\n"
"ptUR.tex1.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[1];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 3\n"
"ptLL.tex2.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[2];\n"
"ptLR.tex2.xy += texOffset * Params.TexOffsetEnable[2];\n"
"ptUR.tex2.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[2];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 4\n"
"ptLL.tex3.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[3];\n"
"ptLR.tex3.xy += texOffset * Params.TexOffsetEnable[3];\n"
"ptUR.tex3.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[3];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 5\n"
"ptLL.tex4.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[4];\n"
"ptLR.tex4.xy += texOffset * Params.TexOffsetEnable[4];\n"
"ptUR.tex4.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[4];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 6\n"
"ptLL.tex5.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[5];\n"
"ptLR.tex5.xy += texOffset * Params.TexOffsetEnable[5];\n"
"ptUR.tex5.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[5];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 7\n"
"ptLL.tex6.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[6];\n"
"ptLR.tex6.xy += texOffset * Params.TexOffsetEnable[6];\n"
"ptUR.tex6.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[6];\n"
"#endif\n"
"#if NUM_TEXCOORDS >= 8\n"
"ptLL.tex7.xy += float2(0,1) * texOffset * Params.TexOffsetEnable[7];\n"
"ptLR.tex7.xy += texOffset * Params.TexOffsetEnable[7];\n"
"ptUR.tex7.xy += float2(1,0) * texOffset * Params.TexOffsetEnable[7];\n"
"#endif\n"
"outStream.Append(ptLL);\n"
"outStream.Append(ptLR);\n"
"outStream.Append(ptUL);\n"
"outStream.Append(ptUR);\n"
"}\n"
;
PointGeometryShader::PointGeometryShader()
: m_ready(false), m_paramsBuffer(NULL)
{ }
void PointGeometryShader::Init()
{
m_ready = false;
HRESULT hr;
// Create constant buffer for uploading data to geometry shader
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(PointGSParams_Padded),
D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
hr = D3D::device->CreateBuffer(&bd, NULL, &m_paramsBuffer);
CHECK(SUCCEEDED(hr), "create point geometry shader params buffer");
D3D::SetDebugObjectName(m_paramsBuffer, "point geometry shader params buffer");
m_ready = true;
}
void PointGeometryShader::Shutdown()
{
m_ready = false;
for (ComboMap::iterator it = m_shaders.begin(); it != m_shaders.end(); ++it)
{
SAFE_RELEASE(it->second);
}
m_shaders.clear();
SAFE_RELEASE(m_paramsBuffer);
}
bool PointGeometryShader::SetShader(u32 components, float pointSize,
float texOffset, float vpWidth, float vpHeight, const bool* texOffsetEnable)
{
if (!m_ready)
return false;
// Make sure geometry shader for "components" is available
ComboMap::iterator shaderIt = m_shaders.find(components);
if (shaderIt == m_shaders.end())
{
// Generate new shader. Warning: not thread-safe.
static char buffer[16384];
ShaderCode code;
code.SetBuffer(buffer);
GenerateVSOutputStructForGS(code, components, API_D3D);
code.Write("\n%s", POINT_GS_COMMON);
std::stringstream numTexCoordsStream;
numTexCoordsStream << xfregs.numTexGen.numTexGens;
INFO_LOG(VIDEO, "Compiling point geometry shader for components 0x%.08X (num texcoords %d)",
components, xfregs.numTexGen.numTexGens);
const std::string& numTexCoordsStr = numTexCoordsStream.str();
D3D_SHADER_MACRO macros[] = {
{ "NUM_TEXCOORDS", numTexCoordsStr.c_str() },
{ NULL, NULL }
};
ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code.GetBuffer(), unsigned int(strlen(code.GetBuffer())), macros);
if (!newShader)
{
WARN_LOG(VIDEO, "Point geometry shader for components 0x%.08X failed to compile", components);
// Add dummy shader to prevent trying to compile again
m_shaders[components] = NULL;
return false;
}
shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first;
}
if (shaderIt != m_shaders.end())
{
if (shaderIt->second)
{
D3D11_MAPPED_SUBRESOURCE map;
HRESULT hr = D3D::context->Map(m_paramsBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
if (SUCCEEDED(hr))
{
PointGSParams* params = (PointGSParams*)map.pData;
params->PointSize = pointSize;
params->TexOffset = texOffset;
params->VpWidth = vpWidth;
params->VpHeight = vpHeight;
for (int i = 0; i < 8; ++i)
params->TexOffsetEnable[i] = texOffsetEnable[i] ? 1.f : 0.f;
D3D::context->Unmap(m_paramsBuffer, 0);
}
else
ERROR_LOG(VIDEO, "Failed to map point gs params buffer");
DEBUG_LOG(VIDEO, "Point params: size %f, texOffset %f, vpWidth %f, vpHeight %f",
pointSize, texOffset, vpWidth, vpHeight);
D3D::context->GSSetShader(shaderIt->second, NULL, 0);
D3D::context->GSSetConstantBuffers(0, 1, &m_paramsBuffer);
return true;
}
else
return false;
}
else
return false;
}
}

View File

@ -0,0 +1,45 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _POINTGEOMETRYSHADER_H
#define _POINTGEOMETRYSHADER_H
#include "VideoCommon.h"
struct ID3D11Buffer;
struct ID3D11GeometryShader;
namespace DX11
{
// This class manages a collection of point geometry shaders, one for each
// vertex format.
class PointGeometryShader
{
public:
PointGeometryShader();
void Init();
void Shutdown();
// Returns true on success, false on failure
bool SetShader(u32 components, float pointSize, float texOffset,
float vpWidth, float vpHeight, const bool* texOffsetEnable);
private:
bool m_ready;
ID3D11Buffer* m_paramsBuffer;
typedef std::map<u32, ID3D11GeometryShader*> ComboMap;
ComboMap m_shaders;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
#ifndef _RENDER_H_
#define _RENDER_H_
#include "RenderBase.h"
namespace DX11
{
class Renderer : public ::Renderer
{
public:
Renderer();
~Renderer();
void SetColorMask();
void SetBlendMode(bool forceUpdate);
void SetScissorRect(const TargetRectangle& rc);
void SetGenerationMode();
void SetDepthMode();
void SetLogicOpMode();
void SetDitherMode();
void SetLineWidth();
void SetSamplerState(int stage,int texindex);
void SetInterlacingMode();
// TODO: Fix confusing names (see ResetAPIState and RestoreAPIState)
void ApplyState(bool bUseDstAlpha);
void RestoreState();
void ApplyCullDisable();
void RestoreCull();
void RenderText(const char* pstr, int left, int top, u32 color);
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data);
void ResetAPIState();
void RestoreAPIState();
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc);
void Swap(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& rc,float Gamma);
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
void ReinterpretPixelData(unsigned int convtype);
void UpdateViewport(Matrix44& vpCorrection);
bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc);
static bool CheckForResize();
void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
void SetPSConstant4fv(unsigned int const_number, const float *f);
void SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float *f);
void SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4);
void SetVSConstant4fv(unsigned int const_number, const float *f);
void SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float *f);
void SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float *f);
};
}
#endif

View File

@ -0,0 +1,172 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "Television.h"
#include "VideoConfig.h"
#include "D3DBase.h"
#include "D3DShader.h"
#include "D3DUtil.h"
#include "VertexShaderCache.h"
#include "HW/Memmap.h"
#include <vector>
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
// Initialize the texture with YCbCr black
//
// Some games use narrower XFB widths (Nintendo titles are fond of 608),
// so the sampler's BorderColor won't cover the right side
// (see sampler state below)
const unsigned int MAX_XFB_SIZE = 2*(MAX_XFB_WIDTH) * MAX_XFB_HEIGHT;
std::vector<u8> fill(MAX_XFB_SIZE);
for (size_t i = 0; i < MAX_XFB_SIZE / sizeof(u32); ++i)
reinterpret_cast<u32*>(fill.data())[i] = 0x80108010;
D3D11_SUBRESOURCE_DATA srd = { fill.data(), 2*(MAX_XFB_WIDTH), 0 };
// 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, &srd, &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");
// Create sampler state and set border color
//
// The default sampler border color of { 0.f, 0.f, 0.f, 0.f }
// creates a green border around the image - see issue 6483
// (remember, the XFB is being interpreted as YUYV, and 0,0,0,0
// is actually two green pixels in YUYV - black should be 16,128,16,128,
// but we reverse the order to match DXGI_FORMAT_G8R8_G8B8_UNORM's ordering)
float border[4] = { 128.0f/255.0f, 16.0f/255.0f, 128.0f/255.0f, 16.0f/255.0f };
D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR,
D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER,
0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f);
hr = D3D::device->CreateSamplerState(&samDesc, &m_samplerState);
CHECK(SUCCEEDED(hr), "create yuyv decoder sampler state");
D3D::SetDebugObjectName(m_samplerState, "yuyv decoder sampler state");
}
void Television::Shutdown()
{
SAFE_RELEASE(m_pShader);
SAFE_RELEASE(m_yuyvTextureSRV);
SAFE_RELEASE(m_yuyvTexture);
SAFE_RELEASE(m_samplerState);
}
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::context->PSSetSamplers(0, 1, &m_samplerState);
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.
}
}
}

View File

@ -0,0 +1,54 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _TELEVISION_H
#define _TELEVISION_H
#include "VideoCommon.h"
struct ID3D11Texture2D;
struct ID3D11ShaderResourceView;
struct ID3D11PixelShader;
struct ID3D11SamplerState;
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;
ID3D11SamplerState* m_samplerState;
};
}
#endif

View File

@ -0,0 +1,186 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "RenderBase.h"
#include "D3DBase.h"
#include "D3DUtil.h"
#include "FramebufferManager.h"
#include "PixelShaderCache.h"
#include "TextureCache.h"
#include "VertexShaderCache.h"
#include "TextureEncoder.h"
#include "PSTextureEncoder.h"
#include "HW/Memmap.h"
#include "VideoConfig.h"
namespace DX11
{
static TextureEncoder* g_encoder = NULL;
const size_t MAX_COPY_BUFFERS = 25;
ID3D11Buffer* efbcopycbuf[MAX_COPY_BUFFERS] = { 0 };
TextureCache::TCacheEntry::~TCacheEntry()
{
texture->Release();
}
void TextureCache::TCacheEntry::Bind(unsigned int stage)
{
D3D::context->PSSetShaderResources(stage, 1, &texture->GetSRV());
}
bool TextureCache::TCacheEntry::Save(const char filename[], unsigned int level)
{
// TODO: Somehow implement this (D3DX11 doesn't support dumping individual LODs)
static bool warn_once = true;
if (level && warn_once)
{
WARN_LOG(VIDEO, "Dumping individual LOD not supported by D3D11 backend!");
warn_once = false;
return false;
}
return SUCCEEDED(PD3DX11SaveTextureToFileA(D3D::context, texture->GetTex(), D3DX11_IFF_PNG, filename));
}
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level)
{
D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, expanded_width, level, usage);
}
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
unsigned int height, unsigned int expanded_width,
unsigned int tex_levels, PC_TexFormat pcfmt)
{
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0;
D3D11_SUBRESOURCE_DATA srdata, *data = NULL;
if (tex_levels == 1)
{
usage = D3D11_USAGE_DYNAMIC;
cpu_access = D3D11_CPU_ACCESS_WRITE;
srdata.pSysMem = TextureCache::temp;
srdata.SysMemPitch = 4 * expanded_width;
data = &srdata;
}
const D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM,
width, height, 1, tex_levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access);
ID3D11Texture2D *pTexture;
const HRESULT hr = D3D::device->CreateTexture2D(&texdesc, data, &pTexture);
CHECK(SUCCEEDED(hr), "Create texture of the TextureCache");
TCacheEntry* const entry = new TCacheEntry(new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE));
entry->usage = usage;
// TODO: better debug names
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetTex(), "a texture of the TextureCache");
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetSRV(), "shader resource view of a texture of the TextureCache");
SAFE_RELEASE(pTexture);
if (tex_levels != 1)
entry->Load(width, height, expanded_width, 0);
return entry;
}
void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
const float *colmat)
{
if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
{
g_renderer->ResetAPIState();
// stretch picture with increased internal resolution
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)virtual_width, (float)virtual_height);
D3D::context->RSSetViewports(1, &vp);
// set transformation
if (NULL == efbcopycbuf[cbufid])
{
const D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(28 * sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
D3D11_SUBRESOURCE_DATA data;
data.pSysMem = colmat;
HRESULT hr = D3D::device->CreateBuffer(&cbdesc, &data, &efbcopycbuf[cbufid]);
CHECK(SUCCEEDED(hr), "Create efb copy constant buffer %d", cbufid);
D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopycbuf[cbufid], "a constant buffer used in TextureCache::CopyRenderTargetToTexture");
}
D3D::context->PSSetConstantBuffers(0, 1, &efbcopycbuf[cbufid]);
const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect);
// TODO: try targetSource.asRECT();
const D3D11_RECT sourcerect = CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom);
// Use linear filtering if (bScaleByHalf), use point filtering otherwise
if (scaleByHalf)
D3D::SetLinearCopySampler();
else
D3D::SetPointCopySampler();
D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), NULL);
// Create texture copy
D3D::drawShadedTexQuad(
(srcFormat == PIXELFMT_Z24) ? FramebufferManager::GetEFBDepthTexture()->GetSRV() : FramebufferManager::GetEFBColorTexture()->GetSRV(),
&sourcerect, Renderer::GetTargetWidth(), Renderer::GetTargetHeight(),
(srcFormat == PIXELFMT_Z24) ? PixelShaderCache::GetDepthMatrixProgram(true) : PixelShaderCache::GetColorMatrixProgram(true),
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
g_renderer->RestoreAPIState();
}
if (!g_ActiveConfig.bCopyEFBToTexture)
{
u8* dst = Memory::GetPointer(dstAddr);
size_t encoded_size = g_encoder->Encode(dst, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf);
u64 hash = GetHash64(dst, (int)encoded_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
if (!g_ActiveConfig.bEFBCopyCacheEnable)
TextureCache::MakeRangeDynamic(addr, (u32)encoded_size);
else if (!TextureCache::Find(addr, hash))
TextureCache::MakeRangeDynamic(addr, (u32)encoded_size);
this->hash = hash;
}
}
TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(
unsigned int scaled_tex_w, unsigned int scaled_tex_h)
{
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));
}
TextureCache::TextureCache()
{
// FIXME: Is it safe here?
g_encoder = new PSTextureEncoder;
g_encoder->Init();
}
TextureCache::~TextureCache()
{
for (unsigned int k = 0; k < MAX_COPY_BUFFERS; ++k)
SAFE_RELEASE(efbcopycbuf[k]);
g_encoder->Shutdown();
delete g_encoder;
g_encoder = NULL;
}
}

View File

@ -0,0 +1,49 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include "TextureCacheBase.h"
#include "D3DTexture.h"
namespace DX11
{
class TextureCache : public ::TextureCache
{
public:
TextureCache();
~TextureCache();
private:
struct TCacheEntry : TCacheEntryBase
{
D3DTexture2D *const texture;
D3D11_USAGE usage;
TCacheEntry(D3DTexture2D *_tex) : texture(_tex) {}
~TCacheEntry();
void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int levels);
void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
const float *colmat);
void Bind(unsigned int stage);
bool Save(const char filename[], unsigned int level);
};
TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt);
TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h);
u64 EncodeToRamFromTexture(u32 address, void* source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) {return 0;};
};
}

View File

@ -0,0 +1,122 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _TEXTUREENCODER_H
#define _TEXTUREENCODER_H
#include "VideoCommon.h"
namespace DX11
{
// 4-bit format: 8x8 texels / cache line
// 8-bit format: 8x4 texels / cache line
// 16-bit format: 4x4 texels / cache line
// 32-bit format: 4x4 texels / 2 cache lines
// Compressed format: 8x8 texels / cache line
// Document EFB encoding formats here with examples of where they are used.
// Format: 0 - R4
// Used in The Legend of Zelda: The Wind Waker for character shadows (srcFormat 1,
// isIntensity 1, scaleByHalf 1).
// Format: 1 - R8
// FIXME: Unseen. May or may not be a duplicate of format 8.
// Format: 2 - A4 R4
// FIXME: Unseen.
// Format: 3 - A8 R8
// FIXME: Unseen.
// Format: 4 - R5 G6 B5
// Used in Wind Waker for most render-to-texture effects like heat shimmer and
// depth-of-field.
// Format: 5 - 1 R5 G5 B5 or 0 A3 R4 G4 B4
// Used in Twilight Princess for character shadows.
// Format: 6 - A8 R8 A8 R8 | G8 B8 G8 B8
// Used in Twilight Princess for bloom effect.
// Format: 7 - A8
// Used in Metroid Prime 2 for the scan visor.
// Format: 8 - R8
// Used in Twilight Princess for the map.
// Format: 9 - G8
// FIXME: Unseen.
// Format: A - B8
// Used in Metroid Prime 2 for the scan visor.
// Format: B - G8 R8
// Used in Wind Waker for depth-of-field. Usually used with srcFormat 3 to
// render depth textures. The bytes are swapped, so games have to correct it
// in RAM before using it as a texture.
// Format: C - B8 G8
// FIXME: Unseen.
const unsigned int BLOCK_WIDTHS[16] = {
8, // R4
8, // R8 (FIXME: duplicate of R8 below?)
8, // A4 R4
4, // A8 R8
4, // R5 G6 B5
4, // 1 R5 G5 B5 or 0 A3 R4 G4 B4
4, // A8 R8 A8 R8 | G8 B8 G8 B8 (two cache lines)
8, // A8
8, // R8 (FIXME: duplicate of R8 above?)
8, // G8
8, // B8
4, // G8 R8
4, // B8 G8
0, 0, 0 // Unknown formats
};
const unsigned int BLOCK_HEIGHTS[16] = {
8, // R4
4, // R8 (FIXME: duplicate of R8 below?)
4, // A4 R4
4, // A8 R8
4, // R5 G6 B5
4, // 1 R5 G5 B5 or 0 A3 R4 G4 B4
4, // A8 R8 A8 R8 | G8 B8 G8 B8 (two cache lines)
4, // A8
4, // R8 (FIXME: duplicate of R8 above?)
4, // G8
4, // B8
4, // G8 R8
4, // B8 G8
0, 0, 0 // Unknown formats
};
// Maximum number of bytes that can occur in a texture block-row generated by
// the encoder
static const UINT MAX_BYTES_PER_BLOCK_ROW = (EFB_WIDTH/4)*64;
// The maximum amount of data that the texture encoder can generate in one call
static const UINT MAX_BYTES_PER_ENCODE = MAX_BYTES_PER_BLOCK_ROW*(EFB_HEIGHT/4);
class TextureEncoder
{
public:
virtual ~TextureEncoder() { }
virtual void Init() = 0;
virtual void Shutdown() = 0;
// Returns size in bytes of encoded block of memory
virtual size_t Encode(u8* dst, unsigned int dstFormat,
unsigned int srcFormat, const EFBRectangle& srcRect, bool isIntensity,
bool scaleByHalf) = 0;
};
}
#endif

View File

@ -0,0 +1,272 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "D3DBase.h"
#include "PixelShaderCache.h"
#include "VertexManager.h"
#include "VertexShaderCache.h"
#include "BPMemory.h"
#include "Debugger.h"
#include "IndexGenerator.h"
#include "MainBase.h"
#include "PixelShaderManager.h"
#include "RenderBase.h"
#include "Render.h"
#include "Statistics.h"
#include "TextureCacheBase.h"
#include "VertexShaderManager.h"
#include "VideoConfig.h"
// internal state for loading vertices
extern NativeVertexFormat *g_nativeVertexFmt;
namespace DX11
{
// TODO: Find sensible values for these two
const UINT IBUFFER_SIZE = VertexManager::MAXIBUFFERSIZE * sizeof(u16) * 8;
const UINT VBUFFER_SIZE = VertexManager::MAXVBUFFERSIZE;
const UINT MAX_VBUFFER_COUNT = 2;
void VertexManager::CreateDeviceObjects()
{
D3D11_BUFFER_DESC bufdesc = CD3D11_BUFFER_DESC(IBUFFER_SIZE,
D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
m_vertex_draw_offset = 0;
m_triangle_draw_index = 0;
m_line_draw_index = 0;
m_point_draw_index = 0;
m_index_buffers = new PID3D11Buffer[MAX_VBUFFER_COUNT];
m_vertex_buffers = new PID3D11Buffer[MAX_VBUFFER_COUNT];
for (m_current_index_buffer = 0; m_current_index_buffer < MAX_VBUFFER_COUNT; m_current_index_buffer++)
{
m_index_buffers[m_current_index_buffer] = NULL;
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, &m_index_buffers[m_current_index_buffer])),
"Failed to create index buffer.");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_index_buffers[m_current_index_buffer], "index buffer of VertexManager");
}
bufdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufdesc.ByteWidth = VBUFFER_SIZE;
for (m_current_vertex_buffer = 0; m_current_vertex_buffer < MAX_VBUFFER_COUNT; m_current_vertex_buffer++)
{
m_vertex_buffers[m_current_vertex_buffer] = NULL;
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, &m_vertex_buffers[m_current_vertex_buffer])),
"Failed to create vertex buffer.");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_vertex_buffers[m_current_vertex_buffer], "Vertex buffer of VertexManager");
}
m_current_vertex_buffer = 0;
m_current_index_buffer = 0;
m_index_buffer_cursor = IBUFFER_SIZE;
m_vertex_buffer_cursor = VBUFFER_SIZE;
m_lineShader.Init();
m_pointShader.Init();
}
void VertexManager::DestroyDeviceObjects()
{
m_pointShader.Shutdown();
m_lineShader.Shutdown();
for (m_current_vertex_buffer = 0; m_current_vertex_buffer < MAX_VBUFFER_COUNT; m_current_vertex_buffer++)
{
SAFE_RELEASE(m_vertex_buffers[m_current_vertex_buffer]);
SAFE_RELEASE(m_index_buffers[m_current_vertex_buffer]);
}
}
VertexManager::VertexManager()
{
CreateDeviceObjects();
}
VertexManager::~VertexManager()
{
DestroyDeviceObjects();
}
void VertexManager::PrepareDrawBuffers()
{
D3D11_MAPPED_SUBRESOURCE map;
UINT vSize = UINT(s_pCurBufferPointer - s_pBaseBufferPointer);
D3D11_MAP MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
if (m_vertex_buffer_cursor + vSize >= VBUFFER_SIZE)
{
// Wrap around
m_current_vertex_buffer = (m_current_vertex_buffer + 1) % MAX_VBUFFER_COUNT;
m_vertex_buffer_cursor = 0;
MapType = D3D11_MAP_WRITE_DISCARD;
}
D3D::context->Map(m_vertex_buffers[m_current_vertex_buffer], 0, MapType, 0, &map);
memcpy((u8*)map.pData + m_vertex_buffer_cursor, s_pBaseBufferPointer, vSize);
D3D::context->Unmap(m_vertex_buffers[m_current_vertex_buffer], 0);
m_vertex_draw_offset = m_vertex_buffer_cursor;
m_vertex_buffer_cursor += vSize;
UINT iCount = IndexGenerator::GetTriangleindexLen() +
IndexGenerator::GetLineindexLen() + IndexGenerator::GetPointindexLen();
MapType = D3D11_MAP_WRITE_NO_OVERWRITE;
if (m_index_buffer_cursor + iCount >= (IBUFFER_SIZE / sizeof(u16)))
{
// Wrap around
m_current_index_buffer = (m_current_index_buffer + 1) % MAX_VBUFFER_COUNT;
m_index_buffer_cursor = 0;
MapType = D3D11_MAP_WRITE_DISCARD;
}
D3D::context->Map(m_index_buffers[m_current_index_buffer], 0, MapType, 0, &map);
m_triangle_draw_index = m_index_buffer_cursor;
m_line_draw_index = m_triangle_draw_index + IndexGenerator::GetTriangleindexLen();
m_point_draw_index = m_line_draw_index + IndexGenerator::GetLineindexLen();
memcpy((u16*)map.pData + m_triangle_draw_index, GetTriangleIndexBuffer(), sizeof(u16) * IndexGenerator::GetTriangleindexLen());
memcpy((u16*)map.pData + m_line_draw_index, GetLineIndexBuffer(), sizeof(u16) * IndexGenerator::GetLineindexLen());
memcpy((u16*)map.pData + m_point_draw_index, GetPointIndexBuffer(), sizeof(u16) * IndexGenerator::GetPointindexLen());
D3D::context->Unmap(m_index_buffers[m_current_index_buffer], 0);
m_index_buffer_cursor += iCount;
ADDSTAT(stats.thisFrame.bytesVertexStreamed, vSize);
ADDSTAT(stats.thisFrame.bytesIndexStreamed, iCount*sizeof(u16));
}
static const float LINE_PT_TEX_OFFSETS[8] = {
0.f, 0.0625f, 0.125f, 0.25f, 0.5f, 1.f, 1.f, 1.f
};
void VertexManager::Draw(UINT stride)
{
D3D::context->IASetVertexBuffers(0, 1, &m_vertex_buffers[m_current_vertex_buffer], &stride, &m_vertex_draw_offset);
D3D::context->IASetIndexBuffer(m_index_buffers[m_current_index_buffer], DXGI_FORMAT_R16_UINT, 0);
if (IndexGenerator::GetNumTriangles() > 0)
{
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
D3D::context->DrawIndexed(IndexGenerator::GetTriangleindexLen(), m_triangle_draw_index, 0);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
// Disable culling for lines and points
if (IndexGenerator::GetNumLines() > 0 || IndexGenerator::GetNumPoints() > 0)
((DX11::Renderer*)g_renderer)->ApplyCullDisable();
if (IndexGenerator::GetNumLines() > 0)
{
float lineWidth = float(bpmem.lineptwidth.linesize) / 6.f;
float texOffset = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.lineoff];
float vpWidth = 2.0f * xfregs.viewport.wd;
float vpHeight = -2.0f * xfregs.viewport.ht;
bool texOffsetEnable[8];
for (int i = 0; i < 8; ++i)
texOffsetEnable[i] = bpmem.texcoords[i].s.line_offset;
if (m_lineShader.SetShader(g_nativeVertexFmt->m_components, lineWidth,
texOffset, vpWidth, vpHeight, texOffsetEnable))
{
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
D3D::context->DrawIndexed(IndexGenerator::GetLineindexLen(), m_line_draw_index, 0);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
D3D::context->GSSetShader(NULL, NULL, 0);
}
}
if (IndexGenerator::GetNumPoints() > 0)
{
float pointSize = float(bpmem.lineptwidth.pointsize) / 6.f;
float texOffset = LINE_PT_TEX_OFFSETS[bpmem.lineptwidth.pointoff];
float vpWidth = 2.0f * xfregs.viewport.wd;
float vpHeight = -2.0f * xfregs.viewport.ht;
bool texOffsetEnable[8];
for (int i = 0; i < 8; ++i)
texOffsetEnable[i] = bpmem.texcoords[i].s.point_offset;
if (m_pointShader.SetShader(g_nativeVertexFmt->m_components, pointSize,
texOffset, vpWidth, vpHeight, texOffsetEnable))
{
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
D3D::context->DrawIndexed(IndexGenerator::GetPointindexLen(), m_point_draw_index, 0);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
D3D::context->GSSetShader(NULL, NULL, 0);
}
}
if (IndexGenerator::GetNumLines() > 0 || IndexGenerator::GetNumPoints() > 0)
((DX11::Renderer*)g_renderer)->RestoreCull();
}
void VertexManager::vFlush()
{
u32 usedtextures = 0;
for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; ++i)
if (bpmem.tevorders[i / 2].getEnable(i & 1))
usedtextures |= 1 << bpmem.tevorders[i/2].getTexMap(i & 1);
if (bpmem.genMode.numindstages > 0)
for (unsigned int i = 0; i < bpmem.genMode.numtevstages + 1; ++i)
if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages)
usedtextures |= 1 << bpmem.tevindref.getTexMap(bpmem.tevind[i].bt);
for (unsigned int i = 0; i < 8; i++)
{
if (usedtextures & (1 << i))
{
g_renderer->SetSamplerState(i & 3, i >> 2);
const FourTexUnits &tex = bpmem.tex[i >> 2];
const TextureCache::TCacheEntryBase* tentry = TextureCache::Load(i,
(tex.texImage3[i&3].image_base/* & 0x1FFFFF*/) << 5,
tex.texImage0[i&3].width + 1, tex.texImage0[i&3].height + 1,
tex.texImage0[i&3].format, tex.texTlut[i&3].tmem_offset<<9,
tex.texTlut[i&3].tlut_format,
(tex.texMode0[i&3].min_filter & 3),
(tex.texMode1[i&3].max_lod + 0xf) / 0x10,
tex.texImage1[i&3].image_type);
if (tentry)
{
// 0s are probably for no manual wrapping needed.
PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height, 0, 0);
}
else
ERROR_LOG(VIDEO, "error loading texture");
}
}
// set global constants
VertexShaderManager::SetConstants();
PixelShaderManager::SetConstants(g_nativeVertexFmt->m_components);
bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate &&
bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24;
if (!PixelShaderCache::SetShader(
useDstAlpha ? DSTALPHA_DUAL_SOURCE_BLEND : DSTALPHA_NONE,
g_nativeVertexFmt->m_components))
{
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");});
return;
}
if (!VertexShaderCache::SetShader(g_nativeVertexFmt->m_components))
{
GFX_DEBUGGER_PAUSE_LOG_AT(NEXT_ERROR,true,{printf("Fail to set pixel shader\n");});
return;
}
PrepareDrawBuffers();
unsigned int stride = g_nativeVertexFmt->GetVertexStride();
g_nativeVertexFmt->SetupVertexPointers();
g_renderer->ApplyState(useDstAlpha);
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
Draw(stride);
g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
GFX_DEBUGGER_PAUSE_AT(NEXT_FLUSH, true);
g_renderer->RestoreState();
}
} // namespace

View File

@ -0,0 +1,50 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _VERTEXMANAGER_H
#define _VERTEXMANAGER_H
#include "VertexManagerBase.h"
#include "LineGeometryShader.h"
#include "PointGeometryShader.h"
namespace DX11
{
class VertexManager : public ::VertexManager
{
public:
VertexManager();
~VertexManager();
NativeVertexFormat* CreateNativeVertexFormat();
void CreateDeviceObjects();
void DestroyDeviceObjects();
private:
void PrepareDrawBuffers();
void Draw(u32 stride);
// temp
void vFlush();
u32 m_vertex_buffer_cursor;
u32 m_vertex_draw_offset;
u32 m_index_buffer_cursor;
u32 m_current_vertex_buffer;
u32 m_current_index_buffer;
u32 m_triangle_draw_index;
u32 m_line_draw_index;
u32 m_point_draw_index;
typedef ID3D11Buffer* PID3D11Buffer;
PID3D11Buffer* m_index_buffers;
PID3D11Buffer* m_vertex_buffers;
LineGeometryShader m_lineShader;
PointGeometryShader m_pointShader;
};
} // namespace
#endif

View File

@ -0,0 +1,315 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "FileUtil.h"
#include "LinearDiskCache.h"
#include "Debugger.h"
#include "Statistics.h"
#include "VertexShaderGen.h"
#include "D3DShader.h"
#include "Globals.h"
#include "VertexShaderCache.h"
#include "ConfigManager.h"
// See comment near the bottom of this file
static unsigned int vs_constant_offset_table[C_VENVCONST_END];
float vsconstants[C_VENVCONST_END*4];
bool vscbufchanged = true;
namespace DX11 {
VertexShaderCache::VSCache VertexShaderCache::vshaders;
const VertexShaderCache::VSCacheEntry *VertexShaderCache::last_entry;
VertexShaderUid VertexShaderCache::last_uid;
UidChecker<VertexShaderUid,VertexShaderCode> VertexShaderCache::vertex_uid_checker;
static ID3D11VertexShader* SimpleVertexShader = NULL;
static ID3D11VertexShader* ClearVertexShader = NULL;
static ID3D11InputLayout* SimpleLayout = NULL;
static ID3D11InputLayout* ClearLayout = NULL;
LinearDiskCache<VertexShaderUid, u8> g_vs_disk_cache;
ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader() { return SimpleVertexShader; }
ID3D11VertexShader* VertexShaderCache::GetClearVertexShader() { return ClearVertexShader; }
ID3D11InputLayout* VertexShaderCache::GetSimpleInputLayout() { return SimpleLayout; }
ID3D11InputLayout* VertexShaderCache::GetClearInputLayout() { return ClearLayout; }
ID3D11Buffer* vscbuf = NULL;
ID3D11Buffer* &VertexShaderCache::GetConstantBuffer()
{
// TODO: divide the global variables of the generated shaders into about 5 constant buffers to speed this up
if (vscbufchanged)
{
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(vscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, vsconstants, sizeof(vsconstants));
D3D::context->Unmap(vscbuf, 0);
vscbufchanged = false;
ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(vsconstants));
}
return vscbuf;
}
// this class will load the precompiled shaders into our cache
class VertexShaderCacheInserter : public LinearDiskCacheReader<VertexShaderUid, u8>
{
public:
void Read(const VertexShaderUid &key, const u8 *value, u32 value_size)
{
D3DBlob* blob = new D3DBlob(value_size, value);
VertexShaderCache::InsertByteCode(key, blob);
blob->Release();
}
};
const char simple_shader_code[] = {
"struct VSOUTPUT\n"
"{\n"
"float4 vPosition : POSITION;\n"
"float2 vTexCoord : TEXCOORD0;\n"
"float vTexCoord1 : TEXCOORD1;\n"
"};\n"
"VSOUTPUT main(float4 inPosition : POSITION,float3 inTEX0 : TEXCOORD0)\n"
"{\n"
"VSOUTPUT OUT;\n"
"OUT.vPosition = inPosition;\n"
"OUT.vTexCoord = inTEX0.xy;\n"
"OUT.vTexCoord1 = inTEX0.z;\n"
"return OUT;\n"
"}\n"
};
const char clear_shader_code[] = {
"struct VSOUTPUT\n"
"{\n"
"float4 vPosition : POSITION;\n"
"float4 vColor0 : COLOR0;\n"
"};\n"
"VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n"
"{\n"
"VSOUTPUT OUT;\n"
"OUT.vPosition = inPosition;\n"
"OUT.vColor0 = inColor0;\n"
"return OUT;\n"
"}\n"
};
void VertexShaderCache::Init()
{
const D3D11_INPUT_ELEMENT_DESC simpleelems[2] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
const D3D11_INPUT_ELEMENT_DESC clearelems[2] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
unsigned int cbsize = ((sizeof(vsconstants))&(~0xf))+0x10; // must be a multiple of 16
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
HRESULT hr = D3D::device->CreateBuffer(&cbdesc, NULL, &vscbuf);
CHECK(hr==S_OK, "Create vertex shader constant buffer (size=%u)", cbsize);
D3D::SetDebugObjectName((ID3D11DeviceChild*)vscbuf, "vertex shader constant buffer used to emulate the GX pipeline");
D3DBlob* blob;
D3D::CompileVertexShader(simple_shader_code, sizeof(simple_shader_code), &blob);
D3D::device->CreateInputLayout(simpleelems, 2, blob->Data(), blob->Size(), &SimpleLayout);
SimpleVertexShader = D3D::CreateVertexShaderFromByteCode(blob);
if (SimpleLayout == NULL || SimpleVertexShader == NULL) PanicAlert("Failed to create simple vertex shader or input layout at %s %d\n", __FILE__, __LINE__);
blob->Release();
D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleVertexShader, "simple vertex shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)SimpleLayout, "simple input layout");
D3D::CompileVertexShader(clear_shader_code, sizeof(clear_shader_code), &blob);
D3D::device->CreateInputLayout(clearelems, 2, blob->Data(), blob->Size(), &ClearLayout);
ClearVertexShader = D3D::CreateVertexShaderFromByteCode(blob);
if (ClearLayout == NULL || ClearVertexShader == NULL) PanicAlert("Failed to create clear vertex shader or input layout at %s %d\n", __FILE__, __LINE__);
blob->Release();
D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearVertexShader, "clear vertex shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)ClearLayout, "clear input layout");
Clear();
// these values are hardcoded, they depend on internal D3DCompile behavior
// TODO: Do this with D3DReflect or something instead
unsigned int k;
for (k = 0;k < 6;k++) vs_constant_offset_table[C_POSNORMALMATRIX+k] = 0+4*k;
for (k = 0;k < 4;k++) vs_constant_offset_table[C_PROJECTION+k] = 24+4*k;
for (k = 0;k < 4;k++) vs_constant_offset_table[C_MATERIALS+k] = 40+4*k;
for (k = 0;k < 40;k++) vs_constant_offset_table[C_LIGHTS+k] = 56+4*k;
for (k = 0;k < 24;k++) vs_constant_offset_table[C_TEXMATRICES+k] = 216+4*k;
for (k = 0;k < 64;k++) vs_constant_offset_table[C_TRANSFORMMATRICES+k] = 312+4*k;
for (k = 0;k < 32;k++) vs_constant_offset_table[C_NORMALMATRICES+k] = 568+4*k;
for (k = 0;k < 64;k++) vs_constant_offset_table[C_POSTTRANSFORMMATRICES+k] = 696+4*k;
vs_constant_offset_table[C_DEPTHPARAMS] = 952;
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str());
SETSTAT(stats.numVertexShadersCreated, 0);
SETSTAT(stats.numVertexShadersAlive, 0);
char cache_filename[MAX_PATH];
sprintf(cache_filename, "%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
SConfig::GetInstance().m_LocalCoreStartupParameter.m_strUniqueID.c_str());
VertexShaderCacheInserter inserter;
g_vs_disk_cache.OpenAndRead(cache_filename, inserter);
if (g_Config.bEnableShaderDebugging)
Clear();
last_entry = NULL;
}
void VertexShaderCache::Clear()
{
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter)
iter->second.Destroy();
vshaders.clear();
vertex_uid_checker.Invalidate();
last_entry = NULL;
}
void VertexShaderCache::Shutdown()
{
SAFE_RELEASE(vscbuf);
SAFE_RELEASE(SimpleVertexShader);
SAFE_RELEASE(ClearVertexShader);
SAFE_RELEASE(SimpleLayout);
SAFE_RELEASE(ClearLayout);
Clear();
g_vs_disk_cache.Sync();
g_vs_disk_cache.Close();
}
bool VertexShaderCache::SetShader(u32 components)
{
VertexShaderUid uid;
GetVertexShaderUid(uid, components, API_D3D);
if (g_ActiveConfig.bEnableShaderDebugging)
{
VertexShaderCode code;
GenerateVertexShaderCode(code, components, API_D3D);
vertex_uid_checker.AddToIndexAndCheck(code, uid, "Vertex", "v");
}
if (last_entry)
{
if (uid == last_uid)
{
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return (last_entry->shader != NULL);
}
}
last_uid = uid;
VSCache::iterator iter = vshaders.find(uid);
if (iter != vshaders.end())
{
const VSCacheEntry &entry = iter->second;
last_entry = &entry;
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return (entry.shader != NULL);
}
VertexShaderCode code;
GenerateVertexShaderCode(code, components, API_D3D);
D3DBlob* pbytecode = NULL;
D3D::CompileVertexShader(code.GetBuffer(), (int)strlen(code.GetBuffer()), &pbytecode);
if (pbytecode == NULL)
{
GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
return false;
}
g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size());
bool success = InsertByteCode(uid, pbytecode);
pbytecode->Release();
if (g_ActiveConfig.bEnableShaderDebugging && success)
{
vshaders[uid].code = code.GetBuffer();
}
GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true);
return success;
}
bool VertexShaderCache::InsertByteCode(const VertexShaderUid &uid, D3DBlob* bcodeblob)
{
ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob);
if (shader == NULL)
return false;
// TODO: Somehow make the debug name a bit more specific
D3D::SetDebugObjectName((ID3D11DeviceChild*)shader, "a vertex shader of VertexShaderCache");
// Make an entry in the table
VSCacheEntry entry;
entry.shader = shader;
entry.SetByteCode(bcodeblob);
vshaders[uid] = entry;
last_entry = &vshaders[uid];
INCSTAT(stats.numVertexShadersCreated);
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
return true;
}
// These are "callbacks" from VideoCommon and thus must be outside namespace DX11.
// This will have to be changed when we merge.
// maps the constant numbers to float indices in the constant buffer
void Renderer::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
{
vsconstants[vs_constant_offset_table[const_number] ] = f1;
vsconstants[vs_constant_offset_table[const_number]+1] = f2;
vsconstants[vs_constant_offset_table[const_number]+2] = f3;
vsconstants[vs_constant_offset_table[const_number]+3] = f4;
vscbufchanged = true;
}
void Renderer::SetVSConstant4fv(unsigned int const_number, const float* f)
{
memcpy(&vsconstants[vs_constant_offset_table[const_number]], f, sizeof(float)*4);
vscbufchanged = true;
}
void Renderer::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f)
{
for (unsigned int i = 0; i < count; i++)
{
memcpy(&vsconstants[vs_constant_offset_table[const_number+i]], f+3*i, sizeof(float)*3);
vsconstants[vs_constant_offset_table[const_number+i]+3] = 0.f;
}
vscbufchanged = true;
}
void Renderer::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f)
{
memcpy(&vsconstants[vs_constant_offset_table[const_number]], f, sizeof(float)*4*count);
vscbufchanged = true;
}
} // namespace DX11

View File

@ -0,0 +1,68 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _VERTEXSHADERCACHE_H
#define _VERTEXSHADERCACHE_H
#include "VertexShaderGen.h"
#include "D3DBase.h"
#include "D3DBlob.h"
#include <map>
namespace DX11 {
class VertexShaderCache
{
public:
static void Init();
static void Clear();
static void Shutdown();
static bool SetShader(u32 components); // TODO: Should be renamed to LoadShader
static ID3D11VertexShader* GetActiveShader() { return last_entry->shader; }
static D3DBlob* GetActiveShaderBytecode() { return last_entry->bytecode; }
static ID3D11Buffer* &GetConstantBuffer();
static ID3D11VertexShader* GetSimpleVertexShader();
static ID3D11VertexShader* GetClearVertexShader();
static ID3D11InputLayout* GetSimpleInputLayout();
static ID3D11InputLayout* GetClearInputLayout();
static bool VertexShaderCache::InsertByteCode(const VertexShaderUid &uid, D3DBlob* bcodeblob);
private:
struct VSCacheEntry
{
ID3D11VertexShader* shader;
D3DBlob* bytecode; // needed to initialize the input layout
std::string code;
VSCacheEntry() : shader(NULL), bytecode(NULL) {}
void SetByteCode(D3DBlob* blob)
{
SAFE_RELEASE(bytecode);
bytecode = blob;
blob->AddRef();
}
void Destroy()
{
SAFE_RELEASE(shader);
SAFE_RELEASE(bytecode);
}
};
typedef std::map<VertexShaderUid, VSCacheEntry> VSCache;
static VSCache vshaders;
static const VSCacheEntry* last_entry;
static VertexShaderUid last_uid;
static UidChecker<VertexShaderUid,VertexShaderCode> vertex_uid_checker;
};
} // namespace DX11
#endif // _VERTEXSHADERCACHE_H

View File

@ -0,0 +1,29 @@
#ifndef DX11_VIDEO_BACKEND_H_
#define DX11_VIDEO_BACKEND_H_
#include "VideoBackendBase.h"
namespace DX11
{
class VideoBackend : public VideoBackendHardware
{
bool Initialize(void *&);
void Shutdown();
std::string GetName();
std::string GetDisplayName();
void Video_Prepare();
void Video_Cleanup();
void ShowConfig(void* parent);
void UpdateFPSDisplay(const char*);
unsigned int PeekMessages();
};
}
#endif

View File

@ -0,0 +1,374 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#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->GetTargetWidth();
params.TexTop = FLOAT(targetRect.top) / g_renderer->GetTargetHeight();
params.TexRight = FLOAT(targetRect.right) / g_renderer->GetTargetWidth();
params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetTargetHeight();
params.Gamma = gamma;
D3D::context->UpdateSubresource(m_encodeParams, 0, NULL, &params, 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());
}
}

View File

@ -0,0 +1,55 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#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

View File

@ -0,0 +1,245 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <wx/wx.h>
#include "LogManager.h"
#include "BPStructs.h"
#include "CommandProcessor.h"
#include "Fifo.h"
#include "OnScreenDisplay.h"
#include "OpcodeDecoding.h"
#include "PixelEngine.h"
#include "PixelShaderManager.h"
#include "VideoConfig.h"
#include "VertexLoaderManager.h"
#include "VertexShaderManager.h"
#include "Core.h"
#include "Host.h"
#include "Debugger/DebuggerPanel.h"
#include "DLCache.h"
#include "EmuWindow.h"
#include "IndexGenerator.h"
#include "FileUtil.h"
#include "Globals.h"
#include "IniFile.h"
#include "VideoConfigDiag.h"
#include "D3DUtil.h"
#include "D3DBase.h"
#include "PerfQuery.h"
#include "PixelShaderCache.h"
#include "TextureCache.h"
#include "VertexManager.h"
#include "VertexShaderCache.h"
#include "VideoBackend.h"
#include "ConfigManager.h"
namespace DX11
{
unsigned int VideoBackend::PeekMessages()
{
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
return FALSE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return TRUE;
}
void VideoBackend::UpdateFPSDisplay(const char *text)
{
TCHAR temp[512];
swprintf_s(temp, sizeof(temp)/sizeof(TCHAR), _T("%hs | D3D | %hs"), scm_rev_str, text);
EmuWindow::SetWindowText(temp);
}
std::string VideoBackend::GetName()
{
return "D3D";
}
std::string VideoBackend::GetDisplayName()
{
return "Direct3D";
}
void InitBackendInfo()
{
HRESULT hr = DX11::D3D::LoadDXGI();
if (SUCCEEDED(hr)) hr = DX11::D3D::LoadD3D();
if (FAILED(hr))
{
DX11::D3D::UnloadDXGI();
return;
}
g_Config.backend_info.APIType = API_D3D;
g_Config.backend_info.bUseRGBATextures = true; // the GX formats barely match any D3D11 formats
g_Config.backend_info.bUseMinimalMipCount = true;
g_Config.backend_info.bSupports3DVision = false;
g_Config.backend_info.bSupportsDualSourceBlend = true;
g_Config.backend_info.bSupportsFormatReinterpretation = true;
g_Config.backend_info.bSupportsPixelLighting = true;
g_Config.backend_info.bSupportsPrimitiveRestart = true;
IDXGIFactory* factory;
IDXGIAdapter* ad;
hr = DX11::PCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
if (FAILED(hr))
PanicAlert("Failed to create IDXGIFactory object");
// adapters
g_Config.backend_info.Adapters.clear();
g_Config.backend_info.AAModes.clear();
while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) != DXGI_ERROR_NOT_FOUND)
{
const size_t adapter_index = g_Config.backend_info.Adapters.size();
DXGI_ADAPTER_DESC desc;
ad->GetDesc(&desc);
// TODO: These don't get updated on adapter change, yet
if (adapter_index == g_Config.iAdapter)
{
char buf[32];
std::vector<DXGI_SAMPLE_DESC> modes;
modes = DX11::D3D::EnumAAModes(ad);
for (unsigned int i = 0; i < modes.size(); ++i)
{
if (i == 0) sprintf_s(buf, 32, _trans("None"));
else if (modes[i].Quality) sprintf_s(buf, 32, _trans("%d samples (quality level %d)"), modes[i].Count, modes[i].Quality);
else sprintf_s(buf, 32, _trans("%d samples"), modes[i].Count);
g_Config.backend_info.AAModes.push_back(buf);
}
// Requires the earlydepthstencil attribute (only available in shader model 5)
g_Config.backend_info.bSupportsEarlyZ = (DX11::D3D::GetFeatureLevel(ad) == D3D_FEATURE_LEVEL_11_0);
}
g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description));
ad->Release();
}
factory->Release();
// Clear ppshaders string vector
g_Config.backend_info.PPShaders.clear();
DX11::D3D::UnloadDXGI();
DX11::D3D::UnloadD3D();
}
void VideoBackend::ShowConfig(void *_hParent)
{
#if defined(HAVE_WX) && HAVE_WX
InitBackendInfo();
VideoConfigDiag diag((wxWindow*)_hParent, _trans("Direct3D"), "gfx_dx11");
diag.ShowModal();
#endif
}
bool VideoBackend::Initialize(void *&window_handle)
{
InitializeShared();
InitBackendInfo();
frameCount = 0;
const SCoreStartupParameter& core_params = SConfig::GetInstance().m_LocalCoreStartupParameter;
g_Config.Load((File::GetUserPath(D_CONFIG_IDX) + "gfx_dx11.ini").c_str());
g_Config.GameIniLoad();
g_Config.UpdateProjectionHack();
g_Config.VerifyValidity();
UpdateActiveConfig();
window_handle = (void*)EmuWindow::Create((HWND)window_handle, GetModuleHandle(0), _T("Loading - Please wait."));
if (window_handle == NULL)
{
ERROR_LOG(VIDEO, "An error has occurred while trying to create the window.");
return false;
}
s_BackendInitialized = true;
return true;
}
void VideoBackend::Video_Prepare()
{
// Better be safe...
s_efbAccessRequested = FALSE;
s_FifoShuttingDown = FALSE;
s_swapRequested = FALSE;
// internal interfaces
g_renderer = new Renderer;
g_texture_cache = new TextureCache;
g_vertex_manager = new VertexManager;
g_perf_query = new PerfQuery;
VertexShaderCache::Init();
PixelShaderCache::Init();
D3D::InitUtils();
// VideoCommon
BPInit();
Fifo_Init();
IndexGenerator::Init();
VertexLoaderManager::Init();
OpcodeDecoder_Init();
VertexShaderManager::Init();
PixelShaderManager::Init();
CommandProcessor::Init();
PixelEngine::Init();
DLCache::Init();
// Tell the host that the window is ready
Host_Message(WM_USER_CREATE);
}
void VideoBackend::Shutdown()
{
s_BackendInitialized = false;
// TODO: should be in Video_Cleanup
if (g_renderer)
{
s_efbAccessRequested = FALSE;
s_FifoShuttingDown = FALSE;
s_swapRequested = FALSE;
// VideoCommon
DLCache::Shutdown();
Fifo_Shutdown();
CommandProcessor::Shutdown();
PixelShaderManager::Shutdown();
VertexShaderManager::Shutdown();
OpcodeDecoder_Shutdown();
VertexLoaderManager::Shutdown();
// internal interfaces
D3D::ShutdownUtils();
PixelShaderCache::Shutdown();
VertexShaderCache::Shutdown();
delete g_perf_query;
delete g_vertex_manager;
delete g_texture_cache;
delete g_renderer;
g_renderer = NULL;
g_texture_cache = NULL;
}
}
void VideoBackend::Video_Cleanup() {
}
}

View File

@ -0,0 +1,11 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef MAIN_H
#define MAIN_H
#include "Render.h"
#include "MainBase.h"
#endif

View File

@ -0,0 +1,5 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "stdafx.h"

View File

@ -0,0 +1,12 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#define _WIN32_WINNT 0x501
#ifndef _WIN32_IE
#define _WIN32_IE 0x0500 // Default value is 0x0400
#endif
#include <tchar.h>
#include <windows.h>