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/Directx9/ShaderManagerDX9.cpp
Views: 1401
1
// Copyright (c) 2012- 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
#ifdef _WIN32
19
//#define SHADERLOG
20
#endif
21
22
#include <cmath>
23
#include <map>
24
25
#include "Common/Data/Convert/SmallDataConvert.h"
26
#include "Common/Data/Encoding/Utf8.h"
27
#include "Common/Data/Text/I18n.h"
28
#include "Common/Math/lin/matrix4x4.h"
29
#include "Common/Math/math_util.h"
30
#include "Common/GPU/D3D9/D3D9ShaderCompiler.h"
31
#include "Common/GPU/thin3d.h"
32
#include "Common/System/OSD.h"
33
#include "Common/System/Display.h"
34
35
#include "Common/CommonTypes.h"
36
#include "Common/Log.h"
37
#include "Common/LogReporting.h"
38
#include "Common/StringUtils.h"
39
40
#include "Core/Config.h"
41
#include "GPU/Math3D.h"
42
#include "GPU/GPUState.h"
43
#include "GPU/ge_constants.h"
44
#include "GPU/Common/ShaderUniforms.h"
45
#include "GPU/Common/FragmentShaderGenerator.h"
46
#include "GPU/Directx9/ShaderManagerDX9.h"
47
#include "GPU/Directx9/DrawEngineDX9.h"
48
#include "GPU/Directx9/FramebufferManagerDX9.h"
49
50
using namespace Lin;
51
52
PSShader::PSShader(LPDIRECT3DDEVICE9 device, FShaderID id, const char *code) : id_(id) {
53
source_ = code;
54
#ifdef SHADERLOG
55
OutputDebugString(ConvertUTF8ToWString(code).c_str());
56
#endif
57
bool success;
58
std::string errorMessage;
59
60
success = CompilePixelShaderD3D9(device, code, &shader, &errorMessage);
61
62
if (!errorMessage.empty()) {
63
if (success) {
64
ERROR_LOG(Log::G3D, "Warnings in shader compilation!");
65
} else {
66
ERROR_LOG(Log::G3D, "Error in shader compilation!");
67
}
68
ERROR_LOG(Log::G3D, "Messages: %s", errorMessage.c_str());
69
ERROR_LOG(Log::G3D, "Shader source:\n%s", LineNumberString(code).c_str());
70
OutputDebugStringUTF8("Messages:\n");
71
OutputDebugStringUTF8(errorMessage.c_str());
72
Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);
73
}
74
75
if (!success) {
76
failed_ = true;
77
shader = nullptr;
78
return;
79
} else {
80
VERBOSE_LOG(Log::G3D, "Compiled pixel shader:\n%s\n", (const char *)code);
81
}
82
}
83
84
PSShader::~PSShader() {
85
}
86
87
std::string PSShader::GetShaderString(DebugShaderStringType type) const {
88
switch (type) {
89
case SHADER_STRING_SOURCE_CODE:
90
return source_;
91
case SHADER_STRING_SHORT_DESC:
92
return FragmentShaderDesc(id_);
93
default:
94
return "N/A";
95
}
96
}
97
98
VSShader::VSShader(LPDIRECT3DDEVICE9 device, VShaderID id, const char *code, bool useHWTransform) : useHWTransform_(useHWTransform), id_(id) {
99
source_ = code;
100
#ifdef SHADERLOG
101
OutputDebugString(ConvertUTF8ToWString(code).c_str());
102
#endif
103
bool success;
104
std::string errorMessage;
105
106
success = CompileVertexShaderD3D9(device, code, &shader, &errorMessage);
107
if (!errorMessage.empty()) {
108
if (success) {
109
ERROR_LOG(Log::G3D, "Warnings in shader compilation!");
110
} else {
111
ERROR_LOG(Log::G3D, "Error in shader compilation!");
112
}
113
ERROR_LOG(Log::G3D, "Messages: %s", errorMessage.c_str());
114
ERROR_LOG(Log::G3D, "Shader source:\n%s", code);
115
OutputDebugStringUTF8("Messages:\n");
116
OutputDebugStringUTF8(errorMessage.c_str());
117
Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);
118
}
119
120
if (!success) {
121
failed_ = true;
122
shader = nullptr;
123
return;
124
} else {
125
VERBOSE_LOG(Log::G3D, "Compiled vertex shader:\n%s\n", (const char *)code);
126
}
127
}
128
129
VSShader::~VSShader() {
130
}
131
132
std::string VSShader::GetShaderString(DebugShaderStringType type) const {
133
switch (type) {
134
case SHADER_STRING_SOURCE_CODE:
135
return source_;
136
case SHADER_STRING_SHORT_DESC:
137
return VertexShaderDesc(id_);
138
default:
139
return "N/A";
140
}
141
}
142
143
void ShaderManagerDX9::PSSetColorUniform3(int creg, u32 color) {
144
float f[4];
145
Uint8x3ToFloat4(f, color);
146
device_->SetPixelShaderConstantF(creg, f, 1);
147
}
148
149
void ShaderManagerDX9::PSSetColorUniform3Alpha255(int creg, u32 color, u8 alpha) {
150
const float col[4] = {
151
(float)((color & 0xFF)),
152
(float)((color & 0xFF00) >> 8),
153
(float)((color & 0xFF0000) >> 16),
154
(float)alpha,
155
};
156
device_->SetPixelShaderConstantF(creg, col, 1);
157
}
158
159
void ShaderManagerDX9::PSSetFloat(int creg, float value) {
160
const float f[4] = { value, 0.0f, 0.0f, 0.0f };
161
device_->SetPixelShaderConstantF(creg, f, 1);
162
}
163
164
void ShaderManagerDX9::PSSetFloatArray(int creg, const float *value, int count) {
165
float f[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
166
for (int i = 0; i < count; i++) {
167
f[i] = value[i];
168
}
169
device_->SetPixelShaderConstantF(creg, f, 1);
170
}
171
172
void ShaderManagerDX9::VSSetFloat(int creg, float value) {
173
const float f[4] = { value, 0.0f, 0.0f, 0.0f };
174
device_->SetVertexShaderConstantF(creg, f, 1);
175
}
176
177
void ShaderManagerDX9::VSSetFloatArray(int creg, const float *value, int count) {
178
float f[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
179
for (int i = 0; i < count; i++) {
180
f[i] = value[i];
181
}
182
device_->SetVertexShaderConstantF(creg, f, 1);
183
}
184
185
// Utility
186
void ShaderManagerDX9::VSSetColorUniform3(int creg, u32 color) {
187
float f[4];
188
Uint8x3ToFloat4(f, color);
189
device_->SetVertexShaderConstantF(creg, f, 1);
190
}
191
192
void ShaderManagerDX9::VSSetFloatUniform4(int creg, const float data[4]) {
193
device_->SetVertexShaderConstantF(creg, data, 1);
194
}
195
196
void ShaderManagerDX9::VSSetFloat24Uniform3(int creg, const u32 data[3]) {
197
float f[4];
198
ExpandFloat24x3ToFloat4(f, data);
199
device_->SetVertexShaderConstantF(creg, f, 1);
200
}
201
202
void ShaderManagerDX9::VSSetFloat24Uniform3Normalized(int creg, const u32 data[3]) {
203
float f[4];
204
ExpandFloat24x3ToFloat4AndNormalize(f, data);
205
device_->SetVertexShaderConstantF(creg, f, 1);
206
}
207
208
void ShaderManagerDX9::VSSetColorUniform3Alpha(int creg, u32 color, u8 alpha) {
209
float f[4];
210
Uint8x3ToFloat4_AlphaUint8(f, color, alpha);
211
device_->SetVertexShaderConstantF(creg, f, 1);
212
}
213
214
void ShaderManagerDX9::VSSetColorUniform3ExtraFloat(int creg, u32 color, float extra) {
215
const float col[4] = {
216
((color & 0xFF)) / 255.0f,
217
((color & 0xFF00) >> 8) / 255.0f,
218
((color & 0xFF0000) >> 16) / 255.0f,
219
extra
220
};
221
device_->SetVertexShaderConstantF(creg, col, 1);
222
}
223
224
void ShaderManagerDX9::VSSetMatrix4x3_3(int creg, const float *m4x3) {
225
float m3x4[12];
226
ConvertMatrix4x3To3x4Transposed(m3x4, m4x3);
227
device_->SetVertexShaderConstantF(creg, m3x4, 3);
228
}
229
230
void ShaderManagerDX9::VSSetMatrix(int creg, const float* pMatrix) {
231
device_->SetVertexShaderConstantF(creg, pMatrix, 4);
232
}
233
234
// Depth in ogl is between -1;1 we need between 0;1 and optionally reverse it
235
static void ConvertProjMatrixToD3D(Matrix4x4 &in, bool invertedX, bool invertedY) {
236
// Half pixel offset hack
237
float xoff = 1.0f / gstate_c.curRTRenderWidth;
238
if (invertedX) {
239
xoff = -gstate_c.vpXOffset - xoff;
240
} else {
241
xoff = gstate_c.vpXOffset - xoff;
242
}
243
244
float yoff = -1.0f / gstate_c.curRTRenderHeight;
245
if (invertedY) {
246
yoff = -gstate_c.vpYOffset - yoff;
247
} else {
248
yoff = gstate_c.vpYOffset - yoff;
249
}
250
251
const Vec3 trans(xoff, yoff, gstate_c.vpZOffset * 0.5f + 0.5f);
252
const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);
253
in.translateAndScale(trans, scale);
254
}
255
256
static void ConvertProjMatrixToD3DThrough(Matrix4x4 &in) {
257
float xoff = -1.0f / gstate_c.curRTRenderWidth;
258
float yoff = 1.0f / gstate_c.curRTRenderHeight;
259
in.translateAndScale(Vec3(xoff, yoff, 0.5f), Vec3(1.0f, 1.0f, 0.5f));
260
}
261
262
const uint64_t psUniforms = DIRTY_TEXENV | DIRTY_TEX_ALPHA_MUL | DIRTY_ALPHACOLORREF | DIRTY_ALPHACOLORMASK | DIRTY_FOGCOLOR | DIRTY_STENCILREPLACEVALUE | DIRTY_SHADERBLEND | DIRTY_TEXCLAMP | DIRTY_MIPBIAS;
263
264
void ShaderManagerDX9::PSUpdateUniforms(u64 dirtyUniforms) {
265
if (dirtyUniforms & DIRTY_TEXENV) {
266
PSSetColorUniform3(CONST_PS_TEXENV, gstate.texenvcolor);
267
}
268
if (dirtyUniforms & DIRTY_ALPHACOLORREF) {
269
PSSetColorUniform3Alpha255(CONST_PS_ALPHACOLORREF, gstate.getColorTestRef(), gstate.getAlphaTestRef() & gstate.getAlphaTestMask());
270
}
271
if (dirtyUniforms & DIRTY_ALPHACOLORMASK) {
272
PSSetColorUniform3Alpha255(CONST_PS_ALPHACOLORMASK, gstate.colortestmask, gstate.getAlphaTestMask());
273
}
274
if (dirtyUniforms & DIRTY_FOGCOLOR) {
275
PSSetColorUniform3(CONST_PS_FOGCOLOR, gstate.fogcolor);
276
}
277
if (dirtyUniforms & DIRTY_STENCILREPLACEVALUE) {
278
PSSetFloat(CONST_PS_STENCILREPLACE, (float)gstate.getStencilTestRef() * (1.0f / 255.0f));
279
}
280
if (dirtyUniforms & DIRTY_TEX_ALPHA_MUL) {
281
bool doTextureAlpha = gstate.isTextureAlphaUsed();
282
if (gstate_c.textureFullAlpha && gstate.getTextureFunction() != GE_TEXFUNC_REPLACE) {
283
doTextureAlpha = false;
284
}
285
// NOTE: Reversed value, more efficient in shader.
286
float noAlphaMul[2] = { doTextureAlpha ? 0.0f : 1.0f, gstate.isColorDoublingEnabled() ? 2.0f : 1.0f };
287
PSSetFloatArray(CONST_PS_TEX_NO_ALPHA_MUL, noAlphaMul, 2);
288
}
289
if (dirtyUniforms & DIRTY_SHADERBLEND) {
290
PSSetColorUniform3(CONST_PS_BLENDFIXA, gstate.getFixA());
291
PSSetColorUniform3(CONST_PS_BLENDFIXB, gstate.getFixB());
292
293
const float fbotexSize[2] = {
294
1.0f / (float)gstate_c.curRTRenderWidth,
295
1.0f / (float)gstate_c.curRTRenderHeight,
296
};
297
PSSetFloatArray(CONST_PS_FBOTEXSIZE, fbotexSize, 2);
298
}
299
300
if (dirtyUniforms & DIRTY_TEXCLAMP) {
301
const float invW = 1.0f / (float)gstate_c.curTextureWidth;
302
const float invH = 1.0f / (float)gstate_c.curTextureHeight;
303
const int w = gstate.getTextureWidth(0);
304
const int h = gstate.getTextureHeight(0);
305
const float widthFactor = (float)w * invW;
306
const float heightFactor = (float)h * invH;
307
308
// First wrap xy, then half texel xy (for clamp.)
309
const float texclamp[4] = {
310
widthFactor,
311
heightFactor,
312
invW * 0.5f,
313
invH * 0.5f,
314
};
315
const float texclampoff[2] = {
316
gstate_c.curTextureXOffset * invW,
317
gstate_c.curTextureYOffset * invH,
318
};
319
PSSetFloatArray(CONST_PS_TEXCLAMP, texclamp, 4);
320
PSSetFloatArray(CONST_PS_TEXCLAMPOFF, texclampoff, 2);
321
}
322
323
if (dirtyUniforms & DIRTY_MIPBIAS) {
324
float mipBias = (float)gstate.getTexLevelOffset16() * (1.0 / 16.0f);
325
326
// NOTE: This equation needs some adjustment in D3D9. Can't get it to look completely smooth :(
327
mipBias = (mipBias + 0.25f) / (float)(gstate.getTextureMaxLevel() + 1);
328
PSSetFloatArray(CONST_PS_MIPBIAS, &mipBias, 1);
329
}
330
}
331
332
const uint64_t vsUniforms = DIRTY_PROJMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_WORLDMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX |
333
DIRTY_FOGCOEF | DIRTY_BONE_UNIFORMS | DIRTY_UVSCALEOFFSET | DIRTY_DEPTHRANGE | DIRTY_CULLRANGE |
334
DIRTY_AMBIENT | DIRTY_MATAMBIENTALPHA | DIRTY_MATSPECULAR | DIRTY_MATDIFFUSE | DIRTY_MATEMISSIVE | DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3;
335
336
void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) {
337
// Update any dirty uniforms before we draw
338
if (dirtyUniforms & DIRTY_PROJMATRIX) {
339
Matrix4x4 flippedMatrix;
340
memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float));
341
342
const bool invertedY = gstate_c.vpHeight < 0;
343
if (!invertedY) {
344
flippedMatrix[1] = -flippedMatrix[1];
345
flippedMatrix[5] = -flippedMatrix[5];
346
flippedMatrix[9] = -flippedMatrix[9];
347
flippedMatrix[13] = -flippedMatrix[13];
348
}
349
const bool invertedX = gstate_c.vpWidth < 0;
350
if (invertedX) {
351
flippedMatrix[0] = -flippedMatrix[0];
352
flippedMatrix[4] = -flippedMatrix[4];
353
flippedMatrix[8] = -flippedMatrix[8];
354
flippedMatrix[12] = -flippedMatrix[12];
355
}
356
357
ConvertProjMatrixToD3D(flippedMatrix, invertedX, invertedY);
358
359
VSSetMatrix(CONST_VS_PROJ, flippedMatrix.getReadPtr());
360
VSSetFloat(CONST_VS_ROTATION, 0); // We don't use this on any platform in D3D9.
361
}
362
if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) {
363
Matrix4x4 proj_through;
364
proj_through.setOrtho(0.0f, gstate_c.curRTWidth, gstate_c.curRTHeight, 0, 0, 1);
365
366
ConvertProjMatrixToD3DThrough(proj_through);
367
368
VSSetMatrix(CONST_VS_PROJ_THROUGH, proj_through.getReadPtr());
369
}
370
// Transform
371
if (dirtyUniforms & DIRTY_WORLDMATRIX) {
372
VSSetMatrix4x3_3(CONST_VS_WORLD, gstate.worldMatrix);
373
}
374
if (dirtyUniforms & DIRTY_VIEWMATRIX) {
375
VSSetMatrix4x3_3(CONST_VS_VIEW, gstate.viewMatrix);
376
}
377
if (dirtyUniforms & DIRTY_TEXMATRIX) {
378
VSSetMatrix4x3_3(CONST_VS_TEXMTX, gstate.tgenMatrix);
379
}
380
if (dirtyUniforms & DIRTY_FOGCOEF) {
381
float fogcoef[2] = {
382
getFloat24(gstate.fog1),
383
getFloat24(gstate.fog2),
384
};
385
// The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float.
386
// Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988
387
if (my_isnanorinf(fogcoef[0])) {
388
// Not really sure what a sensible value might be, but let's try 64k.
389
fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f;
390
}
391
if (my_isnanorinf(fogcoef[1])) {
392
fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f;
393
}
394
VSSetFloatArray(CONST_VS_FOGCOEF, fogcoef, 2);
395
}
396
// TODO: Could even set all bones in one go if they're all dirty.
397
#ifdef USE_BONE_ARRAY
398
if (u_bone != 0) {
399
float allBones[8 * 16];
400
401
bool allDirty = true;
402
for (int i = 0; i < numBones; i++) {
403
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
404
ConvertMatrix4x3To4x4(allBones + 16 * i, gstate.boneMatrix + 12 * i);
405
} else {
406
allDirty = false;
407
}
408
}
409
if (allDirty) {
410
// Set them all with one call
411
//glUniformMatrix4fv(u_bone, numBones, GL_FALSE, allBones);
412
} else {
413
// Set them one by one. Could try to coalesce two in a row etc but too lazy.
414
for (int i = 0; i < numBones; i++) {
415
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
416
//glUniformMatrix4fv(u_bone + i, 1, GL_FALSE, allBones + 16 * i);
417
}
418
}
419
}
420
}
421
#else
422
for (int i = 0; i < 8; i++) {
423
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
424
VSSetMatrix4x3_3(CONST_VS_BONE0 + 3 * i, gstate.boneMatrix + 12 * i);
425
}
426
}
427
#endif
428
429
// Texturing
430
if (dirtyUniforms & DIRTY_UVSCALEOFFSET) {
431
float widthFactor = 1.0f;
432
float heightFactor = 1.0f;
433
if (gstate_c.textureIsFramebuffer) {
434
const float invW = 1.0f / (float)gstate_c.curTextureWidth;
435
const float invH = 1.0f / (float)gstate_c.curTextureHeight;
436
const int w = gstate.getTextureWidth(0);
437
const int h = gstate.getTextureHeight(0);
438
widthFactor = (float)w * invW;
439
heightFactor = (float)h * invH;
440
}
441
float uvscaleoff[4];
442
uvscaleoff[0] = widthFactor;
443
uvscaleoff[1] = heightFactor;
444
uvscaleoff[2] = 0.0f;
445
uvscaleoff[3] = 0.0f;
446
VSSetFloatArray(CONST_VS_UVSCALEOFFSET, uvscaleoff, 4);
447
}
448
449
if (dirtyUniforms & DIRTY_DEPTHRANGE) {
450
// Depth is [0, 1] mapping to [minz, maxz], not too hard.
451
float vpZScale = gstate.getViewportZScale();
452
float vpZCenter = gstate.getViewportZCenter();
453
454
// These are just the reverse of the formulas in GPUStateUtils.
455
float halfActualZRange = InfToZero(gstate_c.vpDepthScale != 0.0f ? vpZScale / gstate_c.vpDepthScale : 0.0f);
456
float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange;
457
float viewZScale = halfActualZRange * 2.0f;
458
float viewZCenter = minz;
459
float reverseScale = InfToZero(gstate_c.vpDepthScale != 0.0f ? 2.0f * (1.0f / gstate_c.vpDepthScale) : 0.0f);
460
float reverseTranslate = gstate_c.vpZOffset * 0.5f + 0.5f;
461
462
float data[4] = { viewZScale, viewZCenter, reverseTranslate, reverseScale };
463
VSSetFloatUniform4(CONST_VS_DEPTHRANGE, data);
464
465
if (draw_->GetDeviceCaps().clipPlanesSupported >= 1) {
466
float clip[4] = { 0.0f, 0.0f, reverseScale, 1.0f - reverseTranslate * reverseScale };
467
// Well, not a uniform, but we treat it as one like other backends.
468
device_->SetClipPlane(0, clip);
469
}
470
}
471
if (dirtyUniforms & DIRTY_CULLRANGE) {
472
float minValues[4], maxValues[4];
473
CalcCullRange(minValues, maxValues, false, false);
474
VSSetFloatUniform4(CONST_VS_CULLRANGEMIN, minValues);
475
VSSetFloatUniform4(CONST_VS_CULLRANGEMAX, maxValues);
476
}
477
478
// Lighting
479
if (dirtyUniforms & DIRTY_AMBIENT) {
480
VSSetColorUniform3Alpha(CONST_VS_AMBIENT, gstate.ambientcolor, gstate.getAmbientA());
481
}
482
if (dirtyUniforms & DIRTY_MATAMBIENTALPHA) {
483
VSSetColorUniform3Alpha(CONST_VS_MATAMBIENTALPHA, gstate.materialambient, gstate.getMaterialAmbientA());
484
}
485
if (dirtyUniforms & DIRTY_MATDIFFUSE) {
486
VSSetColorUniform3(CONST_VS_MATDIFFUSE, gstate.materialdiffuse);
487
}
488
if (dirtyUniforms & DIRTY_MATEMISSIVE) {
489
VSSetColorUniform3(CONST_VS_MATEMISSIVE, gstate.materialemissive);
490
}
491
if (dirtyUniforms & DIRTY_MATSPECULAR) {
492
VSSetColorUniform3ExtraFloat(CONST_VS_MATSPECULAR, gstate.materialspecular, getFloat24(gstate.materialspecularcoef));
493
}
494
for (int i = 0; i < 4; i++) {
495
if (dirtyUniforms & (DIRTY_LIGHT0 << i)) {
496
if (gstate.isDirectionalLight(i)) {
497
VSSetFloat24Uniform3Normalized(CONST_VS_LIGHTPOS + i, &gstate.lpos[i * 3]);
498
} else {
499
VSSetFloat24Uniform3(CONST_VS_LIGHTPOS + i, &gstate.lpos[i * 3]);
500
}
501
VSSetFloat24Uniform3Normalized(CONST_VS_LIGHTDIR + i, &gstate.ldir[i * 3]);
502
VSSetFloat24Uniform3(CONST_VS_LIGHTATT + i, &gstate.latt[i * 3]);
503
float angle_spotCoef[4] = { getFloat24(gstate.lcutoff[i]), getFloat24(gstate.lconv[i]) };
504
VSSetFloatUniform4(CONST_VS_LIGHTANGLE_SPOTCOEF + i, angle_spotCoef);
505
VSSetColorUniform3(CONST_VS_LIGHTAMBIENT + i, gstate.lcolor[i * 3]);
506
VSSetColorUniform3(CONST_VS_LIGHTDIFFUSE + i, gstate.lcolor[i * 3 + 1]);
507
VSSetColorUniform3(CONST_VS_LIGHTSPECULAR + i, gstate.lcolor[i * 3 + 2]);
508
}
509
}
510
}
511
512
ShaderManagerDX9::ShaderManagerDX9(Draw::DrawContext *draw, LPDIRECT3DDEVICE9 device)
513
: ShaderManagerCommon(draw), device_(device) {
514
codeBuffer_ = new char[32768];
515
}
516
517
ShaderManagerDX9::~ShaderManagerDX9() {
518
delete [] codeBuffer_;
519
}
520
521
void ShaderManagerDX9::Clear() {
522
for (auto iter = fsCache_.begin(); iter != fsCache_.end(); ++iter) {
523
delete iter->second;
524
}
525
for (auto iter = vsCache_.begin(); iter != vsCache_.end(); ++iter) {
526
delete iter->second;
527
}
528
fsCache_.clear();
529
vsCache_.clear();
530
DirtyLastShader();
531
}
532
533
void ShaderManagerDX9::ClearShaders() {
534
Clear();
535
}
536
537
void ShaderManagerDX9::DirtyLastShader() {
538
// Forget the last shader ID
539
lastFSID_.set_invalid();
540
lastVSID_.set_invalid();
541
lastVShader_ = nullptr;
542
lastPShader_ = nullptr;
543
// TODO: Probably not necessary to dirty uniforms here on DX9.
544
gstate_c.Dirty(DIRTY_ALL_UNIFORMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
545
}
546
547
VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, VertexDecoder *decoder, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState) {
548
VShaderID VSID;
549
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
550
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
551
ComputeVertexShaderID(&VSID, decoder, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
552
} else {
553
VSID = lastVSID_;
554
}
555
556
FShaderID FSID;
557
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
558
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
559
ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs());
560
} else {
561
FSID = lastFSID_;
562
}
563
564
// Just update uniforms if this is the same shader as last time.
565
if (lastVShader_ != nullptr && lastPShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) {
566
uint64_t dirtyUniforms = gstate_c.GetDirtyUniforms();
567
if (dirtyUniforms) {
568
if (dirtyUniforms & psUniforms)
569
PSUpdateUniforms(dirtyUniforms);
570
if (dirtyUniforms & vsUniforms)
571
VSUpdateUniforms(dirtyUniforms);
572
gstate_c.CleanUniforms();
573
}
574
return lastVShader_; // Already all set.
575
}
576
577
VSCache::iterator vsIter = vsCache_.find(VSID);
578
VSShader *vs = nullptr;
579
if (vsIter == vsCache_.end()) {
580
// Vertex shader not in cache. Let's compile it.
581
std::string genErrorString;
582
uint32_t attrMask;
583
uint64_t uniformMask;
584
VertexShaderFlags flags;
585
if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString)) {
586
vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform);
587
}
588
if (!vs || vs->Failed()) {
589
if (!vs) {
590
// TODO: Report this?
591
ERROR_LOG(Log::G3D, "Shader generation failed, falling back to software transform");
592
} else {
593
ERROR_LOG(Log::G3D, "Shader compilation failed, falling back to software transform");
594
}
595
if (!g_Config.bHideSlowWarnings) {
596
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
597
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("hardware transform error - falling back to software"), 2.5f);
598
}
599
delete vs;
600
601
ComputeVertexShaderID(&VSID, decoder, false, false, weightsAsFloat, useSkinInDecode);
602
603
// TODO: Look for existing shader with the appropriate ID, use that instead of generating a new one - however, need to make sure
604
// that that shader ID is not used when computing the linked shader ID below, because then IDs won't match
605
// next time and we'll do this over and over...
606
607
// Can still work with software transform.
608
uint32_t attrMask;
609
uint64_t uniformMask;
610
bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString);
611
_assert_(success);
612
vs = new VSShader(device_, VSID, codeBuffer_, false);
613
}
614
615
vsCache_[VSID] = vs;
616
} else {
617
vs = vsIter->second;
618
}
619
lastVSID_ = VSID;
620
621
FSCache::iterator fsIter = fsCache_.find(FSID);
622
PSShader *fs;
623
if (fsIter == fsCache_.end()) {
624
// Fragment shader not in cache. Let's compile it.
625
std::string errorString;
626
uint64_t uniformMask;
627
FragmentShaderFlags flags;
628
bool success = GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &errorString);
629
// We're supposed to handle all possible cases.
630
_assert_(success);
631
fs = new PSShader(device_, FSID, codeBuffer_);
632
fsCache_[FSID] = fs;
633
} else {
634
fs = fsIter->second;
635
}
636
637
lastFSID_ = FSID;
638
639
uint64_t dirtyUniforms = gstate_c.GetDirtyUniforms();
640
if (dirtyUniforms) {
641
if (dirtyUniforms & psUniforms)
642
PSUpdateUniforms(dirtyUniforms);
643
if (dirtyUniforms & vsUniforms)
644
VSUpdateUniforms(dirtyUniforms);
645
gstate_c.CleanUniforms();
646
}
647
648
device_->SetPixelShader(fs->shader.Get());
649
device_->SetVertexShader(vs->shader.Get());
650
651
lastPShader_ = fs;
652
lastVShader_ = vs;
653
return vs;
654
}
655
656
std::vector<std::string> ShaderManagerDX9::DebugGetShaderIDs(DebugShaderType type) {
657
std::string id;
658
std::vector<std::string> ids;
659
switch (type) {
660
case SHADER_TYPE_VERTEX:
661
for (auto iter : vsCache_) {
662
iter.first.ToString(&id);
663
ids.push_back(id);
664
}
665
break;
666
case SHADER_TYPE_FRAGMENT:
667
for (auto iter : fsCache_) {
668
iter.first.ToString(&id);
669
ids.push_back(id);
670
}
671
break;
672
}
673
return ids;
674
}
675
676
std::string ShaderManagerDX9::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
677
ShaderID shaderId;
678
shaderId.FromString(id);
679
switch (type) {
680
case SHADER_TYPE_VERTEX:
681
{
682
auto iter = vsCache_.find(VShaderID(shaderId));
683
if (iter == vsCache_.end()) {
684
return "";
685
}
686
return iter->second->GetShaderString(stringType);
687
}
688
689
case SHADER_TYPE_FRAGMENT:
690
{
691
auto iter = fsCache_.find(FShaderID(shaderId));
692
if (iter == fsCache_.end()) {
693
return "";
694
}
695
return iter->second->GetShaderString(stringType);
696
}
697
default:
698
return "N/A";
699
}
700
}
701
702