Some work on merging the video plugins: Added a new plugin to the solution(shouldn't build by default) which combines the DX9, DX11, and OGL plugins with their common code merged (and some things temporarily removed). In it's current state the plugin is hardly usable. Perhaps someone with knowledge of the video plugins will be able to fix the things I have broken more easily than me(or point me in the right direction). I will continue to work on it as well.

Main Issues:
DX11 is functional with a ~2MB/s mem leak.
OpenGL/DirectX9 have a black display while game runs. (DirectX 9 flashes good display on emulation stop)
Too many virtual function calls. (once everything is working, I will work on removing them)
Won't build on non-Windows in its current state. (mainly EmuWindow will need changes for Linux/OS X)
Probably other stuff.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6219 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Jordan Woyak
2010-09-20 21:45:47 +00:00
parent 6583a3f1e2
commit 194493cc04
94 changed files with 19314 additions and 1 deletions

View File

@ -0,0 +1,338 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Common
#include "StringUtil.h"
// VideoCommon
#include "VideoConfig.h"
#include "XFStructs.h"
// DX11
#include "DX11_D3DBase.h"
#include "DX11_D3DTexture.h"
#include "DX11_D3DShader.h"
#include "DX11_Render.h"
#include <D3Dcompiler.h>
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")
namespace DX11
{
HINSTANCE hD3DXDll = NULL;
D3DX11COMPILEFROMMEMORYTYPE PD3DX11CompileFromMemory = NULL;
D3DX11FILTERTEXTURETYPE PD3DX11FilterTexture = NULL;
D3DX11SAVETEXTURETOFILEATYPE PD3DX11SaveTextureToFileA = NULL;
D3DX11SAVETEXTURETOFILEWTYPE PD3DX11SaveTextureToFileW = NULL;
namespace D3D
{
ID3D11Device* device = NULL;
ID3D11DeviceContext* context = NULL;
IDXGISwapChain* swapchain = NULL;
D3D_FEATURE_LEVEL featlevel;
D3DTexture2D* backbuf = NULL;
HWND hWnd;
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 Create(HWND wnd)
{
hWnd = wnd;
HRESULT hr;
RECT client;
GetClientRect(hWnd, &client);
xres = client.right - client.left;
yres = client.bottom - client.top;
// try to load D3DX11 first to check whether we have proper runtime support
// try to use the dll the plugin was compiled against first - don't bother about debug runtimes
hD3DXDll = LoadLibraryA(StringFromFormat("d3dx11_%d.dll", D3DX11_SDK_VERSION).c_str());
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.");
}
}
else
{
NOTICE_LOG(VIDEO, "Successfully loaded %s.", StringFromFormat("d3dx11_%d.dll", D3DX11_SDK_VERSION).c_str());
}
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);
// D3DX11 is fine, initialize D3D11
IDXGIFactory* factory;
IDXGIAdapter* adapter;
IDXGIOutput* output;
hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
if (FAILED(hr)) MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 plugin"), 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 plugin"), 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 plugin"), MB_OK | MB_ICONERROR);
}
// this will need to be changed once multisampling gets implemented
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 plugin"), 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)
D3D11_CREATE_DEVICE_FLAG device_flags = (D3D11_CREATE_DEVICE_FLAG)(D3D11_CREATE_DEVICE_DEBUG|D3D11_CREATE_DEVICE_SINGLETHREADED);
#else
D3D11_CREATE_DEVICE_FLAG device_flags = D3D11_CREATE_DEVICE_SINGLETHREADED;
#endif
hr = D3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, device_flags,
supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS,
D3D11_SDK_VERSION, &swap_chain_desc, &swapchain, &device,
&featlevel, &context);
if (FAILED(hr) || !device || !context || !swapchain)
{
MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"), _T("Dolphin Direct3D 11 plugin"), 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 plugin"), 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;
gfxstate = new EmuGfxState;
stateman = new StateManager;
return S_OK;
}
void Close()
{
// unload D3DX11
FreeLibrary(hD3DXDll);
PD3DX11FilterTexture = NULL;
PD3DX11SaveTextureToFileA = NULL;
PD3DX11SaveTextureToFileW = NULL;
// release all bound resources
context->ClearState();
SAFE_RELEASE(backbuf);
SAFE_RELEASE(swapchain);
SAFE_DELETE(gfxstate);
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;
}
/* just returning the 4_0 ones here */
const char* VertexShaderVersionString() { return "vs_4_0"; }
const char* PixelShaderVersionString() { 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 16384;
break;
case D3D_FEATURE_LEVEL_10_1:
case D3D_FEATURE_LEVEL_10_0:
return 8192;
break;
case D3D_FEATURE_LEVEL_9_3:
return 4096;
break;
case D3D_FEATURE_LEVEL_9_2:
case D3D_FEATURE_LEVEL_9_1:
return 2048;
break;
default:
return 0;
break;
}
}
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 plugin"), 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.bVSync, 0);
}
} // namespace
}

View File

@ -0,0 +1,96 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
// Common
#include "Common.h"
// DX11
#include <d3dx11.h>
#include "DX11_GfxState.h"
#include "DX11_D3DBlob.h"
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 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* 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.
inline void SetDebugObjectName(ID3D11DeviceChild* resource, const char* name)
{
#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 plugin works with DX11 runtimes
// back to August 2009 even if the plugin 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
}

View File

@ -0,0 +1,68 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "DX11_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 = 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;
}
}

View File

@ -0,0 +1,52 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#include "Common.h"
#include <d3d11.h>
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;
};
}

View File

@ -0,0 +1,150 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <d3dx11.h>
#include <d3dcompiler.h>
#include <string>
#include "VideoConfig.h"
#include "DX11_D3DShader.h"
namespace DX11
{
namespace D3D
{
// bytecode->shader
ID3D11VertexShader* CreateVertexShaderFromByteCode(void* bytecode, unsigned int len)
{
ID3D11VertexShader* v_shader;
HRESULT hr = D3D::device->CreateVertexShader(bytecode, len, NULL, &v_shader);
if (FAILED(hr))
{
PanicAlert("CreateVertexShaderFromByteCode failed from %p (size %d) at %s %d\n", bytecode, len, __FILE__, __LINE__);
v_shader = 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 (FAILED(hr) || errorBuffer)
{
std::string msg = (char*)errorBuffer->GetBufferPointer();
msg += "\n\n";
msg += code;
MessageBoxA(0, msg.c_str(), "Error compiling pixel shader", MB_ICONERROR);
*blob = NULL;
errorBuffer->Release();
}
else
{
*blob = new D3DBlob(shaderBuffer);
shaderBuffer->Release();
}
return SUCCEEDED(hr);
}
// bytecode->shader
ID3D11PixelShader* CreatePixelShaderFromByteCode(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)
{
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, NULL, NULL, "main", D3D::PixelShaderVersionString(),
flags, 0, NULL, &shaderBuffer, &errorBuffer, NULL);
if (FAILED(hr) || errorBuffer)
{
std::string msg = (char*)errorBuffer->GetBufferPointer();
msg += "\n\n";
msg += code;
MessageBoxA(0, msg.c_str(), "Error compiling pixel shader", MB_ICONERROR);
*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;
}
PanicAlert("Failed to compile and create vertex shader from %p (size %d) at %s %d\n", code, len, __FILE__, __LINE__);
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;
}
PanicAlert("Failed to compile and create pixel shader, %s %d\n", __FILE__, __LINE__);
return NULL;
}
} // namespace
}

View File

@ -0,0 +1,44 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#include "DX11_D3DBase.h"
namespace DX11
{
namespace D3D
{
ID3D11VertexShader* CreateVertexShaderFromByteCode(void* bytecode, unsigned int len);
ID3D11PixelShader* CreatePixelShaderFromByteCode(void* bytecode, unsigned int len);
// The returned bytecode buffers should be Release()d.
bool CompileVertexShader(const char* code, unsigned int len, D3DBlob** blob);
bool CompilePixelShader(const char* code, unsigned int len, D3DBlob** blob);
// Utility functions
ID3D11VertexShader* CompileAndCreateVertexShader(const char* code, unsigned int len);
ID3D11PixelShader* CompileAndCreatePixelShader(const char* code, unsigned int len);
inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode) { return CreateVertexShaderFromByteCode(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 ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code) { return CompileAndCreatePixelShader((const char*)code->Data(), code->Size()); }
}
}

View File

@ -0,0 +1,125 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <d3dx11.h>
#include "DX11_D3DBase.h"
#include "DX11_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)
{
D3D11_MAPPED_SUBRESOURCE map;
HRESULT hr = D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map);
CHECK(SUCCEEDED(hr), "ID3D11DeviceContext::Map failed! (%x)", hr);
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, map.RowPitch);
}
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;
}
D3DTexture2D::D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind,
DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format)
: ref(1), tex(texptr), srv(NULL), rtv(NULL), dsv(NULL)
{
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(D3D11_SRV_DIMENSION_TEXTURE2D, srv_format);
D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = CD3D11_DEPTH_STENCIL_VIEW_DESC(D3D11_DSV_DIMENSION_TEXTURE2D, dsv_format);
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = CD3D11_RENDER_TARGET_VIEW_DESC(D3D11_RTV_DIMENSION_TEXTURE2D, 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);
}
}

View File

@ -0,0 +1,60 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#include "DX11_D3DBase.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);
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() { return tex; }
ID3D11ShaderResourceView* &GetSRV() { return srv; }
ID3D11RenderTargetView* &GetRTV() { return rtv; }
ID3D11DepthStencilView* &GetDSV() { return dsv; }
private:
~D3DTexture2D();
ID3D11Texture2D* tex;
ID3D11ShaderResourceView* srv;
ID3D11RenderTargetView* rtv;
ID3D11DepthStencilView* dsv;
D3D11_BIND_FLAG bindflags;
UINT ref;
};
}

View File

@ -0,0 +1,651 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Common
#include "Common.h"
// DX11
#include "DX11_Render.h"
#include "DX11_D3DBase.h"
#include "DX11_D3DUtil.h"
#include "DX11_D3DTexture.h"
#include "DX11_PixelShaderCache.h"
#include "DX11_VertexShaderCache.h"
#include "DX11_D3DShader.h"
namespace DX11
{
namespace D3D
{
CD3DFont font;
#define MAX_NUM_VERTICES 300
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()
{
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 /m_dwTexWidth;
m_fTexCoords[c][1] = (float) y /m_dwTexHeight;
m_fTexCoords[c][2] = (float)(x+size.cx)/m_dwTexWidth;
m_fTexCoords[c][3] = (float)(y+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;
}
}
// clean up
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");
// this might need to be changed when adding multisampling support
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, bool center)
{
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;
// if center was requested, set current position as centre
// this is currently never used
if (center)
{
const char *oldText = strText;
float mx=0;
float maxx=0;
while (c = *strText++)
{
if (c == ('\n')) mx = 0;
if (c < (' ') ) continue;
c -= 32;
mx += (m_fTexCoords[c][2]-m_fTexCoords[c][0])/(m_fTexCoords[0][3] - m_fTexCoords[0][1]) + spacing;
if (mx > maxx) maxx = mx;
}
sx -= scalex*maxx*size;
strText = oldText;
}
// 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, h+sy, dwColor, tx1, ty2);
v[1] = InitFont2DVertex( sx, sy, dwColor, tx1, ty1);
v[2] = InitFont2DVertex(w+sx, h+sy, dwColor, tx2, ty2);
v[3] = InitFont2DVertex(w+sx, 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;
}
ID3D11Buffer* CreateQuadVertexBuffer(unsigned int size, void* data)
{
ID3D11Buffer* vb;
D3D11_BUFFER_DESC vbdesc;
vbdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbdesc.ByteWidth = size;
vbdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vbdesc.MiscFlags = 0;
vbdesc.Usage = D3D11_USAGE_DYNAMIC;
if (data)
{
D3D11_SUBRESOURCE_DATA bufdata;
bufdata.pSysMem = data;
if (FAILED(device->CreateBuffer(&vbdesc, &bufdata, &vb))) return NULL;
}
else if (FAILED(device->CreateBuffer(&vbdesc, NULL, &vb))) return NULL;
return vb;
}
ID3D11SamplerState* linear_copy_sampler = NULL;
ID3D11SamplerState* point_copy_sampler = NULL;
ID3D11Buffer* stqvb = NULL;
ID3D11Buffer* stsqvb = NULL;
ID3D11Buffer* clearvb = NULL;
typedef struct { float x,y,z,u,v; } STQVertex;
typedef struct { float x,y,z,u,v; } STSQVertex;
typedef struct { float x,y,z; u32 col; } ClearVertex;
struct
{
float u1, v1, u2, v2;
} tex_quad_data;
struct
{
MathUtil::Rectangle<float> rdest;
float u1, v1, u2, v2;
} tex_sub_quad_data;
struct
{
u32 col;
float z;
} clear_quad_data;
void InitUtils()
{
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, -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX);
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, -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX);
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(&clear_quad_data, 0, sizeof(clear_quad_data));
STQVertex stqcoords[4] = {
{-1.0f, 1.0f, 0.0f, 0, 0},
{ 1.0f, 1.0f, 0.0f, 0, 0},
{-1.0f,-1.0f, 0.0f, 0, 0},
{ 1.0f,-1.0f, 0.0f, 0, 0},
};
STSQVertex stsqcoords[4];
memset(stsqcoords, 0, sizeof(stsqcoords));
ClearVertex cqcoords[4] = {
{-1.0f, 1.0f, 0, 0},
{ 1.0f, 1.0f, 0, 0},
{-1.0f, -1.0f, 0, 0},
{ 1.0f, -1.0f, 0, 0},
};
stqvb = CreateQuadVertexBuffer(4*sizeof(STQVertex), stqcoords);
CHECK(stqvb!=NULL, "Create vertex buffer of drawShadedTexQuad");
SetDebugObjectName((ID3D11DeviceChild*)stqvb, "vertex buffer of drawShadedTexQuad");
stsqvb = CreateQuadVertexBuffer(4*sizeof(STSQVertex), stsqcoords);
CHECK(stsqvb!=NULL, "Create vertex buffer of drawShadedTexSubQuad");
SetDebugObjectName((ID3D11DeviceChild*)stsqvb, "vertex buffer of drawShadedTexSubQuad");
clearvb = CreateQuadVertexBuffer(4*sizeof(ClearVertex), cqcoords);
CHECK(clearvb!=NULL, "Create vertex buffer of drawClearQuad");
SetDebugObjectName((ID3D11DeviceChild*)clearvb, "vertex buffer of drawClearQuad");
font.Init();
}
void ShutdownUtils()
{
font.Shutdown();
SAFE_RELEASE(point_copy_sampler);
SAFE_RELEASE(linear_copy_sampler);
SAFE_RELEASE(stqvb);
SAFE_RELEASE(stsqvb);
SAFE_RELEASE(clearvb);
}
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 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;
STQVertex coords[4] = {
{-1.0f, 1.0f, 0.0f, u1, v1},
{ 1.0f, 1.0f, 0.0f, u2, v1},
{-1.0f,-1.0f, 0.0f, u1, v2},
{ 1.0f,-1.0f, 0.0f, u2, v2},
};
// only upload the data to VRAM if it changed
if (tex_quad_data.u1 != u1 || tex_quad_data.v1 != v1 ||
tex_quad_data.u2 != u2 || tex_quad_data.v2 != v2)
{
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(stqvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, coords, sizeof(coords));
D3D::context->Unmap(stqvb, 0);
tex_quad_data.u1 = u1;
tex_quad_data.v1 = v1;
tex_quad_data.u2 = u2;
tex_quad_data.v2 = v2;
}
UINT stride = sizeof(STQVertex);
UINT offset = 0;
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
D3D::context->IASetInputLayout(layout);
D3D::context->IASetVertexBuffers(0, 1, &stqvb, &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, 0);
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 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;
STSQVertex coords[4] = {
{ rDest->left , rDest->bottom, 0.0f, u1, v1},
{ rDest->right, rDest->bottom, 0.0f, u2, v1},
{ rDest->left , rDest->top , 0.0f, u1, v2},
{ rDest->right, rDest->top , 0.0f, u2, v2},
};
// only upload the data to VRAM if it changed
if (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)
{
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(stsqvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, coords, sizeof(coords));
D3D::context->Unmap(stsqvb, 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;
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, &stsqvb, &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, 0);
ID3D11ShaderResourceView* texres = NULL;
context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture
}
void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout)
{
if (clear_quad_data.col != Color || clear_quad_data.z != z)
{
const 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},
};
D3D11_MAPPED_SUBRESOURCE map;
context->Map(clearvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, coords, sizeof(coords));
context->Unmap(clearvb, 0);
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, &clearvb, &stride, &offset);
stateman->Apply();
context->Draw(4, 0);
}
} // namespace
}

View File

@ -0,0 +1,91 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#include <math.h>
#include <MathUtil.h>
#include "DX11_D3DBase.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, bool center=true);
};
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);
void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture,
const MathUtil::Rectangle<float>* rSource,
int SourceWidth,
int SourceHeight,
const MathUtil::Rectangle<float>* rDest,
ID3D11PixelShader* PShader,
ID3D11VertexShader* Vshader,
ID3D11InputLayout* layout);
void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout);
void SaveRenderStates();
void RestoreRenderStates();
}
}

View File

@ -0,0 +1,162 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// VideoCommon
#include "VideoConfig.h"
// DX11
#include "DX11_Render.h"
#include "DX11_D3DBase.h"
#include "DX11_D3DTexture.h"
#include "DX11_D3DUtil.h"
#include "DX11_FramebufferManager.h"
#include "DX11_PixelShaderCache.h"
#include "DX11_VertexShaderCache.h"
#include "../Main.h"
namespace DX11
{
XFBSource FramebufferManager::m_realXFBSource; // used in real XFB mode
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; }
FramebufferManager::FramebufferManager()
{
m_efb.color_tex = NULL;
m_efb.color_staging_buf = NULL;
m_efb.depth_tex = NULL;
m_efb.depth_staging_buf = NULL;
m_efb.depth_read_texture = NULL;
m_realXFBSource.tex = NULL;
unsigned int target_width = Renderer::GetFullTargetWidth();
unsigned int target_height = Renderer::GetFullTargetHeight();
ID3D11Texture2D* buf;
D3D11_TEXTURE2D_DESC texdesc;
HRESULT hr;
// create framebuffer color texture
m_efb.color_tex = D3DTexture2D::Create(target_width, target_height,
(D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE),
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM);
CHECK(m_efb.color_tex, "create EFB color texture (size: %dx%d)", target_width, target_height);
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetTex(), "EFB color texture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetRTV(), "EFB color texture render target view");
D3D::SetDebugObjectName((ID3D11DeviceChild*)m_efb.color_tex->GetSRV(), "EFB color texture shader resource view");
// create a staging texture for Renderer::AccessEFB
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, 0,
D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_WRITE|D3D11_CPU_ACCESS_READ);
hr = D3D::device->CreateTexture2D(&texdesc, NULL, &m_efb.color_staging_buf);
CHECK(SUCCEEDED(hr), "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
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R24G8_TYPELESS, target_width,
target_height, 1, 1, D3D11_BIND_DEPTH_STENCIL|D3D11_BIND_SHADER_RESOURCE);
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);
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 target for depth buffer access in Renderer::AccessEFB
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 4, 4, 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)");
// staging texture to which we copy the data from m_efb.depth_read_texture
texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R32_FLOAT, 4, 4, 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE);
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)");
}
FramebufferManager::~FramebufferManager()
{
SAFE_RELEASE(m_efb.color_tex);
SAFE_RELEASE(m_efb.color_staging_buf);
SAFE_RELEASE(m_efb.depth_tex);
SAFE_RELEASE(m_efb.depth_staging_buf);
SAFE_RELEASE(m_efb.depth_read_texture);
SAFE_RELEASE(m_realXFBSource.tex);
}
void XFBSource::CopyEFB(const TargetRectangle& efbSource)
{
// copy EFB data to XFB and restore render target again
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();
D3DTexture2D* const ctex = FramebufferManager::GetEFBColorTexture();
D3D::drawShadedTexQuad(ctex->GetSRV(), efbSource.AsRECT(),
Renderer::GetFullTargetWidth(), Renderer::GetFullTargetHeight(),
PixelShaderCache::GetColorCopyProgram(), VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout());
D3D::context->OMSetRenderTargets(1, &ctex->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
}
XFBSource::~XFBSource()
{
tex->Release();
}
XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height)
{
XFBSource* const xfbs = new XFBSource;
xfbs->tex = D3DTexture2D::Create(target_width, target_height,
(D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE),
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM);
return xfbs;
}
void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc)
{
// TODO
PanicAlert("copyToRealXFB not implemented, yet\n");
}
const XFBSource** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount)
{
PanicAlert("getRealXFBSource not implemented, yet\n");
return NULL;
}
}

View File

@ -0,0 +1,108 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DX11_FBMANAGER_D3D_H_
#define _DX11_FBMANAGER_D3D_H_
#include <list>
#include "DX11_D3DBase.h"
#include "../FramebufferManager.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() : tex(NULL) {}
~XFBSource();
void CopyEFB(const TargetRectangle& efbSource);
D3DTexture2D* tex;
};
class FramebufferManager : public ::FramebufferManagerBase
{
friend struct XFBSource;
public:
FramebufferManager();
~FramebufferManager();
static D3DTexture2D* &GetEFBColorTexture();
static ID3D11Texture2D* &GetEFBColorStagingBuffer();
static D3DTexture2D* &GetEFBDepthTexture();
static D3DTexture2D* &GetEFBDepthReadTexture();
static ID3D11Texture2D* &GetEFBDepthStagingBuffer();
XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height);
private:
static void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc);
static const XFBSource** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount);
static XFBSource m_realXFBSource; // used in real XFB mode
static struct EFB
{
D3DTexture2D* color_tex;
ID3D11Texture2D* color_staging_buf;
D3DTexture2D* depth_tex;
ID3D11Texture2D* depth_staging_buf;
D3DTexture2D* depth_read_texture;
} m_efb;
};
}
#endif

View File

@ -0,0 +1,372 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "VideoConfig.h"
#include "DX11_GfxState.h"
namespace DX11
{
namespace D3D
{
EmuGfxState* gfxstate;
StateManager* stateman;
EmuGfxState::EmuGfxState() : vertexshader(NULL), vsbytecode(NULL), pixelshader(NULL), psbytecode(NULL), apply_called(false)
{
for (unsigned int k = 0;k < 8;k++)
{
float border[4] = {0.f, 0.f, 0.f, 0.f};
shader_resources[k] = NULL;
samplerdesc[k] = CD3D11_SAMPLER_DESC(D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_CLAMP, 0.f, 16, D3D11_COMPARISON_ALWAYS, border, -D3D11_FLOAT32_MAX, D3D11_FLOAT32_MAX);
if(g_ActiveConfig.iMaxAnisotropy > 1) samplerdesc[k].Filter = D3D11_FILTER_ANISOTROPIC;
}
memset(&blenddesc, 0, sizeof(blenddesc));
blenddesc.AlphaToCoverageEnable = FALSE;
blenddesc.IndependentBlendEnable = FALSE;
blenddesc.RenderTarget[0].BlendEnable = FALSE;
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
memset(&depthdesc, 0, sizeof(depthdesc));
depthdesc.DepthEnable = TRUE;
depthdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
depthdesc.DepthFunc = D3D11_COMPARISON_LESS;
depthdesc.StencilEnable = FALSE;
depthdesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
depthdesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
// this probably must be changed once multisampling support gets added
rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0, false, true, false, false);
pscbuf = NULL;
vscbuf = NULL;
vshaderchanged = false;
inp_layout = NULL;
num_inp_elems = 0;
pscbufchanged = false;
vscbufchanged = false;
}
EmuGfxState::~EmuGfxState()
{
for (unsigned int k = 0;k < 8;k++)
SAFE_RELEASE(shader_resources[k])
SAFE_RELEASE(vsbytecode);
SAFE_RELEASE(psbytecode);
SAFE_RELEASE(vertexshader);
SAFE_RELEASE(pixelshader);
SAFE_RELEASE(pscbuf);
SAFE_RELEASE(vscbuf);
SAFE_RELEASE(inp_layout);
}
// TODO: No need to store the whole bytecode, signature might be enough (?)
void EmuGfxState::SetVShader(ID3D11VertexShader* shader, D3DBlob* bcode)
{
// TODO: vshaderchanged actually just needs to be true if the signature changed
if (bcode && vsbytecode != bcode) vshaderchanged = true;
SAFE_RELEASE(vsbytecode);
SAFE_RELEASE(vertexshader);
if (shader && bcode)
{
vertexshader = shader;
shader->AddRef();
vsbytecode = bcode;
bcode->AddRef();
}
else if (shader || bcode)
{
PanicAlert("Invalid parameters!\n");
}
}
void EmuGfxState::SetPShader(ID3D11PixelShader* shader)
{
if (pixelshader) pixelshader->Release();
pixelshader = shader;
if (shader) shader->AddRef();
}
void EmuGfxState::SetInputElements(const D3D11_INPUT_ELEMENT_DESC* elems, UINT num)
{
num_inp_elems = num;
memcpy(inp_elems, elems, num*sizeof(D3D11_INPUT_ELEMENT_DESC));
}
void EmuGfxState::SetShaderResource(unsigned int stage, ID3D11ShaderResourceView* srv)
{
if (shader_resources[stage])
shader_resources[stage]->Release();
shader_resources[stage] = srv;
if (srv)
srv->AddRef();
}
void EmuGfxState::ApplyState()
{
HRESULT hr;
// input layout (only needs to be updated if the vertex shader signature changed)
if (vshaderchanged)
{
SAFE_RELEASE(inp_layout);
hr = D3D::device->CreateInputLayout(inp_elems, num_inp_elems, vsbytecode->Data(), vsbytecode->Size(), &inp_layout);
if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
SetDebugObjectName((ID3D11DeviceChild*)inp_layout, "an input layout of EmuGfxState");
vshaderchanged = false;
}
D3D::context->IASetInputLayout(inp_layout);
// vertex shader
// TODO: divide the global variables of the generated shaders into about 5 constant buffers
// TODO: improve interaction between EmuGfxState and global state management, so that we don't need to set the constant buffers every time
if (!vscbuf)
{
unsigned int size = ((sizeof(vsconstants))&(~0xf))+0x10; // must be a multiple of 16
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(size, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
hr = device->CreateBuffer(&cbdesc, NULL, &vscbuf);
CHECK(hr==S_OK, "Create vertex shader constant buffer (size=%u)", size);
SetDebugObjectName((ID3D11DeviceChild*)vscbuf, "a vertex shader constant buffer of EmuGfxState");
}
if (vscbufchanged)
{
D3D11_MAPPED_SUBRESOURCE map;
context->Map(vscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, vsconstants, sizeof(vsconstants));
context->Unmap(vscbuf, 0);
}
D3D::context->VSSetConstantBuffers(0, 1, &vscbuf);
// pixel shader
if (!pscbuf)
{
unsigned int size = ((sizeof(psconstants))&(~0xf))+0x10; // must be a multiple of 16
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(size, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
device->CreateBuffer(&cbdesc, NULL, &pscbuf);
CHECK(hr==S_OK, "Create pixel shader constant buffer (size=%u)", size);
SetDebugObjectName((ID3D11DeviceChild*)pscbuf, "a pixel shader constant buffer of EmuGfxState");
}
if (pscbufchanged)
{
D3D11_MAPPED_SUBRESOURCE map;
context->Map(pscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, psconstants, sizeof(psconstants));
context->Unmap(pscbuf, 0);
pscbufchanged = false;
}
D3D::context->PSSetConstantBuffers(0, 1, &pscbuf);
ID3D11SamplerState* samplerstate[8];
for (unsigned int stage = 0; stage < 8; stage++)
{
if (shader_resources[stage])
{
if(g_ActiveConfig.iMaxAnisotropy > 1) samplerdesc[stage].Filter = D3D11_FILTER_ANISOTROPIC;
hr = D3D::device->CreateSamplerState(&samplerdesc[stage], &samplerstate[stage]);
if (FAILED(hr)) PanicAlert("Fail %s %d, stage=%d\n", __FILE__, __LINE__, stage);
else SetDebugObjectName((ID3D11DeviceChild*)samplerstate[stage], "a sampler state of EmuGfxState");
}
else samplerstate[stage] = NULL;
}
D3D::context->PSSetSamplers(0, 8, samplerstate);
for (unsigned int stage = 0; stage < 8; stage++)
SAFE_RELEASE(samplerstate[stage]);
ID3D11BlendState* blstate;
hr = device->CreateBlendState(&blenddesc, &blstate);
if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__);
stateman->PushBlendState(blstate);
SetDebugObjectName((ID3D11DeviceChild*)blstate, "a blend state of EmuGfxState");
SAFE_RELEASE(blstate);
rastdesc.FillMode = (g_ActiveConfig.bWireFrame) ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID;
ID3D11RasterizerState* raststate;
hr = device->CreateRasterizerState(&rastdesc, &raststate);
if (FAILED(hr)) PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__);
SetDebugObjectName((ID3D11DeviceChild*)raststate, "a rasterizer state of EmuGfxState");
stateman->PushRasterizerState(raststate);
SAFE_RELEASE(raststate);
ID3D11DepthStencilState* depth_state;
hr = device->CreateDepthStencilState(&depthdesc, &depth_state);
if (SUCCEEDED(hr)) SetDebugObjectName((ID3D11DeviceChild*)depth_state, "a depth-stencil state of EmuGfxState");
else PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__);
D3D::stateman->PushDepthState(depth_state);
SAFE_RELEASE(depth_state);
context->PSSetShader(pixelshader, NULL, 0);
context->VSSetShader(vertexshader, NULL, 0);
context->PSSetShaderResources(0, 8, shader_resources);
stateman->Apply();
apply_called = true;
}
void EmuGfxState::AlphaPass()
{
if (!apply_called) ERROR_LOG(VIDEO, "EmuGfxState::AlphaPass called without having called ApplyState before!")
else stateman->PopBlendState();
// pixel shader for alpha pass is different, so update it
context->PSSetShader(pixelshader, NULL, 0);
ID3D11BlendState* blstate;
D3D11_BLEND_DESC desc = blenddesc;
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA;
desc.RenderTarget[0].BlendEnable = FALSE;
HRESULT hr = device->CreateBlendState(&desc, &blstate);
if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__);
SetDebugObjectName((ID3D11DeviceChild*)blstate, "a blend state of EmuGfxState (created during alpha pass)");
stateman->PushBlendState(blstate);
blstate->Release();
stateman->Apply();
}
void EmuGfxState::Reset()
{
for (unsigned int k = 0;k < 8;k++)
SAFE_RELEASE(shader_resources[k]);
context->PSSetShaderResources(0, 8, shader_resources); // unbind all textures
if (apply_called)
{
stateman->PopBlendState();
stateman->PopDepthState();
stateman->PopRasterizerState();
apply_called = false;
}
}
void EmuGfxState::SetAlphaBlendEnable(bool enable)
{
blenddesc.RenderTarget[0].BlendEnable = enable;
}
void EmuGfxState::SetRenderTargetWriteMask(UINT8 mask)
{
blenddesc.RenderTarget[0].RenderTargetWriteMask = mask;
}
void EmuGfxState::SetSrcBlend(D3D11_BLEND val)
{
// TODO: Check whether e.g. the dest color check is needed here
blenddesc.RenderTarget[0].SrcBlend = val;
if (val == D3D11_BLEND_SRC_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
else if (val == D3D11_BLEND_INV_SRC_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
else if (val == D3D11_BLEND_DEST_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA;
else if (val == D3D11_BLEND_INV_DEST_COLOR) blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
else blenddesc.RenderTarget[0].SrcBlendAlpha = val;
}
void EmuGfxState::SetDestBlend(D3D11_BLEND val)
{
// TODO: Check whether e.g. the source color check is needed here
blenddesc.RenderTarget[0].DestBlend = val;
if (val == D3D11_BLEND_SRC_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA;
else if (val == D3D11_BLEND_INV_SRC_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
else if (val == D3D11_BLEND_DEST_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
else if (val == D3D11_BLEND_INV_DEST_COLOR) blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
else blenddesc.RenderTarget[0].DestBlendAlpha = val;
}
void EmuGfxState::SetBlendOp(D3D11_BLEND_OP val)
{
blenddesc.RenderTarget[0].BlendOp = val;
blenddesc.RenderTarget[0].BlendOpAlpha = val;
}
void EmuGfxState::SetSamplerFilter(DWORD stage, D3D11_FILTER filter)
{
samplerdesc[stage].Filter = filter;
}
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
}

View File

@ -0,0 +1,142 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#include <stack>
// VideoCommon
#include "VertexShaderGen.h"
#include "PixelShaderGen.h"
// DX11
#include "DX11_D3DBase.h"
#include "DX11_D3DBlob.h"
namespace DX11
{
namespace D3D
{
// stores the pipeline state to use when calling VertexManager::Flush()
class EmuGfxState
{
public:
EmuGfxState();
~EmuGfxState();
void SetVShader(ID3D11VertexShader* shader, D3DBlob* bcode);
void SetPShader(ID3D11PixelShader* shader);
void SetInputElements(const D3D11_INPUT_ELEMENT_DESC* elems, UINT num);
void SetShaderResource(unsigned int stage, ID3D11ShaderResourceView* srv);
void ApplyState(); // apply current state
void AlphaPass(); // only modify the current state to enable the alpha pass
void Reset();
// blend state
void SetAlphaBlendEnable(bool enable);
void SetRenderTargetWriteMask(UINT8 mask);
void SetSrcBlend(D3D11_BLEND val);
void SetDestBlend(D3D11_BLEND val);
void SetBlendOp(D3D11_BLEND_OP val);
// sampler states
void SetSamplerFilter(DWORD stage, D3D11_FILTER filter);
// TODO: add methods for changing the other states instead of modifying them directly
D3D11_SAMPLER_DESC samplerdesc[8];
D3D11_RASTERIZER_DESC rastdesc;
D3D11_DEPTH_STENCIL_DESC depthdesc;
float psconstants[C_PENVCONST_END*4];
float vsconstants[C_VENVCONST_END*4];
bool vscbufchanged;
bool pscbufchanged;
private:
ID3D11VertexShader* vertexshader;
D3DBlob* vsbytecode;
ID3D11PixelShader* pixelshader;
D3DBlob* psbytecode;
bool vshaderchanged;
ID3D11Buffer* vscbuf;
ID3D11Buffer* pscbuf;
ID3D11InputLayout* inp_layout;
D3D11_INPUT_ELEMENT_DESC inp_elems[32];
int num_inp_elems;
ID3D11ShaderResourceView* shader_resources[8];
D3D11_BLEND_DESC blenddesc;
bool apply_called;
};
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 EmuGfxState* gfxstate;
extern StateManager* stateman;
} // namespace
}

View File

@ -0,0 +1,150 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Common
#include "MemoryUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
// VideoCommon
#include "Profiler.h"
#include "CPMemory.h"
#include "VertexShaderGen.h"
#include "NativeVertexFormat.h"
// DX11
#include "DX11_D3DBase.h"
#include "DX11_VertexShaderCache.h"
#include "DX11_VertexManager.h"
namespace DX11
{
class D3DVertexFormat : public NativeVertexFormat
{
D3D11_INPUT_ELEMENT_DESC m_elems[32];
UINT m_num_elems;
public:
D3DVertexFormat() : m_num_elems(0) {}
void Initialize(const PortableVertexDeclaration &_vtx_decl);
void SetupVertexPointers() const;
};
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() const
{
D3D::gfxstate->SetInputElements(m_elems, m_num_elems);
}
}

View File

@ -0,0 +1,296 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Common
#include "Common.h"
#include "FileUtil.h"
#include "LinearDiskCache.h"
// VideoCommon
#include "Statistics.h"
#include "VideoConfig.h"
#include "VertexLoader.h"
#include "BPMemory.h"
#include "XFMemory.h"
#include "ImageWrite.h"
#include "PixelShaderGen.h"
#include "PixelShaderManager.h"
// DX11
#include "DX11_D3DBase.h"
#include "DX11_D3DShader.h"
#include "DX11_PixelShaderCache.h"
#include <D3Dcompiler.h>
#include "../Main.h"
namespace DX11
{
PixelShaderCache::PSCache PixelShaderCache::PixelShaders;
const PixelShaderCache::PSCacheEntry* PixelShaderCache::last_entry;
LinearDiskCache g_ps_disk_cache;
ID3D11PixelShader* s_ColorMatrixProgram = NULL;
ID3D11PixelShader* s_ColorCopyProgram = NULL;
ID3D11PixelShader* s_DepthMatrixProgram = NULL;
ID3D11PixelShader* s_ClearProgram = 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"
};
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"
};
const char color_matrix_program_code[] = {
"sampler samp0 : register(s0);\n"
"Texture2D Tex0 : register(t0);\n"
"uniform float4 cColMatrix[5] : 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"
"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[5] : 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,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n"
"texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n"
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
"}\n"
};
ID3D11PixelShader* PixelShaderCache::GetColorMatrixProgram()
{
return s_ColorMatrixProgram;
}
ID3D11PixelShader* PixelShaderCache::GetDepthMatrixProgram()
{
return s_DepthMatrixProgram;
}
ID3D11PixelShader* PixelShaderCache::GetColorCopyProgram()
{
return s_ColorCopyProgram;
}
ID3D11PixelShader* PixelShaderCache::GetClearProgram()
{
return s_ClearProgram;
}
// 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
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, // C_FOG, 8
};
void PixelShaderCache::SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
{
D3D::gfxstate->psconstants[ps_constant_offset_table[const_number] ] = f1;
D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]+1] = f2;
D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]+2] = f3;
D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]+3] = f4;
D3D::gfxstate->pscbufchanged = true;
}
void PixelShaderCache::SetPSConstant4fv(unsigned int const_number, const float* f)
{
memcpy(&D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]], f, sizeof(float)*4);
D3D::gfxstate->pscbufchanged = true;
}
void PixelShaderCache::SetMultiPSConstant4fv(unsigned int const_number, unsigned int count, const float* f)
{
memcpy(&D3D::gfxstate->psconstants[ps_constant_offset_table[const_number]], f, sizeof(float)*4*count);
D3D::gfxstate->pscbufchanged = true;
}
// this class will load the precompiled shaders into our cache
class PixelShaderCacheInserter : public LinearDiskCacheReader
{
public:
void Read(const u8* key, int key_size, const u8* value, int value_size)
{
PIXELSHADERUID uid;
if (key_size != sizeof(uid)) {
ERROR_LOG(VIDEO, "Wrong key size in pixel shader cache");
return;
}
memcpy(&uid, key, key_size);
PixelShaderCache::InsertByteCode(uid, (void*)value, value_size);
}
};
PixelShaderCache::PixelShaderCache()
{
// 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 = D3D::CompileAndCreatePixelShader(color_copy_program_code, sizeof(color_copy_program_code));
CHECK(s_ColorCopyProgram!=NULL, "Create color copy pixel shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "color copy pixel shader");
// used for color conversion
s_ColorMatrixProgram = D3D::CompileAndCreatePixelShader(color_matrix_program_code, sizeof(color_matrix_program_code));
CHECK(s_ColorMatrixProgram!=NULL, "Create color matrix pixel shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "color matrix pixel shader");
// used for depth copy
s_DepthMatrixProgram = D3D::CompileAndCreatePixelShader(depth_matrix_program, sizeof(depth_matrix_program));
CHECK(s_DepthMatrixProgram!=NULL, "Create depth matrix pixel shader");
D3D::SetDebugObjectName((ID3D11DeviceChild*)s_ClearProgram, "depth matrix pixel shader");
Clear();
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
char cache_filename[MAX_PATH];
sprintf(cache_filename, "%sdx11-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id);
PixelShaderCacheInserter inserter;
g_ps_disk_cache.OpenAndRead(cache_filename, &inserter);
}
// ONLY to be used during shutdown.
void PixelShaderCache::Clear()
{
for (PSCache::iterator iter = PixelShaders.begin(); iter != PixelShaders.end(); iter++)
iter->second.Destroy();
PixelShaders.clear();
}
PixelShaderCache::~PixelShaderCache()
{
SAFE_RELEASE(s_ColorMatrixProgram);
SAFE_RELEASE(s_ColorCopyProgram);
SAFE_RELEASE(s_DepthMatrixProgram);
SAFE_RELEASE(s_ClearProgram);
Clear();
g_ps_disk_cache.Sync();
g_ps_disk_cache.Close();
}
bool PixelShaderCache::SetShader(bool dstAlpha)
{
PIXELSHADERUID uid;
GetPixelShaderId(&uid, dstAlpha);
// check if the shader is already set
if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount)
{
PSCache::const_iterator iter = PixelShaders.find(uid);
return (iter != PixelShaders.end() && iter->second.shader);
}
memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID));
// check if the shader is already in the cache
PSCache::iterator iter = PixelShaders.find(uid);
if (iter != PixelShaders.end())
{
iter->second.frameCount = frameCount;
const PSCacheEntry &entry = iter->second;
last_entry = &entry;
D3D::gfxstate->SetPShader(entry.shader);
return (entry.shader != NULL);
}
// need to compile a new shader
const char* code = GeneratePixelShaderCode(dstAlpha, API_D3D11);
D3DBlob* pbytecode;
if (!D3D::CompilePixelShader(code, (unsigned int)strlen(code), &pbytecode))
{
PanicAlert("Failed to compile Pixel Shader:\n\n%s", code);
return false;
}
// insert the bytecode into the caches
g_ps_disk_cache.Append((u8*)&uid, sizeof(uid), (const u8*)pbytecode->Data(), pbytecode->Size());
g_ps_disk_cache.Sync();
bool result = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size());
D3D::gfxstate->SetPShader(last_entry->shader);
pbytecode->Release();
return result;
}
bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, void* bytecode, unsigned int bytecodelen)
{
ID3D11PixelShader* shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen);
if (shader == NULL)
{
PanicAlert("Failed to create pixel shader at %s %d\n", __FILE__, __LINE__);
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;
newentry.frameCount = frameCount;
PixelShaders[uid] = newentry;
last_entry = &PixelShaders[uid];
INCSTAT(stats.numPixelShadersCreated);
SETSTAT(stats.numPixelShadersAlive, PixelShaders.size());
return true;
}
}

View File

@ -0,0 +1,74 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
#include <map>
// Common
#include "Common.h"
#include "LinearDiskCache.h"
// VideoCommon
#include "PixelShaderGen.h"
#include "VertexShaderGen.h"
// DX11
#include "DX11_D3DBase.h"
#include "../PixelShaderCache.h"
namespace DX11
{
class PixelShaderCache : public ::PixelShaderCacheBase
{
public:
PixelShaderCache();
~PixelShaderCache();
void Clear();
bool SetShader(bool dstAlpha);
static bool InsertByteCode(const PIXELSHADERUID &uid, void* bytecode, unsigned int bytecodelen);
static ID3D11PixelShader* GetColorMatrixProgram();
static ID3D11PixelShader* GetColorCopyProgram();
static ID3D11PixelShader* GetDepthMatrixProgram();
static ID3D11PixelShader* GetClearProgram();
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);
private:
struct PSCacheEntry
{
ID3D11PixelShader* shader;
int frameCount;
PSCacheEntry() : shader(NULL), frameCount(0) {}
void Destroy() { SAFE_RELEASE(shader); }
};
typedef std::map<PIXELSHADERUID, PSCacheEntry> PSCache;
static PSCache PixelShaders;
static const PSCacheEntry* last_entry;
};
}

View File

@ -0,0 +1,855 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <list>
#include <strsafe.h>
// Common
#include "Common.h"
#include "StringUtil.h"
#include "Atomic.h"
#include "FileUtil.h"
#include "Thread.h"
#include "Timer.h"
#include "Statistics.h"
#include "OnScreenDisplay.h"
// VideoCommon
#include "VideoConfig.h"
#include "OpcodeDecoding.h"
#include "BPStructs.h"
#include "XFStructs.h"
#include "PixelShaderManager.h"
#include "VertexShaderManager.h"
#include "VertexLoaderManager.h"
#include "AVIDump.h"
#include "Fifo.h"
#include "DLCache.h"
// DX11
#include "DX11_D3DUtil.h"
#include "DX11_VertexManager.h"
#include "DX11_VertexShaderCache.h"
#include "DX11_PixelShaderCache.h"
#include "DX11_TextureCache.h"
#include "DX11_FramebufferManager.h"
#include "DX11_Render.h"
#include "../EmuWindow.h"
#include "../Main.h"
namespace DX11
{
ID3D11Buffer* access_efb_cbuf = NULL;
ID3D11DepthStencilState* cleardepthstates[2] = {NULL};
ID3D11RasterizerState* clearraststate = NULL;
ID3D11BlendState* resetblendstate = NULL;
ID3D11DepthStencilState* resetdepthstate = NULL;
ID3D11RasterizerState* resetraststate = NULL;
bool reset_called = false;
// state translation lookup tables
static const D3D11_BLEND d3dSrcFactors[8] =
{
D3D11_BLEND_ZERO,
D3D11_BLEND_ONE,
D3D11_BLEND_DEST_COLOR,
D3D11_BLEND_INV_DEST_COLOR,
D3D11_BLEND_SRC_ALPHA,
D3D11_BLEND_INV_SRC_ALPHA,
D3D11_BLEND_DEST_ALPHA,
D3D11_BLEND_INV_DEST_ALPHA
};
static const D3D11_BLEND d3dDestFactors[8] =
{
D3D11_BLEND_ZERO,
D3D11_BLEND_ONE,
D3D11_BLEND_SRC_COLOR,
D3D11_BLEND_INV_SRC_COLOR,
D3D11_BLEND_SRC_ALPHA,
D3D11_BLEND_INV_SRC_ALPHA,
D3D11_BLEND_DEST_ALPHA,
D3D11_BLEND_INV_DEST_ALPHA
};
// 0 0x00
// 1 Source & destination
// 2 Source & ~destination
// 3 Source
// 4 ~Source & destination
// 5 Destination
// 6 Source ^ destination = Source & ~destination | ~Source & destination
// 7 Source | destination
// 8 ~(Source | destination)
// 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination
// 10 ~Destination
// 11 Source | ~destination
// 12 ~Source
// 13 ~Source | destination
// 14 ~(Source & destination)
// 15 0xff
static const D3D11_BLEND_OP d3dLogicOps[16] =
{
D3D11_BLEND_OP_ADD,//0
D3D11_BLEND_OP_ADD,//1
D3D11_BLEND_OP_SUBTRACT,//2
D3D11_BLEND_OP_ADD,//3
D3D11_BLEND_OP_REV_SUBTRACT,//4
D3D11_BLEND_OP_ADD,//5
D3D11_BLEND_OP_MAX,//6
D3D11_BLEND_OP_ADD,//7
D3D11_BLEND_OP_MAX,//8
D3D11_BLEND_OP_MAX,//9
D3D11_BLEND_OP_ADD,//10
D3D11_BLEND_OP_ADD,//11
D3D11_BLEND_OP_ADD,//12
D3D11_BLEND_OP_ADD,//13
D3D11_BLEND_OP_ADD,//14
D3D11_BLEND_OP_ADD//15
};
static const D3D11_BLEND d3dLogicOpSrcFactors[16] =
{
D3D11_BLEND_ZERO,//0
D3D11_BLEND_DEST_COLOR,//1
D3D11_BLEND_ONE,//2
D3D11_BLEND_ONE,//3
D3D11_BLEND_DEST_COLOR,//4
D3D11_BLEND_ZERO,//5
D3D11_BLEND_INV_DEST_COLOR,//6
D3D11_BLEND_INV_DEST_COLOR,//7
D3D11_BLEND_INV_SRC_COLOR,//8
D3D11_BLEND_INV_SRC_COLOR,//9
D3D11_BLEND_INV_DEST_COLOR,//10
D3D11_BLEND_ONE,//11
D3D11_BLEND_INV_SRC_COLOR,//12
D3D11_BLEND_INV_SRC_COLOR,//13
D3D11_BLEND_INV_DEST_COLOR,//14
D3D11_BLEND_ONE//15
};
static const D3D11_BLEND d3dLogicOpDestFactors[16] =
{
D3D11_BLEND_ZERO,//0
D3D11_BLEND_ZERO,//1
D3D11_BLEND_INV_SRC_COLOR,//2
D3D11_BLEND_ZERO,//3
D3D11_BLEND_ONE,//4
D3D11_BLEND_ONE,//5
D3D11_BLEND_INV_SRC_COLOR,//6
D3D11_BLEND_ONE,//7
D3D11_BLEND_INV_DEST_COLOR,//8
D3D11_BLEND_SRC_COLOR,//9
D3D11_BLEND_INV_DEST_COLOR,//10
D3D11_BLEND_INV_DEST_COLOR,//11
D3D11_BLEND_INV_SRC_COLOR,//12
D3D11_BLEND_ONE,//13
D3D11_BLEND_INV_SRC_COLOR,//14
D3D11_BLEND_ONE//15
};
static const D3D11_CULL_MODE d3dCullModes[4] =
{
D3D11_CULL_NONE,
D3D11_CULL_BACK,
D3D11_CULL_FRONT,
D3D11_CULL_BACK
};
static const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] =
{
D3D11_COMPARISON_NEVER,
D3D11_COMPARISON_LESS,
D3D11_COMPARISON_EQUAL,
D3D11_COMPARISON_LESS_EQUAL,
D3D11_COMPARISON_GREATER,
D3D11_COMPARISON_NOT_EQUAL,
D3D11_COMPARISON_GREATER_EQUAL,
D3D11_COMPARISON_ALWAYS
};
#define TEXF_NONE 0
#define TEXF_POINT 1
#define TEXF_LINEAR 2
static const unsigned int d3dMipFilters[4] =
{
TEXF_NONE,
TEXF_POINT,
TEXF_LINEAR,
TEXF_NONE, //reserved
};
static const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] =
{
D3D11_TEXTURE_ADDRESS_CLAMP,
D3D11_TEXTURE_ADDRESS_WRAP,
D3D11_TEXTURE_ADDRESS_MIRROR,
D3D11_TEXTURE_ADDRESS_WRAP //reserved
};
// what are these 2?
//bool Renderer::Allow2x()
//{
// return false;
//}
//
//bool Renderer::AllowCustom()
//{
// return false;
//}
void Renderer::SetupDeviceObjects()
{
g_framebuffer_manager = new FramebufferManager;
HRESULT hr;
float colmat[20]= {0.0f};
colmat[0] = colmat[5] = colmat[10] = 1.0f;
D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(20*sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT);
D3D11_SUBRESOURCE_DATA data;
data.pSysMem = colmat;
hr = D3D::device->CreateBuffer(&cbdesc, &data, &access_efb_cbuf);
CHECK(hr==S_OK, "Create constant buffer for AccessEFB");
D3D::SetDebugObjectName((ID3D11DeviceChild*)access_efb_cbuf, "constant buffer for AccessEFB");
D3D11_DEPTH_STENCIL_DESC ddesc;
ddesc.DepthEnable = FALSE;
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
ddesc.DepthFunc = D3D11_COMPARISON_ALWAYS;
ddesc.StencilEnable = FALSE;
ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[0]);
CHECK(hr==S_OK, "Create depth state for ClearScreen");
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
ddesc.DepthEnable = TRUE;
hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[1]);
CHECK(hr==S_OK, "Create depth state for ClearScreen");
D3D::SetDebugObjectName((ID3D11DeviceChild*)cleardepthstates[0], "depth state for ClearScreen (depth buffer disabled)");
D3D::SetDebugObjectName((ID3D11DeviceChild*)cleardepthstates[1], "depth state for ClearScreen (depth buffer enabled)");
// TODO: once multisampling gets implemented, this might need to be changed
D3D11_RASTERIZER_DESC rdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0.f, false, true, false, false);
hr = D3D::device->CreateRasterizerState(&rdesc, &clearraststate);
CHECK(hr==S_OK, "Create rasterizer state for ClearScreen");
D3D::SetDebugObjectName((ID3D11DeviceChild*)clearraststate, "rasterizer state for ClearScreen");
D3D11_BLEND_DESC blenddesc;
blenddesc.AlphaToCoverageEnable = FALSE;
blenddesc.IndependentBlendEnable = FALSE;
blenddesc.RenderTarget[0].BlendEnable = FALSE;
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
hr = D3D::device->CreateBlendState(&blenddesc, &resetblendstate);
CHECK(hr==S_OK, "Create blend state for ResetAPIState");
D3D::SetDebugObjectName((ID3D11DeviceChild*)resetblendstate, "blend state for ResetAPIState");
ddesc.DepthEnable = FALSE;
ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
ddesc.DepthFunc = D3D11_COMPARISON_LESS;
ddesc.StencilEnable = FALSE;
ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
hr = D3D::device->CreateDepthStencilState(&ddesc, &resetdepthstate);
CHECK(hr==S_OK, "Create depth state for ResetAPIState");
D3D::SetDebugObjectName((ID3D11DeviceChild*)resetdepthstate, "depth stencil state for ResetAPIState");
// this might need to be changed once multisampling support gets added
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, &resetraststate);
CHECK(hr==S_OK, "Create rasterizer state for ClearScreen");
D3D::SetDebugObjectName((ID3D11DeviceChild*)resetraststate, "rasterizer state for ResetAPIState");
}
void Renderer::TeardownDeviceObjects()
{
delete g_framebuffer_manager;
SAFE_RELEASE(access_efb_cbuf);
SAFE_RELEASE(cleardepthstates[0]);
SAFE_RELEASE(cleardepthstates[1]);
SAFE_RELEASE(clearraststate);
SAFE_RELEASE(resetblendstate);
SAFE_RELEASE(resetdepthstate);
SAFE_RELEASE(resetraststate);
}
Renderer::Renderer()
{
UpdateActiveConfig();
//int x, y, w_temp, h_temp;
//g_VideoInitialize.pRequestWindowSize(x, y, w_temp, h_temp);
D3D::Create(EmuWindow::GetWnd());
FramebufferSize(D3D::GetBackBufferWidth(), D3D::GetBackBufferHeight());
SetupDeviceObjects();
for (unsigned int stage = 0; stage < 8; stage++)
D3D::gfxstate->samplerdesc[stage].MaxAnisotropy = g_ActiveConfig.iMaxAnisotropy;
float ClearColor[4] = { 0.f, 0.f, 0.f, 0.f };
D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), ClearColor);
D3D::context->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV(), D3D11_CLEAR_DEPTH, 1.f, 0);
D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)(s_Fulltarget_width - s_target_width) / 2.f,
(float)(s_Fulltarget_height - s_target_height) / 2.f,
(float)s_target_width, (float)s_target_height);
D3D::context->RSSetViewports(1, &vp);
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
D3D::BeginFrame();
D3D::gfxstate->rastdesc.ScissorEnable = TRUE;
// temporary, maybe
D3D::InitUtils();
reset_called = false;
//return true;
}
Renderer::~Renderer()
{
// temporary, maybe
D3D::ShutdownUtils();
TeardownDeviceObjects();
D3D::EndFrame();
D3D::Present();
D3D::Close();
}
bool Renderer::CheckForResize()
{
while (EmuWindow::IsSizing())
Sleep(10);
if (EmuWindow::GetParentWnd())
{
// re-stretch window to parent window size again, if it has a parent window.
RECT rcParentWindow;
GetWindowRect(EmuWindow::GetParentWnd(), &rcParentWindow);
int width = rcParentWindow.right - rcParentWindow.left;
int height = rcParentWindow.bottom - rcParentWindow.top;
if (width != s_backbuffer_width || height != s_backbuffer_height)
::MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE);
}
RECT rcWindow;
GetClientRect(EmuWindow::GetWnd(), &rcWindow);
int client_width = rcWindow.right - rcWindow.left;
int client_height = rcWindow.bottom - rcWindow.top;
// sanity check
return ((client_width != s_backbuffer_width || client_height != s_backbuffer_height) &&
client_width >= 4 && client_height >= 4);
}
bool Renderer::SetScissorRect()
{
EFBRectangle rc;
if (g_renderer->SetScissorRect(rc))
{
D3D::context->RSSetScissorRects(1, (D3D11_RECT*)&rc);
return true;
}
else
{
//WARN_LOG(VIDEO, "Bad scissor rectangle: %i %i %i %i", rc.left, rc.top, rc.right, rc.bottom);
const int Xstride = (s_Fulltarget_width - s_target_width) / 2;
const int Ystride = (s_Fulltarget_height - s_target_height) / 2;
rc.left = Xstride;
rc.top = Ystride;
rc.right = Xstride + s_target_width;
rc.bottom = Ystride + s_target_height;
D3D::context->RSSetScissorRects(1, (D3D11_RECT*)&rc);
return false;
}
}
void Renderer::SetColorMask()
{
UINT8 color_mask = 0;
if (bpmem.blendmode.alphaupdate)
color_mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA;
if (bpmem.blendmode.colorupdate)
color_mask |= D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE;
D3D::gfxstate->SetRenderTargetWriteMask(color_mask);
}
u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
{
ID3D11Texture2D* read_tex;
if (!g_ActiveConfig.bEFBAccessEnable)
return 0;
if (type == POKE_Z || type == POKE_COLOR)
{
static bool alert_only_once = true;
if (!alert_only_once)
return 0;
PanicAlert("Poke EFB not implemented");
alert_only_once = false;
return 0;
}
// get the rectangular target region covered by the EFB pixel
EFBRectangle efbPixelRc;
efbPixelRc.left = x;
efbPixelRc.top = y;
efbPixelRc.right = x + 1;
efbPixelRc.bottom = y + 1;
TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc);
u32 z = 0;
float val = 0.0f;
D3D11_RECT RectToLock = CD3D11_RECT(targetPixelRc.left,
targetPixelRc.top, targetPixelRc.right, targetPixelRc.bottom);
if (type == PEEK_Z)
{
// depth buffers can only be completely CopySubresourceRegion'ed, so we're using drawShadedTexQuad instead
RectToLock.bottom+=2;
RectToLock.right+=1;
RectToLock.top-=1;
RectToLock.left-=2;
if ((RectToLock.bottom - RectToLock.top) > 4)
RectToLock.bottom--;
if ((RectToLock.right - RectToLock.left) > 4)
RectToLock.left++;
ResetAPIState(); // reset any game specific settings
// Stretch picture with increased internal resolution
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, 4.f, 4.f);
D3D::context->RSSetViewports(1, &vp);
D3D::context->PSSetConstantBuffers(0, 1, &access_efb_cbuf);
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBDepthReadTexture()->GetRTV(), NULL);
D3D::SetPointCopySampler();
D3D::drawShadedTexQuad(FramebufferManager::GetEFBDepthTexture()->GetSRV(),
&RectToLock,
GetFullTargetWidth(),
GetFullTargetHeight(),
PixelShaderCache::GetDepthMatrixProgram(),
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout());
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
RestoreAPIState();
RectToLock = CD3D11_RECT(0, 0, 4, 4);
// copy to system memory
D3D11_BOX box = CD3D11_BOX(0, 0, 0, 4, 4, 1);
read_tex = FramebufferManager::GetEFBDepthStagingBuffer();
D3D::context->CopySubresourceRegion(read_tex, 0, 0, 0, 0, FramebufferManager::GetEFBDepthReadTexture()->GetTex(), 0, &box);
}
else
{
// we can directly copy to system memory here
read_tex = FramebufferManager::GetEFBColorStagingBuffer();
D3D11_BOX box = CD3D11_BOX(RectToLock.left, RectToLock.top, 0, RectToLock.right, RectToLock.bottom, 1);
D3D::context->CopySubresourceRegion(read_tex, 0, 0, 0, 0, FramebufferManager::GetEFBColorTexture()->GetTex(), 0, &box);
RectToLock = CD3D11_RECT(0, 0, 1, 1);
}
// read the data from system memory
D3D11_MAPPED_SUBRESOURCE map;
D3D::context->Map(read_tex, 0, D3D11_MAP_READ, 0, &map);
switch(type)
{
case PEEK_Z:
val = *(float*)map.pData;
z = (u32)(val * 0xffffff);
break;
case PEEK_COLOR:
z = *(u32*)map.pData;
break;
// TODO: Implement POKE_Z and POKE_COLOR
default:
break;
}
D3D::context->Unmap(read_tex, 0);
return z;
}
// Called from VertexShaderManager
void Renderer::UpdateViewport()
{
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
// [0] = width/2
// [1] = height/2
// [2] = 16777215 * (farz - nearz)
// [3] = xorig + width/2 + 342
// [4] = yorig + height/2 + 342
// [5] = 16777215 * farz
const int old_fulltarget_w = s_Fulltarget_width;
const int old_fulltarget_h = s_Fulltarget_height;
int scissorXOff = bpmem.scissorOffset.x * 2;
int scissorYOff = bpmem.scissorOffset.y * 2;
float MValueX = GetTargetScaleX();
float MValueY = GetTargetScaleY();
int Xstride = (s_Fulltarget_width - s_target_width) / 2;
int Ystride = (s_Fulltarget_height - s_target_height) / 2;
// Stretch picture with increased internal resolution
int X = (int)(ceil(xfregs.rawViewport[3] - xfregs.rawViewport[0] - (scissorXOff)) * MValueX) + Xstride;
int Y = (int)(ceil(xfregs.rawViewport[4] + xfregs.rawViewport[1] - (scissorYOff)) * MValueY) + Ystride;
int Width = (int)ceil((int)(2 * xfregs.rawViewport[0]) * MValueX);
int Height = (int)ceil((int)(-2 * xfregs.rawViewport[1]) * MValueY);
if (Width < 0)
{
X += Width;
Width*=-1;
}
if (Height < 0)
{
Y += Height;
Height *= -1;
}
bool sizeChanged = false;
if (X < 0)
{
s_Fulltarget_width -= 2 * X;
X = 0;
sizeChanged=true;
}
if (Y < 0)
{
s_Fulltarget_height -= 2 * Y;
Y = 0;
sizeChanged=true;
}
float newx = (float)X;
float newy = (float)Y;
float newwidth = (float)Width;
float newheight = (float)Height;
if (sizeChanged)
{
// Make sure that the requested size is actually supported by the GFX driver
if (s_Fulltarget_width > (int)D3D::GetMaxTextureSize() || s_Fulltarget_height > (int)D3D::GetMaxTextureSize())
{
// Skip EFB recreation and viewport setting. Most likely causes glitches in this case, but prevents crashes at least
ERROR_LOG(VIDEO, "Tried to set a viewport which is too wide to emulate with Direct3D11. Requested EFB size is %dx%d\n", s_Fulltarget_width, s_Fulltarget_height);
// Fix the viewport to fit to the old EFB size, TODO: Check this for off-by-one errors
newx *= (float)old_fulltarget_w / (float)s_Fulltarget_width;
newy *= (float)old_fulltarget_h / (float)s_Fulltarget_height;
newwidth *= (float)old_fulltarget_w / (float)s_Fulltarget_width;
newheight *= (float)old_fulltarget_h / (float)s_Fulltarget_height;
s_Fulltarget_width = old_fulltarget_w;
s_Fulltarget_height = old_fulltarget_h;
}
else
{
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), NULL);
delete g_framebuffer_manager;
g_framebuffer_manager = new FramebufferManager;
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
}
}
// some games set invalids values MinDepth and MaxDepth so fix them to the max an min allowed and let the shaders do this work
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(newx, newy, newwidth, newheight,
0.f, // (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777216.0f;
1.f); // xfregs.rawViewport[5] / 16777216.0f;
D3D::context->RSSetViewports(1, &vp);
}
// Tino: color is passed in bgra mode so need to convert it to rgba
void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z)
{
const TargetRectangle targetRc = ConvertEFBRectangle(rc);
// update the view port for clearing the picture
D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, (float)targetRc.GetWidth(), (float)targetRc.GetHeight(),
0.f,
1.f);
D3D::context->RSSetViewports(1, &vp);
// always set the scissor in case it was set by the game and has not been reset
D3D11_RECT sirc = CD3D11_RECT(targetRc.left, targetRc.top, targetRc.right, targetRc.bottom);
D3D::context->RSSetScissorRects(1, &sirc);
u32 rgbaColor = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000);
D3D::stateman->PushDepthState(cleardepthstates[zEnable]);
D3D::stateman->PushRasterizerState(clearraststate);
//D3D::stateman->PushBlendState(resetblendstate); temporarily commented until I find the cause of the blending issue in mkwii (see next line)
D3D::gfxstate->ApplyState(); // TODO (neobrain): find out whether this breaks/fixes anything or can just be dropped. Might obsolete the comment above this line
D3D::drawClearQuad(rgbaColor, (z & 0xFFFFFF) / float(0xFFFFFF), PixelShaderCache::GetClearProgram(), VertexShaderCache::GetClearVertexShader(), VertexShaderCache::GetClearInputLayout());
D3D::gfxstate->Reset();
D3D::stateman->PopDepthState();
D3D::stateman->PopRasterizerState();
// D3D::stateman->PopBlendState();
UpdateViewport();
SetScissorRect();
}
void Renderer::SetBlendMode(bool forceUpdate)
{
if (bpmem.blendmode.logicopenable)
return;
if (bpmem.blendmode.subtract) // enable blending src 1 dst 1
{
D3D::gfxstate->SetAlphaBlendEnable(true);
D3D::gfxstate->SetBlendOp(D3D11_BLEND_OP_REV_SUBTRACT);
D3D::gfxstate->SetSrcBlend(d3dSrcFactors[1]);
D3D::gfxstate->SetDestBlend(d3dDestFactors[1]);
}
else
{
D3D::gfxstate->SetAlphaBlendEnable(bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0)));
if (bpmem.blendmode.blendenable && (!( bpmem.blendmode.srcfactor == 1 && bpmem.blendmode.dstfactor == 0)))
{
D3D::gfxstate->SetBlendOp(D3D11_BLEND_OP_ADD);
D3D::gfxstate->SetSrcBlend(d3dSrcFactors[bpmem.blendmode.srcfactor]);
D3D::gfxstate->SetDestBlend(d3dDestFactors[bpmem.blendmode.dstfactor]);
}
}
}
void Renderer::PrepareXFBCopy(const TargetRectangle &dst_rect)
{
D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)s_backbuffer_width, (float)s_backbuffer_height);
D3D::context->RSSetViewports(1, &vp);
static const float clear_color[4] = { 0.f, 0.f, 0.f, 1.f };
D3D::context->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV(), clear_color);
int x = dst_rect.left;
int y = dst_rect.top;
int width = dst_rect.right - dst_rect.left;
int height = dst_rect.bottom - dst_rect.top;
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x > s_backbuffer_width) x = s_backbuffer_width;
if (y > s_backbuffer_height) y = s_backbuffer_height;
if (width < 0) width = 0;
if (height < 0) height = 0;
if (width > (s_backbuffer_width - x)) width = s_backbuffer_width - x;
if (height > (s_backbuffer_height - y)) height = s_backbuffer_height - y;
vp = CD3D11_VIEWPORT((float)x, (float)y, (float)width, (float)height);
D3D::context->RSSetViewports(1, &vp);
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), NULL);
// activate linear filtering for the buffer copies
D3D::SetLinearCopySampler();
}
void Renderer::Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc,
const MathUtil::Rectangle<float>& drawRc, const EFBRectangle& rc)
{
if (xfbSource)
{
D3DTexture2D* const tex = ((XFBSource*)xfbSource)->tex;
// TODO:
PanicAlert("DX11 XFB");
}
else
{
D3DTexture2D* const tex = FramebufferManager::GetEFBColorTexture();
D3D::drawShadedTexQuad(tex->GetSRV(), sourceRc.AsRECT(), GetFullTargetWidth(),
GetFullTargetHeight(), PixelShaderCache::GetColorCopyProgram(),
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
}
}
void Renderer::EndFrame()
{
D3D::EndFrame();
}
void Renderer::Present()
{
D3D::Present();
// TODO: Aren't we still holding a reference to the back buffer right now?
// TODO: this was right before getting the backbuffer size in DX11::Renderer::Swap
D3D::Reset();
}
void Renderer::GetBackBufferSize(int* w, int* h)
{
*w = D3D::GetBackBufferWidth();
*h = D3D::GetBackBufferHeight();
}
void Renderer::RecreateFramebufferManger()
{
// this good?
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), NULL);
delete g_framebuffer_manager;
g_framebuffer_manager = new FramebufferManager;
}
void Renderer::BeginFrame()
{
D3D::BeginFrame();
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
}
// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
void Renderer::ResetAPIState()
{
D3D::gfxstate->Reset();
D3D::stateman->PushBlendState(resetblendstate);
D3D::stateman->PushDepthState(resetdepthstate);
D3D::stateman->PushRasterizerState(resetraststate);
D3D::stateman->Apply();
reset_called = true;
}
void Renderer::RestoreAPIState()
{
// gets us back into a more game-like state.
if (reset_called)
{
D3D::stateman->PopBlendState();
D3D::stateman->PopDepthState();
D3D::stateman->PopRasterizerState();
}
UpdateViewport();
SetScissorRect();
D3D::gfxstate->ApplyState();
reset_called = false;
}
void Renderer::SetGenerationMode()
{
// rastdesc.FrontCounterClockwise must be false for this to work
D3D::gfxstate->rastdesc.CullMode = d3dCullModes[bpmem.genMode.cullmode];
}
void Renderer::SetDepthMode()
{
if (bpmem.zmode.testenable)
{
D3D::gfxstate->depthdesc.DepthEnable = TRUE;
D3D::gfxstate->depthdesc.DepthWriteMask = bpmem.zmode.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
D3D::gfxstate->depthdesc.DepthFunc = d3dCmpFuncs[bpmem.zmode.func];
}
else
{
D3D::gfxstate->depthdesc.DepthEnable = FALSE;
D3D::gfxstate->depthdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
}
}
void Renderer::SetLogicOpMode()
{
if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3)
{
s_blendMode = 0;
D3D::gfxstate->SetAlphaBlendEnable(true);
D3D::gfxstate->SetBlendOp(d3dLogicOps[bpmem.blendmode.logicmode]);
D3D::gfxstate->SetSrcBlend(d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]);
D3D::gfxstate->SetDestBlend(d3dLogicOpDestFactors[bpmem.blendmode.logicmode]);
}
else
{
SetBlendMode(true);
}
}
void Renderer::SetSamplerState(int stage, int texindex)
{
const FourTexUnits &tex = bpmem.tex[texindex];
const TexMode0 &tm0 = tex.texMode0[stage];
const TexMode1 &tm1 = tex.texMode1[stage];
unsigned int mip;
mip = (tm0.min_filter == 8) ? TEXF_NONE : d3dMipFilters[tm0.min_filter & 3];
if ((tm0.min_filter & 3) && (tm0.min_filter != 8) && ((tm1.max_lod >> 4) == 0)) mip = TEXF_NONE;
if (texindex)
stage += 4;
// TODO: Clarify whether these values are correct
// NOTE: since there's no "no filter" in DX11 we're using point filters in these cases
if (tm0.min_filter & 4) // linear min filter
{
if (tm0.mag_filter) // linear mag filter
{
if (mip == TEXF_NONE) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT);
else if (mip == TEXF_POINT) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT);
else if (mip == TEXF_LINEAR) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_MAG_MIP_LINEAR);
}
else // point mag filter
{
if (mip == TEXF_NONE) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT);
else if (mip == TEXF_POINT) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT);
else if (mip == TEXF_LINEAR) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR);
}
}
else // point min filter
{
if (tm0.mag_filter) // linear mag filter
{
if (mip == TEXF_NONE) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT);
else if (mip == TEXF_POINT) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT);
else if (mip == TEXF_LINEAR) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR);
}
else // point mag filter
{
if (mip == TEXF_NONE) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_MAG_MIP_POINT);
else if (mip == TEXF_POINT) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_MAG_MIP_POINT);
else if (mip == TEXF_LINEAR) D3D::gfxstate->SetSamplerFilter(stage, D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR);
}
}
D3D::gfxstate->samplerdesc[stage].AddressU = d3dClamps[tm0.wrap_s];
D3D::gfxstate->samplerdesc[stage].AddressV = d3dClamps[tm0.wrap_t];
D3D::gfxstate->samplerdesc[stage].MipLODBias = (float)tm0.lod_bias / 32.0f;
D3D::gfxstate->samplerdesc[stage].MaxLOD = (float)tm1.max_lod / 16.f;
D3D::gfxstate->samplerdesc[stage].MinLOD = (float)tm1.min_lod / 16.f;
}
}

View File

@ -0,0 +1,52 @@
#pragma once
#include "MathUtil.h"
#include "VideoCommon.h"
#include "Renderer.h"
#include "pluginspecs_video.h"
namespace DX11
{
class Renderer : public ::RendererBase
{
public:
Renderer();
~Renderer();
// What's the real difference between these? Too similar names.
void ResetAPIState();
void RestoreAPIState();
static void SetupDeviceObjects();
static void TeardownDeviceObjects();
void SetColorMask();
void SetBlendMode(bool forceUpdate);
bool SetScissorRect();
void SetGenerationMode();
void SetDepthMode();
void SetLogicOpMode();
void SetSamplerState(int stage,int texindex);
u32 AccessEFB(EFBAccessType type, int x, int y);
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
void UpdateViewport();
// virtual funcs used by RendererBase::Swap
void PrepareXFBCopy(const TargetRectangle &dst_rect);
void Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc,
const MathUtil::Rectangle<float>& drawRc, const EFBRectangle& rc);
void EndFrame();
void Present();
bool CheckForResize();
void GetBackBufferSize(int* w, int* h);
void RecreateFramebufferManger();
void BeginFrame();
};
}

View File

@ -0,0 +1,230 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <d3dx11.h>
// Common
#include "CommonPaths.h"
#include "FileUtil.h"
#include "MemoryUtil.h"
#include "Hash.h"
// VideoCommon
#include "VideoConfig.h"
#include "Statistics.h"
#include "PixelShaderManager.h"
#include "VertexShaderManager.h"
#include "TextureDecoder.h"
#include "HiresTextures.h"
// DX11
#include "DX11_D3DBase.h"
#include "DX11_D3DTexture.h"
#include "DX11_D3DUtil.h"
#include "DX11_FramebufferManager.h"
#include "DX11_PixelShaderCache.h"
#include "DX11_VertexShaderCache.h"
#include "DX11_TextureCache.h"
#include "../Main.h"
namespace DX11
{
ID3D11BlendState* efbcopyblendstate = NULL;
ID3D11RasterizerState* efbcopyraststate = NULL;
ID3D11DepthStencilState* efbcopydepthstate = NULL;
ID3D11Buffer* efbcopycbuf[20] = {};
TextureCache::TCacheEntry::~TCacheEntry()
{
SAFE_RELEASE(texture);
}
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);
}
void TextureCache::TCacheEntry::FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf,
unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect)
{
// stretch picture with increased internal resolution
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)Scaledw, (float)Scaledh);
D3D::context->RSSetViewports(1, &vp);
// set transformation
if (NULL == efbcopycbuf[cbufid])
{
const D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(20 * 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(source_rect);
// 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 (bScaleByHalf)
D3D::SetLinearCopySampler();
else
D3D::SetPointCopySampler();
D3D::stateman->PushBlendState(efbcopyblendstate);
D3D::stateman->PushRasterizerState(efbcopyraststate);
D3D::stateman->PushDepthState(efbcopydepthstate);
D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), NULL);
D3D::drawShadedTexQuad(
(bFromZBuffer) ? FramebufferManager::GetEFBDepthTexture()->GetSRV() : FramebufferManager::GetEFBColorTexture()->GetSRV(),
&sourcerect, g_renderer->GetFullTargetWidth(), g_renderer->GetFullTargetHeight(),
(bFromZBuffer) ? PixelShaderCache::GetDepthMatrixProgram() : PixelShaderCache::GetColorMatrixProgram(),
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout());
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV());
D3D::stateman->PopBlendState();
D3D::stateman->PopDepthState();
D3D::stateman->PopRasterizerState();
}
void TextureCache::TCacheEntry::Bind(unsigned int stage)
{
D3D::gfxstate->SetShaderResource(stage, texture->GetSRV());
}
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width,
unsigned int height, unsigned int expanded_width,
unsigned int tex_levels, PC_TexFormat pcfmt)
{
D3D11_SUBRESOURCE_DATA srdata;
D3D11_SUBRESOURCE_DATA *data = NULL;
D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0;
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
// TODO: temp
tex_levels = 1;
if (1 == tex_levels)
{
cpu_access = D3D11_CPU_ACCESS_WRITE;
usage = D3D11_USAGE_DYNAMIC;
srdata.pSysMem = 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;
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: silly 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");
// wuts this?
//if (0 == tex_levels)
// PD3DX11FilterTexture(D3D::context, entry->texture->GetTex(), 0, D3DX11_DEFAULT);
// TODO: this good?
//if (1 != tex_levels)
// entry->Load(width, height, expanded_width, 0);
SAFE_RELEASE(pTexture);
return entry;
}
TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(int scaled_tex_w, 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()
{
HRESULT hr;
D3D11_BLEND_DESC blenddesc;
blenddesc.AlphaToCoverageEnable = FALSE;
blenddesc.IndependentBlendEnable = FALSE;
blenddesc.RenderTarget[0].BlendEnable = FALSE;
blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
hr = D3D::device->CreateBlendState(&blenddesc, &efbcopyblendstate);
CHECK(hr==S_OK, "Create blend state for CopyRenderTargetToTexture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopyblendstate, "blend state used in CopyRenderTargetToTexture");
D3D11_DEPTH_STENCIL_DESC depthdesc;
depthdesc.DepthEnable = FALSE;
depthdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
depthdesc.DepthFunc = D3D11_COMPARISON_LESS;
depthdesc.StencilEnable = FALSE;
depthdesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
depthdesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
hr = D3D::device->CreateDepthStencilState(&depthdesc, &efbcopydepthstate);
CHECK(hr==S_OK, "Create depth state for CopyRenderTargetToTexture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopydepthstate, "depth stencil state used in CopyRenderTargetToTexture");
D3D11_RASTERIZER_DESC rastdesc;
rastdesc.CullMode = D3D11_CULL_NONE;
rastdesc.FillMode = D3D11_FILL_SOLID;
rastdesc.FrontCounterClockwise = false;
rastdesc.DepthBias = false;
rastdesc.DepthBiasClamp = 0;
rastdesc.SlopeScaledDepthBias = 0;
rastdesc.DepthClipEnable = false;
rastdesc.ScissorEnable = false;
rastdesc.MultisampleEnable = false;
rastdesc.AntialiasedLineEnable = false;
hr = D3D::device->CreateRasterizerState(&rastdesc, &efbcopyraststate);
CHECK(hr==S_OK, "Create rasterizer state for CopyRenderTargetToTexture");
D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopyraststate, "rasterizer state used in CopyRenderTargetToTexture");
}
TextureCache::~TextureCache()
{
SAFE_RELEASE(efbcopyblendstate);
SAFE_RELEASE(efbcopyraststate);
SAFE_RELEASE(efbcopydepthstate);
for (unsigned int k = 0; k < 20; ++k)
SAFE_RELEASE(efbcopycbuf[k]);
}
}

View File

@ -0,0 +1,66 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#pragma once
// VideoCommon
#include "VideoCommon.h"
#include "BPMemory.h"
// DX11
#include "DX11_D3DBase.h"
#include "DX11_D3DTexture.h"
#include "../TextureCache.h"
namespace DX11
{
class TextureCache : public ::TextureCacheBase
{
public:
struct TCacheEntry : TCacheEntryBase
{
D3DTexture2D* texture;
D3D11_USAGE usage;
TCacheEntry(D3DTexture2D* _texture) : texture(_texture) {}
~TCacheEntry();
void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level);
void FromRenderTarget(bool bFromZBuffer, bool bScaleByHalf,
unsigned int cbufid, const float colmat[], const EFBRectangle &source_rect);
void Bind(unsigned int stage);
};
TextureCache();
~TextureCache();
TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int tex_levels, PC_TexFormat pcfmt);
TCacheEntryBase* CreateRenderTargetTexture(int scaled_tex_w, int scaled_tex_h);
void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, unsigned int bScaleByHalf, const EFBRectangle &source_rect);
};
}

View File

@ -0,0 +1,194 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <string>
// Common
#include "Common.h"
#include "FileUtil.h"
// VideoCommon
#include "BPStructs.h"
#include "XFStructs.h"
#include "Fifo.h"
#include "Statistics.h"
#include "Profiler.h"
#include "OpcodeDecoding.h"
#include "IndexGenerator.h"
#include "VertexShaderManager.h"
#include "PixelShaderManager.h"
#include "NativeVertexFormat.h"
#include "NativeVertexWriter.h"
// DX11
#include "DX11_D3DBase.h"
#include "DX11_D3DShader.h"
#include "DX11_D3DUtil.h"
#include "DX11_VertexManager.h"
#include "DX11_VertexShaderCache.h"
#include "DX11_PixelShaderCache.h"
#include "DX11_TextureCache.h"
#include "DX11_FramebufferManager.h"
#include "DX11_Render.h"
#include "../Main.h"
//using std::string;
namespace DX11
{
using namespace D3D;
ID3D11Buffer* indexbuffers[NUM_INDEXBUFFERS] = {};
ID3D11Buffer* vertexbuffers[NUM_VERTEXBUFFERS] = {};
// TODO: these seem ugly
inline ID3D11Buffer* GetSuitableIndexBuffer(const u32 minsize)
{
for (u32 k = 0; k < NUM_INDEXBUFFERS - 1; ++k)
if (minsize > (((u32)MAXIBUFFERSIZE) >> k))
return indexbuffers[k];
return indexbuffers[NUM_INDEXBUFFERS - 1];
}
inline ID3D11Buffer* GetSuitableVertexBuffer(const u32 minsize)
{
for (u32 k = 0; k < NUM_VERTEXBUFFERS - 1; ++k)
if (minsize > (((u32)MAXVBUFFERSIZE) >> (k + 1)))
return vertexbuffers[k];
return vertexbuffers[NUM_VERTEXBUFFERS - 1];
}
void CreateDeviceObjects()
{
D3D11_BUFFER_DESC bufdesc = CD3D11_BUFFER_DESC(MAXIBUFFERSIZE * 2,
D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
for (u32 k = 0; k < NUM_INDEXBUFFERS; ++k, bufdesc.ByteWidth >>= 1)
{
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, indexbuffers + k)),
"Failed to create index buffer [%i].", k);
D3D::SetDebugObjectName((ID3D11DeviceChild*)indexbuffers[k], "an index buffer of VertexManager");
}
bufdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufdesc.ByteWidth = MAXVBUFFERSIZE;
for (u32 k = 0; k < NUM_VERTEXBUFFERS; ++k, bufdesc.ByteWidth >>= 1)
{
CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, NULL, vertexbuffers + k)),
"Failed to create vertex buffer [%i].", k);
D3D::SetDebugObjectName((ID3D11DeviceChild*)vertexbuffers[k], "a vertex buffer of VertexManager");
}
}
void DestroyDeviceObjects()
{
for (u32 k = 0; k < NUM_INDEXBUFFERS; ++k)
SAFE_RELEASE(indexbuffers[k]);
for (u32 k = 0; k < NUM_VERTEXBUFFERS; ++k)
SAFE_RELEASE(vertexbuffers[k]);
}
VertexManager::VertexManager()
{
CreateDeviceObjects();
}
VertexManager::~VertexManager()
{
DestroyDeviceObjects();
ResetBuffer();
}
void VertexManager::Draw(u32 stride, bool alphapass)
{
static const UINT bufoffset = 0;
const UINT bufstride = stride;
D3D11_MAPPED_SUBRESOURCE map;
ID3D11Buffer* const vertexbuffer = GetSuitableVertexBuffer((u32)(s_pCurBufferPointer - LocalVBuffer));
if (alphapass)
{
gfxstate->AlphaPass();
}
else
{
context->Map(vertexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, LocalVBuffer, (u32)(s_pCurBufferPointer - LocalVBuffer));
context->Unmap(vertexbuffer, 0);
gfxstate->ApplyState();
}
D3D::context->IASetVertexBuffers(0, 1, &vertexbuffer, &bufstride, &bufoffset);
if (IndexGenerator::GetNumTriangles() > 0)
{
u32 indexbuffersize = IndexGenerator::GetTriangleindexLen();
ID3D11Buffer* indexbuffer = GetSuitableIndexBuffer(2*indexbuffersize);
if (!alphapass)
{
D3D::context->Map(indexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, TIBuffer, 2*indexbuffersize);
D3D::context->Unmap(indexbuffer, 0);
}
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
D3D::context->IASetIndexBuffer(indexbuffer, DXGI_FORMAT_R16_UINT, 0);
D3D::context->DrawIndexed(indexbuffersize, 0, 0);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
if (IndexGenerator::GetNumLines() > 0)
{
u32 indexbuffersize = IndexGenerator::GetLineindexLen();
ID3D11Buffer* indexbuffer = GetSuitableIndexBuffer(2*indexbuffersize);
if (!alphapass)
{
D3D::context->Map(indexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, LIBuffer, 2*indexbuffersize);
D3D::context->Unmap(indexbuffer, 0);
}
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
D3D::context->IASetIndexBuffer(indexbuffer, DXGI_FORMAT_R16_UINT, 0);
D3D::context->DrawIndexed(indexbuffersize, 0, 0);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
if (IndexGenerator::GetNumPoints() > 0)
{
u32 indexbuffersize = IndexGenerator::GetPointindexLen();
ID3D11Buffer* indexbuffer = GetSuitableIndexBuffer(2*indexbuffersize);
if (!alphapass)
{
D3D::context->Map(indexbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
memcpy(map.pData, PIBuffer, 2*indexbuffersize);
D3D::context->Unmap(indexbuffer, 0);
}
D3D::context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
D3D::context->IASetIndexBuffer(indexbuffer, DXGI_FORMAT_R16_UINT, 0);
D3D::context->DrawIndexed(indexbuffersize, 0, 0);
INCSTAT(stats.thisFrame.numIndexedDrawCalls);
}
}
}

View File

@ -0,0 +1,49 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DX11_VERTEXMANAGER_H
#define _DX11_VERTEXMANAGER_H
#include "CPMemory.h"
#include "VertexLoader.h"
#include "../VertexManager.h"
namespace DX11
{
enum
{
// TODO: find sensible values for these two
NUM_VERTEXBUFFERS = 8,
NUM_INDEXBUFFERS = 10,
};
class VertexManager : public ::VertexManagerBase
{
public:
VertexManager();
~VertexManager();
void Draw(u32 stride, bool alphapass);
NativeVertexFormat* CreateNativeVertexFormat();
};
}
#endif

View File

@ -0,0 +1,283 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <map>
// Common
#include "Common.h"
#include "FileUtil.h"
#include "LinearDiskCache.h"
// VideoCommon
#include "VideoConfig.h"
#include "Statistics.h"
#include "Profiler.h"
#include "VertexLoader.h"
#include "BPMemory.h"
#include "XFMemory.h"
// DX11
#include "DX11_D3DBase.h"
#include "DX11_D3DShader.h"
#include "DX11_VertexShaderCache.h"
#include "DX11_Render.h"
#include "../Main.h"
namespace DX11
{
VertexShaderCache::VSCache VertexShaderCache::vshaders;
const VertexShaderCache::VSCacheEntry* VertexShaderCache::last_entry;
static ID3D11VertexShader* SimpleVertexShader = NULL;
static ID3D11VertexShader* ClearVertexShader = NULL;
static ID3D11InputLayout* SimpleLayout = NULL;
static ID3D11InputLayout* ClearLayout = NULL;
LinearDiskCache g_vs_disk_cache;
ID3D11VertexShader* VertexShaderCache::GetSimpleVertexShader() { return SimpleVertexShader; }
ID3D11VertexShader* VertexShaderCache::GetClearVertexShader() { return ClearVertexShader; }
ID3D11InputLayout* VertexShaderCache::GetSimpleInputLayout() { return SimpleLayout; }
ID3D11InputLayout* VertexShaderCache::GetClearInputLayout() { return ClearLayout; }
// maps the constant numbers to float indices in the constant buffer
unsigned int vs_constant_offset_table[C_VENVCONST_END];
void VertexShaderCache::SetVSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
{
D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number] ] = f1;
D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]+1] = f2;
D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]+2] = f3;
D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]+3] = f4;
D3D::gfxstate->vscbufchanged = true;
}
void VertexShaderCache::SetVSConstant4fv(unsigned int const_number, const float* f)
{
memcpy(&D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]], f, sizeof(float)*4);
D3D::gfxstate->vscbufchanged = true;
}
void VertexShaderCache::SetMultiVSConstant3fv(unsigned int const_number, unsigned int count, const float* f)
{
for (unsigned int i = 0; i < count; i++)
{
memcpy(&D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number+i]], f+3*i, sizeof(float)*3);
D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number+i]+3] = 0.f;
}
D3D::gfxstate->vscbufchanged = true;
}
void VertexShaderCache::SetMultiVSConstant4fv(unsigned int const_number, unsigned int count, const float* f)
{
memcpy(&D3D::gfxstate->vsconstants[vs_constant_offset_table[const_number]], f, sizeof(float)*4*count);
D3D::gfxstate->vscbufchanged = true;
}
// this class will load the precompiled shaders into our cache
class VertexShaderCacheInserter : public LinearDiskCacheReader {
public:
void Read(const u8* key, int key_size, const u8* value, int value_size)
{
VERTEXSHADERUID uid;
if (key_size != sizeof(uid))
{
ERROR_LOG(VIDEO, "Wrong key size in vertex shader cache");
return;
}
memcpy(&uid, key, key_size);
D3DBlob* blob = new D3DBlob(value_size, value);
VertexShaderCache::InsertByteCode(uid, blob);
blob->Release();
}
};
const char simple_shader_code[] = {
"struct VSOUTPUT\n"
"{\n"
"float4 vPosition : POSITION;\n"
"float2 vTexCoord : TEXCOORD0;\n"
"};\n"
"VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0)\n"
"{\n"
"VSOUTPUT OUT;\n"
"OUT.vPosition = inPosition;\n"
"OUT.vTexCoord = inTEX0;\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"
};
VertexShaderCache::VertexShaderCache()
{
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_R32G32_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 },
};
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;
for (k = 0;k < 4;k++) vs_constant_offset_table[C_DEPTHPARAMS+k] = 952+4*k;
if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));
char cache_filename[MAX_PATH];
sprintf(cache_filename, "%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX), g_globals->unique_id);
VertexShaderCacheInserter inserter;
g_vs_disk_cache.OpenAndRead(cache_filename, &inserter);
}
void VertexShaderCache::Clear()
{
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter)
iter->second.Destroy();
vshaders.clear();
}
VertexShaderCache::~VertexShaderCache()
{
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)
{
DVSTARTPROFILE();
VERTEXSHADERUID uid;
GetVertexShaderId(&uid, components);
if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount)
return (vshaders[uid].shader != NULL);
memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID));
VSCache::iterator iter;
iter = vshaders.find(uid);
if (iter != vshaders.end())
{
iter->second.frameCount = frameCount;
const VSCacheEntry &entry = iter->second;
last_entry = &entry;
if (entry.shader) D3D::gfxstate->SetVShader(entry.shader, iter->second.bytecode);
return (entry.shader != NULL);
}
const char* code = GenerateVertexShaderCode(components, API_D3D11);
D3DBlob* pbytecode = NULL;
D3D::CompileVertexShader(code, (int)strlen(code), &pbytecode);
if (pbytecode == NULL)
{
PanicAlert("Failed to compile Vertex Shader %s %d:\n\n%s", __FILE__, __LINE__, code);
return false;
}
g_vs_disk_cache.Append((u8*)&uid, sizeof(uid), (const u8*)pbytecode->Data(), pbytecode->Size());
g_vs_disk_cache.Sync();
bool result = InsertByteCode(uid, pbytecode);
D3D::gfxstate->SetVShader(last_entry->shader, last_entry->bytecode);
pbytecode->Release();
return result;
}
bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcodeblob)
{
ID3D11VertexShader* shader = D3D::CreateVertexShaderFromByteCode(bcodeblob);
if (shader == NULL)
{
PanicAlert("Failed to create vertex shader from %p size %d at %s %d\n", bcodeblob->Data(), bcodeblob->Size(), __FILE__, __LINE__);
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.frameCount = frameCount;
entry.SetByteCode(bcodeblob);
vshaders[uid] = entry;
last_entry = &vshaders[uid];
INCSTAT(stats.numVertexShadersCreated);
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
return true;
}
}

View File

@ -0,0 +1,80 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DX11_VERTEXSHADERCACHE_H
#define _DX11_VERTEXSHADERCACHE_H
#include <map>
#include "VertexShaderGen.h"
#include "DX11_D3DBase.h"
#include "../VertexShaderCache.h"
namespace DX11
{
class VertexShaderCache : public ::VertexShaderCacheBase
{
public:
VertexShaderCache();
~VertexShaderCache();
static void Clear();
bool SetShader(u32 components);
static ID3D11VertexShader* GetSimpleVertexShader();
static ID3D11VertexShader* GetClearVertexShader();
static ID3D11InputLayout* GetSimpleInputLayout();
static ID3D11InputLayout* GetClearInputLayout();
static bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, D3DBlob* bcodeblob);
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);
private:
struct VSCacheEntry
{
ID3D11VertexShader* shader;
D3DBlob* bytecode; // needed to initialize the input layout
int frameCount;
VSCacheEntry() : shader(NULL), bytecode(NULL), frameCount(0) {}
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;
};
}
#endif // _VERTEXSHADERCACHE_H