diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 51c5290d53..5a1256f2e5 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -49,6 +49,31 @@ #define TEXCACHE_MIN_PRESSURE 16 * 1024 * 1024 // Total in VRAM #define TEXCACHE_SECOND_MIN_PRESSURE 4 * 1024 * 1024 +// Just for reference + +// PSP Color formats: +// 565: BBBBBGGGGGGRRRRR +// 5551: ABBBBBGGGGGRRRRR +// 4444: AAAABBBBGGGGRRRR +// 8888: AAAAAAAABBBBBBBBGGGGGGGGRRRRRRRR (Bytes in memory: RGBA) + +// D3D11/9 Color formats: +// DXGI_FORMAT_B4G4R4A4/D3DFMT_A4R4G4B4: AAAARRRRGGGGBBBB +// DXGI_FORMAT_B5G5R5A1/D3DFMT_A1R5G6B5: ARRRRRGGGGGBBBBB +// DXGI_FORMAT_B5G6R6/D3DFMT_R5G6B5: RRRRRGGGGGGBBBBB +// DXGI_FORMAT_B8G8R8A8: AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB (Bytes in memory: BGRA) +// These are Data::Format:: A4R4G4B4_PACK16, A1R5G6B5_PACK16, R5G6B5_PACK16, B8G8R8A8. +// So these are good matches, just with R/B swapped. + +// OpenGL ES color formats: +// GL_UNSIGNED_SHORT_4444: BBBBGGGGRRRRAAAA (4-bit rotation) +// GL_UNSIGNED_SHORT_565: BBBBBGGGGGGRRRRR (match) +// GL_UNSIGNED_SHORT_1555: BBBBBGGGGGRRRRRA (1-bit rotation) +// GL_UNSIGNED_BYTE/RGBA: AAAAAAAABBBBBBBBGGGGGGGGRRRRRRRR (match) +// These are Data::Format:: B4G4R4A4_PACK16, B5G6R6_PACK16, B5G5R5A1_PACK16, R8G8B8A8 + +// Vulkan color formats: +// TODO TextureCacheCommon::TextureCacheCommon(Draw::DrawContext *draw) : draw_(draw), clearCacheNextFrame_(false), @@ -105,7 +130,7 @@ void TextureCacheCommon::GetSamplingParams(int &minFilt, int &magFilt, bool &sCl sClamp = gstate.isTexCoordClampedS(); tClamp = gstate.isTexCoordClampedT(); - bool noMip = (gstate.texlevel & 0xFFFFFF) == 0x000001 || (gstate.texlevel & 0xFFFFFF) == 0x100001 ; // Fix texlevel at 0 + bool noMip = (gstate.texlevel & 0xFFFFFF) == 0x000001 || (gstate.texlevel & 0xFFFFFF) == 0x100001; // Fix texlevel at 0 if (IsFakeMipmapChange()) noMip = gstate.getTexLevelMode() == GE_TEXLEVEL_MODE_CONST; @@ -974,7 +999,7 @@ static void ReverseColors(void *dstBuf, const void *srcBuf, GETextureFormat fmt, } } -void TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, int bufw, bool reverseColors, bool useBGRA) { +void TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, int bufw, bool reverseColors, bool useBGRA, bool expandTo32bit) { bool swizzled = gstate.isTextureSwizzled(); if ((texaddr & 0x00600000) != 0 && Memory::IsVRAMAddress(texaddr)) { // This means it's in a mirror, possibly a swizzled mirror. Let's report. @@ -1008,7 +1033,7 @@ void TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, GETextureForm case GE_CMODE_16BIT_ABGR4444: { const u16 *clut = GetCurrentClut() + clutSharingOffset; - if (clutAlphaLinear_ && mipmapShareClut) { + if (clutAlphaLinear_ && mipmapShareClut && !expandTo32bit) { // Here, reverseColors means the CLUT is already reversed. if (reverseColors) { for (int y = 0; y < h; ++y) { @@ -1020,8 +1045,26 @@ void TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, GETextureForm } } } else { - for (int y = 0; y < h; ++y) { - DeIndexTexture4((u16 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, clut); + if (expandTo32bit && !reverseColors) { + // We simply expand the CLUT to 32-bit, then we deindex as usual. Probably the fastest way. + switch (clutformat) { + case GE_CMODE_16BIT_ABGR4444: + ConvertRGBA4444ToRGBA8888(expandClut_, clut, 16); + break; + case GE_CMODE_16BIT_ABGR5551: + ConvertRGBA5551ToRGBA8888(expandClut_, clut, 16); + break; + case GE_CMODE_16BIT_BGR5650: + ConvertRGBA565ToRGBA8888(expandClut_, clut, 16); + break; + } + for (int y = 0; y < h; ++y) { + DeIndexTexture4((u32 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, expandClut_); + } + } else { + for (int y = 0; y < h; ++y) { + DeIndexTexture4((u16 *)(out + outPitch * y), texptr + (bufw * y) / 2, w, clut); + } } } } @@ -1044,15 +1087,15 @@ void TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, GETextureForm break; case GE_TFMT_CLUT8: - ReadIndexedTex(out, outPitch, level, texptr, 1, bufw); + ReadIndexedTex(out, outPitch, level, texptr, 1, bufw, expandTo32bit); break; case GE_TFMT_CLUT16: - ReadIndexedTex(out, outPitch, level, texptr, 2, bufw); + ReadIndexedTex(out, outPitch, level, texptr, 2, bufw, expandTo32bit); break; case GE_TFMT_CLUT32: - ReadIndexedTex(out, outPitch, level, texptr, 4, bufw); + ReadIndexedTex(out, outPitch, level, texptr, 4, bufw, expandTo32bit); break; case GE_TFMT_4444: @@ -1064,6 +1107,20 @@ void TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, GETextureForm for (int y = 0; y < h; ++y) { ReverseColors(out + outPitch * y, texptr + bufw * sizeof(u16) * y, format, w, useBGRA); } + } else if (expandTo32bit) { + for (int y = 0; y < h; ++y) { + switch (format) { + case GE_CMODE_16BIT_ABGR4444: + ConvertRGBA4444ToRGBA8888((u32 *)(out + outPitch * y), (const u16 *)texptr + bufw * y, w); + break; + case GE_CMODE_16BIT_ABGR5551: + ConvertRGBA5551ToRGBA8888((u32 *)(out + outPitch * y), (const u16 *)texptr + bufw * y, w); + break; + case GE_CMODE_16BIT_BGR5650: + ConvertRGBA565ToRGBA8888((u32 *)(out + outPitch * y), (const u16 *)texptr + bufw * y, w); + break; + } + } } else { for (int y = 0; y < h; ++y) { memcpy(out + outPitch * y, texptr + bufw * sizeof(u16) * y, w * sizeof(u16)); @@ -1084,6 +1141,20 @@ void TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, GETextureForm for (int y = 0; y < h; ++y) { ReverseColors(out + outPitch * y, unswizzled + bufw * sizeof(u16) * y, format, w, useBGRA); } + } else if (expandTo32bit) { + for (int y = 0; y < h; ++y) { + switch (format) { + case GE_CMODE_16BIT_ABGR4444: + ConvertRGBA4444ToRGBA8888((u32 *)(out + outPitch * y), (const u16 *)unswizzled + bufw * y, w); + break; + case GE_CMODE_16BIT_ABGR5551: + ConvertRGBA5551ToRGBA8888((u32 *)(out + outPitch * y), (const u16 *)unswizzled + bufw * y, w); + break; + case GE_CMODE_16BIT_BGR5650: + ConvertRGBA565ToRGBA8888((u32 *)(out + outPitch * y), (const u16 *)unswizzled + bufw * y, w); + break; + } + } } else { for (int y = 0; y < h; ++y) { memcpy(out + outPitch * y, unswizzled + bufw * sizeof(u16) * y, w * sizeof(u16)); @@ -1198,7 +1269,7 @@ void TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, GETextureForm } } -void TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int level, const u8 *texptr, int bytesPerIndex, int bufw) { +void TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int level, const u8 *texptr, int bytesPerIndex, int bufw, bool expandTo32Bit) { int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); @@ -1208,28 +1279,48 @@ void TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int level, const texptr = (u8 *)tmpTexBuf32_.data(); } - switch (gstate.getClutPaletteFormat()) { + int palFormat = gstate.getClutPaletteFormat(); + + const u16 *clut16 = (const u16 *)clutBuf_; + const u32 *clut32 = (const u32 *)clutBuf_; + + if (expandTo32Bit && palFormat != GE_CMODE_32BIT_ABGR8888) { + switch (palFormat) { + case GE_CMODE_16BIT_ABGR4444: + ConvertRGBA4444ToRGBA8888(expandClut_, clut16, 256); + break; + case GE_CMODE_16BIT_ABGR5551: + ConvertRGBA5551ToRGBA8888(expandClut_, clut16, 256); + break; + case GE_CMODE_16BIT_BGR5650: + ConvertRGBA565ToRGBA8888(expandClut_, clut16, 256); + break; + } + clut32 = expandClut_; + palFormat = GE_CMODE_32BIT_ABGR8888; + } + + switch (palFormat) { case GE_CMODE_16BIT_BGR5650: case GE_CMODE_16BIT_ABGR5551: case GE_CMODE_16BIT_ABGR4444: { - const u16 *clut = GetCurrentClut(); switch (bytesPerIndex) { case 1: for (int y = 0; y < h; ++y) { - DeIndexTexture((u16 *)(out + outPitch * y), (const u8 *)texptr + bufw * y, w, clut); + DeIndexTexture((u16 *)(out + outPitch * y), (const u8 *)texptr + bufw * y, w, clut16); } break; case 2: for (int y = 0; y < h; ++y) { - DeIndexTexture((u16 *)(out + outPitch * y), (const u16_le *)texptr + bufw * y, w, clut); + DeIndexTexture((u16 *)(out + outPitch * y), (const u16_le *)texptr + bufw * y, w, clut16); } break; case 4: for (int y = 0; y < h; ++y) { - DeIndexTexture((u16 *)(out + outPitch * y), (const u32_le *)texptr + bufw * y, w, clut); + DeIndexTexture((u16 *)(out + outPitch * y), (const u32_le *)texptr + bufw * y, w, clut16); } break; } @@ -1238,23 +1329,22 @@ void TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int level, const case GE_CMODE_32BIT_ABGR8888: { - const u32 *clut = GetCurrentClut(); switch (bytesPerIndex) { case 1: for (int y = 0; y < h; ++y) { - DeIndexTexture((u32 *)(out + outPitch * y), (const u8 *)texptr + bufw * y, w, clut); + DeIndexTexture((u32 *)(out + outPitch * y), (const u8 *)texptr + bufw * y, w, clut32); } break; case 2: for (int y = 0; y < h; ++y) { - DeIndexTexture((u32 *)(out + outPitch * y), (const u16_le *)texptr + bufw * y, w, clut); + DeIndexTexture((u32 *)(out + outPitch * y), (const u16_le *)texptr + bufw * y, w, clut32); } break; case 4: for (int y = 0; y < h; ++y) { - DeIndexTexture((u32 *)(out + outPitch * y), (const u32_le *)texptr + bufw * y, w, clut); + DeIndexTexture((u32 *)(out + outPitch * y), (const u32_le *)texptr + bufw * y, w, clut32); } break; } diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 341b09b4ee..1443338f41 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -225,9 +225,9 @@ protected: u32 yOffset; }; - void DecodeTextureLevel(u8 *out, int outPitch, GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, int bufw, bool reverseColors, bool useBGRA = false); + void DecodeTextureLevel(u8 *out, int outPitch, GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, int bufw, bool reverseColors, bool useBGRA, bool expandTo32Bit); void UnswizzleFromMem(u32 *dest, u32 destPitch, const u8 *texptr, u32 bufw, u32 height, u32 bytesPerPixel); - void ReadIndexedTex(u8 *out, int outPitch, int level, const u8 *texptr, int bytesPerIndex, int bufw); + void ReadIndexedTex(u8 *out, int outPitch, int level, const u8 *texptr, int bytesPerIndex, int bufw, bool expandTo32Bit); template inline const T *GetCurrentClut() { @@ -322,6 +322,8 @@ protected: bool nextNeedsRebuild_; bool isBgraBackend_; + + u32 expandClut_[256]; }; inline bool TexCacheEntry::Matches(u16 dim2, u8 format2, u8 maxLevel2) const { diff --git a/GPU/D3D11/DepalettizeShaderD3D11.cpp b/GPU/D3D11/DepalettizeShaderD3D11.cpp index 12852b2d13..9d0df8ddad 100644 --- a/GPU/D3D11/DepalettizeShaderD3D11.cpp +++ b/GPU/D3D11/DepalettizeShaderD3D11.cpp @@ -81,7 +81,7 @@ ID3D11ShaderResourceView *DepalShaderCacheD3D11::GetClutTexture(GEPaletteFormat return oldtex->second->view; } - DXGI_FORMAT dstFmt = getClutDestFormatD3D11(clutFormat); + DXGI_FORMAT dstFmt = GetClutDestFormatD3D11(clutFormat); int texturePixels = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512; DepalTextureD3D11 *tex = new DepalTextureD3D11(); diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 21b72dd5e3..f72b6d3d68 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -512,8 +512,11 @@ void GPU_D3D11::CheckGPUFeatures() { features |= GPU_SUPPORTS_DUALSOURCE_BLEND; features |= GPU_SUPPORTS_ANY_COPY_IMAGE; - if (draw_->GetDataFormatSupport(Draw::DataFormat::A4B4G4R4_UNORM_PACK16) & Draw::FMT_TEXTURE) { - features |= GPU_SUPPORTS_4BIT_FORMAT; + uint32_t fmt4444 = draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16); + uint32_t fmt1555 = draw_->GetDataFormatSupport(Draw::DataFormat::A1R5G5B5_UNORM_PACK16); + uint32_t fmt565 = draw_->GetDataFormatSupport(Draw::DataFormat::R5G6B5_UNORM_PACK16); + if ((fmt4444 & Draw::FMT_TEXTURE) && (fmt565 & Draw::FMT_TEXTURE) && (fmt1555 & Draw::FMT_TEXTURE)) { + features |= GPU_SUPPORTS_16BIT_FORMATS; } if (draw_->GetDeviceCaps().logicOpSupported) { diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 07beedfe81..8ff98cc33f 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -146,21 +146,6 @@ void TextureCacheD3D11::InvalidateLastTexture(TexCacheEntry *entry) { } } -DXGI_FORMAT getClutDestFormatD3D11(GEPaletteFormat format) { - switch (format) { - case GE_CMODE_16BIT_ABGR4444: - return DXGI_FORMAT_B4G4R4A4_UNORM; - case GE_CMODE_16BIT_ABGR5551: - return DXGI_FORMAT_B5G5R5A1_UNORM; - case GE_CMODE_16BIT_BGR5650: - return DXGI_FORMAT_B5G6R5_UNORM; - case GE_CMODE_32BIT_ABGR8888: - return DXGI_FORMAT_B8G8R8A8_UNORM; - } - // Should never be here ! - return DXGI_FORMAT_B8G8R8A8_UNORM; -} - void TextureCacheD3D11::UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key) { // TODO: Make GetSamplingParams write SamplerCacheKey directly int minFilt; @@ -427,7 +412,7 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFra const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor; - TexCacheEntry::Status alphaStatus = CheckAlpha(clutBuf_, getClutDestFormatD3D11(clutFormat), clutTotalColors, clutTotalColors, 1); + TexCacheEntry::Status alphaStatus = CheckAlpha(clutBuf_, GetClutDestFormatD3D11(clutFormat), clutTotalColors, clutTotalColors, 1); gstate_c.textureFullAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL; gstate_c.textureSimpleAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE; } else { @@ -572,13 +557,32 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry, bool replaceIma } } +DXGI_FORMAT GetClutDestFormatD3D11(GEPaletteFormat format) { + switch (format) { + case GE_CMODE_16BIT_ABGR4444: + return DXGI_FORMAT_B4G4R4A4_UNORM; + case GE_CMODE_16BIT_ABGR5551: + return DXGI_FORMAT_B5G5R5A1_UNORM; + case GE_CMODE_16BIT_BGR5650: + return DXGI_FORMAT_B5G6R5_UNORM; + case GE_CMODE_32BIT_ABGR8888: + return DXGI_FORMAT_B8G8R8A8_UNORM; + } + // Should never be here ! + return DXGI_FORMAT_B8G8R8A8_UNORM; +} + DXGI_FORMAT TextureCacheD3D11::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const { + if (!gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS)) { + return DXGI_FORMAT_B8G8R8A8_UNORM; + } + switch (format) { case GE_TFMT_CLUT4: case GE_TFMT_CLUT8: case GE_TFMT_CLUT16: case GE_TFMT_CLUT32: - return getClutDestFormatD3D11(clutFormat); + return GetClutDestFormatD3D11(clutFormat); case GE_TFMT_4444: return DXGI_FORMAT_B4G4R4A4_UNORM; case GE_TFMT_5551: @@ -633,7 +637,7 @@ DXGI_FORMAT ToDXGIFormat(ReplacedTextureFormat fmt) { } } -void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, bool replaceImages, int scaleFactor, u32 dstFmt) { +void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, bool replaceImages, int scaleFactor, DXGI_FORMAT dstFmt) { int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); @@ -642,14 +646,13 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & // Create texture int levels = scaleFactor == 1 ? maxLevel + 1 : 1; int tw = w, th = h; - DXGI_FORMAT tfmt = (DXGI_FORMAT)(dstFmt); if (replaced.GetSize(level, tw, th)) { - tfmt = ToDXGIFormat(replaced.Format(level)); + dstFmt = ToDXGIFormat(replaced.Format(level)); } else { tw *= scaleFactor; th *= scaleFactor; if (scaleFactor > 1) { - tfmt = DXGI_FORMAT_B8G8R8A8_UNORM; + dstFmt = DXGI_FORMAT_B8G8R8A8_UNORM; } } @@ -661,7 +664,7 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & desc.SampleDesc.Count = 1; desc.Width = tw; desc.Height = th; - desc.Format = tfmt; + desc.Format = dstFmt; desc.MipLevels = levels; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; @@ -708,10 +711,12 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & decPitch = mapRowPitch; } - DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, false, false); + bool expand32 = !gstate_c.Supports(GPU_SUPPORTS_16BIT_FORMATS); + DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, false, false, expand32); if (scaleFactor > 1) { - scaler.ScaleAlways((u32 *)mapData, pixelData, dstFmt, w, h, scaleFactor); + u32 scaleFmt = (u32)dstFmt; + scaler.ScaleAlways((u32 *)mapData, pixelData, scaleFmt, w, h, scaleFactor); pixelData = (u32 *)mapData; // We always end up at 8888. Other parts assume this. diff --git a/GPU/D3D11/TextureCacheD3D11.h b/GPU/D3D11/TextureCacheD3D11.h index 68b2156f1f..e9e4b0ed58 100644 --- a/GPU/D3D11/TextureCacheD3D11.h +++ b/GPU/D3D11/TextureCacheD3D11.h @@ -71,7 +71,7 @@ protected: private: void UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key); - void LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, bool replaceImages, int scaleFactor, u32 dstFmt); + void LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, bool replaceImages, int scaleFactor, DXGI_FORMAT dstFmt); DXGI_FORMAT GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const; TexCacheEntry::Status CheckAlpha(const u32 *pixelData, u32 dstFmt, int stride, int w, int h); void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) override; @@ -104,4 +104,4 @@ private: ShaderManagerD3D11 *shaderManager_; }; -DXGI_FORMAT getClutDestFormatD3D11(GEPaletteFormat format); +DXGI_FORMAT GetClutDestFormatD3D11(GEPaletteFormat format); diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index d03fe5c9cc..602e91ea12 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -473,11 +473,12 @@ void GPU_DX9::UpdateCmdInfo() { void GPU_DX9::CheckGPUFeatures() { u32 features = 0; - features |= GPU_SUPPORTS_4BIT_FORMAT; + features |= GPU_SUPPORTS_16BIT_FORMATS; features |= GPU_SUPPORTS_BLEND_MINMAX; features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; features |= GPU_PREFER_CPU_DOWNLOAD; features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_SUPPORTS_16BIT_FORMATS; D3DCAPS9 caps; ZeroMemory(&caps, sizeof(caps)); diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index e534b7b63b..0f44224727 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -654,10 +654,8 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re // Create texture D3DPOOL pool = D3DPOOL_MANAGED; int usage = 0; - if (pD3DdeviceEx) { - pool = D3DPOOL_DEFAULT; - usage = D3DUSAGE_DYNAMIC; // TODO: Switch to using a staging texture? - } + pool = D3DPOOL_DEFAULT; + usage = D3DUSAGE_DYNAMIC; // TODO: Switch to using a staging texture? int levels = scaleFactor == 1 ? maxLevel + 1 : 1; int tw = w, th = h; D3DFORMAT tfmt = (D3DFORMAT)(dstFmt); @@ -676,17 +674,24 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re else hr = pD3Ddevice->CreateTexture(tw, th, levels, usage, tfmt, pool, &texture, NULL); if (FAILED(hr)) { - INFO_LOG(G3D, "Failed to create D3D texture"); + INFO_LOG(G3D, "Failed to create D3D texture: %dx%d", tw, th); ReleaseTexture(&entry); return; } } D3DLOCKED_RECT rect; + + HRESULT result; + uint32_t lockFlag = level == 0 ? D3DLOCK_DISCARD : 0; // Can only discard the top level if (IsFakeMipmapChange()) - texture->LockRect(0, &rect, NULL, D3DLOCK_DISCARD); + result = texture->LockRect(0, &rect, NULL, lockFlag); else - texture->LockRect(level, &rect, NULL, D3DLOCK_DISCARD); + result = texture->LockRect(level, &rect, NULL, lockFlag); + if (FAILED(result)) { + ERROR_LOG(G3D, "Failed to lock D3D texture: %dx%d", w, h); + return; + } gpuStats.numTexturesDecoded++; if (replaced.GetSize(level, w, h)) { @@ -708,7 +713,7 @@ void TextureCacheDX9::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &re decPitch = w * bpp; } - DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, false); + DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, false, false, false); if (scaleFactor > 1) { scaler.ScaleAlways((u32 *)rect.pBits, pixelData, dstFmt, w, h, scaleFactor); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 4d125a1f20..6bd2e5b155 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -506,7 +506,7 @@ GPU_GLES::~GPU_GLES() { void GPU_GLES::CheckGPUFeatures() { u32 features = 0; - features |= GPU_SUPPORTS_4BIT_FORMAT; + features |= GPU_SUPPORTS_16BIT_FORMATS; if (gl_extensions.ARB_blend_func_extended || gl_extensions.EXT_blend_func_extended) { if (gl_extensions.gpuVendor == GPU_VENDOR_INTEL || !gl_extensions.VersionGEThan(3, 0, 0)) { diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 8c3b3171c8..0d9ec77cbd 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -766,7 +766,7 @@ void *TextureCacheGLES::DecodeTextureLevelOld(GETextureFormat format, GEPaletteF } tmpTexBufRearrange_.resize(std::max(w, bufw) * h); - DecodeTextureLevel((u8 *)tmpTexBufRearrange_.data(), decPitch, format, clutformat, texaddr, level, bufw, true, UseBGRA8888()); + DecodeTextureLevel((u8 *)tmpTexBufRearrange_.data(), decPitch, format, clutformat, texaddr, level, bufw, true, UseBGRA8888(), false); return tmpTexBufRearrange_.data(); } diff --git a/GPU/GPUState.h b/GPU/GPUState.h index cd198f86e7..9c5fe43811 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -459,7 +459,7 @@ enum { GPU_SUPPORTS_INSTANCE_RENDERING = FLAG_BIT(10), GPU_SUPPORTS_VERTEX_TEXTURE_FETCH = FLAG_BIT(11), GPU_SUPPORTS_TEXTURE_FLOAT = FLAG_BIT(12), - GPU_SUPPORTS_4BIT_FORMAT = FLAG_BIT(13), + GPU_SUPPORTS_16BIT_FORMATS = FLAG_BIT(13), GPU_SUPPORTS_LARGE_VIEWPORTS = FLAG_BIT(16), GPU_SUPPORTS_ACCURATE_DEPTH = FLAG_BIT(17), GPU_SUPPORTS_VAO = FLAG_BIT(18), diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index a3d71a730d..95909dc669 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -463,32 +463,34 @@ GPU_Vulkan::~GPU_Vulkan() { } void GPU_Vulkan::CheckGPUFeatures() { - gstate_c.featureFlags = 0; - gstate_c.featureFlags |= GPU_SUPPORTS_4BIT_FORMAT; + uint32_t features = 0; + features |= GPU_SUPPORTS_16BIT_FORMATS; if (vulkan_->GetFeaturesEnabled().wideLines) { - gstate_c.featureFlags |= GPU_SUPPORTS_WIDE_LINES; + features |= GPU_SUPPORTS_WIDE_LINES; } if (vulkan_->GetFeaturesEnabled().dualSrcBlend) { - gstate_c.featureFlags |= GPU_SUPPORTS_DUALSOURCE_BLEND; + features |= GPU_SUPPORTS_DUALSOURCE_BLEND; } if (vulkan_->GetFeaturesEnabled().logicOp) { - gstate_c.featureFlags |= GPU_SUPPORTS_LOGIC_OP; + features |= GPU_SUPPORTS_LOGIC_OP; } if (vulkan_->GetFeaturesEnabled().samplerAnisotropy) { - gstate_c.featureFlags |= GPU_SUPPORTS_ANISOTROPY; + features |= GPU_SUPPORTS_ANISOTROPY; } if (PSP_CoreParameter().compat.flags().ClearToRAM) { - gstate_c.featureFlags |= GPU_USE_CLEAR_RAM_HACK; + features |= GPU_USE_CLEAR_RAM_HACK; } // Mandatory features on Vulkan, which may be checked in "centralized" code - gstate_c.featureFlags |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; - gstate_c.featureFlags |= GPU_SUPPORTS_FBO; - gstate_c.featureFlags |= GPU_SUPPORTS_BLEND_MINMAX; - gstate_c.featureFlags |= GPU_SUPPORTS_ANY_COPY_IMAGE; - gstate_c.featureFlags |= GPU_SUPPORTS_OES_TEXTURE_NPOT; - gstate_c.featureFlags |= GPU_SUPPORTS_LARGE_VIEWPORTS; + features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; + features |= GPU_SUPPORTS_FBO; + features |= GPU_SUPPORTS_BLEND_MINMAX; + features |= GPU_SUPPORTS_ANY_COPY_IMAGE; + features |= GPU_SUPPORTS_OES_TEXTURE_NPOT; + features |= GPU_SUPPORTS_LARGE_VIEWPORTS; + features |= GPU_SUPPORTS_16BIT_FORMATS; + gstate_c.featureFlags = features; } void GPU_Vulkan::BeginHostFrame() { diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 5152c09fa8..10a5109bbf 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -745,7 +745,7 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt decPitch = w * bpp; } - DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, false); + DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, false, false, false); gpuStats.numTexturesDecoded++; if (scaleFactor > 1) { diff --git a/ext/native/gfx_es2/draw_text.cpp b/ext/native/gfx_es2/draw_text.cpp index 040047bbe8..d574f4396b 100644 --- a/ext/native/gfx_es2/draw_text.cpp +++ b/ext/native/gfx_es2/draw_text.cpp @@ -282,8 +282,8 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float DataFormat texFormat; // For our purposes these are equivalent, so just choose the supported one. D3D can emulate them. - if (draw_->GetDataFormatSupport(Draw::DataFormat::A4B4G4R4_UNORM_PACK16) & FMT_TEXTURE) - texFormat = Draw::DataFormat::A4B4G4R4_UNORM_PACK16; + if (draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16) & FMT_TEXTURE) + texFormat = Draw::DataFormat::A4R4G4B4_UNORM_PACK16; else if (draw_->GetDataFormatSupport(Draw::DataFormat::B4G4R4A4_UNORM_PACK16) & FMT_TEXTURE) texFormat = Draw::DataFormat::B4G4R4A4_UNORM_PACK16; else @@ -294,8 +294,7 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float TextureDesc desc{}; uint32_t *bitmapData32 = nullptr; uint16_t *bitmapData16 = nullptr; - if (texFormat == Draw::DataFormat::R8G8B8A8_UNORM) { - // We need a full 32-bit format :( + if (texFormat == Draw::DataFormat::R8G8B8A8_UNORM || texFormat == Draw::DataFormat::B8G8R8A8_UNORM) { bitmapData32 = new uint32_t[entry->bmWidth * entry->bmHeight]; for (int y = 0; y < entry->bmHeight; y++) { for (int x = 0; x < entry->bmWidth; x++) { @@ -313,7 +312,7 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float } } desc.initData.push_back((uint8_t *)bitmapData16); - } else { + } else if (texFormat == Draw::DataFormat::A4R4G4B4_UNORM_PACK16) { bitmapData16 = new uint16_t[entry->bmWidth * entry->bmHeight]; for (int y = 0; y < entry->bmHeight; y++) { for (int x = 0; x < entry->bmWidth; x++) { diff --git a/ext/native/thin3d/thin3d.cpp b/ext/native/thin3d/thin3d.cpp index 17f83ee8c7..b04626760e 100644 --- a/ext/native/thin3d/thin3d.cpp +++ b/ext/native/thin3d/thin3d.cpp @@ -13,7 +13,7 @@ size_t DataFormatSizeInBytes(DataFormat fmt) { case DataFormat::R4G4B4A4_UNORM_PACK16: return 2; case DataFormat::B4G4R4A4_UNORM_PACK16: return 2; - case DataFormat::A4B4G4R4_UNORM_PACK16: return 2; + case DataFormat::A4R4G4B4_UNORM_PACK16: return 2; case DataFormat::R5G5B5A1_UNORM_PACK16: return 2; case DataFormat::B5G5R5A1_UNORM_PACK16: return 2; case DataFormat::R5G6B5_UNORM_PACK16: return 2; diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index b5366abd52..c75722dcae 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -192,14 +192,14 @@ enum class DataFormat : uint8_t { R8G8B8A8_SINT, R4G4_UNORM_PACK8, - A4B4G4R4_UNORM_PACK16, // This is the one D3D supports - B4G4R4A4_UNORM_PACK16, // Supported by Vulkan (guaranteed one), as is the below but not on all cards. - R4G4B4A4_UNORM_PACK16, // This is the one OpenGL ES supports + A4R4G4B4_UNORM_PACK16, // A4 in the UPPER bit + B4G4R4A4_UNORM_PACK16, + R4G4B4A4_UNORM_PACK16, R5G6B5_UNORM_PACK16, B5G6R5_UNORM_PACK16, - R5G5B5A1_UNORM_PACK16, - B5G5R5A1_UNORM_PACK16, - A1R5G5B5_UNORM_PACK16, + R5G5B5A1_UNORM_PACK16, // A1 in the LOWER bit + B5G5R5A1_UNORM_PACK16, // A1 in the LOWER bit + A1R5G5B5_UNORM_PACK16, // A1 in the UPPER bit. R16_FLOAT, R16G16_FLOAT, @@ -297,6 +297,7 @@ enum FormatSupport { FMT_RENDERTARGET = 1, FMT_TEXTURE = 2, FMT_INPUTLAYOUT = 4, + FMT_DEPTHSTENCIL = 8, }; enum InfoField { diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 42f9cd54c7..5189183db3 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -383,7 +383,7 @@ static DXGI_FORMAT dataFormatToD3D11(DataFormat format) { case DataFormat::R32G32_FLOAT: return DXGI_FORMAT_R32G32_FLOAT; case DataFormat::R32G32B32_FLOAT: return DXGI_FORMAT_R32G32B32_FLOAT; case DataFormat::R32G32B32A32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT; - case DataFormat::A4B4G4R4_UNORM_PACK16: return DXGI_FORMAT_B4G4R4A4_UNORM; + case DataFormat::A4R4G4B4_UNORM_PACK16: return DXGI_FORMAT_B4G4R4A4_UNORM; case DataFormat::A1R5G5B5_UNORM_PACK16: return DXGI_FORMAT_B5G5R5A1_UNORM; case DataFormat::R5G6B5_UNORM_PACK16: return DXGI_FORMAT_B5G6R5_UNORM; case DataFormat::R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; @@ -1023,37 +1023,23 @@ void D3D11DrawContext::DrawUP(const void *vdata, int vertexCount) { } uint32_t D3D11DrawContext::GetDataFormatSupport(DataFormat fmt) const { - // TODO: Actually do proper checks - switch (fmt) { - case DataFormat::B8G8R8A8_UNORM: - return FMT_RENDERTARGET | FMT_TEXTURE; - - // D3D11 has no support for 4-bit component formats, except this one and only on Windows 8. - case DataFormat::A4B4G4R4_UNORM_PACK16: - return b4g4r4a4Supported_ ? FMT_TEXTURE : 0; - - case DataFormat::R4G4B4A4_UNORM_PACK16: - case DataFormat::B4G4R4A4_UNORM_PACK16: + DXGI_FORMAT giFmt = dataFormatToD3D11(fmt); + if (giFmt == DXGI_FORMAT_UNKNOWN) return 0; - - case DataFormat::R8G8B8A8_UNORM: - return FMT_RENDERTARGET | FMT_TEXTURE | FMT_INPUTLAYOUT; - - case DataFormat::R32_FLOAT: - case DataFormat::R32G32_FLOAT: - case DataFormat::R32G32B32_FLOAT: - case DataFormat::R32G32B32A32_FLOAT: - return FMT_INPUTLAYOUT; - - case DataFormat::R8_UNORM: + UINT giSupport = 0; + HRESULT result = device_->CheckFormatSupport(giFmt, &giSupport); + if (FAILED(result)) return 0; - case DataFormat::BC1_RGBA_UNORM_BLOCK: - case DataFormat::BC2_UNORM_BLOCK: - case DataFormat::BC3_UNORM_BLOCK: - return FMT_TEXTURE; - default: - return 0; - } + uint32_t support = 0; + if (giSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) + support |= FMT_TEXTURE; + if (giSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET) + support |= FMT_RENDERTARGET; + if (giSupport & D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER) + support |= FMT_INPUTLAYOUT; + if (giSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL) + support |= FMT_DEPTHSTENCIL; + return support; } // A D3D11Framebuffer is a D3D11Framebuffer plus all the textures it owns. diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index f10c186779..1328db37f6 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -122,7 +122,7 @@ D3DFORMAT FormatToD3DFMT(DataFormat fmt) { case DataFormat::R8G8B8A8_UNORM: return D3DFMT_A8R8G8B8; case DataFormat::R4G4B4A4_UNORM_PACK16: return D3DFMT_A4R4G4B4; // emulated case DataFormat::B4G4R4A4_UNORM_PACK16: return D3DFMT_A4R4G4B4; // native - case DataFormat::A4B4G4R4_UNORM_PACK16: return D3DFMT_A4R4G4B4; // emulated + case DataFormat::A4R4G4B4_UNORM_PACK16: return D3DFMT_A4R4G4B4; // emulated case DataFormat::R5G6B5_UNORM_PACK16: return D3DFMT_R5G6B5; case DataFormat::A1R5G5B5_UNORM_PACK16: return D3DFMT_A1R5G5B5; case DataFormat::D24_S8: return D3DFMT_D24S8; @@ -407,7 +407,7 @@ void D3D9Texture::SetImageData(int x, int y, int z, int width, int height, int d ((uint16_t *)dest)[j] = (color << 12) | (color >> 4); } break; - case DataFormat::A4B4G4R4_UNORM_PACK16: + case DataFormat::A4R4G4B4_UNORM_PACK16: // Native memcpy(dest, source, width * sizeof(uint16_t)); break; @@ -1162,7 +1162,7 @@ uint32_t D3D9Context::GetDataFormatSupport(DataFormat fmt) const { return FMT_TEXTURE; // emulated support case DataFormat::R5G6B5_UNORM_PACK16: case DataFormat::A1R5G5B5_UNORM_PACK16: - case DataFormat::A4B4G4R4_UNORM_PACK16: + case DataFormat::A4R4G4B4_UNORM_PACK16: return FMT_RENDERTARGET | FMT_TEXTURE; // native support case DataFormat::R8G8B8A8_UNORM: diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index fe0ecba528..47a4de1f18 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -743,7 +743,7 @@ void OpenGLTexture::SetImageData(int x, int y, int z, int width, int height, int type = GL_UNSIGNED_SHORT_4_4_4_4; break; #ifndef USING_GLES2 - case DataFormat::A4B4G4R4_UNORM_PACK16: + case DataFormat::A4R4G4B4_UNORM_PACK16: internalFormat = GL_RGBA; format = GL_RGBA; type = GL_UNSIGNED_SHORT_4_4_4_4_REV; @@ -1657,7 +1657,7 @@ uint32_t OpenGLContext::GetDataFormatSupport(DataFormat fmt) const { return FMT_RENDERTARGET | FMT_TEXTURE; case DataFormat::B4G4R4A4_UNORM_PACK16: return FMT_RENDERTARGET | FMT_TEXTURE; // native support - case DataFormat::A4B4G4R4_UNORM_PACK16: + case DataFormat::A4R4G4B4_UNORM_PACK16: #ifndef USING_GLES2 // Can support this if _REV formats are supported. return FMT_TEXTURE; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 09b703168d..af839f1fa5 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -1242,7 +1242,7 @@ uint32_t VKContext::GetDataFormatSupport(DataFormat fmt) const { return FMT_RENDERTARGET | FMT_TEXTURE; case DataFormat::R4G4B4A4_UNORM_PACK16: return 0; - case DataFormat::A4B4G4R4_UNORM_PACK16: + case DataFormat::A4R4G4B4_UNORM_PACK16: return 0; case DataFormat::R8G8B8A8_UNORM: