mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #13514 from hrydgard/replacement-tex-mipmap-gen
Vulkan: Automatically generate mipmaps for replaced/scaled textures
This commit is contained in:
commit
2f79257aad
2 changed files with 17 additions and 55 deletions
|
@ -15,16 +15,13 @@
|
|||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#ifdef USING_QT_UI
|
||||
#include <QtGui/QImage>
|
||||
#else
|
||||
#include <png.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "ext/xxhash.h"
|
||||
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/Data/Format/IniFile.h"
|
||||
#include "Common/Data/Text/Parsers.h"
|
||||
#include "Common/ColorConv.h"
|
||||
|
@ -333,16 +330,6 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey,
|
|||
level.fmt = ReplacedTextureFormat::F_8888;
|
||||
level.file = filename;
|
||||
|
||||
#ifdef USING_QT_UI
|
||||
QImage image(filename.c_str(), "PNG");
|
||||
if (image.isNull()) {
|
||||
ERROR_LOG(G3D, "Could not load texture replacement info: %s", filename.c_str());
|
||||
} else {
|
||||
level.w = (image.width() * w) / newW;
|
||||
level.h = (image.height() * h) / newH;
|
||||
good = true;
|
||||
}
|
||||
#else
|
||||
png_image png = {};
|
||||
png.version = PNG_IMAGE_VERSION;
|
||||
FILE *fp = File::OpenCFile(filename, "rb");
|
||||
|
@ -357,7 +344,6 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey,
|
|||
fclose(fp);
|
||||
|
||||
png_image_free(&png);
|
||||
#endif
|
||||
|
||||
if (good && i != 0) {
|
||||
// Check that the mipmap size is correct. Can't load mips of the wrong size.
|
||||
|
@ -377,7 +363,6 @@ void TextureReplacer::PopulateReplacement(ReplacedTexture *result, u64 cachekey,
|
|||
result->alphaStatus_ = ReplacedTextureAlpha::UNKNOWN;
|
||||
}
|
||||
|
||||
#ifndef USING_QT_UI
|
||||
static bool WriteTextureToPNG(png_imagep image, const std::string &filename, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap) {
|
||||
FILE *fp = File::OpenCFile(filename, "wb");
|
||||
if (!fp) {
|
||||
|
@ -395,7 +380,6 @@ static bool WriteTextureToPNG(png_imagep image, const std::string &filename, int
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &replacedInfo, const void *data, int pitch, int level, int w, int h) {
|
||||
_assert_msg_(enabled_, "Replacement not enabled");
|
||||
|
@ -459,9 +443,6 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl
|
|||
h = lookupH * replacedInfo.scaleFactor;
|
||||
}
|
||||
|
||||
#ifdef USING_QT_UI
|
||||
ERROR_LOG(G3D, "Replacement texture saving not implemented for Qt");
|
||||
#else
|
||||
if (replacedInfo.fmt != ReplacedTextureFormat::F_8888) {
|
||||
saveBuf.resize((pitch * h) / sizeof(u16));
|
||||
switch (replacedInfo.fmt) {
|
||||
|
@ -512,7 +493,6 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl
|
|||
} else if (success) {
|
||||
NOTICE_LOG(G3D, "Saving texture for replacement: %08x / %dx%d", replacedInfo.hash, w, h);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Remember that we've saved this for next time.
|
||||
ReplacedTextureLevel saved;
|
||||
|
@ -600,34 +580,6 @@ void ReplacedTexture::Load(int level, void *out, int rowPitch) {
|
|||
|
||||
const ReplacedTextureLevel &info = levels_[level];
|
||||
|
||||
#ifdef USING_QT_UI
|
||||
QImage image(info.file.c_str(), "PNG");
|
||||
if (image.isNull()) {
|
||||
ERROR_LOG(G3D, "Could not load texture replacement info: %s", info.file.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
bool alphaFull = true;
|
||||
for (int y = 0; y < image.height(); ++y) {
|
||||
const QRgb *src = (const QRgb *)image.constScanLine(y);
|
||||
uint8_t *outLine = (uint8_t *)out + y * rowPitch;
|
||||
for (int x = 0; x < image.width(); ++x) {
|
||||
outLine[x * 4 + 0] = qRed(src[x]);
|
||||
outLine[x * 4 + 1] = qGreen(src[x]);
|
||||
outLine[x * 4 + 2] = qBlue(src[x]);
|
||||
outLine[x * 4 + 3] = qAlpha(src[x]);
|
||||
// We're already scanning each pixel...
|
||||
if (qAlpha(src[x]) != 255) {
|
||||
alphaFull = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (level == 0 || !alphaFull) {
|
||||
alphaStatus_ = alphaFull ? ReplacedTextureAlpha::FULL : ReplacedTextureAlpha::UNKNOWN;
|
||||
}
|
||||
#else
|
||||
png_image png = {};
|
||||
png.version = PNG_IMAGE_VERSION;
|
||||
|
||||
|
@ -662,7 +614,6 @@ void ReplacedTexture::Load(int level, void *out, int rowPitch) {
|
|||
|
||||
fclose(fp);
|
||||
png_image_free(&png);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TextureReplacer::GenerateIni(const std::string &gameID, std::string *generatedFilename) {
|
||||
|
|
|
@ -710,7 +710,10 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
|
|||
|
||||
// Adjust maxLevel to actually present levels..
|
||||
bool badMipSizes = false;
|
||||
|
||||
// maxLevel here is the max level to upload. Not the count.
|
||||
int maxLevel = entry->maxLevel;
|
||||
|
||||
for (int i = 0; i <= maxLevel; i++) {
|
||||
// If encountering levels pointing to nothing, adjust max level.
|
||||
u32 levelTexaddr = gstate.getTextureAddress(i);
|
||||
|
@ -740,6 +743,10 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
|
|||
maxLevel = 0;
|
||||
}
|
||||
|
||||
// We generate missing mipmaps from maxLevel+1 up to this level. maxLevel can get overwritten below
|
||||
// such as when using replacement textures - but let's keep the same amount of levels.
|
||||
int maxLevelToGenerate = maxLevel;
|
||||
|
||||
// If GLES3 is available, we can preallocate the storage, which makes texture loading more efficient.
|
||||
VkFormat dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat());
|
||||
|
||||
|
@ -824,8 +831,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
|
|||
}
|
||||
|
||||
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
// If we want to use the GE debugger, we should add VK_IMAGE_USAGE_TRANSFER_SRC_BIT too...
|
||||
VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
// Compute experiment
|
||||
if (actualFmt == VULKAN_8888_FORMAT && scaleFactor > 1 && hardwareScaling) {
|
||||
|
@ -845,7 +851,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
|
|||
snprintf(texName, sizeof(texName), "texture_%08x_%s", entry->addr, GeTextureFormatToString((GETextureFormat)entry->format));
|
||||
image->SetTag(texName);
|
||||
|
||||
bool allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, imageLayout, usage, mapping);
|
||||
bool allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevelToGenerate + 1, actualFmt, imageLayout, usage, mapping);
|
||||
if (!allocSuccess && !lowMemoryMode_) {
|
||||
WARN_LOG_REPORT(G3D, "Texture cache ran out of GPU memory; switching to low memory mode");
|
||||
lowMemoryMode_ = true;
|
||||
|
@ -864,7 +870,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
|
|||
scaleFactor = 1;
|
||||
actualFmt = dstFmt;
|
||||
|
||||
allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping);
|
||||
allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevelToGenerate + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping);
|
||||
}
|
||||
|
||||
if (!allocSuccess) {
|
||||
|
@ -987,6 +993,11 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
|
|||
}
|
||||
}
|
||||
|
||||
// Generate any additional mipmap levels.
|
||||
for (int level = maxLevel + 1; level <= maxLevelToGenerate; level++) {
|
||||
entry->vkTex->GenerateMip(cmdInit, level);
|
||||
}
|
||||
|
||||
if (maxLevel == 0) {
|
||||
entry->status |= TexCacheEntry::STATUS_BAD_MIPS;
|
||||
} else {
|
||||
|
|
Loading…
Add table
Reference in a new issue