CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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