mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-03-02 19:16:56 +00:00
Reintroduce mipmaps for images in the UI like screenshots (D3D11, OpenGL, D3D9)
This commit is contained in:
parent
21d97a7947
commit
8a8360ef96
@ -85,7 +85,7 @@ void AsyncImageFileView::SetFilename(std::string filename) {
|
||||
void AsyncImageFileView::Draw(UIContext &dc) {
|
||||
using namespace Draw;
|
||||
if (!texture_ && !textureFailed_ && !filename_.empty()) {
|
||||
texture_ = CreateTextureFromFile(dc.GetDrawContext(), filename_.c_str(), DETECT);
|
||||
texture_ = CreateTextureFromFile(dc.GetDrawContext(), filename_.c_str(), DETECT, true);
|
||||
if (!texture_)
|
||||
textureFailed_ = true;
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "thin3d/thin3d.h"
|
||||
#include "image/zim_load.h"
|
||||
#include "image/png_load.h"
|
||||
#include "math/math_util.h"
|
||||
#include "file/vfs.h"
|
||||
#include "ext/jpge/jpgd.h"
|
||||
#include "UI/TextureUtil.h"
|
||||
@ -83,7 +86,7 @@ static bool LoadTextureLevels(const uint8_t *data, size_t size, ImageFileType ty
|
||||
return *num_levels > 0;
|
||||
}
|
||||
|
||||
bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type) {
|
||||
bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type, bool generateMips) {
|
||||
using namespace Draw;
|
||||
|
||||
int width[16]{}, height[16]{};
|
||||
@ -110,13 +113,16 @@ bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, Imag
|
||||
texture_ = nullptr;
|
||||
}
|
||||
|
||||
int potentialLevels = std::min(log2i(width[0]), log2i(height[0]));
|
||||
|
||||
TextureDesc desc{};
|
||||
desc.type = TextureType::LINEAR2D;
|
||||
desc.format = fmt;
|
||||
desc.width = width[0];
|
||||
desc.height = height[0];
|
||||
desc.depth = 1;
|
||||
desc.mipLevels = num_levels;
|
||||
desc.mipLevels = generateMips ? potentialLevels : num_levels;
|
||||
desc.generateMips = generateMips && potentialLevels > num_levels;
|
||||
for (int i = 0; i < num_levels; i++) {
|
||||
desc.initData.push_back(image[i]);
|
||||
}
|
||||
@ -125,10 +131,11 @@ bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, Imag
|
||||
if (image[i])
|
||||
free(image[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ManagedTexture::LoadFromFile(const std::string &filename, ImageFileType type) {
|
||||
bool ManagedTexture::LoadFromFile(const std::string &filename, ImageFileType type, bool generateMips) {
|
||||
filename_ = "";
|
||||
size_t fileSize;
|
||||
uint8_t *buffer = VFSReadFile(filename.c_str(), &fileSize);
|
||||
@ -136,7 +143,7 @@ bool ManagedTexture::LoadFromFile(const std::string &filename, ImageFileType typ
|
||||
ELOG("Failed to read file %s", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
bool retval = LoadFromFileData(buffer, fileSize, type);
|
||||
bool retval = LoadFromFileData(buffer, fileSize, type, generateMips);
|
||||
if (retval) {
|
||||
filename_ = filename;
|
||||
} else {
|
||||
@ -146,11 +153,11 @@ bool ManagedTexture::LoadFromFile(const std::string &filename, ImageFileType typ
|
||||
return retval;
|
||||
}
|
||||
|
||||
ManagedTexture *CreateTextureFromFile(Draw::DrawContext *draw, const char *filename, ImageFileType type) {
|
||||
ManagedTexture *CreateTextureFromFile(Draw::DrawContext *draw, const char *filename, ImageFileType type, bool generateMips) {
|
||||
if (!draw)
|
||||
return nullptr;
|
||||
ManagedTexture *mtex = new ManagedTexture(draw);
|
||||
if (!mtex->LoadFromFile(filename, type)) {
|
||||
if (!mtex->LoadFromFile(filename, type, generateMips)) {
|
||||
delete mtex;
|
||||
return nullptr;
|
||||
}
|
||||
@ -158,10 +165,10 @@ ManagedTexture *CreateTextureFromFile(Draw::DrawContext *draw, const char *filen
|
||||
}
|
||||
|
||||
// TODO: Remove the code duplication between this and LoadFromFileData
|
||||
ManagedTexture *CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType type) {
|
||||
ManagedTexture *CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType type, bool generateMips) {
|
||||
if (!draw)
|
||||
return nullptr;
|
||||
ManagedTexture *mtex = new ManagedTexture(draw);
|
||||
mtex->LoadFromFileData(data, size, type);
|
||||
mtex->LoadFromFileData(data, size, type, generateMips);
|
||||
return mtex;
|
||||
}
|
@ -42,8 +42,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadFromFile(const std::string &filename, ImageFileType type = ImageFileType::DETECT);
|
||||
bool LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type = ImageFileType::DETECT);
|
||||
bool LoadFromFile(const std::string &filename, ImageFileType type = ImageFileType::DETECT, bool generateMips = false);
|
||||
bool LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type = ImageFileType::DETECT, bool generateMips = false);
|
||||
Draw::Texture *GetTexture() { return texture_; } // For immediate use, don't store.
|
||||
int Width() const { return texture_->Width(); }
|
||||
int Height() const { return texture_->Height(); }
|
||||
@ -54,6 +54,5 @@ private:
|
||||
std::string filename_; // Textures that are loaded from files can reload themselves automatically.
|
||||
};
|
||||
|
||||
// Common Thin3D function, uses CreateTexture
|
||||
ManagedTexture *CreateTextureFromFile(Draw::DrawContext *draw, const char *filename, ImageFileType fileType);
|
||||
ManagedTexture *CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType fileType);
|
||||
ManagedTexture *CreateTextureFromFile(Draw::DrawContext *draw, const char *filename, ImageFileType fileType, bool generateMips = false);
|
||||
ManagedTexture *CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType fileType, bool generateMips = false);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "base/logging.h"
|
||||
#include "zlib.h"
|
||||
#include "image/zim_load.h"
|
||||
#include "math/math_util.h"
|
||||
#include "file/vfs.h"
|
||||
|
||||
int ezuncompress(unsigned char* pDest, long* pnDestLen, const unsigned char* pSrc, long nSrcLen) {
|
||||
@ -46,14 +47,6 @@ int ezuncompress(unsigned char* pDest, long* pnDestLen, const unsigned char* pSr
|
||||
return nExtraChunks ? Z_BUF_ERROR : Z_OK;
|
||||
}
|
||||
|
||||
static unsigned int log2i(unsigned int val) {
|
||||
unsigned int ret = -1;
|
||||
while (val != 0) {
|
||||
val >>= 1; ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int *flags, uint8_t **image) {
|
||||
if (zim[0] != 'Z' || zim[1] != 'I' || zim[2] != 'M' || zim[3] != 'G') {
|
||||
ELOG("Not a ZIM file");
|
||||
|
@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// Some of the stuff in this file are snippets from all over the web, esp. dspmusic.org. I think it's all public domain.
|
||||
// In any case, very little of it is used anywhere at the moment.
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
@ -36,14 +39,19 @@ inline uint32_t RoundUpToPowerOf2(uint32_t v) {
|
||||
return v;
|
||||
}
|
||||
|
||||
inline uint32_t log2i(uint32_t val) {
|
||||
unsigned int ret = -1;
|
||||
while (val != 0) {
|
||||
val >>= 1; ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define PI 3.141592653589793f
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592653589793f
|
||||
#endif
|
||||
|
||||
// The stuff in this file is from all over the web, esp. dspmusic.org. I think it's all public domain.
|
||||
// In any case, very little of it is used anywhere at the moment.
|
||||
|
||||
// Calculate pseudo-random 32 bit number based on linear congruential method.
|
||||
void SetSeed(unsigned int seed);
|
||||
unsigned int GenerateRandomNumber();
|
||||
|
@ -299,6 +299,7 @@ enum FormatSupport {
|
||||
FMT_TEXTURE = 2,
|
||||
FMT_INPUTLAYOUT = 4,
|
||||
FMT_DEPTHSTENCIL = 8,
|
||||
FMT_AUTOGEN_MIPS = 16,
|
||||
};
|
||||
|
||||
enum InfoField {
|
||||
@ -552,6 +553,7 @@ struct TextureDesc {
|
||||
int height;
|
||||
int depth;
|
||||
int mipLevels;
|
||||
bool generateMips;
|
||||
std::vector<uint8_t *> initData;
|
||||
};
|
||||
|
||||
|
@ -669,6 +669,12 @@ Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool generateMips = desc.generateMips;
|
||||
if (desc.generateMips && !(GetDataFormatSupport(desc.format) & FMT_AUTOGEN_MIPS)) {
|
||||
// D3D11 does not support autogenerating mipmaps for this format.
|
||||
generateMips = false;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC descColor{};
|
||||
descColor.Width = desc.width;
|
||||
descColor.Height = desc.height;
|
||||
@ -678,12 +684,12 @@ Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) {
|
||||
descColor.SampleDesc.Count = 1;
|
||||
descColor.SampleDesc.Quality = 0;
|
||||
descColor.Usage = D3D11_USAGE_DEFAULT;
|
||||
descColor.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
descColor.BindFlags = generateMips ? (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) : D3D11_BIND_SHADER_RESOURCE;
|
||||
descColor.MiscFlags = generateMips ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
|
||||
descColor.CPUAccessFlags = 0;
|
||||
descColor.MiscFlags = 0;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA initData[12]{};
|
||||
if (desc.initData.size()) {
|
||||
if (desc.initData.size() && !generateMips) {
|
||||
int w = desc.width;
|
||||
int h = desc.height;
|
||||
for (int i = 0; i < (int)desc.initData.size(); i++) {
|
||||
@ -695,7 +701,7 @@ Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) {
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = device_->CreateTexture2D(&descColor, desc.initData.size() ? initData : nullptr, &tex->tex);
|
||||
HRESULT hr = device_->CreateTexture2D(&descColor, (desc.initData.size() && !generateMips) ? initData : nullptr, &tex->tex);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
delete tex;
|
||||
return nullptr;
|
||||
@ -705,6 +711,10 @@ Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) {
|
||||
delete tex;
|
||||
return nullptr;
|
||||
}
|
||||
if (generateMips && desc.initData.size() >= 1) {
|
||||
context_->UpdateSubresource(tex->tex, 0, nullptr, desc.initData[0], desc.width * (int)DataFormatSizeInBytes(desc.format), 0);
|
||||
context_->GenerateMips(tex->view);
|
||||
}
|
||||
return tex;
|
||||
}
|
||||
|
||||
@ -1062,6 +1072,8 @@ uint32_t D3D11DrawContext::GetDataFormatSupport(DataFormat fmt) const {
|
||||
support |= FMT_INPUTLAYOUT;
|
||||
if (giSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL)
|
||||
support |= FMT_DEPTHSTENCIL;
|
||||
if (giSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN)
|
||||
support |= FMT_AUTOGEN_MIPS;
|
||||
return support;
|
||||
}
|
||||
|
||||
|
@ -345,10 +345,12 @@ bool D3D9Texture::Create(const TextureDesc &desc) {
|
||||
pool = D3DPOOL_DEFAULT;
|
||||
usage = D3DUSAGE_DYNAMIC;
|
||||
}
|
||||
if (desc.generateMips)
|
||||
usage |= D3DUSAGE_AUTOGENMIPMAP;
|
||||
switch (type_) {
|
||||
case TextureType::LINEAR1D:
|
||||
case TextureType::LINEAR2D:
|
||||
hr = device_->CreateTexture(desc.width, desc.height, desc.mipLevels, usage, d3dfmt_, pool, &tex_, NULL);
|
||||
hr = device_->CreateTexture(desc.width, desc.height, desc.generateMips ? 0 : desc.mipLevels, usage, d3dfmt_, pool, &tex_, NULL);
|
||||
break;
|
||||
case TextureType::LINEAR3D:
|
||||
hr = device_->CreateVolumeTexture(desc.width, desc.height, desc.depth, desc.mipLevels, usage, d3dfmt_, pool, &volTex_, NULL);
|
||||
@ -363,7 +365,10 @@ bool D3D9Texture::Create(const TextureDesc &desc) {
|
||||
}
|
||||
|
||||
if (desc.initData.size()) {
|
||||
for (int i = 0; i < (int)desc.initData.size(); i++) {
|
||||
// In D3D9, after setting D3DUSAGE_AUTOGENMIPS, we can only access the top layer. The rest will be
|
||||
// automatically generated.
|
||||
int maxLevel = desc.generateMips ? 1 : (int)desc.initData.size();
|
||||
for (int i = 0; i < maxLevel; i++) {
|
||||
SetImageData(0, 0, 0, width_, height_, depth_, i, 0, desc.initData[i]);
|
||||
}
|
||||
}
|
||||
@ -1154,7 +1159,7 @@ DrawContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapt
|
||||
uint32_t D3D9Context::GetDataFormatSupport(DataFormat fmt) const {
|
||||
switch (fmt) {
|
||||
case DataFormat::B8G8R8A8_UNORM:
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE;
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_AUTOGEN_MIPS;
|
||||
|
||||
case DataFormat::R4G4B4A4_UNORM_PACK16:
|
||||
return 0;
|
||||
@ -1163,10 +1168,10 @@ uint32_t D3D9Context::GetDataFormatSupport(DataFormat fmt) const {
|
||||
case DataFormat::R5G6B5_UNORM_PACK16:
|
||||
case DataFormat::A1R5G5B5_UNORM_PACK16:
|
||||
case DataFormat::A4R4G4B4_UNORM_PACK16:
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE; // native support
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_AUTOGEN_MIPS; // native support
|
||||
|
||||
case DataFormat::R8G8B8A8_UNORM:
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_INPUTLAYOUT;
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_INPUTLAYOUT | FMT_AUTOGEN_MIPS;
|
||||
|
||||
case DataFormat::R32_FLOAT:
|
||||
case DataFormat::R32G32_FLOAT:
|
||||
|
@ -683,19 +683,19 @@ OpenGLTexture::OpenGLTexture(const TextureDesc &desc) {
|
||||
height_ = (height_ + 1) / 2;
|
||||
level++;
|
||||
}
|
||||
mipLevels_ = level;
|
||||
mipLevels_ = desc.generateMips ? desc.mipLevels : level;
|
||||
|
||||
#ifdef USING_GLES2
|
||||
if (gl_extensions.GLES3) {
|
||||
glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, level - 1);
|
||||
glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, mipLevels_ - 1);
|
||||
}
|
||||
#else
|
||||
glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, level - 1);
|
||||
glTexParameteri(target_, GL_TEXTURE_MAX_LEVEL, mipLevels_ - 1);
|
||||
#endif
|
||||
glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, level > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
||||
glTexParameteri(target_, GL_TEXTURE_MIN_FILTER, mipLevels_ > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
||||
glTexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
if ((int)desc.initData.size() < desc.mipLevels) {
|
||||
if ((int)desc.initData.size() < desc.mipLevels && desc.generateMips) {
|
||||
ILOG("Generating mipmaps");
|
||||
AutoGenMipmaps();
|
||||
}
|
||||
@ -1667,9 +1667,9 @@ void OpenGLContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) {
|
||||
uint32_t OpenGLContext::GetDataFormatSupport(DataFormat fmt) const {
|
||||
switch (fmt) {
|
||||
case DataFormat::B8G8R8A8_UNORM:
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE;
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_AUTOGEN_MIPS;
|
||||
case DataFormat::B4G4R4A4_UNORM_PACK16:
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE; // native support
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_AUTOGEN_MIPS; // native support
|
||||
case DataFormat::A4R4G4B4_UNORM_PACK16:
|
||||
#ifndef USING_GLES2
|
||||
// Can support this if _REV formats are supported.
|
||||
@ -1678,7 +1678,7 @@ uint32_t OpenGLContext::GetDataFormatSupport(DataFormat fmt) const {
|
||||
return 0;
|
||||
|
||||
case DataFormat::R8G8B8A8_UNORM:
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_INPUTLAYOUT;
|
||||
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_INPUTLAYOUT | FMT_AUTOGEN_MIPS;
|
||||
|
||||
case DataFormat::R32_FLOAT:
|
||||
case DataFormat::R32G32_FLOAT:
|
||||
|
Loading…
x
Reference in New Issue
Block a user