2013-08-17 11:23:51 +02:00
|
|
|
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
2020-10-30 23:29:18 +01:00
|
|
|
//#define SHADERLOG
|
2013-08-17 11:23:51 +02:00
|
|
|
#endif
|
|
|
|
|
2018-09-10 00:27:16 -07:00
|
|
|
#include <cmath>
|
2013-08-17 11:23:51 +02:00
|
|
|
#include <map>
|
2020-08-15 12:25:39 +02:00
|
|
|
|
2021-10-23 13:44:10 -07:00
|
|
|
#include "Common/Data/Convert/SmallDataConvert.h"
|
|
|
|
#include "Common/Data/Encoding/Utf8.h"
|
2020-10-01 13:05:04 +02:00
|
|
|
#include "Common/Data/Text/I18n.h"
|
2020-10-04 00:25:21 +02:00
|
|
|
#include "Common/Math/lin/matrix4x4.h"
|
|
|
|
#include "Common/Math/math_util.h"
|
2020-10-04 23:24:14 +02:00
|
|
|
#include "Common/GPU/D3D9/D3D9ShaderCompiler.h"
|
|
|
|
#include "Common/GPU/thin3d.h"
|
2021-10-23 13:44:10 -07:00
|
|
|
#include "Common/System/Display.h"
|
2013-08-17 11:23:51 +02:00
|
|
|
|
2022-01-30 15:49:02 -08:00
|
|
|
#include "Common/CommonTypes.h"
|
2020-08-15 16:13:24 +02:00
|
|
|
#include "Common/Log.h"
|
2022-12-27 14:58:20 -08:00
|
|
|
#include "Common/LogReporting.h"
|
2020-09-29 12:19:22 +02:00
|
|
|
#include "Common/StringUtils.h"
|
|
|
|
|
2014-09-21 10:41:44 -07:00
|
|
|
#include "Core/Config.h"
|
2016-05-27 22:00:14 -07:00
|
|
|
#include "Core/Host.h"
|
2013-12-29 13:32:55 -08:00
|
|
|
#include "GPU/Math3D.h"
|
2013-08-17 11:23:51 +02:00
|
|
|
#include "GPU/GPUState.h"
|
|
|
|
#include "GPU/ge_constants.h"
|
2018-09-17 22:27:25 -07:00
|
|
|
#include "GPU/Common/ShaderUniforms.h"
|
2020-10-31 18:56:44 +01:00
|
|
|
#include "GPU/Common/FragmentShaderGenerator.h"
|
2013-09-15 12:46:14 +02:00
|
|
|
#include "GPU/Directx9/ShaderManagerDX9.h"
|
2016-04-10 10:55:13 +02:00
|
|
|
#include "GPU/Directx9/DrawEngineDX9.h"
|
2020-08-03 23:24:50 +02:00
|
|
|
#include "GPU/Directx9/FramebufferManagerDX9.h"
|
2013-08-17 11:23:51 +02:00
|
|
|
|
2019-10-22 22:58:10 +02:00
|
|
|
using namespace Lin;
|
|
|
|
|
2021-02-15 10:29:34 -08:00
|
|
|
PSShader::PSShader(LPDIRECT3DDEVICE9 device, FShaderID id, const char *code) : id_(id) {
|
2013-08-17 11:23:51 +02:00
|
|
|
source_ = code;
|
|
|
|
#ifdef SHADERLOG
|
2013-09-15 12:46:14 +02:00
|
|
|
OutputDebugString(ConvertUTF8ToWString(code).c_str());
|
2013-08-17 11:23:51 +02:00
|
|
|
#endif
|
|
|
|
bool success;
|
2014-09-07 11:01:19 -07:00
|
|
|
std::string errorMessage;
|
2013-08-17 11:23:51 +02:00
|
|
|
|
2020-10-30 10:22:40 +01:00
|
|
|
success = CompilePixelShaderD3D9(device, code, &shader, &errorMessage);
|
2014-09-07 11:01:19 -07:00
|
|
|
|
|
|
|
if (!errorMessage.empty()) {
|
|
|
|
if (success) {
|
|
|
|
ERROR_LOG(G3D, "Warnings in shader compilation!");
|
|
|
|
} else {
|
|
|
|
ERROR_LOG(G3D, "Error in shader compilation!");
|
|
|
|
}
|
|
|
|
ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str());
|
2018-09-08 19:24:10 -07:00
|
|
|
ERROR_LOG(G3D, "Shader source:\n%s", LineNumberString(code).c_str());
|
2014-09-07 11:01:19 -07:00
|
|
|
OutputDebugStringUTF8("Messages:\n");
|
|
|
|
OutputDebugStringUTF8(errorMessage.c_str());
|
|
|
|
Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);
|
|
|
|
}
|
2013-08-17 11:23:51 +02:00
|
|
|
|
|
|
|
if (!success) {
|
|
|
|
failed_ = true;
|
2014-09-07 10:38:49 -07:00
|
|
|
if (shader)
|
|
|
|
shader->Release();
|
2013-08-17 11:23:51 +02:00
|
|
|
shader = NULL;
|
2014-09-10 12:40:15 +02:00
|
|
|
return;
|
2013-08-17 11:23:51 +02:00
|
|
|
} else {
|
2020-02-29 10:43:50 +01:00
|
|
|
VERBOSE_LOG(G3D, "Compiled pixel shader:\n%s\n", (const char *)code);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PSShader::~PSShader() {
|
|
|
|
if (shader)
|
|
|
|
shader->Release();
|
|
|
|
}
|
|
|
|
|
2015-10-25 00:34:23 +02:00
|
|
|
std::string PSShader::GetShaderString(DebugShaderStringType type) const {
|
|
|
|
switch (type) {
|
|
|
|
case SHADER_STRING_SOURCE_CODE:
|
|
|
|
return source_;
|
|
|
|
case SHADER_STRING_SHORT_DESC:
|
|
|
|
return FragmentShaderDesc(id_);
|
|
|
|
default:
|
|
|
|
return "N/A";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-15 10:29:34 -08:00
|
|
|
VSShader::VSShader(LPDIRECT3DDEVICE9 device, VShaderID id, const char *code, bool useHWTransform) : useHWTransform_(useHWTransform), id_(id) {
|
2013-08-17 11:23:51 +02:00
|
|
|
source_ = code;
|
|
|
|
#ifdef SHADERLOG
|
2013-09-15 12:46:14 +02:00
|
|
|
OutputDebugString(ConvertUTF8ToWString(code).c_str());
|
2013-08-17 11:23:51 +02:00
|
|
|
#endif
|
|
|
|
bool success;
|
2014-09-07 11:01:19 -07:00
|
|
|
std::string errorMessage;
|
2013-08-17 11:23:51 +02:00
|
|
|
|
2020-10-30 10:22:40 +01:00
|
|
|
success = CompileVertexShaderD3D9(device, code, &shader, &errorMessage);
|
2014-09-07 11:01:19 -07:00
|
|
|
if (!errorMessage.empty()) {
|
|
|
|
if (success) {
|
|
|
|
ERROR_LOG(G3D, "Warnings in shader compilation!");
|
|
|
|
} else {
|
|
|
|
ERROR_LOG(G3D, "Error in shader compilation!");
|
|
|
|
}
|
|
|
|
ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str());
|
|
|
|
ERROR_LOG(G3D, "Shader source:\n%s", code);
|
|
|
|
OutputDebugStringUTF8("Messages:\n");
|
|
|
|
OutputDebugStringUTF8(errorMessage.c_str());
|
|
|
|
Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);
|
|
|
|
}
|
2013-08-17 11:23:51 +02:00
|
|
|
|
|
|
|
if (!success) {
|
|
|
|
failed_ = true;
|
2014-09-07 10:38:49 -07:00
|
|
|
if (shader)
|
|
|
|
shader->Release();
|
2013-08-17 11:23:51 +02:00
|
|
|
shader = NULL;
|
2014-09-10 12:40:15 +02:00
|
|
|
return;
|
2013-08-17 11:23:51 +02:00
|
|
|
} else {
|
2020-02-29 10:43:50 +01:00
|
|
|
VERBOSE_LOG(G3D, "Compiled vertex shader:\n%s\n", (const char *)code);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
2014-09-10 12:40:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
VSShader::~VSShader() {
|
|
|
|
if (shader)
|
|
|
|
shader->Release();
|
|
|
|
}
|
|
|
|
|
2015-10-25 00:34:23 +02:00
|
|
|
std::string VSShader::GetShaderString(DebugShaderStringType type) const {
|
|
|
|
switch (type) {
|
|
|
|
case SHADER_STRING_SOURCE_CODE:
|
|
|
|
return source_;
|
|
|
|
case SHADER_STRING_SHORT_DESC:
|
|
|
|
return VertexShaderDesc(id_);
|
|
|
|
default:
|
|
|
|
return "N/A";
|
|
|
|
}
|
|
|
|
}
|
2014-09-10 12:40:15 +02:00
|
|
|
|
2014-09-10 13:57:19 +02:00
|
|
|
void ShaderManagerDX9::PSSetColorUniform3(int creg, u32 color) {
|
2017-08-20 13:53:39 +02:00
|
|
|
float f[4];
|
|
|
|
Uint8x3ToFloat4(f, color);
|
|
|
|
device_->SetPixelShaderConstantF(creg, f, 1);
|
2014-09-10 12:59:33 +02:00
|
|
|
}
|
|
|
|
|
2014-09-10 13:57:19 +02:00
|
|
|
void ShaderManagerDX9::PSSetColorUniform3Alpha255(int creg, u32 color, u8 alpha) {
|
2017-11-30 15:28:15 +01:00
|
|
|
const float col[4] = {
|
|
|
|
(float)((color & 0xFF)),
|
|
|
|
(float)((color & 0xFF00) >> 8),
|
|
|
|
(float)((color & 0xFF0000) >> 16),
|
|
|
|
(float)alpha,
|
|
|
|
};
|
|
|
|
device_->SetPixelShaderConstantF(creg, col, 1);
|
2013-08-23 14:29:33 +02:00
|
|
|
}
|
|
|
|
|
2014-09-21 10:41:44 -07:00
|
|
|
void ShaderManagerDX9::PSSetFloat(int creg, float value) {
|
|
|
|
const float f[4] = { value, 0.0f, 0.0f, 0.0f };
|
2017-02-05 20:36:00 +01:00
|
|
|
device_->SetPixelShaderConstantF(creg, f, 1);
|
2014-09-21 10:41:44 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShaderManagerDX9::PSSetFloatArray(int creg, const float *value, int count) {
|
|
|
|
float f[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
f[i] = value[i];
|
|
|
|
}
|
2017-02-05 20:36:00 +01:00
|
|
|
device_->SetPixelShaderConstantF(creg, f, 1);
|
2014-09-21 10:41:44 -07:00
|
|
|
}
|
|
|
|
|
2014-09-10 13:57:19 +02:00
|
|
|
void ShaderManagerDX9::VSSetFloat(int creg, float value) {
|
2014-09-10 13:22:05 +02:00
|
|
|
const float f[4] = { value, 0.0f, 0.0f, 0.0f };
|
2017-02-05 20:36:00 +01:00
|
|
|
device_->SetVertexShaderConstantF(creg, f, 1);
|
2014-09-10 12:40:15 +02:00
|
|
|
}
|
|
|
|
|
2014-09-10 13:57:19 +02:00
|
|
|
void ShaderManagerDX9::VSSetFloatArray(int creg, const float *value, int count) {
|
2014-09-10 13:22:05 +02:00
|
|
|
float f[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
f[i] = value[i];
|
|
|
|
}
|
2017-02-05 20:36:00 +01:00
|
|
|
device_->SetVertexShaderConstantF(creg, f, 1);
|
2013-08-23 14:29:33 +02:00
|
|
|
}
|
|
|
|
|
2013-08-23 17:11:01 +02:00
|
|
|
// Utility
|
2014-09-10 13:57:19 +02:00
|
|
|
void ShaderManagerDX9::VSSetColorUniform3(int creg, u32 color) {
|
2017-08-20 13:53:39 +02:00
|
|
|
float f[4];
|
|
|
|
Uint8x3ToFloat4(f, color);
|
|
|
|
device_->SetVertexShaderConstantF(creg, f, 1);
|
2014-09-10 12:40:15 +02:00
|
|
|
}
|
|
|
|
|
2022-12-10 21:02:44 -08:00
|
|
|
void ShaderManagerDX9::VSSetFloatUniform4(int creg, const float data[4]) {
|
2017-02-05 20:36:00 +01:00
|
|
|
device_->SetVertexShaderConstantF(creg, data, 1);
|
2015-08-26 17:45:21 +02:00
|
|
|
}
|
|
|
|
|
2014-09-10 13:57:19 +02:00
|
|
|
void ShaderManagerDX9::VSSetFloat24Uniform3(int creg, const u32 data[3]) {
|
2017-08-20 13:53:39 +02:00
|
|
|
float f[4];
|
|
|
|
ExpandFloat24x3ToFloat4(f, data);
|
|
|
|
device_->SetVertexShaderConstantF(creg, f, 1);
|
2014-04-18 14:30:18 +02:00
|
|
|
}
|
2013-08-17 11:23:51 +02:00
|
|
|
|
2014-09-10 13:57:19 +02:00
|
|
|
void ShaderManagerDX9::VSSetColorUniform3Alpha(int creg, u32 color, u8 alpha) {
|
2017-08-20 13:53:39 +02:00
|
|
|
float f[4];
|
|
|
|
Uint8x3ToFloat4_AlphaUint8(f, color, alpha);
|
|
|
|
device_->SetVertexShaderConstantF(creg, f, 1);
|
2013-08-23 14:29:33 +02:00
|
|
|
}
|
|
|
|
|
2014-09-10 13:57:19 +02:00
|
|
|
void ShaderManagerDX9::VSSetColorUniform3ExtraFloat(int creg, u32 color, float extra) {
|
2013-08-23 17:11:01 +02:00
|
|
|
const float col[4] = {
|
|
|
|
((color & 0xFF)) / 255.0f,
|
|
|
|
((color & 0xFF00) >> 8) / 255.0f,
|
|
|
|
((color & 0xFF0000) >> 16) / 255.0f,
|
|
|
|
extra
|
|
|
|
};
|
2017-02-05 20:36:00 +01:00
|
|
|
device_->SetVertexShaderConstantF(creg, col, 1);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
|
|
|
|
2014-09-18 23:08:46 +02:00
|
|
|
void ShaderManagerDX9::VSSetMatrix4x3_3(int creg, const float *m4x3) {
|
2017-02-14 11:53:46 +01:00
|
|
|
float m3x4[12];
|
2014-09-18 23:08:46 +02:00
|
|
|
ConvertMatrix4x3To3x4Transposed(m3x4, m4x3);
|
2017-02-05 20:36:00 +01:00
|
|
|
device_->SetVertexShaderConstantF(creg, m3x4, 3);
|
2014-09-18 23:08:46 +02:00
|
|
|
}
|
|
|
|
|
2014-09-10 13:57:19 +02:00
|
|
|
void ShaderManagerDX9::VSSetMatrix(int creg, const float* pMatrix) {
|
2020-11-01 11:35:23 +01:00
|
|
|
device_->SetVertexShaderConstantF(creg, pMatrix, 4);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
|
|
|
|
2014-09-08 23:10:23 +02:00
|
|
|
// Depth in ogl is between -1;1 we need between 0;1 and optionally reverse it
|
2016-01-03 12:11:05 -08:00
|
|
|
static void ConvertProjMatrixToD3D(Matrix4x4 &in, bool invertedX, bool invertedY) {
|
2015-11-04 22:37:42 +01:00
|
|
|
// Half pixel offset hack
|
2017-05-23 23:45:55 -07:00
|
|
|
float xoff = 1.0f / gstate_c.curRTRenderWidth;
|
2020-01-26 16:34:46 +01:00
|
|
|
if (invertedX) {
|
|
|
|
xoff = -gstate_c.vpXOffset - xoff;
|
|
|
|
} else {
|
|
|
|
xoff = gstate_c.vpXOffset - xoff;
|
|
|
|
}
|
2015-11-04 22:37:42 +01:00
|
|
|
|
2020-01-26 16:34:46 +01:00
|
|
|
float yoff = -1.0f / gstate_c.curRTRenderHeight;
|
|
|
|
if (invertedY) {
|
|
|
|
yoff = -gstate_c.vpYOffset - yoff;
|
2020-06-28 18:18:12 +02:00
|
|
|
} else {
|
|
|
|
yoff = gstate_c.vpYOffset - yoff;
|
2020-01-26 16:34:46 +01:00
|
|
|
}
|
2015-11-09 19:35:25 +01:00
|
|
|
|
2016-01-16 00:17:27 -08:00
|
|
|
const Vec3 trans(xoff, yoff, gstate_c.vpZOffset * 0.5f + 0.5f);
|
2016-01-03 12:11:05 -08:00
|
|
|
const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);
|
|
|
|
in.translateAndScale(trans, scale);
|
2014-12-18 22:16:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ConvertProjMatrixToD3DThrough(Matrix4x4 &in) {
|
2017-05-23 23:45:55 -07:00
|
|
|
float xoff = -1.0f / gstate_c.curRTRenderWidth;
|
|
|
|
float yoff = 1.0f / gstate_c.curRTRenderHeight;
|
2014-12-20 07:29:27 -08:00
|
|
|
in.translateAndScale(Vec3(xoff, yoff, 0.5f), Vec3(1.0f, 1.0f, 0.5f));
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
|
|
|
|
2022-07-31 10:43:12 +02:00
|
|
|
const uint64_t psUniforms = DIRTY_TEXENV | DIRTY_ALPHACOLORREF | DIRTY_ALPHACOLORMASK | DIRTY_FOGCOLOR | DIRTY_STENCILREPLACEVALUE | DIRTY_SHADERBLEND | DIRTY_TEXCLAMP | DIRTY_MIPBIAS;
|
2017-01-24 14:16:51 +01:00
|
|
|
|
2017-01-23 17:32:18 +01:00
|
|
|
void ShaderManagerDX9::PSUpdateUniforms(u64 dirtyUniforms) {
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_TEXENV) {
|
2014-09-10 13:48:55 +02:00
|
|
|
PSSetColorUniform3(CONST_PS_TEXENV, gstate.texenvcolor);
|
2014-09-10 12:40:15 +02:00
|
|
|
}
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_ALPHACOLORREF) {
|
2018-09-08 20:05:19 -07:00
|
|
|
PSSetColorUniform3Alpha255(CONST_PS_ALPHACOLORREF, gstate.getColorTestRef(), gstate.getAlphaTestRef() & gstate.getAlphaTestMask());
|
2014-09-10 12:40:15 +02:00
|
|
|
}
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_ALPHACOLORMASK) {
|
2018-09-08 20:05:19 -07:00
|
|
|
PSSetColorUniform3Alpha255(CONST_PS_ALPHACOLORMASK, gstate.colortestmask, gstate.getAlphaTestMask());
|
2014-09-10 12:40:15 +02:00
|
|
|
}
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_FOGCOLOR) {
|
2014-09-10 13:48:55 +02:00
|
|
|
PSSetColorUniform3(CONST_PS_FOGCOLOR, gstate.fogcolor);
|
2014-09-10 12:40:15 +02:00
|
|
|
}
|
2014-09-21 10:41:44 -07:00
|
|
|
if (dirtyUniforms & DIRTY_STENCILREPLACEVALUE) {
|
|
|
|
PSSetFloat(CONST_PS_STENCILREPLACE, (float)gstate.getStencilTestRef() * (1.0f / 255.0f));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dirtyUniforms & DIRTY_SHADERBLEND) {
|
|
|
|
PSSetColorUniform3(CONST_PS_BLENDFIXA, gstate.getFixA());
|
|
|
|
PSSetColorUniform3(CONST_PS_BLENDFIXB, gstate.getFixB());
|
|
|
|
|
|
|
|
const float fbotexSize[2] = {
|
|
|
|
1.0f / (float)gstate_c.curRTRenderWidth,
|
|
|
|
1.0f / (float)gstate_c.curRTRenderHeight,
|
|
|
|
};
|
|
|
|
PSSetFloatArray(CONST_PS_FBOTEXSIZE, fbotexSize, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dirtyUniforms & DIRTY_TEXCLAMP) {
|
|
|
|
const float invW = 1.0f / (float)gstate_c.curTextureWidth;
|
|
|
|
const float invH = 1.0f / (float)gstate_c.curTextureHeight;
|
|
|
|
const int w = gstate.getTextureWidth(0);
|
|
|
|
const int h = gstate.getTextureHeight(0);
|
|
|
|
const float widthFactor = (float)w * invW;
|
|
|
|
const float heightFactor = (float)h * invH;
|
|
|
|
|
|
|
|
// First wrap xy, then half texel xy (for clamp.)
|
|
|
|
const float texclamp[4] = {
|
|
|
|
widthFactor,
|
|
|
|
heightFactor,
|
|
|
|
invW * 0.5f,
|
|
|
|
invH * 0.5f,
|
|
|
|
};
|
|
|
|
const float texclampoff[2] = {
|
|
|
|
gstate_c.curTextureXOffset * invW,
|
|
|
|
gstate_c.curTextureYOffset * invH,
|
|
|
|
};
|
|
|
|
PSSetFloatArray(CONST_PS_TEXCLAMP, texclamp, 4);
|
|
|
|
PSSetFloatArray(CONST_PS_TEXCLAMPOFF, texclampoff, 2);
|
2022-07-31 10:43:12 +02:00
|
|
|
}
|
2022-07-30 20:41:31 +02:00
|
|
|
|
2022-07-31 10:43:12 +02:00
|
|
|
if (dirtyUniforms & DIRTY_MIPBIAS) {
|
2022-07-30 20:41:31 +02:00
|
|
|
float mipBias = (float)gstate.getTexLevelOffset16() * (1.0 / 16.0f);
|
|
|
|
|
2022-07-30 21:33:24 +02:00
|
|
|
// NOTE: This equation needs some adjustment in D3D9. Can't get it to look completely smooth :(
|
|
|
|
mipBias = (mipBias + 0.25f) / (float)(gstate.getTextureMaxLevel() + 1);
|
2022-07-30 20:41:31 +02:00
|
|
|
PSSetFloatArray(CONST_PS_MIPBIAS, &mipBias, 1);
|
2014-09-21 10:41:44 -07:00
|
|
|
}
|
2013-08-23 17:11:01 +02:00
|
|
|
}
|
|
|
|
|
2017-01-24 14:16:51 +01:00
|
|
|
const uint64_t vsUniforms = DIRTY_PROJMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_WORLDMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX |
|
2018-09-16 23:40:30 -07:00
|
|
|
DIRTY_FOGCOEF | DIRTY_BONE_UNIFORMS | DIRTY_UVSCALEOFFSET | DIRTY_DEPTHRANGE | DIRTY_CULLRANGE |
|
2017-01-24 14:16:51 +01:00
|
|
|
DIRTY_AMBIENT | DIRTY_MATAMBIENTALPHA | DIRTY_MATSPECULAR | DIRTY_MATDIFFUSE | DIRTY_MATEMISSIVE | DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3;
|
|
|
|
|
2017-01-23 17:32:18 +01:00
|
|
|
void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) {
|
2013-08-17 11:23:51 +02:00
|
|
|
// Update any dirty uniforms before we draw
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_PROJMATRIX) {
|
2013-08-17 11:23:51 +02:00
|
|
|
Matrix4x4 flippedMatrix;
|
|
|
|
memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float));
|
2014-09-13 22:01:32 -07:00
|
|
|
|
|
|
|
const bool invertedY = gstate_c.vpHeight < 0;
|
2014-09-24 23:09:09 -07:00
|
|
|
if (!invertedY) {
|
2015-11-04 22:37:42 +01:00
|
|
|
flippedMatrix[1] = -flippedMatrix[1];
|
2013-08-17 11:23:51 +02:00
|
|
|
flippedMatrix[5] = -flippedMatrix[5];
|
2015-11-04 22:37:42 +01:00
|
|
|
flippedMatrix[9] = -flippedMatrix[9];
|
2013-08-17 11:23:51 +02:00
|
|
|
flippedMatrix[13] = -flippedMatrix[13];
|
|
|
|
}
|
2014-09-13 22:01:32 -07:00
|
|
|
const bool invertedX = gstate_c.vpWidth < 0;
|
|
|
|
if (invertedX) {
|
2013-08-17 11:23:51 +02:00
|
|
|
flippedMatrix[0] = -flippedMatrix[0];
|
2015-11-04 22:37:42 +01:00
|
|
|
flippedMatrix[4] = -flippedMatrix[4];
|
|
|
|
flippedMatrix[8] = -flippedMatrix[8];
|
2013-08-17 11:23:51 +02:00
|
|
|
flippedMatrix[12] = -flippedMatrix[12];
|
|
|
|
}
|
2014-09-09 00:29:01 +02:00
|
|
|
|
2016-01-03 12:11:05 -08:00
|
|
|
ConvertProjMatrixToD3D(flippedMatrix, invertedX, invertedY);
|
2013-08-17 11:23:51 +02:00
|
|
|
|
2014-09-10 13:48:55 +02:00
|
|
|
VSSetMatrix(CONST_VS_PROJ, flippedMatrix.getReadPtr());
|
2021-10-31 13:35:13 +01:00
|
|
|
VSSetFloat(CONST_VS_ROTATION, 0); // We don't use this on any platform in D3D9.
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) {
|
2013-08-17 11:23:51 +02:00
|
|
|
Matrix4x4 proj_through;
|
|
|
|
proj_through.setOrtho(0.0f, gstate_c.curRTWidth, gstate_c.curRTHeight, 0, 0, 1);
|
|
|
|
|
2014-12-18 22:16:26 -08:00
|
|
|
ConvertProjMatrixToD3DThrough(proj_through);
|
2013-08-17 11:23:51 +02:00
|
|
|
|
2014-09-10 13:48:55 +02:00
|
|
|
VSSetMatrix(CONST_VS_PROJ_THROUGH, proj_through.getReadPtr());
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
|
|
|
// Transform
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_WORLDMATRIX) {
|
2014-09-18 23:08:46 +02:00
|
|
|
VSSetMatrix4x3_3(CONST_VS_WORLD, gstate.worldMatrix);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_VIEWMATRIX) {
|
2014-09-18 23:08:46 +02:00
|
|
|
VSSetMatrix4x3_3(CONST_VS_VIEW, gstate.viewMatrix);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_TEXMATRIX) {
|
2014-09-18 23:08:46 +02:00
|
|
|
VSSetMatrix4x3_3(CONST_VS_TEXMTX, gstate.tgenMatrix);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_FOGCOEF) {
|
2014-12-22 00:47:55 +01:00
|
|
|
float fogcoef[2] = {
|
2014-09-10 12:40:15 +02:00
|
|
|
getFloat24(gstate.fog1),
|
|
|
|
getFloat24(gstate.fog2),
|
|
|
|
};
|
2018-09-10 00:27:16 -07:00
|
|
|
// The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float.
|
|
|
|
// Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988
|
|
|
|
if (my_isnanorinf(fogcoef[0])) {
|
|
|
|
// Not really sure what a sensible value might be, but let's try 64k.
|
|
|
|
fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f;
|
2014-12-22 00:47:55 +01:00
|
|
|
}
|
2018-09-10 00:27:16 -07:00
|
|
|
if (my_isnanorinf(fogcoef[1])) {
|
|
|
|
fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f;
|
2014-12-22 00:47:55 +01:00
|
|
|
}
|
2014-09-10 13:48:55 +02:00
|
|
|
VSSetFloatArray(CONST_VS_FOGCOEF, fogcoef, 2);
|
2014-09-10 12:40:15 +02:00
|
|
|
}
|
2018-04-10 12:22:02 +02:00
|
|
|
// TODO: Could even set all bones in one go if they're all dirty.
|
|
|
|
#ifdef USE_BONE_ARRAY
|
|
|
|
if (u_bone != 0) {
|
|
|
|
float allBones[8 * 16];
|
|
|
|
|
|
|
|
bool allDirty = true;
|
|
|
|
for (int i = 0; i < numBones; i++) {
|
|
|
|
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
|
|
|
|
ConvertMatrix4x3To4x4(allBones + 16 * i, gstate.boneMatrix + 12 * i);
|
|
|
|
} else {
|
|
|
|
allDirty = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (allDirty) {
|
|
|
|
// Set them all with one call
|
|
|
|
//glUniformMatrix4fv(u_bone, numBones, GL_FALSE, allBones);
|
|
|
|
} else {
|
|
|
|
// Set them one by one. Could try to coalesce two in a row etc but too lazy.
|
|
|
|
for (int i = 0; i < numBones; i++) {
|
|
|
|
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
|
|
|
|
//glUniformMatrix4fv(u_bone + i, 1, GL_FALSE, allBones + 16 * i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
|
|
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
|
|
|
|
VSSetMatrix4x3_3(CONST_VS_BONE0 + 3 * i, gstate.boneMatrix + 12 * i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2013-08-17 11:23:51 +02:00
|
|
|
|
2014-09-10 12:40:15 +02:00
|
|
|
// Texturing
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_UVSCALEOFFSET) {
|
2014-09-21 10:41:44 -07:00
|
|
|
const float invW = 1.0f / (float)gstate_c.curTextureWidth;
|
|
|
|
const float invH = 1.0f / (float)gstate_c.curTextureHeight;
|
|
|
|
const int w = gstate.getTextureWidth(0);
|
|
|
|
const int h = gstate.getTextureHeight(0);
|
|
|
|
const float widthFactor = (float)w * invW;
|
|
|
|
const float heightFactor = (float)h * invH;
|
2014-09-10 12:40:15 +02:00
|
|
|
float uvscaleoff[4];
|
2016-12-20 13:27:44 +01:00
|
|
|
uvscaleoff[0] = widthFactor;
|
|
|
|
uvscaleoff[1] = heightFactor;
|
|
|
|
uvscaleoff[2] = 0.0f;
|
|
|
|
uvscaleoff[3] = 0.0f;
|
2014-09-10 13:48:55 +02:00
|
|
|
VSSetFloatArray(CONST_VS_UVSCALEOFFSET, uvscaleoff, 4);
|
2014-09-10 12:40:15 +02:00
|
|
|
}
|
|
|
|
|
2018-09-16 23:40:30 -07:00
|
|
|
if (dirtyUniforms & DIRTY_DEPTHRANGE) {
|
2016-01-18 20:26:31 -08:00
|
|
|
// Depth is [0, 1] mapping to [minz, maxz], not too hard.
|
2016-01-18 20:53:38 -08:00
|
|
|
float vpZScale = gstate.getViewportZScale();
|
|
|
|
float vpZCenter = gstate.getViewportZCenter();
|
2015-08-29 17:43:09 +02:00
|
|
|
|
2016-01-18 20:53:38 -08:00
|
|
|
// These are just the reverse of the formulas in GPUStateUtils.
|
|
|
|
float halfActualZRange = vpZScale / gstate_c.vpDepthScale;
|
|
|
|
float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange;
|
|
|
|
float viewZScale = halfActualZRange * 2.0f;
|
2016-01-20 22:53:47 -08:00
|
|
|
// Account for the half pixel offset.
|
|
|
|
float viewZCenter = minz + (DepthSliceFactor() / 256.0f) * 0.5f;
|
2021-09-11 16:54:25 -07:00
|
|
|
float reverseScale = 2.0f * (1.0f / gstate_c.vpDepthScale);
|
|
|
|
float reverseTranslate = gstate_c.vpZOffset * 0.5f + 0.5f;
|
2015-08-30 22:43:44 +02:00
|
|
|
|
2021-09-11 16:54:25 -07:00
|
|
|
float data[4] = { viewZScale, viewZCenter, reverseTranslate, reverseScale };
|
2015-08-26 17:45:21 +02:00
|
|
|
VSSetFloatUniform4(CONST_VS_DEPTHRANGE, data);
|
2022-12-18 11:01:05 -08:00
|
|
|
|
|
|
|
if (draw_->GetDeviceCaps().clipPlanesSupported >= 1) {
|
|
|
|
float clip[4] = { 0.0f, 0.0f, reverseScale, 1.0f - reverseTranslate * reverseScale };
|
|
|
|
// Well, not a uniform, but we treat it as one like other backends.
|
|
|
|
device_->SetClipPlane(0, clip);
|
|
|
|
}
|
2015-08-26 17:45:21 +02:00
|
|
|
}
|
2018-09-16 23:40:30 -07:00
|
|
|
if (dirtyUniforms & DIRTY_CULLRANGE) {
|
2018-09-17 22:27:25 -07:00
|
|
|
float minValues[4], maxValues[4];
|
|
|
|
CalcCullRange(minValues, maxValues, false, false);
|
2018-09-16 23:40:30 -07:00
|
|
|
VSSetFloatUniform4(CONST_VS_CULLRANGEMIN, minValues);
|
|
|
|
VSSetFloatUniform4(CONST_VS_CULLRANGEMAX, maxValues);
|
|
|
|
}
|
|
|
|
|
2013-08-17 11:23:51 +02:00
|
|
|
// Lighting
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_AMBIENT) {
|
2014-09-10 13:48:55 +02:00
|
|
|
VSSetColorUniform3Alpha(CONST_VS_AMBIENT, gstate.ambientcolor, gstate.getAmbientA());
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_MATAMBIENTALPHA) {
|
2014-09-10 13:48:55 +02:00
|
|
|
VSSetColorUniform3Alpha(CONST_VS_MATAMBIENTALPHA, gstate.materialambient, gstate.getMaterialAmbientA());
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_MATDIFFUSE) {
|
2014-09-10 13:48:55 +02:00
|
|
|
VSSetColorUniform3(CONST_VS_MATDIFFUSE, gstate.materialdiffuse);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_MATEMISSIVE) {
|
2014-09-10 13:48:55 +02:00
|
|
|
VSSetColorUniform3(CONST_VS_MATEMISSIVE, gstate.materialemissive);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
2014-09-10 13:57:19 +02:00
|
|
|
if (dirtyUniforms & DIRTY_MATSPECULAR) {
|
2014-09-10 13:48:55 +02:00
|
|
|
VSSetColorUniform3ExtraFloat(CONST_VS_MATSPECULAR, gstate.materialspecular, getFloat24(gstate.materialspecularcoef));
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
if (dirtyUniforms & (DIRTY_LIGHT0 << i)) {
|
2014-09-10 13:57:19 +02:00
|
|
|
if (gstate.isDirectionalLight(i)) {
|
|
|
|
// Prenormalize
|
|
|
|
float x = getFloat24(gstate.lpos[i * 3 + 0]);
|
|
|
|
float y = getFloat24(gstate.lpos[i * 3 + 1]);
|
|
|
|
float z = getFloat24(gstate.lpos[i * 3 + 2]);
|
|
|
|
float len = sqrtf(x*x + y*y + z*z);
|
|
|
|
if (len == 0.0f)
|
|
|
|
len = 1.0f;
|
|
|
|
else
|
|
|
|
len = 1.0f / len;
|
|
|
|
float vec[3] = { x * len, y * len, z * len };
|
|
|
|
VSSetFloatArray(CONST_VS_LIGHTPOS + i, vec, 3);
|
|
|
|
} else {
|
|
|
|
VSSetFloat24Uniform3(CONST_VS_LIGHTPOS + i, &gstate.lpos[i * 3]);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
2014-09-10 13:57:19 +02:00
|
|
|
VSSetFloat24Uniform3(CONST_VS_LIGHTDIR + i, &gstate.ldir[i * 3]);
|
|
|
|
VSSetFloat24Uniform3(CONST_VS_LIGHTATT + i, &gstate.latt[i * 3]);
|
2018-03-12 11:07:51 +01:00
|
|
|
float angle_spotCoef[4] = { getFloat24(gstate.lcutoff[i]), getFloat24(gstate.lconv[i]) };
|
|
|
|
VSSetFloatUniform4(CONST_VS_LIGHTANGLE_SPOTCOEF + i, angle_spotCoef);
|
2014-09-10 13:57:19 +02:00
|
|
|
VSSetColorUniform3(CONST_VS_LIGHTAMBIENT + i, gstate.lcolor[i * 3]);
|
|
|
|
VSSetColorUniform3(CONST_VS_LIGHTDIFFUSE + i, gstate.lcolor[i * 3 + 1]);
|
|
|
|
VSSetColorUniform3(CONST_VS_LIGHTSPECULAR + i, gstate.lcolor[i * 3 + 2]);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-23 12:06:29 -08:00
|
|
|
ShaderManagerDX9::ShaderManagerDX9(Draw::DrawContext *draw, LPDIRECT3DDEVICE9 device)
|
2020-11-06 09:01:13 +01:00
|
|
|
: ShaderManagerCommon(draw), device_(device) {
|
2020-10-31 11:31:16 +01:00
|
|
|
codeBuffer_ = new char[32768];
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
|
|
|
|
2013-09-15 12:46:14 +02:00
|
|
|
ShaderManagerDX9::~ShaderManagerDX9() {
|
2013-08-17 11:23:51 +02:00
|
|
|
delete [] codeBuffer_;
|
|
|
|
}
|
|
|
|
|
2013-09-15 12:46:14 +02:00
|
|
|
void ShaderManagerDX9::Clear() {
|
2013-08-23 17:11:01 +02:00
|
|
|
for (auto iter = fsCache_.begin(); iter != fsCache_.end(); ++iter) {
|
2013-08-17 11:23:51 +02:00
|
|
|
delete iter->second;
|
|
|
|
}
|
2013-08-23 17:11:01 +02:00
|
|
|
for (auto iter = vsCache_.begin(); iter != vsCache_.end(); ++iter) {
|
2013-08-17 11:23:51 +02:00
|
|
|
delete iter->second;
|
|
|
|
}
|
2013-08-23 17:11:01 +02:00
|
|
|
fsCache_.clear();
|
|
|
|
vsCache_.clear();
|
2013-08-17 11:23:51 +02:00
|
|
|
DirtyShader();
|
|
|
|
}
|
|
|
|
|
2013-09-15 12:46:14 +02:00
|
|
|
void ShaderManagerDX9::ClearCache(bool deleteThem) {
|
2013-08-17 11:23:51 +02:00
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-15 12:46:14 +02:00
|
|
|
void ShaderManagerDX9::DirtyShader() {
|
2013-08-17 11:23:51 +02:00
|
|
|
// Forget the last shader ID
|
2017-09-20 08:30:34 -07:00
|
|
|
lastFSID_.set_invalid();
|
|
|
|
lastVSID_.set_invalid();
|
2014-09-10 15:20:57 +02:00
|
|
|
lastVShader_ = nullptr;
|
|
|
|
lastPShader_ = nullptr;
|
2017-09-20 08:30:34 -07:00
|
|
|
gstate_c.Dirty(DIRTY_ALL_UNIFORMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
|
|
|
|
2013-11-15 14:24:25 +01:00
|
|
|
void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays
|
2014-09-10 15:20:57 +02:00
|
|
|
lastVShader_ = nullptr;
|
|
|
|
lastPShader_ = nullptr;
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
|
|
|
|
2022-11-06 08:40:54 -08:00
|
|
|
VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState) {
|
2017-12-02 09:07:27 -08:00
|
|
|
VShaderID VSID;
|
2017-01-30 14:04:20 +01:00
|
|
|
if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {
|
|
|
|
gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);
|
2022-11-06 08:40:54 -08:00
|
|
|
ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);
|
2017-01-30 14:04:20 +01:00
|
|
|
} else {
|
|
|
|
VSID = lastVSID_;
|
|
|
|
}
|
|
|
|
|
2017-12-02 09:07:27 -08:00
|
|
|
FShaderID FSID;
|
2017-03-19 11:32:29 +01:00
|
|
|
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
|
|
|
|
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
|
2022-09-02 22:07:42 +02:00
|
|
|
ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs());
|
2017-03-19 11:32:29 +01:00
|
|
|
} else {
|
|
|
|
FSID = lastFSID_;
|
|
|
|
}
|
2013-08-17 11:23:51 +02:00
|
|
|
|
|
|
|
// Just update uniforms if this is the same shader as last time.
|
2014-09-10 14:07:30 +02:00
|
|
|
if (lastVShader_ != nullptr && lastPShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) {
|
2017-01-23 23:15:54 +01:00
|
|
|
uint64_t dirtyUniforms = gstate_c.GetDirtyUniforms();
|
|
|
|
if (dirtyUniforms) {
|
2017-01-24 14:16:51 +01:00
|
|
|
if (dirtyUniforms & psUniforms)
|
|
|
|
PSUpdateUniforms(dirtyUniforms);
|
|
|
|
if (dirtyUniforms & vsUniforms)
|
|
|
|
VSUpdateUniforms(dirtyUniforms);
|
2017-01-23 23:15:54 +01:00
|
|
|
gstate_c.CleanUniforms();
|
2014-09-10 15:20:57 +02:00
|
|
|
}
|
2014-09-10 14:07:30 +02:00
|
|
|
return lastVShader_; // Already all set.
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
|
|
|
|
2013-08-23 17:11:01 +02:00
|
|
|
VSCache::iterator vsIter = vsCache_.find(VSID);
|
2020-10-21 23:09:34 +02:00
|
|
|
VSShader *vs = nullptr;
|
2013-08-23 17:11:01 +02:00
|
|
|
if (vsIter == vsCache_.end()) {
|
2013-08-17 11:23:51 +02:00
|
|
|
// Vertex shader not in cache. Let's compile it.
|
2020-10-21 23:09:34 +02:00
|
|
|
std::string genErrorString;
|
2020-11-01 12:54:44 +01:00
|
|
|
uint32_t attrMask;
|
|
|
|
uint64_t uniformMask;
|
2022-12-02 13:49:28 +01:00
|
|
|
VertexShaderFlags flags;
|
|
|
|
if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString)) {
|
2020-10-21 23:09:34 +02:00
|
|
|
vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform);
|
|
|
|
}
|
|
|
|
if (!vs || vs->Failed()) {
|
2020-01-26 10:43:18 -08:00
|
|
|
auto gr = GetI18NCategory("Graphics");
|
2020-10-21 23:09:34 +02:00
|
|
|
if (!vs) {
|
|
|
|
// TODO: Report this?
|
|
|
|
ERROR_LOG(G3D, "Shader generation failed, falling back to software transform");
|
|
|
|
} else {
|
|
|
|
ERROR_LOG(G3D, "Shader compilation failed, falling back to software transform");
|
|
|
|
}
|
2017-03-11 19:31:00 -08:00
|
|
|
if (!g_Config.bHideSlowWarnings) {
|
|
|
|
host->NotifyUserMessage(gr->T("hardware transform error - falling back to software"), 2.5f, 0xFF3030FF);
|
|
|
|
}
|
2013-08-17 11:23:51 +02:00
|
|
|
delete vs;
|
|
|
|
|
2022-11-06 08:40:54 -08:00
|
|
|
ComputeVertexShaderID(&VSID, vertType, false, false, weightsAsFloat, useSkinInDecode);
|
2015-10-25 00:34:23 +02:00
|
|
|
|
2013-08-17 11:23:51 +02:00
|
|
|
// TODO: Look for existing shader with the appropriate ID, use that instead of generating a new one - however, need to make sure
|
|
|
|
// that that shader ID is not used when computing the linked shader ID below, because then IDs won't match
|
|
|
|
// next time and we'll do this over and over...
|
|
|
|
|
|
|
|
// Can still work with software transform.
|
2020-11-01 12:54:44 +01:00
|
|
|
uint32_t attrMask;
|
|
|
|
uint64_t uniformMask;
|
2022-12-02 13:49:28 +01:00
|
|
|
bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString);
|
2020-10-21 23:09:34 +02:00
|
|
|
_assert_(success);
|
2017-02-05 20:46:26 +01:00
|
|
|
vs = new VSShader(device_, VSID, codeBuffer_, false);
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
|
|
|
|
2013-08-23 17:11:01 +02:00
|
|
|
vsCache_[VSID] = vs;
|
2013-08-17 11:23:51 +02:00
|
|
|
} else {
|
|
|
|
vs = vsIter->second;
|
|
|
|
}
|
2014-09-10 15:20:57 +02:00
|
|
|
lastVSID_ = VSID;
|
2013-08-17 11:23:51 +02:00
|
|
|
|
2013-08-23 17:11:01 +02:00
|
|
|
FSCache::iterator fsIter = fsCache_.find(FSID);
|
2013-08-17 11:23:51 +02:00
|
|
|
PSShader *fs;
|
2013-08-23 17:11:01 +02:00
|
|
|
if (fsIter == fsCache_.end()) {
|
2013-08-17 11:23:51 +02:00
|
|
|
// Fragment shader not in cache. Let's compile it.
|
2020-10-21 23:09:34 +02:00
|
|
|
std::string errorString;
|
2020-10-31 00:19:20 +01:00
|
|
|
uint64_t uniformMask;
|
2022-12-02 13:49:28 +01:00
|
|
|
FragmentShaderFlags flags;
|
|
|
|
bool success = GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &errorString);
|
2020-10-21 23:09:34 +02:00
|
|
|
// We're supposed to handle all possible cases.
|
|
|
|
_assert_(success);
|
2017-02-05 20:46:26 +01:00
|
|
|
fs = new PSShader(device_, FSID, codeBuffer_);
|
2013-08-23 17:11:01 +02:00
|
|
|
fsCache_[FSID] = fs;
|
2013-08-17 11:23:51 +02:00
|
|
|
} else {
|
|
|
|
fs = fsIter->second;
|
|
|
|
}
|
|
|
|
|
2014-09-10 15:20:57 +02:00
|
|
|
lastFSID_ = FSID;
|
|
|
|
|
2017-01-23 23:15:54 +01:00
|
|
|
uint64_t dirtyUniforms = gstate_c.GetDirtyUniforms();
|
|
|
|
if (dirtyUniforms) {
|
2017-01-24 14:16:51 +01:00
|
|
|
if (dirtyUniforms & psUniforms)
|
|
|
|
PSUpdateUniforms(dirtyUniforms);
|
|
|
|
if (dirtyUniforms & vsUniforms)
|
|
|
|
VSUpdateUniforms(dirtyUniforms);
|
2017-01-23 23:15:54 +01:00
|
|
|
gstate_c.CleanUniforms();
|
2014-09-10 15:20:57 +02:00
|
|
|
}
|
|
|
|
|
2017-02-05 20:36:00 +01:00
|
|
|
device_->SetPixelShader(fs->shader);
|
|
|
|
device_->SetVertexShader(vs->shader);
|
2013-08-17 11:23:51 +02:00
|
|
|
|
2014-09-10 14:07:30 +02:00
|
|
|
lastPShader_ = fs;
|
|
|
|
lastVShader_ = vs;
|
|
|
|
return vs;
|
2013-08-17 11:23:51 +02:00
|
|
|
}
|
2013-09-15 08:53:21 -07:00
|
|
|
|
2015-10-25 00:34:23 +02:00
|
|
|
std::vector<std::string> ShaderManagerDX9::DebugGetShaderIDs(DebugShaderType type) {
|
|
|
|
std::string id;
|
|
|
|
std::vector<std::string> ids;
|
|
|
|
switch (type) {
|
|
|
|
case SHADER_TYPE_VERTEX:
|
|
|
|
{
|
|
|
|
for (auto iter : vsCache_) {
|
|
|
|
iter.first.ToString(&id);
|
|
|
|
ids.push_back(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SHADER_TYPE_FRAGMENT:
|
|
|
|
{
|
|
|
|
for (auto iter : fsCache_) {
|
|
|
|
iter.first.ToString(&id);
|
|
|
|
ids.push_back(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string ShaderManagerDX9::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
|
|
|
|
ShaderID shaderId;
|
|
|
|
shaderId.FromString(id);
|
|
|
|
switch (type) {
|
|
|
|
case SHADER_TYPE_VERTEX:
|
|
|
|
{
|
2017-12-02 09:07:27 -08:00
|
|
|
auto iter = vsCache_.find(VShaderID(shaderId));
|
2015-10-25 00:34:23 +02:00
|
|
|
if (iter == vsCache_.end()) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return iter->second->GetShaderString(stringType);
|
|
|
|
}
|
|
|
|
|
|
|
|
case SHADER_TYPE_FRAGMENT:
|
|
|
|
{
|
2017-12-02 09:07:27 -08:00
|
|
|
auto iter = fsCache_.find(FShaderID(shaderId));
|
2015-10-25 00:34:23 +02:00
|
|
|
if (iter == fsCache_.end()) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return iter->second->GetShaderString(stringType);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return "N/A";
|
|
|
|
}
|
|
|
|
}
|