1072 lines
34 KiB
C++
1072 lines
34 KiB
C++
/********************************************************************************
|
|
Copyright (C) 2012 Hugh Bailey <obs.jim@gmail.com>
|
|
|
|
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; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
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 for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
********************************************************************************/
|
|
|
|
|
|
#include "Main.h"
|
|
|
|
//extern "C" _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000000;
|
|
|
|
void GetDisplayDevices(DeviceOutputs &deviceList)
|
|
{
|
|
HRESULT err;
|
|
|
|
deviceList.ClearData();
|
|
|
|
#ifdef USE_DXGI1_2
|
|
REFIID iidVal = OSGetVersion() >= 8 ? __uuidof(IDXGIFactory2) : __uuidof(IDXGIFactory1);
|
|
#else
|
|
REFIIF iidVal = __uuidof(IDXGIFactory1);
|
|
#endif
|
|
|
|
IDXGIFactory1 *factory;
|
|
if(SUCCEEDED(err = CreateDXGIFactory1(iidVal, (void**)&factory)))
|
|
{
|
|
UINT i=0;
|
|
IDXGIAdapter1 *giAdapter;
|
|
|
|
while(factory->EnumAdapters1(i++, &giAdapter) == S_OK)
|
|
{
|
|
//Log(TEXT("------------------------------------------"));
|
|
|
|
DXGI_ADAPTER_DESC adapterDesc;
|
|
if(SUCCEEDED(err = giAdapter->GetDesc(&adapterDesc)))
|
|
{
|
|
if (adapterDesc.DedicatedVideoMemory != 0) {
|
|
DeviceOutputData &deviceData = *deviceList.devices.CreateNew();
|
|
deviceData.strDevice = adapterDesc.Description;
|
|
|
|
UINT j=0;
|
|
IDXGIOutput *giOutput;
|
|
while(giAdapter->EnumOutputs(j++, &giOutput) == S_OK)
|
|
{
|
|
DXGI_OUTPUT_DESC outputDesc;
|
|
if(SUCCEEDED(giOutput->GetDesc(&outputDesc)))
|
|
{
|
|
if(outputDesc.AttachedToDesktop)
|
|
{
|
|
deviceData.monitorNameList << outputDesc.DeviceName;
|
|
|
|
MonitorInfo &monitorInfo = *deviceData.monitors.CreateNew();
|
|
monitorInfo.hMonitor = outputDesc.Monitor;
|
|
mcpy(&monitorInfo.rect, &outputDesc.DesktopCoordinates, sizeof(RECT));
|
|
switch (outputDesc.Rotation) {
|
|
case DXGI_MODE_ROTATION_ROTATE90:
|
|
monitorInfo.rotationDegrees = 90.0f;
|
|
break;
|
|
case DXGI_MODE_ROTATION_ROTATE180:
|
|
monitorInfo.rotationDegrees = 180.0f;
|
|
break;
|
|
case DXGI_MODE_ROTATION_ROTATE270:
|
|
monitorInfo.rotationDegrees = 270.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
giOutput->Release();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
AppWarning(TEXT("Could not query adapter %u"), i);
|
|
|
|
giAdapter->Release();
|
|
}
|
|
|
|
factory->Release();
|
|
}
|
|
}
|
|
|
|
|
|
void LogVideoCardStats()
|
|
{
|
|
HRESULT err;
|
|
|
|
#ifdef USE_DXGI1_2
|
|
REFIID iidVal = OSGetVersion() >= 8 ? __uuidof(IDXGIFactory2) : __uuidof(IDXGIFactory1);
|
|
#else
|
|
REFIIF iidVal = __uuidof(IDXGIFactory1);
|
|
#endif
|
|
|
|
IDXGIFactory1 *factory;
|
|
if(SUCCEEDED(err = CreateDXGIFactory1(iidVal, (void**)&factory)))
|
|
{
|
|
UINT i=0;
|
|
IDXGIAdapter1 *giAdapter;
|
|
|
|
while(factory->EnumAdapters1(i++, &giAdapter) == S_OK)
|
|
{
|
|
DXGI_ADAPTER_DESC adapterDesc;
|
|
if(SUCCEEDED(err = giAdapter->GetDesc(&adapterDesc)))
|
|
{
|
|
if (!(adapterDesc.VendorId == 0x1414 && adapterDesc.DeviceId == 0x8c)) { // Ignore Microsoft Basic Render Driver
|
|
Log(TEXT("------------------------------------------"));
|
|
Log(TEXT("Adapter %u"), i);
|
|
Log(TEXT(" Video Adapter: %s"), adapterDesc.Description);
|
|
Log(TEXT(" Video Adapter Dedicated Video Memory: %u"), adapterDesc.DedicatedVideoMemory);
|
|
Log(TEXT(" Video Adapter Shared System Memory: %u"), adapterDesc.SharedSystemMemory);
|
|
|
|
UINT j = 0;
|
|
IDXGIOutput *output;
|
|
while(SUCCEEDED(giAdapter->EnumOutputs(j++, &output)))
|
|
{
|
|
DXGI_OUTPUT_DESC desc;
|
|
if(SUCCEEDED(output->GetDesc(&desc)))
|
|
Log(TEXT(" Video Adapter Output %u: pos={%d, %d}, size={%d, %d}, attached=%s"), j,
|
|
desc.DesktopCoordinates.left, desc.DesktopCoordinates.top,
|
|
desc.DesktopCoordinates.right-desc.DesktopCoordinates.left, desc.DesktopCoordinates.bottom-desc.DesktopCoordinates.top,
|
|
desc.AttachedToDesktop ? L"true" : L"false");
|
|
output->Release();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
AppWarning(TEXT("Could not query adapter %u"), i);
|
|
|
|
giAdapter->Release();
|
|
}
|
|
|
|
factory->Release();
|
|
}
|
|
}
|
|
|
|
static void HandleNvidiaOptimus(IDXGIFactory1 *factory, IDXGIAdapter1 *&adapter, UINT &adapterID)
|
|
{
|
|
if (adapterID != 1)
|
|
return;
|
|
|
|
//NvOptimusEnablement = 0;
|
|
DXGI_ADAPTER_DESC adapterDesc;
|
|
if (SUCCEEDED(adapter->GetDesc(&adapterDesc)))
|
|
{
|
|
String name = adapterDesc.Description;
|
|
name.KillSpaces();
|
|
|
|
if (name.IsEmpty())
|
|
return;
|
|
|
|
if (sstri(adapterDesc.Description, L"NVIDIA") != NULL)
|
|
{
|
|
if (name[name.Length()-1] == 'M' || name[name.Length()-1] == 'm') {
|
|
adapter->Release();
|
|
|
|
adapterID = 0;
|
|
//NvOptimusEnablement = 1;
|
|
Log(L"Nvidia optimus detected, second adapter selected, ignoring useless second adapter, I guess.");
|
|
if(FAILED(factory->EnumAdapters1(adapterID, &adapter)))
|
|
CrashError(TEXT("Could not get DXGI adapter"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
D3D10System::D3D10System()
|
|
{
|
|
HRESULT err;
|
|
|
|
#ifdef USE_DXGI1_2
|
|
REFIID iidVal = OSGetVersion() >= 8 ? __uuidof(IDXGIFactory2) : __uuidof(IDXGIFactory1);
|
|
#else
|
|
REFIID iidVal = __uuidof(IDXGIFactory1);
|
|
#endif
|
|
|
|
UINT adapterID = GlobalConfig->GetInt(TEXT("Video"), TEXT("Adapter"), 0);
|
|
|
|
if(FAILED(err = CreateDXGIFactory1(iidVal, (void**)&factory)))
|
|
CrashError(TEXT("Could not create DXGI factory"));
|
|
|
|
UINT numAdapters = 0, i = 0;
|
|
IDXGIAdapter1 *giAdapter;
|
|
|
|
while (factory->EnumAdapters1(i++, &giAdapter) == S_OK)
|
|
{
|
|
numAdapters++;
|
|
giAdapter->Release();
|
|
}
|
|
|
|
if (adapterID >= numAdapters)
|
|
{
|
|
Log(TEXT("Invalid adapter id %d, only %d adapters on system. Resetting to 0."), adapterID, numAdapters);
|
|
GlobalConfig->SetInt(TEXT("Video"), TEXT("Adapter"), 0);
|
|
adapterID = 0;
|
|
}
|
|
|
|
IDXGIAdapter1 *adapter;
|
|
if(FAILED(err = factory->EnumAdapters1(adapterID, &adapter)))
|
|
CrashError(TEXT("Could not get DXGI adapter %d"), adapterID);
|
|
|
|
HandleNvidiaOptimus(factory, adapter, adapterID);
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
DXGI_SWAP_CHAIN_DESC swapDesc;
|
|
zero(&swapDesc, sizeof(swapDesc));
|
|
swapDesc.BufferCount = 2;
|
|
swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
swapDesc.BufferDesc.Width = App->renderFrameWidth;
|
|
swapDesc.BufferDesc.Height = App->renderFrameHeight;
|
|
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
swapDesc.OutputWindow = hwndRenderFrame;
|
|
swapDesc.SampleDesc.Count = 1;
|
|
swapDesc.Windowed = TRUE;
|
|
|
|
bDisableCompatibilityMode = 1;//AppConfig->GetInt(TEXT("Video"), TEXT("DisableD3DCompatibilityMode"), 1) != 0;
|
|
|
|
UINT createFlags = D3D10_CREATE_DEVICE_BGRA_SUPPORT;
|
|
if(GlobalConfig->GetInt(TEXT("General"), TEXT("UseDebugD3D")))
|
|
createFlags |= D3D10_CREATE_DEVICE_DEBUG;
|
|
|
|
D3D10_FEATURE_LEVEL1 level = bDisableCompatibilityMode ? D3D10_FEATURE_LEVEL_10_1 : D3D10_FEATURE_LEVEL_9_3;
|
|
|
|
String adapterName;
|
|
DXGI_ADAPTER_DESC desc;
|
|
if (adapter->GetDesc(&desc) == S_OK)
|
|
adapterName = desc.Description;
|
|
else
|
|
adapterName = TEXT("<unknown>");
|
|
|
|
adapterName.KillSpaces();
|
|
|
|
Log(TEXT("Loading up D3D10 on %s (Adapter %u)..."), adapterName.Array(), adapterID+1);
|
|
|
|
//D3D10_CREATE_DEVICE_DEBUG
|
|
//D3D11_DRIVER_TYPE_REFERENCE, D3D11_DRIVER_TYPE_HARDWARE
|
|
err = D3D10CreateDeviceAndSwapChain1(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, createFlags, level, D3D10_1_SDK_VERSION, &swapDesc, &swap, &d3d);
|
|
if(FAILED(err))
|
|
{
|
|
Log (TEXT("D3D10CreateDeviceAndSwapChain1: Failed on %s: 0x%08x. Trying compatibility mode"), adapterName.Array(), err);
|
|
|
|
bDisableCompatibilityMode = !bDisableCompatibilityMode;
|
|
level = bDisableCompatibilityMode ? D3D10_FEATURE_LEVEL_10_1 : D3D10_FEATURE_LEVEL_9_3;
|
|
err = D3D10CreateDeviceAndSwapChain1(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, createFlags, level, D3D10_1_SDK_VERSION, &swapDesc, &swap, &d3d);
|
|
}
|
|
|
|
if(FAILED(err))
|
|
{
|
|
Log (TEXT("D3D10CreateDeviceAndSwapChain1: Failed on %s: 0x%08x"), adapterName.Array(), err);
|
|
CrashError(TEXT("Could not initialize DirectX 10 on %s. This error can happen for one of the following reasons:\r\n\r\n1.) Your GPU is not supported (DirectX 10 is required - note that many integrated laptop GPUs do not support DX10)\r\n2.) You're running Windows Vista without the \"Platform Update\"\r\n3.) Your video card drivers are out of date\r\n\r\nIf you are using a laptop with NVIDIA Optimus or AMD Switchable Graphics, make sure OBS is set to run on the high performance GPU in your driver settings."), adapterName.Array());
|
|
}
|
|
|
|
adapter->Release();
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
D3D10_DEPTH_STENCIL_DESC depthDesc;
|
|
zero(&depthDesc, sizeof(depthDesc));
|
|
depthDesc.DepthEnable = FALSE;
|
|
|
|
err = d3d->CreateDepthStencilState(&depthDesc, &depthState);
|
|
if(FAILED(err))
|
|
CrashError(TEXT("Unable to create depth state"));
|
|
|
|
d3d->OMSetDepthStencilState(depthState, 0);
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
D3D10_RASTERIZER_DESC rasterizerDesc;
|
|
zero(&rasterizerDesc, sizeof(rasterizerDesc));
|
|
rasterizerDesc.FillMode = D3D10_FILL_SOLID;
|
|
rasterizerDesc.CullMode = D3D10_CULL_NONE;
|
|
rasterizerDesc.FrontCounterClockwise = FALSE;
|
|
rasterizerDesc.DepthClipEnable = TRUE;
|
|
|
|
err = d3d->CreateRasterizerState(&rasterizerDesc, &rasterizerState);
|
|
if(FAILED(err))
|
|
CrashError(TEXT("Unable to create rasterizer state"));
|
|
|
|
d3d->RSSetState(rasterizerState);
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
rasterizerDesc.ScissorEnable = TRUE;
|
|
|
|
err = d3d->CreateRasterizerState(&rasterizerDesc, &scissorState);
|
|
if(FAILED(err))
|
|
CrashError(TEXT("Unable to create scissor state"));
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
ID3D10Texture2D *backBuffer = NULL;
|
|
err = swap->GetBuffer(0, IID_ID3D10Texture2D, (void**)&backBuffer);
|
|
if(FAILED(err))
|
|
CrashError(TEXT("Unable to get back buffer from swap chain"));
|
|
|
|
err = d3d->CreateRenderTargetView(backBuffer, NULL, &swapRenderView);
|
|
if(FAILED(err))
|
|
CrashError(TEXT("Unable to get render view from back buffer"));
|
|
|
|
backBuffer->Release();
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
D3D10_BLEND_DESC disabledBlendDesc;
|
|
zero(&disabledBlendDesc, sizeof(disabledBlendDesc));
|
|
for(int i=0; i<8; i++)
|
|
{
|
|
disabledBlendDesc.BlendEnable[i] = TRUE;
|
|
disabledBlendDesc.RenderTargetWriteMask[i] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
|
}
|
|
disabledBlendDesc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
disabledBlendDesc.BlendOp = D3D10_BLEND_OP_ADD;
|
|
disabledBlendDesc.SrcBlendAlpha = D3D10_BLEND_ONE;
|
|
disabledBlendDesc.DestBlendAlpha = D3D10_BLEND_ZERO;
|
|
disabledBlendDesc.SrcBlend = D3D10_BLEND_ONE;
|
|
disabledBlendDesc.DestBlend = D3D10_BLEND_ZERO;
|
|
|
|
err = d3d->CreateBlendState(&disabledBlendDesc, &disabledBlend);
|
|
if(FAILED(err))
|
|
CrashError(TEXT("Unable to create disabled blend state"));
|
|
|
|
this->BlendFunction(GS_BLEND_SRCALPHA, GS_BLEND_INVSRCALPHA, 1.0f);
|
|
bBlendingEnabled = true;
|
|
}
|
|
|
|
D3D10System::~D3D10System()
|
|
{
|
|
delete spriteVertexBuffer;
|
|
delete boxVertexBuffer;
|
|
|
|
for(UINT i=0; i<blends.Num(); i++)
|
|
SafeRelease(blends[i].blendState);
|
|
|
|
SafeRelease(scissorState);
|
|
SafeRelease(rasterizerState);
|
|
SafeRelease(depthState);
|
|
SafeRelease(disabledBlend);
|
|
SafeRelease(swapRenderView);
|
|
SafeRelease(swap);
|
|
SafeRelease(d3d);
|
|
SafeRelease(factory);
|
|
}
|
|
|
|
void D3D10System::UnloadAllData()
|
|
{
|
|
LoadVertexShader(NULL);
|
|
LoadPixelShader(NULL);
|
|
LoadVertexBuffer(NULL);
|
|
for(UINT i=0; i<8; i++)
|
|
{
|
|
LoadSamplerState(NULL, i);
|
|
LoadTexture(NULL, i);
|
|
}
|
|
|
|
UINT zeroVal = 0;
|
|
LPVOID nullBuff[8];
|
|
float bla[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
|
|
|
zero(nullBuff, sizeof(nullBuff));
|
|
|
|
d3d->VSSetConstantBuffers(0, 1, (ID3D10Buffer**)nullBuff);
|
|
d3d->PSSetConstantBuffers(0, 1, (ID3D10Buffer**)nullBuff);
|
|
d3d->OMSetDepthStencilState(NULL, 0);
|
|
d3d->PSSetSamplers(0, 1, (ID3D10SamplerState**)nullBuff);
|
|
d3d->OMSetBlendState(NULL, bla, 0xFFFFFFFF);
|
|
d3d->OMSetRenderTargets(1, (ID3D10RenderTargetView**)nullBuff, NULL);
|
|
d3d->IASetVertexBuffers(0, 8, (ID3D10Buffer**)nullBuff, &zeroVal, &zeroVal);
|
|
d3d->PSSetShaderResources(0, 8, (ID3D10ShaderResourceView**)nullBuff);
|
|
d3d->IASetInputLayout(NULL);
|
|
d3d->PSSetShader(NULL);
|
|
d3d->VSSetShader(NULL);
|
|
d3d->RSSetState(NULL);
|
|
d3d->RSSetScissorRects(0, NULL);
|
|
}
|
|
|
|
LPVOID D3D10System::GetDevice()
|
|
{
|
|
return (LPVOID)d3d;
|
|
}
|
|
|
|
|
|
void D3D10System::Init()
|
|
{
|
|
VBData *data = new VBData;
|
|
data->UVList.SetSize(1);
|
|
|
|
data->VertList.SetSize(4);
|
|
data->UVList[0].SetSize(4);
|
|
|
|
spriteVertexBuffer = CreateVertexBuffer(data, FALSE);
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
data = new VBData;
|
|
data->VertList.SetSize(5);
|
|
boxVertexBuffer = CreateVertexBuffer(data, FALSE);
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
GraphicsSystem::Init();
|
|
}
|
|
|
|
|
|
////////////////////////////
|
|
//Texture Functions
|
|
Texture* D3D10System::CreateTextureFromSharedHandle(unsigned int width, unsigned int height, HANDLE handle)
|
|
{
|
|
return D3D10Texture::CreateFromSharedHandle(width, height, handle);
|
|
}
|
|
|
|
Texture* D3D10System::CreateSharedTexture(unsigned int width, unsigned int height)
|
|
{
|
|
return D3D10Texture::CreateShared(width, height);
|
|
}
|
|
|
|
Texture* D3D10System::CreateTexture(unsigned int width, unsigned int height, GSColorFormat colorFormat, void *lpData, BOOL bBuildMipMaps, BOOL bStatic)
|
|
{
|
|
return D3D10Texture::CreateTexture(width, height, colorFormat, lpData, bBuildMipMaps, bStatic);
|
|
}
|
|
|
|
Texture* D3D10System::CreateTextureFromFile(CTSTR lpFile, BOOL bBuildMipMaps)
|
|
{
|
|
return D3D10Texture::CreateFromFile(lpFile, bBuildMipMaps);
|
|
}
|
|
|
|
Texture* D3D10System::CreateRenderTarget(unsigned int width, unsigned int height, GSColorFormat colorFormat, BOOL bGenMipMaps)
|
|
{
|
|
return D3D10Texture::CreateRenderTarget(width, height, colorFormat, bGenMipMaps);
|
|
}
|
|
|
|
Texture* D3D10System::CreateGDITexture(unsigned int width, unsigned int height)
|
|
{
|
|
return D3D10Texture::CreateGDITexture(width, height);
|
|
}
|
|
|
|
bool D3D10System::GetTextureFileInfo(CTSTR lpFile, TextureInfo &info)
|
|
{
|
|
D3DX10_IMAGE_INFO ii;
|
|
if(SUCCEEDED(D3DX10GetImageInfoFromFile(lpFile, NULL, &ii, NULL)))
|
|
{
|
|
info.width = ii.Width;
|
|
info.height = ii.Height;
|
|
switch(ii.Format)
|
|
{
|
|
case DXGI_FORMAT_A8_UNORM: info.type = GS_ALPHA; break;
|
|
case DXGI_FORMAT_R8_UNORM: info.type = GS_GRAYSCALE; break;
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM: info.type = GS_BGR; break;
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM: info.type = GS_BGRA; break;
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM: info.type = GS_RGBA; break;
|
|
case DXGI_FORMAT_R16G16B16A16_FLOAT: info.type = GS_RGBA16F; break;
|
|
case DXGI_FORMAT_R32G32B32A32_FLOAT: info.type = GS_RGBA32F; break;
|
|
case DXGI_FORMAT_BC1_UNORM: info.type = GS_DXT1; break;
|
|
case DXGI_FORMAT_BC2_UNORM: info.type = GS_DXT3; break;
|
|
case DXGI_FORMAT_BC3_UNORM: info.type = GS_DXT5; break;
|
|
default:
|
|
info.type = GS_UNKNOWNFORMAT;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
SamplerState* D3D10System::CreateSamplerState(SamplerInfo &info)
|
|
{
|
|
return D3D10SamplerState::CreateSamplerState(info);
|
|
}
|
|
|
|
|
|
UINT D3D10System::GetNumOutputs()
|
|
{
|
|
UINT count = 0;
|
|
|
|
IDXGIDevice *device;
|
|
if(SUCCEEDED(d3d->QueryInterface(__uuidof(IDXGIDevice), (void**)&device)))
|
|
{
|
|
IDXGIAdapter *adapter;
|
|
if(SUCCEEDED(device->GetAdapter(&adapter)))
|
|
{
|
|
IDXGIOutput *outputInterface;
|
|
|
|
while(SUCCEEDED(adapter->EnumOutputs(count, &outputInterface)))
|
|
{
|
|
count++;
|
|
outputInterface->Release();
|
|
}
|
|
|
|
adapter->Release();
|
|
}
|
|
|
|
device->Release();
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
OutputDuplicator *D3D10System::CreateOutputDuplicator(UINT outputID)
|
|
{
|
|
D3D10OutputDuplicator *duplicator = new D3D10OutputDuplicator;
|
|
if(duplicator->Init(outputID))
|
|
return duplicator;
|
|
|
|
delete duplicator;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
////////////////////////////
|
|
//Shader Functions
|
|
Shader* D3D10System::CreateVertexShaderFromBlob(ShaderBlob const &blob, CTSTR lpShader, CTSTR lpFileName)
|
|
{
|
|
return D3D10VertexShader::CreateVertexShaderFromBlob(blob, lpShader, lpFileName);
|
|
}
|
|
|
|
Shader* D3D10System::CreatePixelShaderFromBlob(ShaderBlob const &blob, CTSTR lpShader, CTSTR lpFileName)
|
|
{
|
|
return D3D10PixelShader::CreatePixelShaderFromBlob(blob, lpShader, lpFileName);
|
|
}
|
|
|
|
Shader* D3D10System::CreateVertexShader(CTSTR lpShader, CTSTR lpFileName)
|
|
{
|
|
return D3D10VertexShader::CreateVertexShader(lpShader, lpFileName);
|
|
}
|
|
|
|
Shader* D3D10System::CreatePixelShader(CTSTR lpShader, CTSTR lpFileName)
|
|
{
|
|
return D3D10PixelShader::CreatePixelShader(lpShader, lpFileName);
|
|
}
|
|
|
|
void D3D10System::CreateVertexShaderBlob(ShaderBlob &blob, CTSTR lpShader, CTSTR lpFileName)
|
|
{
|
|
D3D10VertexShader::CreateVertexShaderBlob(blob, lpShader, lpFileName);
|
|
}
|
|
|
|
void D3D10System::CreatePixelShaderBlob(ShaderBlob &blob, CTSTR lpShader, CTSTR lpFileName)
|
|
{
|
|
D3D10PixelShader::CreatePixelShaderBlob(blob, lpShader, lpFileName);
|
|
}
|
|
|
|
|
|
////////////////////////////
|
|
//Vertex Buffer Functions
|
|
VertexBuffer* D3D10System::CreateVertexBuffer(VBData *vbData, BOOL bStatic)
|
|
{
|
|
return D3D10VertexBuffer::CreateVertexBuffer(vbData, bStatic);
|
|
}
|
|
|
|
|
|
////////////////////////////
|
|
//Main Rendering Functions
|
|
void D3D10System::LoadVertexBuffer(VertexBuffer* vb)
|
|
{
|
|
if(vb != curVertexBuffer)
|
|
{
|
|
D3D10VertexBuffer *d3dVB = static_cast<D3D10VertexBuffer*>(vb);
|
|
if(curVertexShader)
|
|
{
|
|
List<ID3D10Buffer*> buffers;
|
|
List<UINT> strides;
|
|
List<UINT> offsets;
|
|
|
|
if(d3dVB)
|
|
d3dVB->MakeBufferList(curVertexShader, buffers, strides);
|
|
else
|
|
{
|
|
UINT nBuffersToClear = curVertexShader->NumBuffersExpected();
|
|
buffers.SetSize(nBuffersToClear);
|
|
strides.SetSize(nBuffersToClear);
|
|
}
|
|
|
|
offsets.SetSize(buffers.Num());
|
|
d3d->IASetVertexBuffers(0, buffers.Num(), buffers.Array(), strides.Array(), offsets.Array());
|
|
}
|
|
|
|
curVertexBuffer = d3dVB;
|
|
}
|
|
}
|
|
|
|
void D3D10System::LoadTexture(Texture *texture, UINT idTexture)
|
|
{
|
|
if(curTextures[idTexture] != texture)
|
|
{
|
|
D3D10Texture *d3dTex = static_cast<D3D10Texture*>(texture);
|
|
if(d3dTex)
|
|
d3d->PSSetShaderResources(idTexture, 1, &d3dTex->resource);
|
|
else
|
|
{
|
|
LPVOID lpNull = NULL;
|
|
d3d->PSSetShaderResources(idTexture, 1, (ID3D10ShaderResourceView**)&lpNull);
|
|
}
|
|
|
|
curTextures[idTexture] = d3dTex;
|
|
}
|
|
}
|
|
|
|
void D3D10System::LoadSamplerState(SamplerState *sampler, UINT idSampler)
|
|
{
|
|
if(curSamplers[idSampler] != sampler)
|
|
{
|
|
D3D10SamplerState *d3dSampler = static_cast<D3D10SamplerState*>(sampler);
|
|
if(d3dSampler)
|
|
d3d->PSSetSamplers(idSampler, 1, &d3dSampler->state);
|
|
else
|
|
{
|
|
LPVOID lpNull = NULL;
|
|
d3d->PSSetSamplers(idSampler, 1, (ID3D10SamplerState**)&lpNull);
|
|
}
|
|
curSamplers[idSampler] = d3dSampler;
|
|
}
|
|
}
|
|
|
|
void D3D10System::LoadVertexShader(Shader *vShader)
|
|
{
|
|
if(curVertexShader != vShader)
|
|
{
|
|
if(vShader)
|
|
{
|
|
D3D10VertexBuffer *lastVertexBuffer = curVertexBuffer;
|
|
if(curVertexBuffer)
|
|
LoadVertexBuffer(NULL);
|
|
|
|
D3D10VertexShader *shader = static_cast<D3D10VertexShader*>(vShader);
|
|
|
|
d3d->VSSetShader(shader->vertexShader);
|
|
d3d->IASetInputLayout(shader->inputLayout);
|
|
d3d->VSSetConstantBuffers(0, 1, &shader->constantBuffer);
|
|
|
|
if(lastVertexBuffer)
|
|
LoadVertexBuffer(lastVertexBuffer);
|
|
}
|
|
else
|
|
{
|
|
LPVOID lpNULL = NULL;
|
|
|
|
d3d->VSSetShader(NULL);
|
|
d3d->VSSetConstantBuffers(0, 1, (ID3D10Buffer**)&lpNULL);
|
|
}
|
|
|
|
curVertexShader = static_cast<D3D10VertexShader*>(vShader);
|
|
}
|
|
}
|
|
|
|
void D3D10System::LoadPixelShader(Shader *pShader)
|
|
{
|
|
if(curPixelShader != pShader)
|
|
{
|
|
if(pShader)
|
|
{
|
|
D3D10PixelShader *shader = static_cast<D3D10PixelShader*>(pShader);
|
|
|
|
d3d->PSSetShader(shader->pixelShader);
|
|
d3d->PSSetConstantBuffers(0, 1, &shader->constantBuffer);
|
|
|
|
for(UINT i=0; i<shader->Samplers.Num(); i++)
|
|
LoadSamplerState(shader->Samplers[i].sampler, i);
|
|
}
|
|
else
|
|
{
|
|
LPVOID lpNULL = NULL;
|
|
|
|
d3d->PSSetShader(NULL);
|
|
d3d->PSSetConstantBuffers(0, 1, (ID3D10Buffer**)&lpNULL);
|
|
|
|
for(UINT i=0; i<8; i++)
|
|
curSamplers[i] = NULL;
|
|
|
|
ID3D10SamplerState *states[8];
|
|
zero(states, sizeof(states));
|
|
d3d->PSSetSamplers(0, 8, states);
|
|
}
|
|
|
|
curPixelShader = static_cast<D3D10PixelShader*>(pShader);
|
|
}
|
|
}
|
|
|
|
Shader* D3D10System::GetCurrentPixelShader()
|
|
{
|
|
return curPixelShader;
|
|
}
|
|
|
|
Shader* D3D10System::GetCurrentVertexShader()
|
|
{
|
|
return curVertexShader;
|
|
}
|
|
|
|
void D3D10System::SetRenderTarget(Texture *texture)
|
|
{
|
|
if(curRenderTarget != texture)
|
|
{
|
|
if(texture)
|
|
{
|
|
ID3D10RenderTargetView *view = static_cast<D3D10Texture*>(texture)->renderTarget;
|
|
if(!view)
|
|
{
|
|
AppWarning(TEXT("tried to set a texture that wasn't a render target as a render target"));
|
|
return;
|
|
}
|
|
|
|
d3d->OMSetRenderTargets(1, &view, NULL);
|
|
}
|
|
else
|
|
d3d->OMSetRenderTargets(1, &swapRenderView, NULL);
|
|
|
|
curRenderTarget = static_cast<D3D10Texture*>(texture);
|
|
}
|
|
}
|
|
|
|
const D3D10_PRIMITIVE_TOPOLOGY topologies[] = {D3D10_PRIMITIVE_TOPOLOGY_POINTLIST, D3D10_PRIMITIVE_TOPOLOGY_LINELIST, D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP, D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST, D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP};
|
|
|
|
void D3D10System::Draw(GSDrawMode drawMode, DWORD startVert, DWORD nVerts)
|
|
{
|
|
if(!curVertexBuffer)
|
|
{
|
|
AppWarning(TEXT("Tried to call draw without setting a vertex buffer"));
|
|
return;
|
|
}
|
|
|
|
if(!curVertexShader)
|
|
{
|
|
AppWarning(TEXT("Tried to call draw without setting a vertex shader"));
|
|
return;
|
|
}
|
|
|
|
if(!curPixelShader)
|
|
{
|
|
AppWarning(TEXT("Tried to call draw without setting a pixel shader"));
|
|
return;
|
|
}
|
|
|
|
curVertexShader->SetMatrix(curVertexShader->GetViewProj(), curViewProjMatrix);
|
|
|
|
curVertexShader->UpdateParams();
|
|
curPixelShader->UpdateParams();
|
|
|
|
D3D10_PRIMITIVE_TOPOLOGY newTopology = topologies[(int)drawMode];
|
|
if(newTopology != curTopology)
|
|
{
|
|
d3d->IASetPrimitiveTopology(newTopology);
|
|
curTopology = newTopology;
|
|
}
|
|
|
|
if(nVerts == 0)
|
|
nVerts = static_cast<D3D10VertexBuffer*>(curVertexBuffer)->numVerts;
|
|
|
|
d3d->Draw(nVerts, startVert);
|
|
}
|
|
|
|
|
|
////////////////////////////
|
|
//Drawing mode functions
|
|
|
|
const D3D10_BLEND blendConvert[] = {D3D10_BLEND_ZERO, D3D10_BLEND_ONE, D3D10_BLEND_SRC_COLOR, D3D10_BLEND_INV_SRC_COLOR, D3D10_BLEND_SRC_ALPHA, D3D10_BLEND_INV_SRC_ALPHA, D3D10_BLEND_DEST_COLOR, D3D10_BLEND_INV_DEST_COLOR, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_INV_DEST_ALPHA, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_INV_BLEND_FACTOR};
|
|
|
|
void D3D10System::EnableBlending(BOOL bEnable)
|
|
{
|
|
if(bBlendingEnabled != bEnable)
|
|
{
|
|
if(bBlendingEnabled = bEnable)
|
|
d3d->OMSetBlendState(curBlendState, curBlendFactor, 0xFFFFFFFF);
|
|
else
|
|
d3d->OMSetBlendState(disabledBlend, curBlendFactor, 0xFFFFFFFF);
|
|
}
|
|
}
|
|
|
|
void D3D10System::BlendFunction(GSBlendType srcFactor, GSBlendType destFactor, float fFactor)
|
|
{
|
|
bool bUseFactor = (srcFactor >= GS_BLEND_FACTOR || destFactor >= GS_BLEND_FACTOR);
|
|
|
|
if(bUseFactor)
|
|
curBlendFactor[0] = curBlendFactor[1] = curBlendFactor[2] = curBlendFactor[3] = fFactor;
|
|
|
|
for(UINT i=0; i<blends.Num(); i++)
|
|
{
|
|
SavedBlendState &blendInfo = blends[i];
|
|
if(blendInfo.srcFactor == srcFactor && blendInfo.destFactor == destFactor)
|
|
{
|
|
if(bUseFactor || curBlendState != blendInfo.blendState)
|
|
{
|
|
d3d->OMSetBlendState(blendInfo.blendState, curBlendFactor, 0xFFFFFFFF);
|
|
curBlendState = blendInfo.blendState;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
//blend wasn't found, create a new one and save it for later
|
|
D3D10_BLEND_DESC blendDesc;
|
|
zero(&blendDesc, sizeof(blendDesc));
|
|
for(int i=0; i<8; i++)
|
|
{
|
|
blendDesc.BlendEnable[i] = TRUE;
|
|
blendDesc.RenderTargetWriteMask[i] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
|
}
|
|
blendDesc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
blendDesc.BlendOp = D3D10_BLEND_OP_ADD;
|
|
blendDesc.SrcBlendAlpha = D3D10_BLEND_ONE;
|
|
blendDesc.DestBlendAlpha = D3D10_BLEND_ZERO;
|
|
blendDesc.SrcBlend = blendConvert[srcFactor];
|
|
blendDesc.DestBlend = blendConvert[destFactor];
|
|
|
|
SavedBlendState *savedBlend = blends.CreateNew();
|
|
savedBlend->destFactor = destFactor;
|
|
savedBlend->srcFactor = srcFactor;
|
|
|
|
if(FAILED(d3d->CreateBlendState(&blendDesc, &savedBlend->blendState)))
|
|
CrashError(TEXT("Could not set blend state"));
|
|
|
|
if(bBlendingEnabled)
|
|
d3d->OMSetBlendState(savedBlend->blendState, curBlendFactor, 0xFFFFFFFF);
|
|
|
|
curBlendState = savedBlend->blendState;
|
|
}
|
|
|
|
void D3D10System::ClearColorBuffer(DWORD color)
|
|
{
|
|
Color4 floatColor;
|
|
floatColor.MakeFromRGBA(color);
|
|
|
|
D3D10Texture *d3dTex = static_cast<D3D10Texture*>(curRenderTarget);
|
|
if(d3dTex)
|
|
d3d->ClearRenderTargetView(d3dTex->renderTarget, floatColor.ptr);
|
|
else
|
|
d3d->ClearRenderTargetView(swapRenderView, floatColor.ptr);
|
|
}
|
|
|
|
|
|
////////////////////////////
|
|
//Other Functions
|
|
void D3D10System::Ortho(float left, float right, float top, float bottom, float znear, float zfar)
|
|
{
|
|
Matrix4x4Ortho(curProjMatrix, left, right, top, bottom, znear, zfar);
|
|
ResetViewMatrix();
|
|
}
|
|
|
|
void D3D10System::Frustum(float left, float right, float top, float bottom, float znear, float zfar)
|
|
{
|
|
Matrix4x4Frustum(curProjMatrix, left, right, top, bottom, znear, zfar);
|
|
ResetViewMatrix();
|
|
}
|
|
|
|
|
|
void D3D10System::SetViewport(float x, float y, float width, float height)
|
|
{
|
|
D3D10_VIEWPORT vp;
|
|
zero(&vp, sizeof(vp));
|
|
vp.MaxDepth = 1.0f;
|
|
vp.TopLeftX = INT(x);
|
|
vp.TopLeftY = INT(y);
|
|
vp.Width = UINT(width);
|
|
vp.Height = UINT(height);
|
|
d3d->RSSetViewports(1, &vp);
|
|
}
|
|
|
|
void D3D10System::SetScissorRect(XRect *pRect)
|
|
{
|
|
if(pRect)
|
|
{
|
|
d3d->RSSetState(scissorState);
|
|
D3D10_RECT rc = {pRect->x, pRect->y, pRect->x+pRect->cx, pRect->y+pRect->cy};
|
|
d3d->RSSetScissorRects(1, &rc);
|
|
}
|
|
else
|
|
{
|
|
d3d->RSSetState(rasterizerState);
|
|
d3d->RSSetScissorRects(0, NULL);
|
|
}
|
|
}
|
|
|
|
//(jim) hey, I changed this to x, y, x2, y2
|
|
void D3D10System::SetCropping(float left, float top, float right, float bottom)
|
|
{
|
|
curCropping[0] = left;
|
|
curCropping[1] = top;
|
|
curCropping[2] = right;
|
|
curCropping[3] = bottom;
|
|
}
|
|
|
|
void D3D10System::DrawSpriteEx(Texture *texture, DWORD color, float x, float y, float x2, float y2, float u, float v, float u2, float v2)
|
|
{
|
|
DrawSpriteExRotate(texture, color, x, y, x2, y2, 0.0f, u, v, u2, v2, 0.0f);
|
|
}
|
|
|
|
void D3D10System::DrawSpriteExRotate(Texture *texture, DWORD color, float x, float y, float x2, float y2, float degrees, float u, float v, float u2, float v2, float texDegrees)
|
|
{
|
|
if(!curPixelShader)
|
|
return;
|
|
|
|
if(!texture)
|
|
{
|
|
AppWarning(TEXT("Trying to draw a sprite with a NULL texture"));
|
|
return;
|
|
}
|
|
|
|
HANDLE hColor = curPixelShader->GetParameterByName(TEXT("outputColor"));
|
|
|
|
if(hColor)
|
|
curPixelShader->SetColor(hColor, color);
|
|
|
|
//------------------------------
|
|
// crop positional values
|
|
|
|
Vect2 totalSize = Vect2(x2-x, y2-y);
|
|
Vect2 invMult = Vect2(totalSize.x < 0.0f ? -1.0f : 1.0f, totalSize.y < 0.0f ? -1.0f : 1.0f);
|
|
totalSize.Abs();
|
|
|
|
if(y2-y < 0) {
|
|
float tempFloat = curCropping[1];
|
|
curCropping[1] = curCropping[3];
|
|
curCropping[3] = tempFloat;
|
|
}
|
|
|
|
if(x2-x < 0) {
|
|
float tempFloat = curCropping[0];
|
|
curCropping[0] = curCropping[2];
|
|
curCropping[2] = tempFloat;
|
|
}
|
|
|
|
bool bFlipX = (x2 - x) < 0.0f;
|
|
bool bFlipY = (y2 - y) < 0.0f;
|
|
|
|
x += curCropping[0] * invMult.x;
|
|
y += curCropping[1] * invMult.y;
|
|
x2 -= curCropping[2] * invMult.x;
|
|
y2 -= curCropping[3] * invMult.y;
|
|
|
|
bool cropXUnder = bFlipX ? ((x - x2) < 0.0f) : ((x2 - x) < 0.0f);
|
|
bool cropYUnder = bFlipY ? ((y - y2) < 0.0f) : ((y2 - y) < 0.0f);
|
|
|
|
// cropped out completely (eg mouse cursor texture)
|
|
if (cropXUnder || cropYUnder)
|
|
return;
|
|
|
|
//------------------------------
|
|
// crop texture coordinate values
|
|
|
|
float cropMult[4];
|
|
cropMult[0] = curCropping[0]/totalSize.x;
|
|
cropMult[1] = curCropping[1]/totalSize.y;
|
|
cropMult[2] = curCropping[2]/totalSize.x;
|
|
cropMult[3] = curCropping[3]/totalSize.y;
|
|
|
|
Vect2 totalUVSize = Vect2(u2-u, v2-v);
|
|
u += cropMult[0] * totalUVSize.x;
|
|
v += cropMult[1] * totalUVSize.y;
|
|
u2 -= cropMult[2] * totalUVSize.x;
|
|
v2 -= cropMult[3] * totalUVSize.y;
|
|
|
|
//------------------------------
|
|
// draw
|
|
|
|
VBData *data = spriteVertexBuffer->GetData();
|
|
data->VertList[0].Set(x, y, 0.0f);
|
|
data->VertList[1].Set(x, y2, 0.0f);
|
|
data->VertList[2].Set(x2, y, 0.0f);
|
|
data->VertList[3].Set(x2, y2, 0.0f);
|
|
|
|
if (!CloseFloat(degrees, 0.0f)) {
|
|
List<Vect> &coords = data->VertList;
|
|
|
|
Vect2 center(x+totalSize.x/2, y+totalSize.y/2);
|
|
|
|
Matrix rotMatrix;
|
|
rotMatrix.SetIdentity();
|
|
rotMatrix.Rotate(AxisAngle(0.0f, 0.0f, 1.0f, RAD(degrees)));
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
Vect val = coords[i]-Vect(center);
|
|
val.TransformVector(rotMatrix);
|
|
coords[i] = val;
|
|
coords[i] += Vect(center);
|
|
}
|
|
}
|
|
|
|
List<UVCoord> &coords = data->UVList[0];
|
|
coords[0].Set(u, v);
|
|
coords[1].Set(u, v2);
|
|
coords[2].Set(u2, v);
|
|
coords[3].Set(u2, v2);
|
|
|
|
if (!CloseFloat(texDegrees, 0.0f)) {
|
|
Matrix rotMatrix;
|
|
rotMatrix.SetIdentity();
|
|
rotMatrix.Rotate(AxisAngle(0.0f, 0.0f, 1.0f, -RAD(texDegrees)));
|
|
|
|
Vect2 minVal = Vect2(0.0f, 0.0f);
|
|
for (int i = 0; i < 4; i++) {
|
|
Vect val = Vect(coords[i]);
|
|
val.TransformVector(rotMatrix);
|
|
coords[i] = val;
|
|
minVal.ClampMax(coords[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
coords[i] -= minVal;
|
|
}
|
|
|
|
spriteVertexBuffer->FlushBuffers();
|
|
|
|
LoadVertexBuffer(spriteVertexBuffer);
|
|
LoadTexture(texture);
|
|
|
|
Draw(GS_TRIANGLESTRIP);
|
|
}
|
|
|
|
void D3D10System::DrawBox(const Vect2 &upperLeft, const Vect2 &size)
|
|
{
|
|
VBData *data = boxVertexBuffer->GetData();
|
|
|
|
Vect2 bottomRight = upperLeft+size;
|
|
|
|
data->VertList[0] = upperLeft;
|
|
data->VertList[1].Set(bottomRight.x, upperLeft.y);
|
|
data->VertList[2].Set(bottomRight.x, bottomRight.y);
|
|
data->VertList[3].Set(upperLeft.x, bottomRight.y);
|
|
data->VertList[4] = upperLeft;
|
|
|
|
boxVertexBuffer->FlushBuffers();
|
|
|
|
LoadVertexBuffer(boxVertexBuffer);
|
|
|
|
Draw(GS_LINESTRIP);
|
|
}
|
|
|
|
void D3D10System::ResetViewMatrix()
|
|
{
|
|
Matrix4x4Convert(curViewMatrix, MatrixStack[curMatrix].GetTranspose());
|
|
Matrix4x4Multiply(curViewProjMatrix, curViewMatrix, curProjMatrix);
|
|
Matrix4x4Transpose(curViewProjMatrix, curViewProjMatrix);
|
|
}
|
|
|
|
void D3D10System::ResizeView()
|
|
{
|
|
LPVOID nullVal = NULL;
|
|
d3d->OMSetRenderTargets(1, (ID3D10RenderTargetView**)&nullVal, NULL);
|
|
|
|
SafeRelease(swapRenderView);
|
|
|
|
swap->ResizeBuffers(2, 0, 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
|
|
|
|
ID3D10Texture2D *backBuffer = NULL;
|
|
HRESULT err = swap->GetBuffer(0, IID_ID3D10Texture2D, (void**)&backBuffer);
|
|
if(FAILED(err))
|
|
CrashError(TEXT("Unable to get back buffer from swap chain"));
|
|
|
|
err = d3d->CreateRenderTargetView(backBuffer, NULL, &swapRenderView);
|
|
if(FAILED(err))
|
|
CrashError(TEXT("Unable to get render view from back buffer"));
|
|
|
|
backBuffer->Release();
|
|
}
|
|
|
|
void D3D10System::CopyTexture(Texture *texDest, Texture *texSrc)
|
|
{
|
|
D3D10Texture *d3d10Dest = static_cast<D3D10Texture*>(texDest);
|
|
D3D10Texture *d3d10Src = static_cast<D3D10Texture*>(texSrc);
|
|
|
|
d3d->CopyResource(d3d10Dest->texture, d3d10Src->texture);
|
|
}
|