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"
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);
64 vshaderchanged
= false;
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
);
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
);
98 vertexshader
= shader
;
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
)
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()
133 // input layout (only needs to be updated if the vertex shader signature changed)
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
);
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
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");
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
);
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");
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
);
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
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
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
;
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
;
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
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
;
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
;
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
;
331 blenddesc
.RenderTarget
[0].BlendOpAlpha
= D3D11_BLEND_OP_ADD
;
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();
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!");