CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/GPU/Directx9/ShaderManagerDX9.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#ifdef _WIN3218//#define SHADERLOG19#endif2021#include <cmath>22#include <map>2324#include "Common/Data/Convert/SmallDataConvert.h"25#include "Common/Data/Encoding/Utf8.h"26#include "Common/Data/Text/I18n.h"27#include "Common/Math/lin/matrix4x4.h"28#include "Common/Math/math_util.h"29#include "Common/GPU/D3D9/D3D9ShaderCompiler.h"30#include "Common/GPU/thin3d.h"31#include "Common/System/OSD.h"32#include "Common/System/Display.h"3334#include "Common/CommonTypes.h"35#include "Common/Log.h"36#include "Common/LogReporting.h"37#include "Common/StringUtils.h"3839#include "Core/Config.h"40#include "GPU/Math3D.h"41#include "GPU/GPUState.h"42#include "GPU/ge_constants.h"43#include "GPU/Common/ShaderUniforms.h"44#include "GPU/Common/FragmentShaderGenerator.h"45#include "GPU/Directx9/ShaderManagerDX9.h"46#include "GPU/Directx9/DrawEngineDX9.h"47#include "GPU/Directx9/FramebufferManagerDX9.h"4849using namespace Lin;5051PSShader::PSShader(LPDIRECT3DDEVICE9 device, FShaderID id, const char *code) : id_(id) {52source_ = code;53#ifdef SHADERLOG54OutputDebugString(ConvertUTF8ToWString(code).c_str());55#endif56bool success;57std::string errorMessage;5859success = CompilePixelShaderD3D9(device, code, &shader, &errorMessage);6061if (!errorMessage.empty()) {62if (success) {63ERROR_LOG(Log::G3D, "Warnings in shader compilation!");64} else {65ERROR_LOG(Log::G3D, "Error in shader compilation!");66}67ERROR_LOG(Log::G3D, "Messages: %s", errorMessage.c_str());68ERROR_LOG(Log::G3D, "Shader source:\n%s", LineNumberString(code).c_str());69OutputDebugStringUTF8("Messages:\n");70OutputDebugStringUTF8(errorMessage.c_str());71Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);72}7374if (!success) {75failed_ = true;76shader = nullptr;77return;78} else {79VERBOSE_LOG(Log::G3D, "Compiled pixel shader:\n%s\n", (const char *)code);80}81}8283PSShader::~PSShader() {84}8586std::string PSShader::GetShaderString(DebugShaderStringType type) const {87switch (type) {88case SHADER_STRING_SOURCE_CODE:89return source_;90case SHADER_STRING_SHORT_DESC:91return FragmentShaderDesc(id_);92default:93return "N/A";94}95}9697VSShader::VSShader(LPDIRECT3DDEVICE9 device, VShaderID id, const char *code, bool useHWTransform) : useHWTransform_(useHWTransform), id_(id) {98source_ = code;99#ifdef SHADERLOG100OutputDebugString(ConvertUTF8ToWString(code).c_str());101#endif102bool success;103std::string errorMessage;104105success = CompileVertexShaderD3D9(device, code, &shader, &errorMessage);106if (!errorMessage.empty()) {107if (success) {108ERROR_LOG(Log::G3D, "Warnings in shader compilation!");109} else {110ERROR_LOG(Log::G3D, "Error in shader compilation!");111}112ERROR_LOG(Log::G3D, "Messages: %s", errorMessage.c_str());113ERROR_LOG(Log::G3D, "Shader source:\n%s", code);114OutputDebugStringUTF8("Messages:\n");115OutputDebugStringUTF8(errorMessage.c_str());116Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), code);117}118119if (!success) {120failed_ = true;121shader = nullptr;122return;123} else {124VERBOSE_LOG(Log::G3D, "Compiled vertex shader:\n%s\n", (const char *)code);125}126}127128VSShader::~VSShader() {129}130131std::string VSShader::GetShaderString(DebugShaderStringType type) const {132switch (type) {133case SHADER_STRING_SOURCE_CODE:134return source_;135case SHADER_STRING_SHORT_DESC:136return VertexShaderDesc(id_);137default:138return "N/A";139}140}141142void ShaderManagerDX9::PSSetColorUniform3(int creg, u32 color) {143float f[4];144Uint8x3ToFloat4(f, color);145device_->SetPixelShaderConstantF(creg, f, 1);146}147148void ShaderManagerDX9::PSSetColorUniform3Alpha255(int creg, u32 color, u8 alpha) {149const float col[4] = {150(float)((color & 0xFF)),151(float)((color & 0xFF00) >> 8),152(float)((color & 0xFF0000) >> 16),153(float)alpha,154};155device_->SetPixelShaderConstantF(creg, col, 1);156}157158void ShaderManagerDX9::PSSetFloat(int creg, float value) {159const float f[4] = { value, 0.0f, 0.0f, 0.0f };160device_->SetPixelShaderConstantF(creg, f, 1);161}162163void ShaderManagerDX9::PSSetFloatArray(int creg, const float *value, int count) {164float f[4] = { 0.0f, 0.0f, 0.0f, 0.0f };165for (int i = 0; i < count; i++) {166f[i] = value[i];167}168device_->SetPixelShaderConstantF(creg, f, 1);169}170171void ShaderManagerDX9::VSSetFloat(int creg, float value) {172const float f[4] = { value, 0.0f, 0.0f, 0.0f };173device_->SetVertexShaderConstantF(creg, f, 1);174}175176void ShaderManagerDX9::VSSetFloatArray(int creg, const float *value, int count) {177float f[4] = { 0.0f, 0.0f, 0.0f, 0.0f };178for (int i = 0; i < count; i++) {179f[i] = value[i];180}181device_->SetVertexShaderConstantF(creg, f, 1);182}183184// Utility185void ShaderManagerDX9::VSSetColorUniform3(int creg, u32 color) {186float f[4];187Uint8x3ToFloat4(f, color);188device_->SetVertexShaderConstantF(creg, f, 1);189}190191void ShaderManagerDX9::VSSetFloatUniform4(int creg, const float data[4]) {192device_->SetVertexShaderConstantF(creg, data, 1);193}194195void ShaderManagerDX9::VSSetFloat24Uniform3(int creg, const u32 data[3]) {196float f[4];197ExpandFloat24x3ToFloat4(f, data);198device_->SetVertexShaderConstantF(creg, f, 1);199}200201void ShaderManagerDX9::VSSetFloat24Uniform3Normalized(int creg, const u32 data[3]) {202float f[4];203ExpandFloat24x3ToFloat4AndNormalize(f, data);204device_->SetVertexShaderConstantF(creg, f, 1);205}206207void ShaderManagerDX9::VSSetColorUniform3Alpha(int creg, u32 color, u8 alpha) {208float f[4];209Uint8x3ToFloat4_AlphaUint8(f, color, alpha);210device_->SetVertexShaderConstantF(creg, f, 1);211}212213void ShaderManagerDX9::VSSetColorUniform3ExtraFloat(int creg, u32 color, float extra) {214const float col[4] = {215((color & 0xFF)) / 255.0f,216((color & 0xFF00) >> 8) / 255.0f,217((color & 0xFF0000) >> 16) / 255.0f,218extra219};220device_->SetVertexShaderConstantF(creg, col, 1);221}222223void ShaderManagerDX9::VSSetMatrix4x3_3(int creg, const float *m4x3) {224float m3x4[12];225ConvertMatrix4x3To3x4Transposed(m3x4, m4x3);226device_->SetVertexShaderConstantF(creg, m3x4, 3);227}228229void ShaderManagerDX9::VSSetMatrix(int creg, const float* pMatrix) {230device_->SetVertexShaderConstantF(creg, pMatrix, 4);231}232233// Depth in ogl is between -1;1 we need between 0;1 and optionally reverse it234static void ConvertProjMatrixToD3D(Matrix4x4 &in, bool invertedX, bool invertedY) {235// Half pixel offset hack236float xoff = 1.0f / gstate_c.curRTRenderWidth;237if (invertedX) {238xoff = -gstate_c.vpXOffset - xoff;239} else {240xoff = gstate_c.vpXOffset - xoff;241}242243float yoff = -1.0f / gstate_c.curRTRenderHeight;244if (invertedY) {245yoff = -gstate_c.vpYOffset - yoff;246} else {247yoff = gstate_c.vpYOffset - yoff;248}249250const Vec3 trans(xoff, yoff, gstate_c.vpZOffset * 0.5f + 0.5f);251const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);252in.translateAndScale(trans, scale);253}254255static void ConvertProjMatrixToD3DThrough(Matrix4x4 &in) {256float xoff = -1.0f / gstate_c.curRTRenderWidth;257float yoff = 1.0f / gstate_c.curRTRenderHeight;258in.translateAndScale(Vec3(xoff, yoff, 0.5f), Vec3(1.0f, 1.0f, 0.5f));259}260261const uint64_t psUniforms = DIRTY_TEXENV | DIRTY_TEX_ALPHA_MUL | DIRTY_ALPHACOLORREF | DIRTY_ALPHACOLORMASK | DIRTY_FOGCOLOR | DIRTY_STENCILREPLACEVALUE | DIRTY_SHADERBLEND | DIRTY_TEXCLAMP | DIRTY_MIPBIAS;262263void ShaderManagerDX9::PSUpdateUniforms(u64 dirtyUniforms) {264if (dirtyUniforms & DIRTY_TEXENV) {265PSSetColorUniform3(CONST_PS_TEXENV, gstate.texenvcolor);266}267if (dirtyUniforms & DIRTY_ALPHACOLORREF) {268PSSetColorUniform3Alpha255(CONST_PS_ALPHACOLORREF, gstate.getColorTestRef(), gstate.getAlphaTestRef() & gstate.getAlphaTestMask());269}270if (dirtyUniforms & DIRTY_ALPHACOLORMASK) {271PSSetColorUniform3Alpha255(CONST_PS_ALPHACOLORMASK, gstate.colortestmask, gstate.getAlphaTestMask());272}273if (dirtyUniforms & DIRTY_FOGCOLOR) {274PSSetColorUniform3(CONST_PS_FOGCOLOR, gstate.fogcolor);275}276if (dirtyUniforms & DIRTY_STENCILREPLACEVALUE) {277PSSetFloat(CONST_PS_STENCILREPLACE, (float)gstate.getStencilTestRef() * (1.0f / 255.0f));278}279if (dirtyUniforms & DIRTY_TEX_ALPHA_MUL) {280bool doTextureAlpha = gstate.isTextureAlphaUsed();281if (gstate_c.textureFullAlpha && gstate.getTextureFunction() != GE_TEXFUNC_REPLACE) {282doTextureAlpha = false;283}284// NOTE: Reversed value, more efficient in shader.285float noAlphaMul[2] = { doTextureAlpha ? 0.0f : 1.0f, gstate.isColorDoublingEnabled() ? 2.0f : 1.0f };286PSSetFloatArray(CONST_PS_TEX_NO_ALPHA_MUL, noAlphaMul, 2);287}288if (dirtyUniforms & DIRTY_SHADERBLEND) {289PSSetColorUniform3(CONST_PS_BLENDFIXA, gstate.getFixA());290PSSetColorUniform3(CONST_PS_BLENDFIXB, gstate.getFixB());291292const float fbotexSize[2] = {2931.0f / (float)gstate_c.curRTRenderWidth,2941.0f / (float)gstate_c.curRTRenderHeight,295};296PSSetFloatArray(CONST_PS_FBOTEXSIZE, fbotexSize, 2);297}298299if (dirtyUniforms & DIRTY_TEXCLAMP) {300const float invW = 1.0f / (float)gstate_c.curTextureWidth;301const float invH = 1.0f / (float)gstate_c.curTextureHeight;302const int w = gstate.getTextureWidth(0);303const int h = gstate.getTextureHeight(0);304const float widthFactor = (float)w * invW;305const float heightFactor = (float)h * invH;306307// First wrap xy, then half texel xy (for clamp.)308const float texclamp[4] = {309widthFactor,310heightFactor,311invW * 0.5f,312invH * 0.5f,313};314const float texclampoff[2] = {315gstate_c.curTextureXOffset * invW,316gstate_c.curTextureYOffset * invH,317};318PSSetFloatArray(CONST_PS_TEXCLAMP, texclamp, 4);319PSSetFloatArray(CONST_PS_TEXCLAMPOFF, texclampoff, 2);320}321322if (dirtyUniforms & DIRTY_MIPBIAS) {323float mipBias = (float)gstate.getTexLevelOffset16() * (1.0 / 16.0f);324325// NOTE: This equation needs some adjustment in D3D9. Can't get it to look completely smooth :(326mipBias = (mipBias + 0.25f) / (float)(gstate.getTextureMaxLevel() + 1);327PSSetFloatArray(CONST_PS_MIPBIAS, &mipBias, 1);328}329}330331const uint64_t vsUniforms = DIRTY_PROJMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_WORLDMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX |332DIRTY_FOGCOEF | DIRTY_BONE_UNIFORMS | DIRTY_UVSCALEOFFSET | DIRTY_DEPTHRANGE | DIRTY_CULLRANGE |333DIRTY_AMBIENT | DIRTY_MATAMBIENTALPHA | DIRTY_MATSPECULAR | DIRTY_MATDIFFUSE | DIRTY_MATEMISSIVE | DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3;334335void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) {336// Update any dirty uniforms before we draw337if (dirtyUniforms & DIRTY_PROJMATRIX) {338Matrix4x4 flippedMatrix;339memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float));340341const bool invertedY = gstate_c.vpHeight < 0;342if (!invertedY) {343flippedMatrix[1] = -flippedMatrix[1];344flippedMatrix[5] = -flippedMatrix[5];345flippedMatrix[9] = -flippedMatrix[9];346flippedMatrix[13] = -flippedMatrix[13];347}348const bool invertedX = gstate_c.vpWidth < 0;349if (invertedX) {350flippedMatrix[0] = -flippedMatrix[0];351flippedMatrix[4] = -flippedMatrix[4];352flippedMatrix[8] = -flippedMatrix[8];353flippedMatrix[12] = -flippedMatrix[12];354}355356ConvertProjMatrixToD3D(flippedMatrix, invertedX, invertedY);357358VSSetMatrix(CONST_VS_PROJ, flippedMatrix.getReadPtr());359VSSetFloat(CONST_VS_ROTATION, 0); // We don't use this on any platform in D3D9.360}361if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) {362Matrix4x4 proj_through;363proj_through.setOrtho(0.0f, gstate_c.curRTWidth, gstate_c.curRTHeight, 0, 0, 1);364365ConvertProjMatrixToD3DThrough(proj_through);366367VSSetMatrix(CONST_VS_PROJ_THROUGH, proj_through.getReadPtr());368}369// Transform370if (dirtyUniforms & DIRTY_WORLDMATRIX) {371VSSetMatrix4x3_3(CONST_VS_WORLD, gstate.worldMatrix);372}373if (dirtyUniforms & DIRTY_VIEWMATRIX) {374VSSetMatrix4x3_3(CONST_VS_VIEW, gstate.viewMatrix);375}376if (dirtyUniforms & DIRTY_TEXMATRIX) {377VSSetMatrix4x3_3(CONST_VS_TEXMTX, gstate.tgenMatrix);378}379if (dirtyUniforms & DIRTY_FOGCOEF) {380float fogcoef[2] = {381getFloat24(gstate.fog1),382getFloat24(gstate.fog2),383};384// The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float.385// Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988386if (my_isnanorinf(fogcoef[0])) {387// Not really sure what a sensible value might be, but let's try 64k.388fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f;389}390if (my_isnanorinf(fogcoef[1])) {391fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f;392}393VSSetFloatArray(CONST_VS_FOGCOEF, fogcoef, 2);394}395// TODO: Could even set all bones in one go if they're all dirty.396#ifdef USE_BONE_ARRAY397if (u_bone != 0) {398float allBones[8 * 16];399400bool allDirty = true;401for (int i = 0; i < numBones; i++) {402if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {403ConvertMatrix4x3To4x4(allBones + 16 * i, gstate.boneMatrix + 12 * i);404} else {405allDirty = false;406}407}408if (allDirty) {409// Set them all with one call410//glUniformMatrix4fv(u_bone, numBones, GL_FALSE, allBones);411} else {412// Set them one by one. Could try to coalesce two in a row etc but too lazy.413for (int i = 0; i < numBones; i++) {414if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {415//glUniformMatrix4fv(u_bone + i, 1, GL_FALSE, allBones + 16 * i);416}417}418}419}420#else421for (int i = 0; i < 8; i++) {422if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {423VSSetMatrix4x3_3(CONST_VS_BONE0 + 3 * i, gstate.boneMatrix + 12 * i);424}425}426#endif427428// Texturing429if (dirtyUniforms & DIRTY_UVSCALEOFFSET) {430float widthFactor = 1.0f;431float heightFactor = 1.0f;432if (gstate_c.textureIsFramebuffer) {433const float invW = 1.0f / (float)gstate_c.curTextureWidth;434const float invH = 1.0f / (float)gstate_c.curTextureHeight;435const int w = gstate.getTextureWidth(0);436const int h = gstate.getTextureHeight(0);437widthFactor = (float)w * invW;438heightFactor = (float)h * invH;439}440float uvscaleoff[4];441uvscaleoff[0] = widthFactor;442uvscaleoff[1] = heightFactor;443uvscaleoff[2] = 0.0f;444uvscaleoff[3] = 0.0f;445VSSetFloatArray(CONST_VS_UVSCALEOFFSET, uvscaleoff, 4);446}447448if (dirtyUniforms & DIRTY_DEPTHRANGE) {449// Depth is [0, 1] mapping to [minz, maxz], not too hard.450float vpZScale = gstate.getViewportZScale();451float vpZCenter = gstate.getViewportZCenter();452453// These are just the reverse of the formulas in GPUStateUtils.454float halfActualZRange = InfToZero(gstate_c.vpDepthScale != 0.0f ? vpZScale / gstate_c.vpDepthScale : 0.0f);455float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange;456float viewZScale = halfActualZRange * 2.0f;457float viewZCenter = minz;458float reverseScale = InfToZero(gstate_c.vpDepthScale != 0.0f ? 2.0f * (1.0f / gstate_c.vpDepthScale) : 0.0f);459float reverseTranslate = gstate_c.vpZOffset * 0.5f + 0.5f;460461float data[4] = { viewZScale, viewZCenter, reverseTranslate, reverseScale };462VSSetFloatUniform4(CONST_VS_DEPTHRANGE, data);463464if (draw_->GetDeviceCaps().clipPlanesSupported >= 1) {465float clip[4] = { 0.0f, 0.0f, reverseScale, 1.0f - reverseTranslate * reverseScale };466// Well, not a uniform, but we treat it as one like other backends.467device_->SetClipPlane(0, clip);468}469}470if (dirtyUniforms & DIRTY_CULLRANGE) {471float minValues[4], maxValues[4];472CalcCullRange(minValues, maxValues, false, false);473VSSetFloatUniform4(CONST_VS_CULLRANGEMIN, minValues);474VSSetFloatUniform4(CONST_VS_CULLRANGEMAX, maxValues);475}476477// Lighting478if (dirtyUniforms & DIRTY_AMBIENT) {479VSSetColorUniform3Alpha(CONST_VS_AMBIENT, gstate.ambientcolor, gstate.getAmbientA());480}481if (dirtyUniforms & DIRTY_MATAMBIENTALPHA) {482VSSetColorUniform3Alpha(CONST_VS_MATAMBIENTALPHA, gstate.materialambient, gstate.getMaterialAmbientA());483}484if (dirtyUniforms & DIRTY_MATDIFFUSE) {485VSSetColorUniform3(CONST_VS_MATDIFFUSE, gstate.materialdiffuse);486}487if (dirtyUniforms & DIRTY_MATEMISSIVE) {488VSSetColorUniform3(CONST_VS_MATEMISSIVE, gstate.materialemissive);489}490if (dirtyUniforms & DIRTY_MATSPECULAR) {491VSSetColorUniform3ExtraFloat(CONST_VS_MATSPECULAR, gstate.materialspecular, getFloat24(gstate.materialspecularcoef));492}493for (int i = 0; i < 4; i++) {494if (dirtyUniforms & (DIRTY_LIGHT0 << i)) {495if (gstate.isDirectionalLight(i)) {496VSSetFloat24Uniform3Normalized(CONST_VS_LIGHTPOS + i, &gstate.lpos[i * 3]);497} else {498VSSetFloat24Uniform3(CONST_VS_LIGHTPOS + i, &gstate.lpos[i * 3]);499}500VSSetFloat24Uniform3Normalized(CONST_VS_LIGHTDIR + i, &gstate.ldir[i * 3]);501VSSetFloat24Uniform3(CONST_VS_LIGHTATT + i, &gstate.latt[i * 3]);502float angle_spotCoef[4] = { getFloat24(gstate.lcutoff[i]), getFloat24(gstate.lconv[i]) };503VSSetFloatUniform4(CONST_VS_LIGHTANGLE_SPOTCOEF + i, angle_spotCoef);504VSSetColorUniform3(CONST_VS_LIGHTAMBIENT + i, gstate.lcolor[i * 3]);505VSSetColorUniform3(CONST_VS_LIGHTDIFFUSE + i, gstate.lcolor[i * 3 + 1]);506VSSetColorUniform3(CONST_VS_LIGHTSPECULAR + i, gstate.lcolor[i * 3 + 2]);507}508}509}510511ShaderManagerDX9::ShaderManagerDX9(Draw::DrawContext *draw, LPDIRECT3DDEVICE9 device)512: ShaderManagerCommon(draw), device_(device) {513codeBuffer_ = new char[32768];514}515516ShaderManagerDX9::~ShaderManagerDX9() {517delete [] codeBuffer_;518}519520void ShaderManagerDX9::Clear() {521for (auto iter = fsCache_.begin(); iter != fsCache_.end(); ++iter) {522delete iter->second;523}524for (auto iter = vsCache_.begin(); iter != vsCache_.end(); ++iter) {525delete iter->second;526}527fsCache_.clear();528vsCache_.clear();529DirtyLastShader();530}531532void ShaderManagerDX9::ClearShaders() {533Clear();534}535536void ShaderManagerDX9::DirtyLastShader() {537// Forget the last shader ID538lastFSID_.set_invalid();539lastVSID_.set_invalid();540lastVShader_ = nullptr;541lastPShader_ = nullptr;542// TODO: Probably not necessary to dirty uniforms here on DX9.543gstate_c.Dirty(DIRTY_ALL_UNIFORMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);544}545546VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, VertexDecoder *decoder, bool weightsAsFloat, bool useSkinInDecode, const ComputedPipelineState &pipelineState) {547VShaderID VSID;548if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) {549gstate_c.Clean(DIRTY_VERTEXSHADER_STATE);550ComputeVertexShaderID(&VSID, decoder, useHWTransform, useHWTessellation, weightsAsFloat, useSkinInDecode);551} else {552VSID = lastVSID_;553}554555FShaderID FSID;556if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {557gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);558ComputeFragmentShaderID(&FSID, pipelineState, draw_->GetBugs());559} else {560FSID = lastFSID_;561}562563// Just update uniforms if this is the same shader as last time.564if (lastVShader_ != nullptr && lastPShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) {565uint64_t dirtyUniforms = gstate_c.GetDirtyUniforms();566if (dirtyUniforms) {567if (dirtyUniforms & psUniforms)568PSUpdateUniforms(dirtyUniforms);569if (dirtyUniforms & vsUniforms)570VSUpdateUniforms(dirtyUniforms);571gstate_c.CleanUniforms();572}573return lastVShader_; // Already all set.574}575576VSCache::iterator vsIter = vsCache_.find(VSID);577VSShader *vs = nullptr;578if (vsIter == vsCache_.end()) {579// Vertex shader not in cache. Let's compile it.580std::string genErrorString;581uint32_t attrMask;582uint64_t uniformMask;583VertexShaderFlags flags;584if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString)) {585vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform);586}587if (!vs || vs->Failed()) {588if (!vs) {589// TODO: Report this?590ERROR_LOG(Log::G3D, "Shader generation failed, falling back to software transform");591} else {592ERROR_LOG(Log::G3D, "Shader compilation failed, falling back to software transform");593}594if (!g_Config.bHideSlowWarnings) {595auto gr = GetI18NCategory(I18NCat::GRAPHICS);596g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("hardware transform error - falling back to software"), 2.5f);597}598delete vs;599600ComputeVertexShaderID(&VSID, decoder, false, false, weightsAsFloat, useSkinInDecode);601602// TODO: Look for existing shader with the appropriate ID, use that instead of generating a new one - however, need to make sure603// that that shader ID is not used when computing the linked shader ID below, because then IDs won't match604// next time and we'll do this over and over...605606// Can still work with software transform.607uint32_t attrMask;608uint64_t uniformMask;609bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &flags, &genErrorString);610_assert_(success);611vs = new VSShader(device_, VSID, codeBuffer_, false);612}613614vsCache_[VSID] = vs;615} else {616vs = vsIter->second;617}618lastVSID_ = VSID;619620FSCache::iterator fsIter = fsCache_.find(FSID);621PSShader *fs;622if (fsIter == fsCache_.end()) {623// Fragment shader not in cache. Let's compile it.624std::string errorString;625uint64_t uniformMask;626FragmentShaderFlags flags;627bool success = GenerateFragmentShader(FSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &uniformMask, &flags, &errorString);628// We're supposed to handle all possible cases.629_assert_(success);630fs = new PSShader(device_, FSID, codeBuffer_);631fsCache_[FSID] = fs;632} else {633fs = fsIter->second;634}635636lastFSID_ = FSID;637638uint64_t dirtyUniforms = gstate_c.GetDirtyUniforms();639if (dirtyUniforms) {640if (dirtyUniforms & psUniforms)641PSUpdateUniforms(dirtyUniforms);642if (dirtyUniforms & vsUniforms)643VSUpdateUniforms(dirtyUniforms);644gstate_c.CleanUniforms();645}646647device_->SetPixelShader(fs->shader.Get());648device_->SetVertexShader(vs->shader.Get());649650lastPShader_ = fs;651lastVShader_ = vs;652return vs;653}654655std::vector<std::string> ShaderManagerDX9::DebugGetShaderIDs(DebugShaderType type) {656std::string id;657std::vector<std::string> ids;658switch (type) {659case SHADER_TYPE_VERTEX:660for (auto iter : vsCache_) {661iter.first.ToString(&id);662ids.push_back(id);663}664break;665case SHADER_TYPE_FRAGMENT:666for (auto iter : fsCache_) {667iter.first.ToString(&id);668ids.push_back(id);669}670break;671}672return ids;673}674675std::string ShaderManagerDX9::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {676ShaderID shaderId;677shaderId.FromString(id);678switch (type) {679case SHADER_TYPE_VERTEX:680{681auto iter = vsCache_.find(VShaderID(shaderId));682if (iter == vsCache_.end()) {683return "";684}685return iter->second->GetShaderString(stringType);686}687688case SHADER_TYPE_FRAGMENT:689{690auto iter = fsCache_.find(FShaderID(shaderId));691if (iter == fsCache_.end()) {692return "";693}694return iter->second->GetShaderString(stringType);695}696default:697return "N/A";698}699}700701702