Windows: Link debug build against debug wiiuse. Can't keep linking to the release...
[dolphin.git] / Source / Plugins / Plugin_VideoDX11 / Src / GfxState.cpp
blob1138e10f1359fc71e254ed17a46672fb87382302
1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
18 #include "VideoConfig.h"
19 #include "GfxState.h"
21 namespace D3D
24 EmuGfxState* gfxstate;
25 StateManager* stateman;
27 EmuGfxState::EmuGfxState() : vertexshader(NULL), vsbytecode(NULL), pixelshader(NULL), psbytecode(NULL), apply_called(false)
29 for (unsigned int k = 0;k < 8;k++)
31 float border[4] = {0.f, 0.f, 0.f, 0.f};
32 shader_resources[k] = NULL;
33 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);
34 if(g_ActiveConfig.iMaxAnisotropy > 1) samplerdesc[k].Filter = D3D11_FILTER_ANISOTROPIC;
37 m_useDstAlpha = false;
39 memset(&blenddesc, 0, sizeof(blenddesc));
40 blenddesc.AlphaToCoverageEnable = FALSE;
41 blenddesc.IndependentBlendEnable = FALSE;
42 blenddesc.RenderTarget[0].BlendEnable = FALSE;
43 blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
44 blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
45 blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
46 blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
47 blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
48 blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
49 blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
51 memset(&depthdesc, 0, sizeof(depthdesc));
52 depthdesc.DepthEnable = TRUE;
53 depthdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
54 depthdesc.DepthFunc = D3D11_COMPARISON_LESS;
55 depthdesc.StencilEnable = FALSE;
56 depthdesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
57 depthdesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
59 // this probably must be changed once multisampling support gets added
60 rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0, false, true, false, false);
62 pscbuf = NULL;
63 vscbuf = NULL;
64 vshaderchanged = false;
65 inp_layout = NULL;
66 num_inp_elems = 0;
68 pscbufchanged = false;
69 vscbufchanged = false;
72 EmuGfxState::~EmuGfxState()
74 for (unsigned int k = 0;k < 8;k++)
75 SAFE_RELEASE(shader_resources[k]);
77 SAFE_RELEASE(vsbytecode);
78 SAFE_RELEASE(psbytecode);
79 SAFE_RELEASE(vertexshader);
80 SAFE_RELEASE(pixelshader);
82 SAFE_RELEASE(pscbuf);
83 SAFE_RELEASE(vscbuf);
85 SAFE_RELEASE(inp_layout);
88 // TODO: No need to store the whole bytecode, signature might be enough (?)
89 void EmuGfxState::SetVShader(ID3D11VertexShader* shader, D3DBlob* bcode)
91 // TODO: vshaderchanged actually just needs to be true if the signature changed
92 if (bcode && vsbytecode != bcode) vshaderchanged = true;
93 SAFE_RELEASE(vsbytecode);
94 SAFE_RELEASE(vertexshader);
96 if (shader && bcode)
98 vertexshader = shader;
99 shader->AddRef();
100 vsbytecode = bcode;
101 bcode->AddRef();
103 else if (shader || bcode)
105 PanicAlert("Invalid parameters!\n");
109 void EmuGfxState::SetPShader(ID3D11PixelShader* shader)
111 if (pixelshader) pixelshader->Release();
112 pixelshader = shader;
113 if (shader) shader->AddRef();
116 void EmuGfxState::SetInputElements(const D3D11_INPUT_ELEMENT_DESC* elems, UINT num)
118 num_inp_elems = num;
119 memcpy(inp_elems, elems, num*sizeof(D3D11_INPUT_ELEMENT_DESC));
122 void EmuGfxState::SetShaderResource(unsigned int stage, ID3D11ShaderResourceView* srv)
124 if (shader_resources[stage]) shader_resources[stage]->Release();
125 shader_resources[stage] = srv;
126 if (srv) srv->AddRef();
129 void EmuGfxState::ApplyState()
131 HRESULT hr;
133 // input layout (only needs to be updated if the vertex shader signature changed)
134 if (vshaderchanged)
136 SAFE_RELEASE(inp_layout);
137 hr = D3D::device->CreateInputLayout(inp_elems, num_inp_elems, vsbytecode->Data(), vsbytecode->Size(), &inp_layout);
138 if (FAILED(hr)) PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
139 SetDebugObjectName((ID3D11DeviceChild*)inp_layout, "an input layout of EmuGfxState");
140 vshaderchanged = false;
142 D3D::context->IASetInputLayout(inp_layout);
144 // vertex shader
145 // TODO: divide the global variables of the generated shaders into about 5 constant buffers
146 // TODO: improve interaction between EmuGfxState and global state management, so that we don't need to set the constant buffers every time
147 if (!vscbuf)
149 unsigned int size = ((sizeof(vsconstants))&(~0xf))+0x10; // must be a multiple of 16
150 D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(size, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
151 hr = device->CreateBuffer(&cbdesc, NULL, &vscbuf);
152 CHECK(hr==S_OK, "Create vertex shader constant buffer (size=%u)", size);
153 SetDebugObjectName((ID3D11DeviceChild*)vscbuf, "a vertex shader constant buffer of EmuGfxState");
155 if (vscbufchanged)
157 D3D11_MAPPED_SUBRESOURCE map;
158 context->Map(vscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
159 memcpy(map.pData, vsconstants, sizeof(vsconstants));
160 context->Unmap(vscbuf, 0);
162 D3D::context->VSSetConstantBuffers(0, 1, &vscbuf);
164 // pixel shader
165 if (!pscbuf)
167 unsigned int size = ((sizeof(psconstants))&(~0xf))+0x10; // must be a multiple of 16
168 D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(size, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
169 device->CreateBuffer(&cbdesc, NULL, &pscbuf);
170 CHECK(hr==S_OK, "Create pixel shader constant buffer (size=%u)", size);
171 SetDebugObjectName((ID3D11DeviceChild*)pscbuf, "a pixel shader constant buffer of EmuGfxState");
173 if (pscbufchanged)
175 D3D11_MAPPED_SUBRESOURCE map;
176 context->Map(pscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
177 memcpy(map.pData, psconstants, sizeof(psconstants));
178 context->Unmap(pscbuf, 0);
179 pscbufchanged = false;
181 D3D::context->PSSetConstantBuffers(0, 1, &pscbuf);
183 ID3D11SamplerState* samplerstate[8];
184 for (unsigned int stage = 0; stage < 8; stage++)
186 if (shader_resources[stage])
188 if(g_ActiveConfig.iMaxAnisotropy > 1) samplerdesc[stage].Filter = D3D11_FILTER_ANISOTROPIC;
189 hr = D3D::device->CreateSamplerState(&samplerdesc[stage], &samplerstate[stage]);
190 if (FAILED(hr)) PanicAlert("Fail %s %d, stage=%d\n", __FILE__, __LINE__, stage);
191 else SetDebugObjectName((ID3D11DeviceChild*)samplerstate[stage], "a sampler state of EmuGfxState");
193 else samplerstate[stage] = NULL;
195 D3D::context->PSSetSamplers(0, 8, samplerstate);
196 for (unsigned int stage = 0; stage < 8; stage++)
197 SAFE_RELEASE(samplerstate[stage]);
199 ID3D11BlendState* blstate;
200 hr = device->CreateBlendState(&blenddesc, &blstate);
201 if (FAILED(hr)) PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__);
202 stateman->PushBlendState(blstate);
203 SetDebugObjectName((ID3D11DeviceChild*)blstate, "a blend state of EmuGfxState");
204 SAFE_RELEASE(blstate);
206 rastdesc.FillMode = (g_ActiveConfig.bWireFrame) ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID;
207 ID3D11RasterizerState* raststate;
208 hr = device->CreateRasterizerState(&rastdesc, &raststate);
209 if (FAILED(hr)) PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__);
210 SetDebugObjectName((ID3D11DeviceChild*)raststate, "a rasterizer state of EmuGfxState");
211 stateman->PushRasterizerState(raststate);
212 SAFE_RELEASE(raststate);
214 ID3D11DepthStencilState* depth_state;
215 hr = device->CreateDepthStencilState(&depthdesc, &depth_state);
216 if (SUCCEEDED(hr)) SetDebugObjectName((ID3D11DeviceChild*)depth_state, "a depth-stencil state of EmuGfxState");
217 else PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__);
218 D3D::stateman->PushDepthState(depth_state);
219 SAFE_RELEASE(depth_state);
221 context->PSSetShader(pixelshader, NULL, 0);
222 context->VSSetShader(vertexshader, NULL, 0);
223 context->PSSetShaderResources(0, 8, shader_resources);
225 stateman->Apply();
226 apply_called = true;
229 void EmuGfxState::Reset()
231 for (unsigned int k = 0;k < 8;k++)
232 SAFE_RELEASE(shader_resources[k]);
234 context->PSSetShaderResources(0, 8, shader_resources); // unbind all textures
235 if (apply_called)
237 stateman->PopBlendState();
238 stateman->PopDepthState();
239 stateman->PopRasterizerState();
240 apply_called = false;
244 void EmuGfxState::SetAlphaBlendEnable(bool enable)
246 blenddesc.RenderTarget[0].BlendEnable = enable;
249 void EmuGfxState::SetRenderTargetWriteMask(UINT8 mask)
251 blenddesc.RenderTarget[0].RenderTargetWriteMask = mask;
254 void EmuGfxState::SetSrcBlend(D3D11_BLEND val)
256 // TODO: Check whether e.g. the dest color check is needed here
257 if (m_useDstAlpha)
259 // Colors should blend against SRC1_ALPHA
260 if (val == D3D11_BLEND_SRC_ALPHA)
261 val = D3D11_BLEND_SRC1_ALPHA;
262 else if (val == D3D11_BLEND_INV_SRC_ALPHA)
263 val = D3D11_BLEND_INV_SRC1_ALPHA;
265 blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
267 else
269 // Colors should blend against SRC_ALPHA
270 if (val == D3D11_BLEND_SRC1_ALPHA)
271 val = D3D11_BLEND_SRC_ALPHA;
272 else if (val == D3D11_BLEND_INV_SRC1_ALPHA)
273 val = D3D11_BLEND_INV_SRC_ALPHA;
275 if (val == D3D11_BLEND_SRC_COLOR)
276 blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
277 else if (val == D3D11_BLEND_INV_SRC_COLOR)
278 blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
279 else if (val == D3D11_BLEND_DEST_COLOR)
280 blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_DEST_ALPHA;
281 else if (val == D3D11_BLEND_INV_DEST_COLOR)
282 blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
283 else
284 blenddesc.RenderTarget[0].SrcBlendAlpha = val;
287 blenddesc.RenderTarget[0].SrcBlend = val;
290 void EmuGfxState::SetDestBlend(D3D11_BLEND val)
292 // TODO: Check whether e.g. the source color check is needed here
293 if (m_useDstAlpha)
295 // Colors should blend against SRC1_ALPHA
296 if (val == D3D11_BLEND_SRC_ALPHA)
297 val = D3D11_BLEND_SRC1_ALPHA;
298 else if (val == D3D11_BLEND_INV_SRC_ALPHA)
299 val = D3D11_BLEND_INV_SRC1_ALPHA;
301 blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
303 else
305 // Colors should blend against SRC_ALPHA
306 if (val == D3D11_BLEND_SRC1_ALPHA)
307 val = D3D11_BLEND_SRC_ALPHA;
308 else if (val == D3D11_BLEND_INV_SRC1_ALPHA)
309 val = D3D11_BLEND_INV_SRC_ALPHA;
311 if (val == D3D11_BLEND_SRC_COLOR)
312 blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_SRC_ALPHA;
313 else if (val == D3D11_BLEND_INV_SRC_COLOR)
314 blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
315 else if (val == D3D11_BLEND_DEST_COLOR)
316 blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
317 else if (val == D3D11_BLEND_INV_DEST_COLOR)
318 blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
319 else
320 blenddesc.RenderTarget[0].DestBlendAlpha = val;
323 blenddesc.RenderTarget[0].DestBlend = val;
326 void EmuGfxState::SetBlendOp(D3D11_BLEND_OP val)
328 blenddesc.RenderTarget[0].BlendOp = val;
329 if (m_useDstAlpha)
331 blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
333 else
335 blenddesc.RenderTarget[0].BlendOpAlpha = val;
339 void EmuGfxState::SetDstAlpha(bool enable)
341 m_useDstAlpha = enable;
342 SetSrcBlend(blenddesc.RenderTarget[0].SrcBlend);
343 SetDestBlend(blenddesc.RenderTarget[0].DestBlend);
344 SetBlendOp(blenddesc.RenderTarget[0].BlendOp);
347 void EmuGfxState::SetSamplerFilter(DWORD stage, D3D11_FILTER filter)
349 samplerdesc[stage].Filter = filter;
352 template<typename T> AutoState<T>::AutoState(const T* object) : state(object)
354 ((IUnknown*)state)->AddRef();
357 template<typename T> AutoState<T>::AutoState(const AutoState<T> &source)
359 state = source.GetPtr();
360 ((T*)state)->AddRef();
363 template<typename T> AutoState<T>::~AutoState()
365 if(state) ((T*)state)->Release();
366 state = NULL;
369 StateManager::StateManager() : cur_blendstate(NULL), cur_depthstate(NULL), cur_raststate(NULL) {}
371 void StateManager::PushBlendState(const ID3D11BlendState* state) { blendstates.push(AutoBlendState(state)); }
372 void StateManager::PushDepthState(const ID3D11DepthStencilState* state) { depthstates.push(AutoDepthStencilState(state)); }
373 void StateManager::PushRasterizerState(const ID3D11RasterizerState* state) { raststates.push(AutoRasterizerState(state)); }
374 void StateManager::PopBlendState() { blendstates.pop(); }
375 void StateManager::PopDepthState() { depthstates.pop(); }
376 void StateManager::PopRasterizerState() { raststates.pop(); }
378 void StateManager::Apply()
380 if (!blendstates.empty())
382 if (cur_blendstate != blendstates.top().GetPtr())
384 cur_blendstate = (ID3D11BlendState*)blendstates.top().GetPtr();
385 D3D::context->OMSetBlendState(cur_blendstate, NULL, 0xFFFFFFFF);
388 else ERROR_LOG(VIDEO, "Tried to apply without blend state!");
390 if (!depthstates.empty())
392 if (cur_depthstate != depthstates.top().GetPtr())
394 cur_depthstate = (ID3D11DepthStencilState*)depthstates.top().GetPtr();
395 D3D::context->OMSetDepthStencilState(cur_depthstate, 0);
398 else ERROR_LOG(VIDEO, "Tried to apply without depth state!");
400 if (!raststates.empty())
402 if (cur_raststate != raststates.top().GetPtr())
404 cur_raststate = (ID3D11RasterizerState*)raststates.top().GetPtr();
405 D3D::context->RSSetState(cur_raststate);
408 else ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!");
411 } // namespace