1 #include <assert.h>
2 #include <sys/stat.h>
3 #include "math/Matrix4.h"
4 #include "GSH_Direct3D9.h"
5 #include "../../gs/GsPixelFormats.h"
6
SetupTextureUpdaters()7 void CGSH_Direct3D9::SetupTextureUpdaters()
8 {
9 for(unsigned int i = 0; i < PSM_MAX; i++)
10 {
11 m_textureUpdater[i] = &CGSH_Direct3D9::TexUpdater_Invalid;
12 }
13
14 m_textureUpdater[PSMCT32] = &CGSH_Direct3D9::TexUpdater_Psm32;
15 m_textureUpdater[PSMCT24] = &CGSH_Direct3D9::TexUpdater_Psm32;
16 m_textureUpdater[PSMCT16] = &CGSH_Direct3D9::TexUpdater_Psm16<CGsPixelFormats::CPixelIndexorPSMCT16>;
17 m_textureUpdater[PSMCT16S] = &CGSH_Direct3D9::TexUpdater_Psm16<CGsPixelFormats::CPixelIndexorPSMCT16S>;
18 m_textureUpdater[PSMT8] = &CGSH_Direct3D9::TexUpdater_Psm48<CGsPixelFormats::CPixelIndexorPSMT8>;
19 m_textureUpdater[PSMT4] = &CGSH_Direct3D9::TexUpdater_Psm48<CGsPixelFormats::CPixelIndexorPSMT4>;
20 m_textureUpdater[PSMT8H] = &CGSH_Direct3D9::TexUpdater_Psm48H<24, 0xFF>;
21 m_textureUpdater[PSMT4HL] = &CGSH_Direct3D9::TexUpdater_Psm48H<24, 0x0F>;
22 m_textureUpdater[PSMT4HH] = &CGSH_Direct3D9::TexUpdater_Psm48H<28, 0x0F>;
23 }
24
LoadTexture(const TEX0 & tex0,uint32 maxMip,const MIPTBP1 & miptbp1,const MIPTBP2 & miptbp2)25 CGSH_Direct3D9::TEXTURE_INFO CGSH_Direct3D9::LoadTexture(const TEX0& tex0, uint32 maxMip, const MIPTBP1& miptbp1, const MIPTBP2& miptbp2)
26 {
27 TEXTURE_INFO result;
28
29 {
30 auto textureMatrix = CMatrix4::MakeIdentity();
31 m_device->SetVertexShaderConstantF(VS_INDEX_TEXMATRIX, textureMatrix.coeff, 4);
32 }
33
34 for(const auto& candidateFramebuffer : m_framebuffers)
35 {
36 if(candidateFramebuffer->m_basePtr == tex0.GetBufPtr() &&
37 candidateFramebuffer->m_width == tex0.GetBufWidth() &&
38 IsCompatibleFramebufferPSM(candidateFramebuffer->m_psm, tex0.nPsm) &&
39 candidateFramebuffer->m_canBeUsedAsTexture)
40 {
41 float scaleRatioX = static_cast<float>(tex0.GetWidth()) / static_cast<float>(candidateFramebuffer->m_width);
42 float scaleRatioY = static_cast<float>(tex0.GetHeight()) / static_cast<float>(candidateFramebuffer->m_height);
43
44 {
45 auto textureMatrix = CMatrix4::MakeScale(scaleRatioX, scaleRatioY, 1);
46 m_device->SetVertexShaderConstantF(VS_INDEX_TEXMATRIX, textureMatrix.coeff, 4);
47 }
48
49 result.texture = candidateFramebuffer->m_renderTarget;
50 result.isRenderTarget = true;
51 result.renderTargetWidth = candidateFramebuffer->m_width;
52 result.renderTargetHeight = candidateFramebuffer->m_height;
53
54 return result;
55 }
56 }
57
58 HRESULT resultCode = S_OK;
59
60 auto texture = m_textureCache.Search(tex0);
61 if(!texture)
62 {
63 uint32 width = tex0.GetWidth();
64 uint32 height = tex0.GetHeight();
65
66 D3DFORMAT textureFormat = D3DFMT_A8R8G8B8;
67 switch(tex0.nPsm)
68 {
69 case PSMCT32:
70 textureFormat = D3DFMT_A8R8G8B8;
71 break;
72 case PSMCT24:
73 textureFormat = D3DFMT_X8R8G8B8;
74 break;
75 case PSMCT16:
76 case PSMCT16S:
77 textureFormat = D3DFMT_A1R5G5B5;
78 break;
79 case PSMT8:
80 case PSMT4:
81 case PSMT8H:
82 case PSMT4HL:
83 case PSMT4HH:
84 textureFormat = D3DFMT_L8;
85 break;
86 default:
87 assert(false);
88 break;
89 }
90
91 {
92 TexturePtr textureHandle;
93 resultCode = m_device->CreateTexture(width, height, 1 + maxMip, D3DUSAGE_DYNAMIC, textureFormat, D3DPOOL_DEFAULT, &textureHandle, NULL);
94 assert(SUCCEEDED(resultCode));
95 m_textureCache.Insert(tex0, std::move(textureHandle));
96 }
97
98 texture = m_textureCache.Search(tex0);
99 texture->m_cachedArea.Invalidate(0, RAMSIZE);
100 }
101
102 auto& cachedArea = texture->m_cachedArea;
103
104 if(cachedArea.HasDirtyPages())
105 {
106 D3DLOCKED_RECT lockedRect;
107 resultCode = texture->m_textureHandle->LockRect(0, &lockedRect, nullptr, 0);
108 assert(SUCCEEDED(resultCode));
109
110 auto texturePageSize = CGsPixelFormats::GetPsmPageSize(tex0.nPsm);
111 auto areaRect = cachedArea.GetAreaPageRect();
112
113 for(unsigned int dirtyPageIndex = 0; dirtyPageIndex < CGsCachedArea::MAX_DIRTYPAGES; dirtyPageIndex++)
114 {
115 if(!cachedArea.IsPageDirty(dirtyPageIndex)) continue;
116
117 uint32 pageX = dirtyPageIndex % areaRect.width;
118 uint32 pageY = dirtyPageIndex / areaRect.width;
119 uint32 texX = pageX * texturePageSize.first;
120 uint32 texY = pageY * texturePageSize.second;
121 uint32 texWidth = texturePageSize.first;
122 uint32 texHeight = texturePageSize.second;
123 if(texX >= tex0.GetWidth()) continue;
124 if(texY >= tex0.GetHeight()) continue;
125 if((texX + texWidth) > tex0.GetWidth())
126 {
127 texWidth = tex0.GetWidth() - texX;
128 }
129 if((texY + texHeight) > tex0.GetHeight())
130 {
131 texHeight = tex0.GetHeight() - texY;
132 }
133 ((this)->*(m_textureUpdater[tex0.nPsm]))(&lockedRect, tex0.GetBufPtr(), tex0.nBufWidth, texX, texY, texWidth, texHeight);
134 }
135
136 cachedArea.ClearDirtyPages();
137
138 resultCode = texture->m_textureHandle->UnlockRect(0);
139 assert(SUCCEEDED(resultCode));
140
141 //Update mipmap levels
142 for(uint32 mipLevel = 1; mipLevel <= maxMip; mipLevel++)
143 {
144 uint32 mipLevelWidth = std::max<uint32>(tex0.GetWidth() >> mipLevel, 1);
145 uint32 mipLevelHeight = std::max<uint32>(tex0.GetHeight() >> mipLevel, 1);
146
147 uint32 mipLevelBufferPointer = 0;
148 uint32 mipLevelBufferWidth = 0;
149 switch(mipLevel)
150 {
151 case 1:
152 mipLevelBufferPointer = miptbp1.GetTbp1();
153 mipLevelBufferWidth = miptbp1.GetTbw1();
154 break;
155 case 2:
156 mipLevelBufferPointer = miptbp1.GetTbp2();
157 mipLevelBufferWidth = miptbp1.GetTbw2();
158 break;
159 case 3:
160 mipLevelBufferPointer = miptbp1.GetTbp3();
161 mipLevelBufferWidth = miptbp1.GetTbw3();
162 break;
163 case 4:
164 mipLevelBufferPointer = miptbp2.GetTbp4();
165 mipLevelBufferWidth = miptbp2.GetTbw4();
166 break;
167 case 5:
168 mipLevelBufferPointer = miptbp2.GetTbp5();
169 mipLevelBufferWidth = miptbp2.GetTbw5();
170 break;
171 case 6:
172 mipLevelBufferPointer = miptbp2.GetTbp6();
173 mipLevelBufferWidth = miptbp2.GetTbw6();
174 break;
175 }
176
177 if(mipLevelBufferWidth == 0) break;
178
179 resultCode = texture->m_textureHandle->LockRect(mipLevel, &lockedRect, nullptr, 0);
180 assert(SUCCEEDED(resultCode));
181
182 ((this)->*(m_textureUpdater[tex0.nPsm]))(&lockedRect, mipLevelBufferPointer, mipLevelBufferWidth / 64, 0, 0, mipLevelWidth, mipLevelHeight);
183
184 resultCode = texture->m_textureHandle->UnlockRect(mipLevel);
185 assert(SUCCEEDED(resultCode));
186 }
187 }
188
189 result.texture = texture->m_textureHandle;
190 return result;
191 }
192
Color_Ps2ToDx9(uint32 color)193 uint32 CGSH_Direct3D9::Color_Ps2ToDx9(uint32 color)
194 {
195 return D3DCOLOR_ARGB(
196 (color >> 24) & 0xFF,
197 (color >> 0) & 0xFF,
198 (color >> 8) & 0xFF,
199 (color >> 16) & 0xFF);
200 }
201
TexUpdater_Invalid(D3DLOCKED_RECT *,uint32,uint32,unsigned int,unsigned int,unsigned int,unsigned int)202 void CGSH_Direct3D9::TexUpdater_Invalid(D3DLOCKED_RECT*, uint32, uint32, unsigned int, unsigned int, unsigned int, unsigned int)
203 {
204 assert(false);
205 }
206
TexUpdater_Psm32(D3DLOCKED_RECT * lockedRect,uint32 bufPtr,uint32 bufWidth,unsigned int texX,unsigned int texY,unsigned int texWidth,unsigned int texHeight)207 void CGSH_Direct3D9::TexUpdater_Psm32(D3DLOCKED_RECT* lockedRect, uint32 bufPtr, uint32 bufWidth, unsigned int texX, unsigned int texY, unsigned int texWidth, unsigned int texHeight)
208 {
209 CGsPixelFormats::CPixelIndexorPSMCT32 indexor(m_pRAM, bufPtr, bufWidth);
210
211 auto dstPitch = lockedRect->Pitch / 4;
212 auto dst = reinterpret_cast<uint32*>(lockedRect->pBits);
213 dst += texX + (texY * dstPitch);
214
215 for(unsigned int y = 0; y < texHeight; y++)
216 {
217 for(unsigned int x = 0; x < texWidth; x++)
218 {
219 uint32 color = indexor.GetPixel(texX + x, texY + y);
220 dst[x] = Color_Ps2ToDx9(color);
221 }
222
223 dst += dstPitch;
224 }
225 }
226
227 template <typename IndexorType>
TexUpdater_Psm16(D3DLOCKED_RECT * lockedRect,uint32 bufPtr,uint32 bufWidth,unsigned int texX,unsigned int texY,unsigned int texWidth,unsigned int texHeight)228 void CGSH_Direct3D9::TexUpdater_Psm16(D3DLOCKED_RECT* lockedRect, uint32 bufPtr, uint32 bufWidth, unsigned int texX, unsigned int texY, unsigned int texWidth, unsigned int texHeight)
229 {
230 IndexorType indexor(m_pRAM, bufPtr, bufWidth);
231
232 auto dstPitch = lockedRect->Pitch / 2;
233 auto dst = reinterpret_cast<uint16*>(lockedRect->pBits);
234 dst += texX + (texY * dstPitch);
235
236 for(unsigned int y = 0; y < texHeight; y++)
237 {
238 for(unsigned int x = 0; x < texWidth; x++)
239 {
240 auto pixel = indexor.GetPixel(texX + x, texY + y);
241 auto cvtPixel =
242 (((pixel & 0x001F) >> 0) << 10) | //R
243 (((pixel & 0x03E0) >> 5) << 5) | //G
244 (((pixel & 0x7C00) >> 10) << 0) | //B
245 (((pixel & 0x8000) >> 15) << 15); //A
246 dst[x] = cvtPixel;
247 }
248
249 dst += dstPitch;
250 }
251 }
252
253 template <typename IndexorType>
TexUpdater_Psm48(D3DLOCKED_RECT * lockedRect,uint32 bufPtr,uint32 bufWidth,unsigned int texX,unsigned int texY,unsigned int texWidth,unsigned int texHeight)254 void CGSH_Direct3D9::TexUpdater_Psm48(D3DLOCKED_RECT* lockedRect, uint32 bufPtr, uint32 bufWidth, unsigned int texX, unsigned int texY, unsigned int texWidth, unsigned int texHeight)
255 {
256 IndexorType indexor(m_pRAM, bufPtr, bufWidth);
257
258 auto dstPitch = lockedRect->Pitch;
259 auto dst = reinterpret_cast<uint8*>(lockedRect->pBits);
260 dst += texX + (texY * dstPitch);
261
262 for(unsigned int y = 0; y < texHeight; y++)
263 {
264 for(unsigned int x = 0; x < texWidth; x++)
265 {
266 uint8 pixel = indexor.GetPixel(texX + x, texY + y);
267 dst[x] = pixel;
268 }
269
270 dst += dstPitch;
271 }
272 }
273
274 template <uint32 shiftAmount, uint32 mask>
TexUpdater_Psm48H(D3DLOCKED_RECT * lockedRect,uint32 bufPtr,uint32 bufWidth,unsigned int texX,unsigned int texY,unsigned int texWidth,unsigned int texHeight)275 void CGSH_Direct3D9::TexUpdater_Psm48H(D3DLOCKED_RECT* lockedRect, uint32 bufPtr, uint32 bufWidth, unsigned int texX, unsigned int texY, unsigned int texWidth, unsigned int texHeight)
276 {
277 CGsPixelFormats::CPixelIndexorPSMCT32 indexor(m_pRAM, bufPtr, bufWidth);
278
279 auto dstPitch = lockedRect->Pitch;
280 auto dst = reinterpret_cast<uint8*>(lockedRect->pBits);
281 dst += texX + (texY * dstPitch);
282
283 for(unsigned int y = 0; y < texHeight; y++)
284 {
285 for(unsigned int x = 0; x < texWidth; x++)
286 {
287 uint32 pixel = indexor.GetPixel(texX + x, texY + y);
288 pixel = (pixel >> shiftAmount) & mask;
289 dst[x] = static_cast<uint8>(pixel);
290 }
291
292 dst += dstPitch;
293 }
294 }
295
296 //------------------------------------------------------------------------
297 //CLUT Stuff
298 //------------------------------------------------------------------------
299
GetClutTexture(const TEX0 & tex0)300 CGSH_Direct3D9::TexturePtr CGSH_Direct3D9::GetClutTexture(const TEX0& tex0)
301 {
302 HRESULT result = S_OK;
303
304 std::array<uint32, 256> convertedClut;
305 MakeLinearCLUT(tex0, convertedClut);
306
307 unsigned int entryCount = CGsPixelFormats::IsPsmIDTEX4(tex0.nPsm) ? 16 : 256;
308 auto clutTexture = CGsPixelFormats::IsPsmIDTEX4(tex0.nPsm) ? m_clutTexture4 : m_clutTexture8;
309
310 {
311 D3DLOCKED_RECT rect;
312 result = clutTexture->LockRect(0, &rect, NULL, D3DLOCK_DISCARD);
313 assert(SUCCEEDED(result));
314
315 auto dst = reinterpret_cast<uint32*>(rect.pBits);
316 unsigned int nDstPitch = rect.Pitch / 4;
317
318 for(uint32 i = 0; i < entryCount; i++)
319 {
320 dst[i] = Color_Ps2ToDx9(convertedClut[i]);
321 }
322
323 result = clutTexture->UnlockRect(0);
324 assert(SUCCEEDED(result));
325 }
326
327 return clutTexture;
328 }
329