From e7ea1da99f6a96977670b0603e3a40409718640c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Mar 2016 13:17:17 -0700 Subject: [PATCH 1/7] Vulkan: Swizzle instead of converting colors. --- Common/Vulkan/VulkanImage.cpp | 14 +++++--- Common/Vulkan/VulkanImage.h | 2 +- GPU/Vulkan/TextureCacheVulkan.cpp | 58 +++++++++++++++++++------------ 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index 205c360bb4..86484b0547 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -240,7 +240,7 @@ void VulkanTexture::Wipe() { } } -void VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkImageUsageFlags usage) { +void VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkImageUsageFlags usage, const VkComponentMapping *mapping) { Wipe(); VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer(); @@ -294,10 +294,14 @@ void VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkI view_info.image = VK_NULL_HANDLE; view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; view_info.format = format_; - view_info.components.r = VK_COMPONENT_SWIZZLE_R; - view_info.components.g = VK_COMPONENT_SWIZZLE_G; - view_info.components.b = VK_COMPONENT_SWIZZLE_B; - view_info.components.a = VK_COMPONENT_SWIZZLE_A; + if (mapping) { + view_info.components = *mapping; + } else { + view_info.components.r = VK_COMPONENT_SWIZZLE_R; + view_info.components.g = VK_COMPONENT_SWIZZLE_G; + view_info.components.b = VK_COMPONENT_SWIZZLE_B; + view_info.components.a = VK_COMPONENT_SWIZZLE_A; + } view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; view_info.subresourceRange.baseMipLevel = 0; view_info.subresourceRange.levelCount = numMips; diff --git a/Common/Vulkan/VulkanImage.h b/Common/Vulkan/VulkanImage.h index fe2dbe6dbd..3b0a3ece81 100644 --- a/Common/Vulkan/VulkanImage.h +++ b/Common/Vulkan/VulkanImage.h @@ -26,7 +26,7 @@ public: void Unlock(); // Fast uploads from buffer. Mipmaps supported. Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip. - void CreateDirect(int w, int h, int numMips, VkFormat format, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + void CreateDirect(int w, int h, int numMips, VkFormat format, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr); void UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels void EndCreate(); int GetNumMips() const { return numMips_; } diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 9672c8efbc..04d0b1785c 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -69,13 +69,17 @@ #define TEXCACHE_MIN_PRESSURE 16 * 1024 * 1024 // Total in GL #define TEXCACHE_SECOND_MIN_PRESSURE 4 * 1024 * 1024 -// TODO: Except for color swizzle, exact matches are available. -// So we can get rid of the conversion functions entirely. -#define VULKAN_4444_FORMAT VK_FORMAT_R4G4B4A4_UNORM_PACK16 -#define VULKAN_1555_FORMAT VK_FORMAT_R5G5B5A1_UNORM_PACK16 -#define VULKAN_565_FORMAT VK_FORMAT_R5G6B5_UNORM_PACK16 +// Note: some drivers prefer B4G4R4A4_UNORM_PACK16 over R4G4B4A4_UNORM_PACK16. +#define VULKAN_4444_FORMAT VK_FORMAT_B4G4R4A4_UNORM_PACK16 +#define VULKAN_1555_FORMAT VK_FORMAT_A1R5G5B5_UNORM_PACK16 +#define VULKAN_565_FORMAT VK_FORMAT_B5G6R5_UNORM_PACK16 #define VULKAN_8888_FORMAT VK_FORMAT_R8G8B8A8_UNORM +static const VkComponentMapping VULKAN_4444_SWIZZLE = { VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B }; +static const VkComponentMapping VULKAN_1555_SWIZZLE = { VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_A }; +static const VkComponentMapping VULKAN_565_SWIZZLE = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; +static const VkComponentMapping VULKAN_8888_SWIZZLE = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; + // Hack! extern int g_iNumVideos; @@ -620,14 +624,10 @@ static void ConvertColors(void *dstBuf, const void *srcBuf, VkFormat dstFmt, int u32 *dst = (u32 *)dstBuf; switch (dstFmt) { case VULKAN_4444_FORMAT: - ConvertRGBA4444ToABGR4444((u16 *)dst, (const u16 *)src, numPixels); - break; - // Final Fantasy 2 uses this heavily in animated textures. case VULKAN_1555_FORMAT: - ConvertRGBA5551ToABGR1555((u16 *)dst, (const u16 *)src, numPixels); - break; case VULKAN_565_FORMAT: - ConvertRGB565ToBGR565((u16 *)dst, (const u16 *)src, numPixels); + if (dst != src) + memcpy(dst, src, numPixels * sizeof(u16)); break; default: // No need to convert RGBA8888, right order already @@ -680,15 +680,7 @@ void TextureCacheVulkan::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutB const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_); clutHash_ = DoReliableHash32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); - - // Avoid a copy when we don't need to convert colors. - if (clutFormat != GE_CMODE_32BIT_ABGR8888) { - const int numColors = clutFormat == GE_CMODE_32BIT_ABGR8888 ? (clutMaxBytes_ / sizeof(u32)) : (clutMaxBytes_ / sizeof(u16)); - ConvertColors(clutBufConverted_, clutBufRaw_, getClutDestFormatVulkan(clutFormat), numColors); - clutBuf_ = clutBufConverted_; - } else { - clutBuf_ = clutBufRaw_; - } + clutBuf_ = clutBufRaw_; // Special optimization: fonts typically draw clut4 with just alpha values in a single color. clutAlphaLinear_ = false; @@ -1405,7 +1397,27 @@ void TextureCacheVulkan::SetTexture(VulkanPushBuffer *uploadBuffer) { entry->vkTex = new CachedTextureVulkan(); entry->vkTex->texture_ = new VulkanTexture(vulkan_); VulkanTexture *image = entry->vkTex->texture_; - image->CreateDirect(w * scaleFactor, h * scaleFactor, maxLevel + 1, dstFmt); + + const VkComponentMapping *mapping; + switch (dstFmt) { + case VULKAN_4444_FORMAT: + mapping = &VULKAN_4444_SWIZZLE; + break; + + case VULKAN_1555_FORMAT: + mapping = &VULKAN_1555_SWIZZLE; + break; + + case VULKAN_565_FORMAT: + mapping = &VULKAN_565_SWIZZLE; + break; + + default: + mapping = &VULKAN_8888_SWIZZLE; + break; + } + + image->CreateDirect(w * scaleFactor, h * scaleFactor, maxLevel + 1, dstFmt, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); } lastBoundTexture = entry->vkTex; @@ -1647,10 +1659,10 @@ TextureCacheVulkan::TexCacheEntry::Status TextureCacheVulkan::CheckAlpha(const u CheckAlphaResult res; switch (dstFmt) { case VULKAN_4444_FORMAT: - res = CheckAlphaABGR4444Basic(pixelData, stride, w, h); + res = CheckAlphaRGBA4444Basic(pixelData, stride, w, h); break; case VULKAN_1555_FORMAT: - res = CheckAlphaABGR1555Basic(pixelData, stride, w, h); + res = CheckAlphaRGBA5551Basic(pixelData, stride, w, h); break; case VULKAN_565_FORMAT: // Never has any alpha. From 29287ea0ee3681fd859e35d7fdcdc25df20194bb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Mar 2016 13:33:18 -0700 Subject: [PATCH 2/7] Vulkan: Reorganize a bit so we can decode directly. --- GPU/Vulkan/TextureCacheVulkan.cpp | 29 ++++++++++++++++++++--------- GPU/Vulkan/TextureCacheVulkan.h | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 04d0b1785c..17d945f67c 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -1463,7 +1463,7 @@ VkFormat TextureCacheVulkan::GetDestFormat(GETextureFormat format, GEPaletteForm } } -void *TextureCacheVulkan::DecodeTextureLevel(GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, VkFormat dstFmt, int scaleFactor, int bufw) { +void *TextureCacheVulkan::DecodeTextureLevel(u8 *out, int outPitch, GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, VkFormat dstFmt, int scaleFactor, int bufw) { void *finalBuf = NULL; bool swizzled = gstate.isTextureSwizzled(); @@ -1690,12 +1690,24 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt GEPaletteFormat clutformat = gstate.getClutPaletteFormat(); u32 texaddr = gstate.getTextureAddress(level); int bufw = GetTextureBufw(level, texaddr, tfmt); - void *finalBuf = DecodeTextureLevel(tfmt, clutformat, texaddr, level, dstFmt, scaleFactor, bufw); + int bpp = dstFmt == VULKAN_8888_FORMAT ? 4 : 2; + + pixelData = (u32 *)writePtr; + decPitch = rowPitch; + if (scaleFactor > 1) { + tmpTexBufRearrange.resize(std::max(bufw, w) * h); + pixelData = tmpTexBufRearrange.data(); + decPitch = bufw * bpp; + } + + void *finalBuf = DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, dstFmt, scaleFactor, bufw); if (finalBuf == NULL) { return; } - decPitch = bufw * (dstFmt == VULKAN_8888_FORMAT ? 4 : 2); - rowBytes = w * (dstFmt == VULKAN_8888_FORMAT ? 4 : 2); + if (finalBuf != pixelData) { + decPitch = bufw * bpp; + } + rowBytes = w * bpp; gpuStats.numTexturesDecoded++; pixelData = (u32 *)finalBuf; @@ -1721,11 +1733,10 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt } PROFILE_THIS_SCOPE("loadtex"); - // TODO: Get rid of this, and decode or scale directly into this. - for (int y = 0; y < h; y++) { - memcpy(writePtr + rowPitch * y, (const uint8_t *)pixelData + decPitch * y, rowBytes); - // uncomment to make all textures white for debugging - //memset(writePtr + rowPitch * y, 0xff, rowBytes); + if (pixelData != (u32 *)writePtr) { + for (int y = 0; y < h; y++) { + memcpy(writePtr + rowPitch * y, (const uint8_t *)pixelData + decPitch * y, rowBytes); + } } /* diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h index 2e063ac56b..8e4137de27 100644 --- a/GPU/Vulkan/TextureCacheVulkan.h +++ b/GPU/Vulkan/TextureCacheVulkan.h @@ -128,7 +128,7 @@ private: void UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key); void LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, bool replaceImages, int scaleFactor, VkFormat dstFmt); VkFormat GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const; - void *DecodeTextureLevel(GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, VkFormat dstFmt, int scaleFactor, int bufw); + void *DecodeTextureLevel(u8 *out, int outPitch, GETextureFormat format, GEPaletteFormat clutformat, uint32_t texaddr, int level, VkFormat dstFmt, int scaleFactor, int bufw); TexCacheEntry::Status CheckAlpha(const u32 *pixelData, VkFormat dstFmt, int stride, int w, int h); template const T *GetCurrentClut(); From 99bf2c5aeb1c673c128ed5a260c10e1f5c7ccac1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Mar 2016 13:43:42 -0700 Subject: [PATCH 3/7] Vulkan: Decode the simplest tex formats directly. --- GPU/Vulkan/TextureCacheVulkan.cpp | 60 +++++++++++++++---------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 17d945f67c..061eb2373f 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -1553,93 +1553,93 @@ void *TextureCacheVulkan::DecodeTextureLevel(u8 *out, int outPitch, GETextureFor case GE_TFMT_5551: case GE_TFMT_5650: if (!swizzled) { - int len = std::max(bufw, w) * h; - tmpTexBuf16.resize(len); - finalBuf = tmpTexBuf16.data(); - ConvertColors(finalBuf, texptr, dstFmt, bufw * h); + // Just a simple copy, we swizzle the color format. + for (int y = 0; y < h; ++y) { + memcpy(out + outPitch * y, texptr + bufw * sizeof(u16) * y, w * sizeof(u16)); + } + finalBuf = out; } else { tmpTexBuf32.resize(std::max(bufw, w) * h); UnswizzleFromMem(tmpTexBuf32.data(), texptr, bufw, h, 2); - finalBuf = tmpTexBuf32.data(); - ConvertColors(finalBuf, finalBuf, dstFmt, bufw * h); + const u8 *unswizzled = (u8 *)tmpTexBuf32.data(); + for (int y = 0; y < h; ++y) { + memcpy(out + outPitch * y, unswizzled + bufw * sizeof(u16) * y, w * sizeof(u16)); + } + finalBuf = out; } break; case GE_TFMT_8888: if (!swizzled) { - // Special case: if we don't need to deal with packing, we don't need to copy. - if (scaleFactor == 1 || w == bufw) { - finalBuf = (void *)texptr; - } else { - tmpTexBuf32.resize(std::max(bufw, w) * h); - finalBuf = tmpTexBuf32.data(); - ConvertColors(finalBuf, texptr, dstFmt, bufw * h); + for (int y = 0; y < h; ++y) { + memcpy(out + outPitch * y, texptr + bufw * sizeof(u32) * y, w * sizeof(u32)); } + finalBuf = out; } else { tmpTexBuf32.resize(std::max(bufw, w) * h); UnswizzleFromMem(tmpTexBuf32.data(), texptr, bufw, h, 4); - finalBuf = tmpTexBuf32.data(); - ConvertColors(finalBuf, finalBuf, dstFmt, bufw * h); + const u8 *unswizzled = (u8 *)tmpTexBuf32.data(); + for (int y = 0; y < h; ++y) { + memcpy(out + outPitch * y, unswizzled + bufw * sizeof(u32) * y, w * sizeof(u32)); + } + finalBuf = out; } break; case GE_TFMT_DXT1: { int minw = std::min(bufw, w); - tmpTexBuf32.resize(std::max(bufw, w) * h); - u32 *dst = tmpTexBuf32.data(); + u32 *dst = (u32 *)out; DXT1Block *src = (DXT1Block*)texptr; for (int y = 0; y < h; y += 4) { u32 blockIndex = (y / 4) * (bufw / 4); for (int x = 0; x < minw; x += 4) { - DecodeDXT1Block(dst + bufw * y + x, src + blockIndex, bufw); + DecodeDXT1Block(dst + outPitch * y + x, src + blockIndex, outPitch); blockIndex++; } } - finalBuf = tmpTexBuf32.data(); - ConvertColors(finalBuf, finalBuf, dstFmt, bufw * h); + // TODO: Not height also? w = (w + 3) & ~3; + finalBuf = out; } break; case GE_TFMT_DXT3: { int minw = std::min(bufw, w); - tmpTexBuf32.resize(std::max(bufw, w) * h); - u32 *dst = tmpTexBuf32.data(); + u32 *dst = (u32 *)out; DXT3Block *src = (DXT3Block*)texptr; for (int y = 0; y < h; y += 4) { u32 blockIndex = (y / 4) * (bufw / 4); for (int x = 0; x < minw; x += 4) { - DecodeDXT3Block(dst + bufw * y + x, src + blockIndex, bufw); + DecodeDXT3Block(dst + outPitch * y + x, src + blockIndex, outPitch); blockIndex++; } } + // TODO: Not height also? w = (w + 3) & ~3; - finalBuf = tmpTexBuf32.data(); - ConvertColors(finalBuf, finalBuf, dstFmt, bufw * h); + finalBuf = out; } break; case GE_TFMT_DXT5: { int minw = std::min(bufw, w); - tmpTexBuf32.resize(std::max(bufw, w) * h); - u32 *dst = tmpTexBuf32.data(); + u32 *dst = (u32 *)out; DXT5Block *src = (DXT5Block*)texptr; for (int y = 0; y < h; y += 4) { u32 blockIndex = (y / 4) * (bufw / 4); for (int x = 0; x < minw; x += 4) { - DecodeDXT5Block(dst + bufw * y + x, src + blockIndex, bufw); + DecodeDXT5Block(dst + outPitch * y + x, src + blockIndex, outPitch); blockIndex++; } } + // TODO: Not height also? w = (w + 3) & ~3; - finalBuf = tmpTexBuf32.data(); - ConvertColors(finalBuf, finalBuf, dstFmt, bufw * h); + finalBuf = out; } break; From fe4c0e9f5a74e2682301c05bd35ff247ba5146b0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Mar 2016 14:28:03 -0700 Subject: [PATCH 4/7] Vulkan: Fix various problems with tex scaling. --- GPU/Vulkan/TextureCacheVulkan.cpp | 34 ++++++++++++++++++++++++------ GPU/Vulkan/TextureScalerVulkan.cpp | 31 ++++++++++++++++----------- 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 061eb2373f..43ca25d835 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -1389,6 +1389,8 @@ void TextureCacheVulkan::SetTexture(VulkanPushBuffer *uploadBuffer) { maxLevel = 0; } + VkFormat actualFmt = scaleFactor > 1 ? VULKAN_8888_FORMAT : dstFmt; + if (replaceImages) { if (!entry->vkTex) { Crash(); @@ -1399,7 +1401,7 @@ void TextureCacheVulkan::SetTexture(VulkanPushBuffer *uploadBuffer) { VulkanTexture *image = entry->vkTex->texture_; const VkComponentMapping *mapping; - switch (dstFmt) { + switch (actualFmt) { case VULKAN_4444_FORMAT: mapping = &VULKAN_4444_SWIZZLE; break; @@ -1417,7 +1419,7 @@ void TextureCacheVulkan::SetTexture(VulkanPushBuffer *uploadBuffer) { break; } - image->CreateDirect(w * scaleFactor, h * scaleFactor, maxLevel + 1, dstFmt, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); + image->CreateDirect(w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); } lastBoundTexture = entry->vkTex; @@ -1425,7 +1427,7 @@ void TextureCacheVulkan::SetTexture(VulkanPushBuffer *uploadBuffer) { for (int i = 0; i <= maxLevel; i++) { int mipWidth = gstate.getTextureWidth(i) * scaleFactor; int mipHeight = gstate.getTextureHeight(i) * scaleFactor; - int bpp = dstFmt == VULKAN_8888_FORMAT ? 4 : 2; + int bpp = actualFmt == VULKAN_8888_FORMAT ? 4 : 2; int stride = (mipWidth * bpp + 15) & ~15; int size = stride * mipHeight; uint32_t bufferOffset; @@ -1697,7 +1699,8 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt if (scaleFactor > 1) { tmpTexBufRearrange.resize(std::max(bufw, w) * h); pixelData = tmpTexBufRearrange.data(); - decPitch = bufw * bpp; + // We want to end up with a neatly packed texture for scaling. + decPitch = w * bpp; } void *finalBuf = DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, dstFmt, scaleFactor, bufw); @@ -1705,18 +1708,35 @@ void TextureCacheVulkan::LoadTextureLevel(TexCacheEntry &entry, uint8_t *writePt return; } if (finalBuf != pixelData) { + // Since we didn't write to pixelData, we must've ignored decPitch too. + // TODO: Can remove once all formats are decoded directly and respect decPitch. decPitch = bufw * bpp; } + pixelData = (u32 *)finalBuf; rowBytes = w * bpp; gpuStats.numTexturesDecoded++; - pixelData = (u32 *)finalBuf; if (scaleFactor > 1) { u32 fmt = dstFmt; + // We need to repack it sometimes. + // TODO: Can remove once all formats are decoded directly and respect decPitch. + if (decPitch != w * bpp) { + tmpTexBufRearrange.resize(w * h); + const u8 *src = (u8 *)pixelData; + u8 *dst = (u8 *)tmpTexBufRearrange.data(); + for (int y = 0; y < h; y++) { + memcpy(dst + rowBytes * y, src + decPitch * y, rowBytes); + } + pixelData = (u32 *)dst; + } + scaler.Scale(pixelData, fmt, w, h, scaleFactor); dstFmt = (VkFormat)fmt; - decPitch *= scaleFactor; - rowBytes *= scaleFactor; + + // We always end up at 8888. Other parts check for this. + assert(dstFmt == VULKAN_8888_FORMAT); + decPitch = w * sizeof(u32); + rowBytes = w * sizeof(u32); } if ((entry.status & TexCacheEntry::STATUS_CHANGE_FREQUENT) == 0) { diff --git a/GPU/Vulkan/TextureScalerVulkan.cpp b/GPU/Vulkan/TextureScalerVulkan.cpp index 267538846c..278607349d 100644 --- a/GPU/Vulkan/TextureScalerVulkan.cpp +++ b/GPU/Vulkan/TextureScalerVulkan.cpp @@ -21,38 +21,45 @@ #endif #include -#include "gfx/gl_common.h" -#include "GPU/Common/TextureScalerCommon.h" -#include "GPU/Vulkan/TextureScalerVulkan.h" +#include "Common/Vulkan/VulkanContext.h" #include "Common/ColorConv.h" #include "Common/Log.h" #include "Common/ThreadPools.h" +#include "GPU/Common/TextureScalerCommon.h" +#include "GPU/Vulkan/TextureScalerVulkan.h" + +// TODO: Share in TextureCacheVulkan.h? +// Note: some drivers prefer B4G4R4A4_UNORM_PACK16 over R4G4B4A4_UNORM_PACK16. +#define VULKAN_4444_FORMAT VK_FORMAT_B4G4R4A4_UNORM_PACK16 +#define VULKAN_1555_FORMAT VK_FORMAT_A1R5G5B5_UNORM_PACK16 +#define VULKAN_565_FORMAT VK_FORMAT_B5G6R5_UNORM_PACK16 +#define VULKAN_8888_FORMAT VK_FORMAT_R8G8B8A8_UNORM int TextureScalerVulkan::BytesPerPixel(u32 format) { - return (format == GL_UNSIGNED_BYTE) ? 4 : 2; + return (format == VULKAN_8888_FORMAT) ? 4 : 2; } u32 TextureScalerVulkan::Get8888Format() { - return GL_UNSIGNED_BYTE; + return VULKAN_8888_FORMAT; } void TextureScalerVulkan::ConvertTo8888(u32 format, u32* source, u32* &dest, int width, int height) { switch (format) { - case GL_UNSIGNED_BYTE: + case VULKAN_8888_FORMAT: dest = source; // already fine break; - case GL_UNSIGNED_SHORT_4_4_4_4: - GlobalThreadPool::Loop(std::bind(&convert4444_gl, (u16*)source, dest, width, placeholder::_1, placeholder::_2), 0, height); + case VULKAN_4444_FORMAT: + GlobalThreadPool::Loop(std::bind(&convert4444_dx9, (u16*)source, dest, width, placeholder::_1, placeholder::_2), 0, height); break; - case GL_UNSIGNED_SHORT_5_6_5: - GlobalThreadPool::Loop(std::bind(&convert565_gl, (u16*)source, dest, width, placeholder::_1, placeholder::_2), 0, height); + case VULKAN_565_FORMAT: + GlobalThreadPool::Loop(std::bind(&convert565_dx9, (u16*)source, dest, width, placeholder::_1, placeholder::_2), 0, height); break; - case GL_UNSIGNED_SHORT_5_5_5_1: - GlobalThreadPool::Loop(std::bind(&convert5551_gl, (u16*)source, dest, width, placeholder::_1, placeholder::_2), 0, height); + case VULKAN_1555_FORMAT: + GlobalThreadPool::Loop(std::bind(&convert5551_dx9, (u16*)source, dest, width, placeholder::_1, placeholder::_2), 0, height); break; default: From 9b15ce093443b7289fc4dc3667530fdc416f3514 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Mar 2016 14:34:24 -0700 Subject: [PATCH 5/7] UI: Fix texture scaling level selection. It previously was not possible to select 4 on a POT-only device, since it would become 3, which would in turn become 2. Also, this allows selection on other backends, e.g. Vulkan. --- UI/GameSettingsScreen.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 3651c0bf66..56854e5b73 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -250,22 +250,18 @@ void GameSettingsScreen::CreateViews() { graphicsSettings->Add(new ItemHeader(gr->T("Texture Scaling"))); #ifndef MOBILE_DEVICE static const char *texScaleLevelsNPOT[] = {"Auto", "Off", "2x", "3x", "4x", "5x"}; - static const char *texScaleLevelsPOT[] = {"Auto", "Off", "2x", "4x"}; #else static const char *texScaleLevelsNPOT[] = {"Auto", "Off", "2x", "3x"}; - static const char *texScaleLevelsPOT[] = {"Auto", "Off", "2x"}; #endif - static const char **texScaleLevels; - static int numTexScaleLevels; - if (gl_extensions.OES_texture_npot) { - texScaleLevels = texScaleLevelsNPOT; - numTexScaleLevels = ARRAY_SIZE(texScaleLevelsNPOT); - } else { - texScaleLevels = texScaleLevelsPOT; - numTexScaleLevels = ARRAY_SIZE(texScaleLevelsPOT); - } + static const char **texScaleLevels = texScaleLevelsNPOT; + static int numTexScaleLevels = ARRAY_SIZE(texScaleLevelsNPOT); PopupMultiChoice *texScalingChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iTexScalingLevel, gr->T("Upscale Level"), texScaleLevels, 0, numTexScaleLevels, gr->GetName(), screenManager())); + // TODO: Better check? When it won't work, it scales down anyway. + if (!gl_extensions.OES_texture_npot && GetGPUBackend() == GPUBackend::OPENGL) { + texScalingChoice->HideChoice(3); // 3x + texScalingChoice->HideChoice(5); // 5x + } texScalingChoice->SetDisabledPtr(&g_Config.bSoftwareRendering); static const char *texScaleAlgos[] = { "xBRZ", "Hybrid", "Bicubic", "Hybrid + Bicubic", }; From a130e2695ea22fe30f40b909c32188b68f4beba1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Mar 2016 14:36:54 -0700 Subject: [PATCH 6/7] Vulkan: Remove unused color conv func. --- GPU/Vulkan/TextureCacheVulkan.cpp | 50 ------------------------------- 1 file changed, 50 deletions(-) diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 43ca25d835..256c57af2c 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -151,38 +151,6 @@ void TextureCacheVulkan::DownloadFramebufferForClut(u32 clutAddr, u32 bytes) { } -static u32 EstimateTexMemoryUsage(const TextureCacheVulkan::TexCacheEntry *entry) { - const u16 dim = entry->dim; - const u8 dimW = ((dim >> 0) & 0xf); - const u8 dimH = ((dim >> 8) & 0xf); - - u32 pixelSize = 2; - switch (entry->format) { - case GE_TFMT_CLUT4: - case GE_TFMT_CLUT8: - case GE_TFMT_CLUT16: - case GE_TFMT_CLUT32: - // We assume cluts always point to 8888 for simplicity. - pixelSize = 4; - break; - case GE_TFMT_4444: - case GE_TFMT_5551: - case GE_TFMT_5650: - break; - - case GE_TFMT_8888: - case GE_TFMT_DXT1: - case GE_TFMT_DXT3: - case GE_TFMT_DXT5: - default: - pixelSize = 4; - break; - } - - // This in other words multiplies by w and h. - return pixelSize << (dimW + dimH); -} - void TextureCacheVulkan::Clear(bool delete_them) { lastBoundTexture = nullptr; if (delete_them) { @@ -619,24 +587,6 @@ void TextureCacheVulkan::SetFramebufferSamplingParams(u16 bufferWidth, u16 buffe } } -static void ConvertColors(void *dstBuf, const void *srcBuf, VkFormat dstFmt, int numPixels) { - const u32 *src = (const u32 *)srcBuf; - u32 *dst = (u32 *)dstBuf; - switch (dstFmt) { - case VULKAN_4444_FORMAT: - case VULKAN_1555_FORMAT: - case VULKAN_565_FORMAT: - if (dst != src) - memcpy(dst, src, numPixels * sizeof(u16)); - break; - default: - // No need to convert RGBA8888, right order already - if (dst != src) - memcpy(dst, src, numPixels * sizeof(u32)); - break; - } -} - void TextureCacheVulkan::StartFrame() { lastBoundTexture = nullptr; timesInvalidatedAllThisFrame_ = 0; From 6c0a5ca503316dfc19a1c757f15eb086babccf74 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 26 Mar 2016 14:43:35 -0700 Subject: [PATCH 7/7] Vulkan: Oops, correct DXT stride. --- GPU/Vulkan/TextureCacheVulkan.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 256c57af2c..67c17f0afb 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -1542,12 +1542,13 @@ void *TextureCacheVulkan::DecodeTextureLevel(u8 *out, int outPitch, GETextureFor { int minw = std::min(bufw, w); u32 *dst = (u32 *)out; + int outPitch32 = outPitch / sizeof(u32); DXT1Block *src = (DXT1Block*)texptr; for (int y = 0; y < h; y += 4) { u32 blockIndex = (y / 4) * (bufw / 4); for (int x = 0; x < minw; x += 4) { - DecodeDXT1Block(dst + outPitch * y + x, src + blockIndex, outPitch); + DecodeDXT1Block(dst + outPitch32 * y + x, src + blockIndex, outPitch32); blockIndex++; } } @@ -1561,12 +1562,13 @@ void *TextureCacheVulkan::DecodeTextureLevel(u8 *out, int outPitch, GETextureFor { int minw = std::min(bufw, w); u32 *dst = (u32 *)out; + int outPitch32 = outPitch / sizeof(u32); DXT3Block *src = (DXT3Block*)texptr; for (int y = 0; y < h; y += 4) { u32 blockIndex = (y / 4) * (bufw / 4); for (int x = 0; x < minw; x += 4) { - DecodeDXT3Block(dst + outPitch * y + x, src + blockIndex, outPitch); + DecodeDXT3Block(dst + outPitch32 * y + x, src + blockIndex, outPitch32); blockIndex++; } } @@ -1580,12 +1582,13 @@ void *TextureCacheVulkan::DecodeTextureLevel(u8 *out, int outPitch, GETextureFor { int minw = std::min(bufw, w); u32 *dst = (u32 *)out; + int outPitch32 = outPitch / sizeof(u32); DXT5Block *src = (DXT5Block*)texptr; for (int y = 0; y < h; y += 4) { u32 blockIndex = (y / 4) * (bufw / 4); for (int x = 0; x < minw; x += 4) { - DecodeDXT5Block(dst + outPitch * y + x, src + blockIndex, outPitch); + DecodeDXT5Block(dst + outPitch32 * y + x, src + blockIndex, outPitch32); blockIndex++; } }