Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/GPU/D3D11/ShaderManagerD3D11.cpp
3186 views
1
// Copyright (c) 2015- PPSSPP Project.
2
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 or later versions.
6
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.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include "ppsspp_config.h"
19
20
#include <d3d11.h>
21
#include <D3Dcompiler.h>
22
23
#include <map>
24
25
#include "Common/GPU/thin3d.h"
26
#include "Common/Log.h"
27
#include "Common/CommonTypes.h"
28
#include "GPU/GPUState.h"
29
#include "GPU/Common/VertexShaderGenerator.h"
30
#include "GPU/Common/VertexDecoderCommon.h"
31
#include "GPU/D3D11/ShaderManagerD3D11.h"
32
#include "GPU/D3D11/D3D11Util.h"
33
34
D3D11FragmentShader::D3D11FragmentShader(ID3D11Device *device, D3D_FEATURE_LEVEL featureLevel, FShaderID id, const char *code, bool useHWTransform)
35
: device_(device), useHWTransform_(useHWTransform), id_(id) {
36
source_ = code;
37
38
if (FAILED(CreatePixelShaderD3D11(device, code, strlen(code), featureLevel, 0, &module_)))
39
failed_ = true;
40
}
41
42
D3D11FragmentShader::~D3D11FragmentShader() {
43
}
44
45
std::string D3D11FragmentShader::GetShaderString(DebugShaderStringType type) const {
46
switch (type) {
47
case SHADER_STRING_SOURCE_CODE:
48
return source_;
49
case SHADER_STRING_SHORT_DESC:
50
return FragmentShaderDesc(id_);
51
default:
52
return "N/A";
53
}
54
}
55
56
D3D11VertexShader::D3D11VertexShader(ID3D11Device *device, D3D_FEATURE_LEVEL featureLevel, VShaderID id, const char *code, bool useHWTransform)
57
: device_(device), useHWTransform_(useHWTransform), id_(id) {
58
source_ = code;
59
60
if(FAILED(CreateVertexShaderD3D11(device, code, strlen(code), &bytecode_, featureLevel, 0, &module_)))
61
failed_ = true;
62
}
63
64
D3D11VertexShader::~D3D11VertexShader() {
65
}
66
67
std::string D3D11VertexShader::GetShaderString(DebugShaderStringType type) const {
68
switch (type) {
69
case SHADER_STRING_SOURCE_CODE:
70
return source_;
71
case SHADER_STRING_SHORT_DESC:
72
return VertexShaderDesc(id_);
73
default:
74
return "N/A";
75
}
76
}
77
78
static constexpr size_t CODE_BUFFER_SIZE = 32768;
79
80
ShaderManagerD3D11::ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel)
81
: ShaderManagerCommon(draw), device_(device), context_(context), featureLevel_(featureLevel) {
82
codeBuffer_ = new char[CODE_BUFFER_SIZE];
83
memset(&ub_base, 0, sizeof(ub_base));
84
memset(&ub_lights, 0, sizeof(ub_lights));
85
memset(&ub_bones, 0, sizeof(ub_bones));
86
87
static_assert(sizeof(ub_base) <= 512, "ub_base grew too big");
88
static_assert(sizeof(ub_lights) <= 512, "ub_lights grew too big");
89
static_assert(sizeof(ub_bones) <= 384, "ub_bones grew too big");
90
91
InitDeviceObjects();
92
}
93
94
ShaderManagerD3D11::~ShaderManagerD3D11() {
95
ClearShaders();
96
delete[] codeBuffer_;
97
DestroyDeviceObjects();
98
}
99
100
void ShaderManagerD3D11::InitDeviceObjects() {
101
102
D3D11_BUFFER_DESC desc{sizeof(ub_base), D3D11_USAGE_DYNAMIC, D3D11_BIND_CONSTANT_BUFFER, D3D11_CPU_ACCESS_WRITE};
103
ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &push_base));
104
desc.ByteWidth = sizeof(ub_lights);
105
ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &push_lights));
106
desc.ByteWidth = sizeof(ub_bones);
107
ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &push_bones));
108
}
109
110
void ShaderManagerD3D11::DestroyDeviceObjects() {
111
push_base.Reset();
112
push_lights.Reset();
113
push_bones.Reset();
114
Clear();
115
}
116
117
void ShaderManagerD3D11::DeviceLost() {
118
DestroyDeviceObjects();
119
draw_ = nullptr;
120
}
121
122
void ShaderManagerD3D11::DeviceRestore(Draw::DrawContext *draw) {
123
draw_ = draw;
124
InitDeviceObjects();
125
}
126
127
void ShaderManagerD3D11::Clear() {
128
for (const auto &[_, fs] : fsCache_) {
129
delete fs;
130
}
131
for (const auto &[_, vs] : vsCache_) {
132
delete vs;
133
}
134
fsCache_.clear();
135
vsCache_.clear();
136
lastFSID_.set_invalid();
137
lastVSID_.set_invalid();
138
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
139
}
140
141
void ShaderManagerD3D11::ClearShaders() {
142
Clear();
143
DirtyLastShader();
144
gstate_c.Dirty(DIRTY_ALL_UNIFORMS);
145
}
146
147
void ShaderManagerD3D11::DirtyLastShader() {
148
lastFSID_.set_invalid();
149
lastVSID_.set_invalid();
150
lastVShader_ = nullptr;
151
lastFShader_ = nullptr;
152
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
153
}
154
155
uint64_t ShaderManagerD3D11::UpdateUniforms(bool useBufferedRendering) {
156
uint64_t dirty = gstate_c.GetDirtyUniforms();
157
if (dirty != 0) {
158
D3D11_MAPPED_SUBRESOURCE map;
159
if (dirty & DIRTY_BASE_UNIFORMS) {
160
BaseUpdateUniforms(&ub_base, dirty, true, useBufferedRendering);
161
context_->Map(push_base.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
162
memcpy(map.pData, &ub_base, sizeof(ub_base));
163
context_->Unmap(push_base.Get(), 0);
164
}
165
if (dirty & DIRTY_LIGHT_UNIFORMS) {
166
LightUpdateUniforms(&ub_lights, dirty);
167
context_->Map(push_lights.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
168
memcpy(map.pData, &ub_lights, sizeof(ub_lights));
169
context_->Unmap(push_lights.Get(), 0);
170
}
171
if (dirty & DIRTY_BONE_UNIFORMS) {
172
BoneUpdateUniforms(&ub_bones, dirty);
173
context_->Map(push_bones.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
174
memcpy(map.pData, &ub_bones, sizeof(ub_bones));
175
context_->Unmap(push_bones.Get(), 0);
176
}
177
}
178
gstate_c.CleanUniforms();
179
return dirty;
180
}
181
182
void ShaderManagerD3D11::BindUniforms() {
183
ID3D11Buffer *vs_cbs[3] = { push_base.Get(), push_lights.Get(), push_bones.Get() };
184
ID3D11Buffer *ps_cbs[1] = { push_base.Get() };
185
context_->VSSetConstantBuffers(0, 3, vs_cbs);
186
context_->PSSetConstantBuffers(0, 1, ps_cbs);
187
}
188
189
void ShaderManagerD3D11::GetShaders(int prim, u32 vertexType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, const ComputedPipelineState &pipelineState, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat, bool useSkinInDecode) {
190
VShaderID VSID;
191
FShaderID FSID;
192
193
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
194
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
195
ComputeVertexShaderID(&VSID, vertexType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
196
} else {
197
VSID = lastVSID_;
198
}
199
200
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
201
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
202
ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs());
203
} else {
204
FSID = lastFSID_;
205
}
206
207
// Just update uniforms if this is the same shader as last time.
208
if (lastVShader_ != nullptr && lastFShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) {
209
*vshader = lastVShader_;
210
*fshader = lastFShader_;
211
// Already all set, no need to look up in shader maps.
212
return;
213
}
214
215
VSCache::iterator vsIter = vsCache_.find(VSID);
216
D3D11VertexShader *vs;
217
if (vsIter == vsCache_.end()) {
218
// Vertex shader not in cache. Let's compile it.
219
std::string genErrorString;
220
uint32_t attrMask;
221
uint64_t uniformMask;
222
VertexShaderFlags flags;
223
GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString);
224
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
225
vs = new D3D11VertexShader(device_, featureLevel_, VSID, codeBuffer_, useHWTransform);
226
vsCache_[VSID] = vs;
227
} else {
228
vs = vsIter->second;
229
}
230
lastVSID_ = VSID;
231
232
FSCache::iterator fsIter = fsCache_.find(FSID);
233
D3D11FragmentShader *fs;
234
if (fsIter == fsCache_.end()) {
235
// Fragment shader not in cache. Let's compile it.
236
std::string genErrorString;
237
uint64_t uniformMask;
238
FragmentShaderFlags flags;
239
GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &genErrorString);
240
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
241
fs = new D3D11FragmentShader(device_, featureLevel_, FSID, codeBuffer_, useHWTransform);
242
fsCache_[FSID] = fs;
243
} else {
244
fs = fsIter->second;
245
}
246
247
lastFSID_ = FSID;
248
249
lastVShader_ = vs;
250
lastFShader_ = fs;
251
252
*vshader = vs;
253
*fshader = fs;
254
}
255
256
std::vector<std::string> ShaderManagerD3D11::DebugGetShaderIDs(DebugShaderType type) {
257
std::string id;
258
std::vector<std::string> ids;
259
switch (type) {
260
case SHADER_TYPE_VERTEX:
261
{
262
for (auto iter : vsCache_) {
263
iter.first.ToString(&id);
264
ids.push_back(id);
265
}
266
break;
267
}
268
case SHADER_TYPE_FRAGMENT:
269
{
270
for (auto iter : fsCache_) {
271
iter.first.ToString(&id);
272
ids.push_back(id);
273
}
274
break;
275
}
276
default:
277
break;
278
}
279
return ids;
280
}
281
282
std::string ShaderManagerD3D11::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
283
ShaderID shaderId;
284
shaderId.FromString(id);
285
switch (type) {
286
case SHADER_TYPE_VERTEX:
287
{
288
auto iter = vsCache_.find(VShaderID(shaderId));
289
if (iter == vsCache_.end()) {
290
return "";
291
}
292
return iter->second->GetShaderString(stringType);
293
}
294
295
case SHADER_TYPE_FRAGMENT:
296
{
297
auto iter = fsCache_.find(FShaderID(shaderId));
298
if (iter == fsCache_.end()) {
299
return "";
300
}
301
return iter->second->GetShaderString(stringType);
302
}
303
default:
304
return "N/A";
305
}
306
}
307
308