1 // Copyright (c) 2014- 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 <map> 19 #include <d3d9.h> 20 21 #include "Common/GPU/D3D9/D3D9ShaderCompiler.h" 22 #include "Common/GPU/thin3d.h" 23 #include "Common/Log.h" 24 #include "Common/StringUtils.h" 25 #include "Core/Reporting.h" 26 #include "GPU/Directx9/TextureCacheDX9.h" 27 #include "GPU/Directx9/DepalettizeShaderDX9.h" 28 #include "GPU/Common/DepalettizeShaderCommon.h" 29 30 namespace DX9 { 31 32 static const int DEPAL_TEXTURE_OLD_AGE = 120; 33 34 #ifdef _WIN32 35 #define SHADERLOG 36 #endif 37 38 static const char *depalVShaderHLSL = R"( 39 struct VS_IN { 40 float3 a_position : POSITION; 41 float2 a_texcoord0 : TEXCOORD0; 42 }; 43 struct VS_OUT { 44 float4 Position : POSITION; 45 float2 Texcoord : TEXCOORD0; 46 }; 47 VS_OUT main(VS_IN input) { 48 VS_OUT output; 49 output.Texcoord = input.a_texcoord0; 50 output.Position = float4(input.a_position, 1.0); 51 return output; 52 } 53 )"; 54 55 DepalShaderCacheDX9::DepalShaderCacheDX9(Draw::DrawContext *draw) { 56 device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE); 57 std::string errorMessage; 58 if (!CompileVertexShaderD3D9(device_, depalVShaderHLSL, &vertexShader_, &errorMessage)) { 59 ERROR_LOG(G3D, "error compling depal vshader: %s", errorMessage.c_str()); 60 } 61 } 62 63 DepalShaderCacheDX9::~DepalShaderCacheDX9() { 64 Clear(); 65 if (vertexShader_) { 66 vertexShader_->Release(); 67 } 68 } 69 70 LPDIRECT3DTEXTURE9 DepalShaderCacheDX9::GetClutTexture(GEPaletteFormat clutFormat, u32 clutHash, u32 *rawClut) { 71 u32 clutId = GetClutID(clutFormat, clutHash); 72 73 auto oldtex = texCache_.find(clutId); 74 if (oldtex != texCache_.end()) { 75 oldtex->second->lastFrame = gpuStats.numFlips; 76 return oldtex->second->texture; 77 } 78 79 D3DFORMAT dstFmt = DX9::getClutDestFormat(clutFormat); 80 int texturePixels = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512; 81 82 DepalTextureDX9 *tex = new DepalTextureDX9(); 83 84 // Create texture 85 D3DPOOL pool = D3DPOOL_MANAGED; 86 int usage = 0; 87 if (device_) { 88 pool = D3DPOOL_DEFAULT; 89 usage = D3DUSAGE_DYNAMIC; // TODO: Switch to using a staging texture? 90 } 91 92 HRESULT hr = device_->CreateTexture(texturePixels, 1, 1, usage, dstFmt, pool, &tex->texture, NULL); 93 if (FAILED(hr)) { 94 ERROR_LOG(G3D, "Failed to create D3D texture for depal"); 95 delete tex; 96 return nullptr; 97 } 98 99 D3DLOCKED_RECT rect; 100 hr = tex->texture->LockRect(0, &rect, NULL, 0); 101 if (FAILED(hr)) { 102 ERROR_LOG(G3D, "Failed to lock D3D texture for depal"); 103 delete tex; 104 return nullptr; 105 } 106 // Regardless of format, the CLUT should always be 1024 bytes. 107 memcpy(rect.pBits, rawClut, 1024); 108 tex->texture->UnlockRect(0); 109 110 device_->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); 111 device_->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); 112 device_->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_POINT); 113 device_->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 114 115 tex->lastFrame = gpuStats.numFlips; 116 texCache_[clutId] = tex; 117 return tex->texture; 118 } 119 120 void DepalShaderCacheDX9::Clear() { 121 for (auto shader = cache_.begin(); shader != cache_.end(); ++shader) { 122 shader->second->pixelShader->Release(); 123 delete shader->second; 124 } 125 cache_.clear(); 126 for (auto tex = texCache_.begin(); tex != texCache_.end(); ++tex) { 127 tex->second->texture->Release(); 128 delete tex->second; 129 } 130 texCache_.clear(); 131 } 132 133 void DepalShaderCacheDX9::Decimate() { 134 for (auto tex = texCache_.begin(); tex != texCache_.end();) { 135 if (tex->second->lastFrame + DEPAL_TEXTURE_OLD_AGE < gpuStats.numFlips) { 136 tex->second->texture->Release(); 137 delete tex->second; 138 texCache_.erase(tex++); 139 } else { 140 ++tex; 141 } 142 } 143 } 144 145 LPDIRECT3DPIXELSHADER9 DepalShaderCacheDX9::GetDepalettizePixelShader(uint32_t clutMode, GEBufferFormat pixelFormat) { 146 u32 id = GenerateShaderID(clutMode, pixelFormat); 147 148 auto shader = cache_.find(id); 149 if (shader != cache_.end()) { 150 return shader->second->pixelShader; 151 } 152 153 char *buffer = new char[2048]; 154 155 GenerateDepalShader(buffer, pixelFormat, HLSL_D3D9); 156 157 LPDIRECT3DPIXELSHADER9 pshader; 158 std::string errorMessage; 159 if (!CompilePixelShaderD3D9(device_, buffer, &pshader, &errorMessage)) { 160 ERROR_LOG(G3D, "Failed to compile depal pixel shader: %s\n\n%s", buffer, errorMessage.c_str()); 161 delete[] buffer; 162 return nullptr; 163 } 164 165 DepalShaderDX9 *depal = new DepalShaderDX9(); 166 depal->pixelShader = pshader; 167 depal->code = buffer; 168 169 cache_[id] = depal; 170 171 delete[] buffer; 172 173 return depal->pixelShader; 174 } 175 176 std::vector<std::string> DepalShaderCacheDX9::DebugGetShaderIDs(DebugShaderType type) { 177 std::vector<std::string> ids; 178 for (auto &iter : cache_) { 179 ids.push_back(StringFromFormat("%08x", iter.first)); 180 } 181 return ids; 182 } 183 184 std::string DepalShaderCacheDX9::DebugGetShaderString(std::string idstr, DebugShaderType type, DebugShaderStringType stringType) { 185 uint32_t id; 186 sscanf(idstr.c_str(), "%08x", &id); 187 auto iter = cache_.find(id); 188 if (iter == cache_.end()) 189 return ""; 190 switch (stringType) { 191 case SHADER_STRING_SHORT_DESC: 192 return idstr; 193 case SHADER_STRING_SOURCE_CODE: 194 return iter->second->code; 195 default: 196 return ""; 197 } 198 } 199 200 } // namespace 201