Break out image file management from DrawContext (thin3d)

This commit is contained in:
Henrik Rydgård 2016-12-27 22:26:49 +01:00
parent 4199eb3493
commit 6a7d3a3910
24 changed files with 275 additions and 229 deletions

View File

@ -187,7 +187,7 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
fbTex->SetImageData(0, 0, 0, srcwidth, srcheight, 1, 0, srcwidth * 4, (const uint8_t *)&fbTexBuffer[0]); fbTex->SetImageData(0, 0, 0, srcwidth, srcheight, 1, 0, srcwidth * 4, (const uint8_t *)&fbTexBuffer[0]);
u1 = 1.0f; u1 = 1.0f;
} }
fbTex->Finalize(0); fbTex->Finalize();
float x, y, w, h; float x, y, w, h;
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, dstwidth, dstheight, ROTATION_LOCKED_HORIZONTAL); CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, dstwidth, dstheight, ROTATION_LOCKED_HORIZONTAL);

View File

@ -40,6 +40,7 @@
#include "Core/Util/GameManager.h" #include "Core/Util/GameManager.h"
#include "Core/Config.h" #include "Core/Config.h"
#include "UI/GameInfoCache.h" #include "UI/GameInfoCache.h"
#include "UI/TextureUtil.h"
GameInfoCache *g_gameInfoCache; GameInfoCache *g_gameInfoCache;
@ -781,11 +782,11 @@ again:
return info; return info;
} }
void GameInfoCache::SetupTexture(GameInfo *info, std::string &textureData, Draw::DrawContext *thin3d, Draw::Texture *&tex, double &loadTime) { void GameInfoCache::SetupTexture(GameInfo *info, std::string &textureData, Draw::DrawContext *thin3d, ManagedTexture *&tex, double &loadTime) {
using namespace Draw; using namespace Draw;
if (textureData.size()) { if (textureData.size()) {
if (!tex) { if (!tex) {
tex = thin3d->CreateTextureFromFileData((const uint8_t *)textureData.data(), (int)textureData.size(), ImageFileType::DETECT); tex = CreateTextureFromFileData(thin3d, (const uint8_t *)textureData.data(), (int)textureData.size(), ImageFileType::DETECT);
if (tex) { if (tex) {
loadTime = time_now_d(); loadTime = time_now_d();
} }

View File

@ -24,6 +24,7 @@
#include "file/file_util.h" #include "file/file_util.h"
#include "Core/ELF/ParamSFO.h" #include "Core/ELF/ParamSFO.h"
#include "Core/Loaders.h" #include "Core/Loaders.h"
#include "UI/TextureUtil.h"
namespace Draw { namespace Draw {
class DrawContext; class DrawContext;
@ -142,11 +143,11 @@ public:
// Pre read the data, create a texture the next time (GL thread..) // Pre read the data, create a texture the next time (GL thread..)
std::string iconTextureData; std::string iconTextureData;
Draw::Texture *iconTexture; ManagedTexture *iconTexture;
std::string pic0TextureData; std::string pic0TextureData;
Draw::Texture *pic0Texture; ManagedTexture *pic0Texture;
std::string pic1TextureData; std::string pic1TextureData;
Draw::Texture *pic1Texture; ManagedTexture *pic1Texture;
std::string sndFileData; std::string sndFileData;
@ -202,7 +203,7 @@ public:
private: private:
void Init(); void Init();
void Shutdown(); void Shutdown();
void SetupTexture(GameInfo *info, std::string &textureData, Draw::DrawContext *thin3d, Draw::Texture *&tex, double &loadTime); void SetupTexture(GameInfo *info, std::string &textureData, Draw::DrawContext *thin3d, ManagedTexture *&tex, double &loadTime);
// Maps ISO path to info. // Maps ISO path to info.
std::map<std::string, GameInfo *> info_; std::map<std::string, GameInfo *> info_;

View File

@ -192,7 +192,7 @@ void GameScreen::update(InputState &input) {
if (tvTitle_) if (tvTitle_)
tvTitle_->SetText(info->GetTitle() + " (" + info->id + ")"); tvTitle_->SetText(info->GetTitle() + " (" + info->id + ")");
if (info->iconTexture && texvGameIcon_) { if (info->iconTexture && texvGameIcon_) {
texvGameIcon_->SetTexture(info->iconTexture); texvGameIcon_->SetTexture(info->iconTexture->GetTexture());
// Fade the icon with the background. // Fade the icon with the background.
double loadTime = info->timeIconWasLoaded; double loadTime = info->timeIconWasLoaded;
if (info->pic1Texture) { if (info->pic1Texture) {

View File

@ -179,7 +179,7 @@ void GameButton::Draw(UIContext &dc) {
using namespace UI; using namespace UI;
if (ginfo->iconTexture) { if (ginfo->iconTexture) {
texture = ginfo->iconTexture; texture = ginfo->iconTexture->GetTexture();
} }
int x = bounds_.x; int x = bounds_.x;
@ -1013,9 +1013,9 @@ bool MainScreen::DrawBackgroundFor(UIContext &dc, const std::string &gamePath, f
} }
if (ginfo->pic1Texture) { if (ginfo->pic1Texture) {
dc.GetThin3DContext()->BindTexture(0, ginfo->pic1Texture); dc.GetThin3DContext()->BindTexture(0, ginfo->pic1Texture->GetTexture());
} else if (ginfo->pic0Texture) { } else if (ginfo->pic0Texture) {
dc.GetThin3DContext()->BindTexture(0, ginfo->pic0Texture); dc.GetThin3DContext()->BindTexture(0, ginfo->pic0Texture->GetTexture());
} }
uint32_t color = whiteAlpha(ease(progress)) & 0xFFc0c0c0; uint32_t color = whiteAlpha(ease(progress)) & 0xFFc0c0c0;

View File

@ -110,11 +110,11 @@ void DrawGameBackground(UIContext &dc, const std::string &gamePath) {
bool hasPic = false; bool hasPic = false;
double loadTime; double loadTime;
if (ginfo->pic1Texture) { if (ginfo->pic1Texture) {
dc.GetThin3DContext()->BindTexture(0, ginfo->pic1Texture); dc.GetThin3DContext()->BindTexture(0, ginfo->pic1Texture->GetTexture());
loadTime = ginfo->timePic1WasLoaded; loadTime = ginfo->timePic1WasLoaded;
hasPic = true; hasPic = true;
} else if (ginfo->pic0Texture) { } else if (ginfo->pic0Texture) {
dc.GetThin3DContext()->BindTexture(0, ginfo->pic0Texture); dc.GetThin3DContext()->BindTexture(0, ginfo->pic0Texture->GetTexture());
loadTime = ginfo->timePic0WasLoaded; loadTime = ginfo->timePic0WasLoaded;
hasPic = true; hasPic = true;
} }

View File

@ -90,6 +90,7 @@
#include "UI/MiscScreens.h" #include "UI/MiscScreens.h"
#include "UI/TiltEventProcessor.h" #include "UI/TiltEventProcessor.h"
#include "UI/BackgroundAudio.h" #include "UI/BackgroundAudio.h"
#include "UI/TextureUtil.h"
#if !defined(MOBILE_DEVICE) #if !defined(MOBILE_DEVICE)
#include "Common/KeyMap.h" #include "Common/KeyMap.h"
@ -117,7 +118,7 @@ static UI::Theme ui_theme;
#include "android/android-ndk-profiler/prof.h" #include "android/android-ndk-profiler/prof.h"
#endif #endif
Draw::Texture *uiTexture; ManagedTexture *uiTexture;
ScreenManager *screenManager; ScreenManager *screenManager;
std::string config_filename; std::string config_filename;
@ -578,7 +579,7 @@ void NativeInitGraphics(GraphicsContext *graphicsContext) {
ui_theme.popupTitle.fgColor = 0xFF59BEE3; ui_theme.popupTitle.fgColor = 0xFF59BEE3;
#endif #endif
uiTexture = thin3d->CreateTextureFromFile("ui_atlas.zim", ImageFileType::ZIM); uiTexture = CreateTextureFromFile(thin3d, "ui_atlas.zim", ImageFileType::ZIM);
if (!uiTexture) { if (!uiTexture) {
PanicAlert("Failed to load ui_atlas.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory."); PanicAlert("Failed to load ui_atlas.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory.");
ELOG("Failed to load ui_atlas.zim"); ELOG("Failed to load ui_atlas.zim");
@ -618,7 +619,7 @@ void NativeInitGraphics(GraphicsContext *graphicsContext) {
ui_draw2d.Init(thin3d, texColorPipeline); ui_draw2d.Init(thin3d, texColorPipeline);
ui_draw2d_front.Init(thin3d, texColorPipeline); ui_draw2d_front.Init(thin3d, texColorPipeline);
uiContext->Init(thin3d, texColorPipeline, colorPipeline, uiTexture, &ui_draw2d, &ui_draw2d_front); uiContext->Init(thin3d, texColorPipeline, colorPipeline, &ui_draw2d, &ui_draw2d_front);
RasterStateDesc desc; RasterStateDesc desc;
desc.cull = CullMode::NONE; desc.cull = CullMode::NONE;
desc.frontFace = Facing::CCW; desc.frontFace = Facing::CCW;
@ -648,9 +649,8 @@ void NativeShutdownGraphics() {
delete g_gameInfoCache; delete g_gameInfoCache;
g_gameInfoCache = nullptr; g_gameInfoCache = nullptr;
if (uiTexture->Release()) { delete uiTexture;
uiTexture = nullptr; uiTexture = nullptr;
}
delete uiContext; delete uiContext;
uiContext = NULL; uiContext = NULL;
@ -737,6 +737,8 @@ void DrawDownloadsOverlay(UIContext &dc) {
void NativeRender(GraphicsContext *graphicsContext) { void NativeRender(GraphicsContext *graphicsContext) {
g_GameManager.Update(); g_GameManager.Update();
// If uitexture gets reloaded, make sure we use the latest one.
uiContext->FrameSetup(uiTexture->GetTexture());
float xres = dp_xres; float xres = dp_xres;
float yres = dp_yres; float yres = dp_yres;

View File

@ -69,7 +69,7 @@ void AsyncImageFileView::SetFilename(std::string filename) {
textureFailed_ = false; textureFailed_ = false;
filename_ = filename; filename_ = filename;
if (texture_) { if (texture_) {
texture_->Release(); delete texture_;
texture_ = nullptr; texture_ = nullptr;
} }
} }
@ -78,11 +78,11 @@ void AsyncImageFileView::SetFilename(std::string filename) {
void AsyncImageFileView::Draw(UIContext &dc) { void AsyncImageFileView::Draw(UIContext &dc) {
using namespace Draw; using namespace Draw;
if (!texture_ && !textureFailed_ && !filename_.empty()) { if (!texture_ && !textureFailed_ && !filename_.empty()) {
texture_ = dc.GetThin3DContext()->CreateTextureFromFile(filename_.c_str(), DETECT); texture_ = CreateTextureFromFile(dc.GetThin3DContext(), filename_.c_str(), DETECT);
if (!texture_) if (!texture_)
textureFailed_ = true; textureFailed_ = true;
else if (textureAutoGen_) else if (textureAutoGen_) // TODO: Iffy
texture_->AutoGenMipmaps(); texture_->GetTexture()->AutoGenMipmaps();
} }
if (HasFocus()) { if (HasFocus()) {
@ -92,7 +92,7 @@ void AsyncImageFileView::Draw(UIContext &dc) {
// TODO: involve sizemode // TODO: involve sizemode
if (texture_) { if (texture_) {
dc.Flush(); dc.Flush();
dc.GetThin3DContext()->BindTexture(0, texture_); dc.GetThin3DContext()->BindTexture(0, texture_->GetTexture());
dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, color_); dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, color_);
dc.Flush(); dc.Flush();
dc.RebindTexture(); dc.RebindTexture();

View File

@ -22,6 +22,7 @@
#include "ui/ui_screen.h" #include "ui/ui_screen.h"
#include "ui/viewgroup.h" #include "ui/viewgroup.h"
#include "UI/MiscScreens.h" #include "UI/MiscScreens.h"
#include "UI/TextureUtil.h"
class GamePauseScreen : public UIDialogScreenWithGameBackground { class GamePauseScreen : public UIDialogScreenWithGameBackground {
public: public:
@ -95,7 +96,7 @@ private:
uint32_t color_; uint32_t color_;
UI::ImageSizeMode sizeMode_; UI::ImageSizeMode sizeMode_;
Draw::Texture *texture_; ManagedTexture *texture_;
bool textureFailed_; bool textureFailed_;
bool textureAutoGen_; bool textureAutoGen_;
float fixedSizeW_; float fixedSizeW_;

View File

@ -80,7 +80,7 @@ public:
std::string savedata_title = ginfo->paramSFO.GetValueString("SAVEDATA_TITLE"); std::string savedata_title = ginfo->paramSFO.GetValueString("SAVEDATA_TITLE");
if (ginfo->iconTexture) { if (ginfo->iconTexture) {
toprow->Add(new Thin3DTextureView(ginfo->iconTexture, IS_FIXED, new LinearLayoutParams(Margins(10, 5)))); toprow->Add(new Thin3DTextureView(ginfo->iconTexture->GetTexture(), IS_FIXED, new LinearLayoutParams(Margins(10, 5))));
} }
LinearLayout *topright = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1.0f)); LinearLayout *topright = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1.0f));
topright->SetSpacing(1.0f); topright->SetSpacing(1.0f);
@ -159,7 +159,7 @@ void SavedataButton::Draw(UIContext &dc) {
using namespace UI; using namespace UI;
if (ginfo->iconTexture) { if (ginfo->iconTexture) {
texture = ginfo->iconTexture; texture = ginfo->iconTexture->GetTexture();
} }
int x = bounds_.x; int x = bounds_.x;

View File

@ -33,6 +33,7 @@
#include "Core/Util/GameManager.h" #include "Core/Util/GameManager.h"
#include "UI/EmuScreen.h" #include "UI/EmuScreen.h"
#include "UI/Store.h" #include "UI/Store.h"
#include "UI/TextureUtil.h"
const std::string storeBaseUrl = "http://store.ppsspp.org/"; const std::string storeBaseUrl = "http://store.ppsspp.org/";
@ -84,7 +85,7 @@ private:
std::shared_ptr<http::Download> download_; std::shared_ptr<http::Download> download_;
std::string textureData_; std::string textureData_;
Draw::Texture *texture_; ManagedTexture *texture_;
bool textureFailed_; bool textureFailed_;
float fixedSizeW_; float fixedSizeW_;
float fixedSizeH_; float fixedSizeH_;
@ -116,7 +117,7 @@ void HttpImageFileView::SetFilename(std::string filename) {
textureFailed_ = false; textureFailed_ = false;
path_ = filename; path_ = filename;
if (texture_) { if (texture_) {
texture_->Release(); delete texture_;
texture_ = nullptr; texture_ = nullptr;
} }
} }
@ -142,7 +143,7 @@ void HttpImageFileView::Draw(UIContext &dc) {
} }
if (!textureData_.empty()) { if (!textureData_.empty()) {
texture_ = dc.GetThin3DContext()->CreateTextureFromFileData((const uint8_t *)(textureData_.data()), (int)textureData_.size(), DETECT); texture_ = CreateTextureFromFileData(dc.GetThin3DContext(), (const uint8_t *)(textureData_.data()), (int)textureData_.size(), DETECT);
if (!texture_) if (!texture_)
textureFailed_ = true; textureFailed_ = true;
textureData_.clear(); textureData_.clear();
@ -156,7 +157,7 @@ void HttpImageFileView::Draw(UIContext &dc) {
// TODO: involve sizemode // TODO: involve sizemode
if (texture_) { if (texture_) {
dc.Flush(); dc.Flush();
dc.GetThin3DContext()->BindTexture(0, texture_); dc.GetThin3DContext()->BindTexture(0, texture_->GetTexture());
dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, color_); dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, color_);
dc.Flush(); dc.Flush();
dc.RebindTexture(); dc.RebindTexture();

142
UI/TextureUtil.cpp Normal file
View File

@ -0,0 +1,142 @@
#include "thin3d/thin3d.h"
#include "image/zim_load.h"
#include "image/png_load.h"
#include "file/vfs.h"
#include "ext/jpge/jpgd.h"
#include "UI/TextureUtil.h"
static Draw::DataFormat ZimToT3DFormat(int zim) {
switch (zim) {
case ZIM_ETC1: return Draw::DataFormat::ETC1;
case ZIM_RGBA8888: return Draw::DataFormat::R8G8B8A8_UNORM;
case ZIM_LUMINANCE: return Draw::DataFormat::R8_UNORM;
default: return Draw::DataFormat::R8G8B8A8_UNORM;
}
}
static ImageFileType DetectImageFileType(const uint8_t *data, size_t size) {
if (!memcmp(data, "ZIMG", 4)) {
return ZIM;
}
else if (!memcmp(data, "\x89\x50\x4E\x47", 4)) {
return PNG;
}
else if (!memcmp(data, "\xff\xd8\xff\xe0", 4)) {
return JPEG;
}
else {
return TYPE_UNKNOWN;
}
}
static bool LoadTextureLevels(const uint8_t *data, size_t size, ImageFileType type, int width[16], int height[16], int *num_levels, Draw::DataFormat *fmt, uint8_t *image[16], int *zim_flags) {
if (type == DETECT) {
type = DetectImageFileType(data, size);
}
if (type == TYPE_UNKNOWN) {
ELOG("File has unknown format");
return false;
}
*num_levels = 0;
*zim_flags = 0;
switch (type) {
case ZIM:
{
*num_levels = LoadZIMPtr((const uint8_t *)data, size, width, height, zim_flags, image);
*fmt = ZimToT3DFormat(*zim_flags & ZIM_FORMAT_MASK);
}
break;
case PNG:
if (1 == pngLoadPtr((const unsigned char *)data, size, &width[0], &height[0], &image[0], false)) {
*num_levels = 1;
*fmt = Draw::DataFormat::R8G8B8A8_UNORM;
}
break;
case JPEG:
{
int actual_components = 0;
unsigned char *jpegBuf = jpgd::decompress_jpeg_image_from_memory(data, (int)size, &width[0], &height[0], &actual_components, 4);
if (jpegBuf) {
*num_levels = 1;
*fmt = Draw::DataFormat::R8G8B8A8_UNORM;
image[0] = (uint8_t *)jpegBuf;
}
}
break;
default:
ELOG("Unknown image format");
return false;
}
return *num_levels > 0;
}
bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type) {
int width[16], height[16];
uint8_t *image[16] = { nullptr };
int num_levels;
int zim_flags;
Draw::DataFormat fmt;
if (!LoadTextureLevels(data, dataSize, type, width, height, &num_levels, &fmt, image, &zim_flags)) {
return false;
}
if (num_levels < 0 || num_levels >= 16) {
ELOG("Invalid num_levels: %d. Falling back to one. Image: %dx%d", num_levels, width[0], height[0]);
num_levels = 1;
}
texture_->Create(Draw::LINEAR2D, fmt, width[0], height[0], 1, num_levels);
for (int i = 0; i < num_levels; i++) {
if (image[i]) {
texture_->SetImageData(0, 0, 0, width[i], height[i], 1, i, width[i] * 4, image[i]);
free(image[i]);
}
else {
ELOG("Missing image level %i", i);
}
}
texture_->Finalize();
return true;
}
bool ManagedTexture::LoadFromFile(const std::string &filename, ImageFileType type) {
filename_ = "";
size_t fileSize;
uint8_t *buffer = VFSReadFile(filename.c_str(), &fileSize);
if (!buffer) {
return false;
}
bool retval = LoadFromFileData(buffer, fileSize, type);
if (retval) {
filename_ = filename;
}
else {
ELOG("%s: Failed to load texture %s", __FUNCTION__, filename.c_str());
}
delete[] buffer;
return retval;
}
ManagedTexture *CreateTextureFromFile(Draw::DrawContext *draw, const char *filename, ImageFileType type) {
ManagedTexture *mtex = new ManagedTexture(draw);
if (!mtex->LoadFromFile(filename, type)) {
delete mtex;
return nullptr;
}
return mtex;
}
// TODO: Remove the code duplication between this and LoadFromFileData
ManagedTexture *CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType type) {
ManagedTexture *mtex = new ManagedTexture(draw);
mtex->LoadFromFileData(data, size, type);
return mtex;
}

54
UI/TextureUtil.h Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include "thin3d/thin3d.h"
#include "gfx/gl_lost_manager.h"
enum ImageFileType {
PNG,
JPEG,
ZIM,
DETECT,
TYPE_UNKNOWN,
};
class ManagedTexture : public GfxResourceHolder {
public:
ManagedTexture(Draw::DrawContext *draw) : draw_(draw) {
register_gl_resource_holder(this);
texture_ = draw->CreateTexture();
}
~ManagedTexture() {
unregister_gl_resource_holder(this);
}
void GLLost() override {
delete texture_;
}
void GLRestore() override {
if (!filename_.empty()) {
if (LoadFromFile(filename_.c_str())) {
ILOG("Reloaded lost texture %s", filename_.c_str());
}
else {
ELOG("Failed to reload lost texture %s", filename_.c_str());
}
}
else {
WLOG("Texture cannot be restored - has no filename");
}
}
bool LoadFromFile(const std::string &filename, ImageFileType type = ImageFileType::DETECT);
bool LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type = ImageFileType::DETECT);
Draw::Texture *GetTexture() { return texture_; } // For immediate use, don't store.
int Width() const { return texture_->Width(); }
int Height() const { return texture_->Height(); }
private:
Draw::Texture *texture_;
Draw::DrawContext *draw_;
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);

View File

@ -41,6 +41,7 @@
<ClCompile Include="ReportScreen.cpp" /> <ClCompile Include="ReportScreen.cpp" />
<ClCompile Include="SavedataScreen.cpp" /> <ClCompile Include="SavedataScreen.cpp" />
<ClCompile Include="Store.cpp" /> <ClCompile Include="Store.cpp" />
<ClCompile Include="TextureUtil.cpp" />
<ClCompile Include="TiltAnalogSettingsScreen.cpp" /> <ClCompile Include="TiltAnalogSettingsScreen.cpp" />
<ClCompile Include="TiltEventProcessor.cpp" /> <ClCompile Include="TiltEventProcessor.cpp" />
<ClCompile Include="TouchControlLayoutScreen.cpp" /> <ClCompile Include="TouchControlLayoutScreen.cpp" />
@ -71,6 +72,7 @@
<ClInclude Include="ReportScreen.h" /> <ClInclude Include="ReportScreen.h" />
<ClInclude Include="SavedataScreen.h" /> <ClInclude Include="SavedataScreen.h" />
<ClInclude Include="Store.h" /> <ClInclude Include="Store.h" />
<ClInclude Include="TextureUtil.h" />
<ClInclude Include="TiltAnalogSettingsScreen.h" /> <ClInclude Include="TiltAnalogSettingsScreen.h" />
<ClInclude Include="TiltEventProcessor.h" /> <ClInclude Include="TiltEventProcessor.h" />
<ClInclude Include="TouchControlLayoutScreen.h" /> <ClInclude Include="TouchControlLayoutScreen.h" />
@ -125,7 +127,6 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile> <ClCompile>
<PrecompiledHeader> <PrecompiledHeader>

View File

@ -69,6 +69,7 @@
<ClCompile Include="RemoteISOScreen.cpp"> <ClCompile Include="RemoteISOScreen.cpp">
<Filter>Screens</Filter> <Filter>Screens</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="TextureUtil.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="GameInfoCache.h" /> <ClInclude Include="GameInfoCache.h" />
@ -139,10 +140,11 @@
<ClInclude Include="RemoteISOScreen.h"> <ClInclude Include="RemoteISOScreen.h">
<Filter>Screens</Filter> <Filter>Screens</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="TextureUtil.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="Screens"> <Filter Include="Screens">
<UniqueIdentifier>{faee5dce-633b-4ba6-b19d-ea70ee3c1c38}</UniqueIdentifier> <UniqueIdentifier>{faee5dce-633b-4ba6-b19d-ea70ee3c1c38}</UniqueIdentifier>
</Filter> </Filter>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -290,7 +290,7 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float
} }
} }
entry->texture->SetImageData(0, 0, 0, entry->bmWidth, entry->bmHeight, 1, 0, entry->bmWidth * 2, (const uint8_t *)bitmapData); entry->texture->SetImageData(0, 0, 0, entry->bmWidth, entry->bmHeight, 1, 0, entry->bmWidth * 2, (const uint8_t *)bitmapData);
entry->texture->Finalize(0); entry->texture->Finalize();
delete [] bitmapData; delete [] bitmapData;
cache_[entryHash] = std::unique_ptr<TextStringEntry>(entry); cache_[entryHash] = std::unique_ptr<TextStringEntry>(entry);

View File

@ -2,10 +2,6 @@
#include <thin3d/thin3d.h> #include <thin3d/thin3d.h>
#include "base/logging.h" #include "base/logging.h"
#include "image/zim_load.h"
#include "image/png_load.h"
#include "file/vfs.h"
#include "ext/jpge/jpgd.h"
namespace Draw { namespace Draw {
@ -211,151 +207,4 @@ DrawContext::~DrawContext() {
} }
} }
static DataFormat ZimToT3DFormat(int zim) {
switch (zim) {
case ZIM_ETC1: return DataFormat::ETC1;
case ZIM_RGBA8888: return DataFormat::R8G8B8A8_UNORM;
case ZIM_LUMINANCE: return DataFormat::R8_UNORM;
default: return DataFormat::R8G8B8A8_UNORM;
}
}
static ImageFileType DetectImageFileType(const uint8_t *data, size_t size) {
if (!memcmp(data, "ZIMG", 4)) {
return ZIM;
} else if (!memcmp(data, "\x89\x50\x4E\x47", 4)) {
return PNG;
} else if (!memcmp(data, "\xff\xd8\xff\xe0", 4)) {
return JPEG;
} else {
return TYPE_UNKNOWN;
}
}
static bool LoadTextureLevels(const uint8_t *data, size_t size, ImageFileType type, int width[16], int height[16], int *num_levels, DataFormat *fmt, uint8_t *image[16], int *zim_flags) {
if (type == DETECT) {
type = DetectImageFileType(data, size);
}
if (type == TYPE_UNKNOWN) {
ELOG("File has unknown format");
return false;
}
*num_levels = 0;
*zim_flags = 0;
switch (type) {
case ZIM:
{
*num_levels = LoadZIMPtr((const uint8_t *)data, size, width, height, zim_flags, image);
*fmt = ZimToT3DFormat(*zim_flags & ZIM_FORMAT_MASK);
}
break;
case PNG:
if (1 == pngLoadPtr((const unsigned char *)data, size, &width[0], &height[0], &image[0], false)) {
*num_levels = 1;
*fmt = DataFormat::R8G8B8A8_UNORM;
}
break;
case JPEG:
{
int actual_components = 0;
unsigned char *jpegBuf = jpgd::decompress_jpeg_image_from_memory(data, (int)size, &width[0], &height[0], &actual_components, 4);
if (jpegBuf) {
*num_levels = 1;
*fmt = DataFormat::R8G8B8A8_UNORM;
image[0] = (uint8_t *)jpegBuf;
}
}
break;
default:
ELOG("Unknown image format");
return false;
}
return *num_levels > 0;
}
bool Texture::LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type) {
int width[16], height[16];
uint8_t *image[16] = { nullptr };
int num_levels;
int zim_flags;
DataFormat fmt;
if (!LoadTextureLevels(data, dataSize, type, width, height, &num_levels, &fmt, image, &zim_flags)) {
return false;
}
if (num_levels < 0 || num_levels >= 16) {
ELOG("Invalid num_levels: %d. Falling back to one. Image: %dx%d", num_levels, width[0], height[0]);
num_levels = 1;
}
Create(LINEAR2D, fmt, width[0], height[0], 1, num_levels);
for (int i = 0; i < num_levels; i++) {
if (image[i]) {
SetImageData(0, 0, 0, width[i], height[i], 1, i, width[i] * 4, image[i]);
free(image[i]);
} else {
ELOG("Missing image level %i", i);
}
}
Finalize(zim_flags);
return true;
}
bool Texture::LoadFromFile(const std::string &filename, ImageFileType type) {
filename_ = "";
size_t fileSize;
uint8_t *buffer = VFSReadFile(filename.c_str(), &fileSize);
if (!buffer) {
return false;
}
bool retval = LoadFromFileData(buffer, fileSize, type);
if (retval) {
filename_ = filename;
} else {
ELOG("%s: Failed to load texture %s", __FUNCTION__, filename.c_str());
}
delete[] buffer;
return retval;
}
Texture *DrawContext::CreateTextureFromFile(const char *filename, ImageFileType type) {
Texture *tex = CreateTexture();
if (!tex->LoadFromFile(filename, type)) {
tex->Release();
return NULL;
}
return tex;
}
// TODO: Remove the code duplication between this and LoadFromFileData
Texture *DrawContext::CreateTextureFromFileData(const uint8_t *data, int size, ImageFileType type) {
int width[16], height[16];
int num_levels = 0;
int zim_flags = 0;
DataFormat fmt;
uint8_t *image[16] = { nullptr };
if (!LoadTextureLevels(data, size, type, width, height, &num_levels, &fmt, image, &zim_flags)) {
return NULL;
}
Texture *tex = CreateTexture(LINEAR2D, fmt, width[0], height[0], 1, num_levels);
for (int i = 0; i < num_levels; i++) {
tex->SetImageData(0, 0, 0, width[i], height[i], 1, i, width[i] * 4, image[i]);
free(image[i]);
}
tex->Finalize(zim_flags);
return tex;
}
} // namespace Draw } // namespace Draw

View File

@ -281,14 +281,6 @@ enum class ShaderLanguage {
METAL_BYTECODE = 1024, METAL_BYTECODE = 1024,
}; };
enum ImageFileType {
PNG,
JPEG,
ZIM,
DETECT,
TYPE_UNKNOWN,
};
enum InfoField { enum InfoField {
APINAME, APINAME,
APIVERSION, APIVERSION,
@ -340,19 +332,15 @@ public:
class Texture : public RefCountedObject { class Texture : public RefCountedObject {
public: public:
bool LoadFromFile(const std::string &filename, ImageFileType type = ImageFileType::DETECT);
bool LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type = ImageFileType::DETECT);
virtual bool Create(TextureType type, DataFormat format, int width, int height, int depth, int mipLevels) = 0; virtual bool Create(TextureType type, DataFormat format, int width, int height, int depth, int mipLevels) = 0;
virtual void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) = 0; virtual void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) = 0;
virtual void AutoGenMipmaps() = 0; virtual void AutoGenMipmaps() = 0;
virtual void Finalize(int zim_flags) = 0; // TODO: Tidy up virtual void Finalize() = 0; // TODO: Tidy up
int Width() { return width_; } int Width() { return width_; }
int Height() { return height_; } int Height() { return height_; }
int Depth() { return depth_; } int Depth() { return depth_; }
protected: protected:
std::string filename_; // Textures that are loaded from files can reload themselves automatically.
int width_, height_, depth_; int width_, height_, depth_;
}; };
@ -497,10 +485,6 @@ public:
// virtual ComputePipeline CreateComputePipeline(const ComputePipelineDesc &desc) = 0 // virtual ComputePipeline CreateComputePipeline(const ComputePipelineDesc &desc) = 0
virtual InputLayout *CreateInputLayout(const InputLayoutDesc &desc) = 0; virtual InputLayout *CreateInputLayout(const InputLayoutDesc &desc) = 0;
// Common Thin3D function, uses CreateTexture
Texture *CreateTextureFromFile(const char *filename, ImageFileType fileType);
Texture *CreateTextureFromFileData(const uint8_t *data, int size, ImageFileType fileType);
// Note that these DO NOT AddRef so you must not ->Release presets unless you manually AddRef them. // Note that these DO NOT AddRef so you must not ->Release presets unless you manually AddRef them.
ShaderModule *GetVshaderPreset(VertexShaderPreset preset) { return fsPresets_[preset]; } ShaderModule *GetVshaderPreset(VertexShaderPreset preset) { return fsPresets_[preset]; }
ShaderModule *GetFshaderPreset(FragmentShaderPreset preset) { return vsPresets_[preset]; } ShaderModule *GetFshaderPreset(FragmentShaderPreset preset) { return vsPresets_[preset]; }

View File

@ -6,6 +6,10 @@ namespace Draw {
#if 0 #if 0
// A problem is that we can't get the D3Dcompiler.dll without using a later SDK than 7.1, which was the last that
// supported XP. A possible solution might be here:
// https://tedwvc.wordpress.com/2014/01/01/how-to-target-xp-with-vc2012-or-vc2013-and-continue-to-use-the-windows-8-x-sdk/
class D3D11Pipeline; class D3D11Pipeline;
class D3D11DrawContext : public DrawContext { class D3D11DrawContext : public DrawContext {
@ -308,7 +312,7 @@ public:
std::vector<uint8_t> byteCode_; std::vector<uint8_t> byteCode_;
}; };
ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize) { ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize) {
// ... // ...
return nullptr; return nullptr;
@ -371,6 +375,22 @@ void D3D11DrawContext::ApplyCurrentState() {
} }
} }
class D3D11Buffer : public Buffer {
public:
ID3D11Buffer *buf;
virtual void SetData(const uint8_t *data, size_t size) override {
}
virtual void SubData(const uint8_t *data, size_t offset, size_t size) override {
}
};
Buffer *D3D11DrawContext::CreateBuffer(size_t size, uint32_t usageFlags) {
D3D11Buffer *b = new D3D11Buffer();
}
void D3D11DrawContext::Draw(Buffer *vdata, int vertexCount, int offset) { void D3D11DrawContext::Draw(Buffer *vdata, int vertexCount, int offset) {
ApplyCurrentState(); ApplyCurrentState();
} }

View File

@ -359,7 +359,7 @@ public:
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override; void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override;
void AutoGenMipmaps() override {} void AutoGenMipmaps() override {}
void SetToSampler(LPDIRECT3DDEVICE9 device, int sampler); void SetToSampler(LPDIRECT3DDEVICE9 device, int sampler);
void Finalize(int zim_flags) override {} void Finalize() override {}
private: private:
LPDIRECT3DDEVICE9 device_; LPDIRECT3DDEVICE9 device_;

View File

@ -4,7 +4,6 @@
#include <map> #include <map>
#include "base/logging.h" #include "base/logging.h"
#include "image/zim_load.h"
#include "math/dataconv.h" #include "math/dataconv.h"
#include "math/lin/matrix4x4.h" #include "math/lin/matrix4x4.h"
#include "thin3d/thin3d.h" #include "thin3d/thin3d.h"
@ -542,7 +541,7 @@ public:
} }
void SetViewports(int count, Viewport *viewports) override { void SetViewports(int count, Viewport *viewports) override {
// TODO: Add support for multiple viewports. // TODO: Use glViewportArrayv.
glViewport(viewports[0].TopLeftX, viewports[0].TopLeftY, viewports[0].Width, viewports[0].Height); glViewport(viewports[0].TopLeftX, viewports[0].TopLeftY, viewports[0].Width, viewports[0].Height);
#if defined(USING_GLES2) #if defined(USING_GLES2)
glDepthRangef(viewports[0].MinDepth, viewports[0].MaxDepth); glDepthRangef(viewports[0].MinDepth, viewports[0].MaxDepth);
@ -702,20 +701,9 @@ public:
} }
void GLRestore() override { void GLRestore() override {
if (!filename_.empty()) {
if (LoadFromFile(filename_.c_str())) {
ILOG("Reloaded lost texture %s", filename_.c_str());
} else {
ELOG("Failed to reload lost texture %s", filename_.c_str());
tex_ = 0;
}
} else {
WLOG("Texture %p cannot be restored - has no filename", this);
tex_ = 0;
}
} }
void Finalize(int zim_flags) override; void Finalize() override;
private: private:
GLuint tex_; GLuint tex_;
@ -784,11 +772,10 @@ bool isPowerOf2(int n) {
return n == 1 || (n & (n - 1)) == 0; return n == 1 || (n & (n - 1)) == 0;
} }
void Thin3DGLTexture::Finalize(int zim_flags) { void Thin3DGLTexture::Finalize() {
canWrap_ = (zim_flags & ZIM_CLAMP) || !isPowerOf2(width_) || !isPowerOf2(height_); canWrap_ = !isPowerOf2(width_) || !isPowerOf2(height_);
} }
OpenGLInputLayout::~OpenGLInputLayout() { OpenGLInputLayout::~OpenGLInputLayout() {
if (id_) { if (id_) {
glDeleteVertexArrays(1, &id_); glDeleteVertexArrays(1, &id_);

View File

@ -588,7 +588,7 @@ public:
} }
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override; void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override;
void Finalize(int zim_flags) override; void Finalize() override {}
void AutoGenMipmaps() override {} void AutoGenMipmaps() override {}
VkImageView GetImageView() { return vkTex_->GetImageView(); } VkImageView GetImageView() { return vkTex_->GetImageView(); }
@ -965,10 +965,6 @@ void VKTexture::SetImageData(int x, int y, int z, int width, int height, int dep
vkTex_->Unlock(); vkTex_->Unlock();
} }
void VKTexture::Finalize(int zim_flags) {
// TODO
}
inline void CopySide(VkStencilOpState &dest, const StencilSide &src) { inline void CopySide(VkStencilOpState &dest, const StencilSide &src) {
dest.compareMask = src.compareMask; dest.compareMask = src.compareMask;
dest.reference = src.reference; dest.reference = src.reference;

View File

@ -18,13 +18,12 @@ UIContext::~UIContext() {
delete textDrawer_; delete textDrawer_;
} }
void UIContext::Init(Draw::DrawContext *thin3d, Draw::Pipeline *uipipe, Draw::Pipeline *uipipenotex, Draw::Texture *uitexture, DrawBuffer *uidrawbuffer, DrawBuffer *uidrawbufferTop) { void UIContext::Init(Draw::DrawContext *thin3d, Draw::Pipeline *uipipe, Draw::Pipeline *uipipenotex, DrawBuffer *uidrawbuffer, DrawBuffer *uidrawbufferTop) {
using namespace Draw; using namespace Draw;
thin3d_ = thin3d; thin3d_ = thin3d;
sampler_ = thin3d_->CreateSamplerState({ TextureFilter::LINEAR, TextureFilter::LINEAR, TextureFilter::LINEAR }); sampler_ = thin3d_->CreateSamplerState({ TextureFilter::LINEAR, TextureFilter::LINEAR, TextureFilter::LINEAR });
ui_pipeline_ = uipipe; ui_pipeline_ = uipipe;
ui_pipeline_notex_ = uipipenotex; ui_pipeline_notex_ = uipipenotex;
uitexture_ = uitexture;
uidrawbuffer_ = uidrawbuffer; uidrawbuffer_ = uidrawbuffer;
uidrawbufferTop_ = uidrawbufferTop; uidrawbufferTop_ = uidrawbufferTop;
#if defined(_WIN32) || defined(USING_QT_UI) #if defined(_WIN32) || defined(USING_QT_UI)
@ -34,6 +33,10 @@ void UIContext::Init(Draw::DrawContext *thin3d, Draw::Pipeline *uipipe, Draw::Pi
#endif #endif
} }
void UIContext::FrameSetup(Draw::Texture *uiTexture) {
uitexture_ = uiTexture;
}
void UIContext::Begin() { void UIContext::Begin() {
thin3d_->BindSamplerStates(0, 1, &sampler_); thin3d_->BindSamplerStates(0, 1, &sampler_);
thin3d_->BindTexture(0, uitexture_); thin3d_->BindTexture(0, uitexture_);

View File

@ -36,7 +36,9 @@ public:
UIContext(); UIContext();
~UIContext(); ~UIContext();
void Init(Draw::DrawContext *thin3d, Draw::Pipeline *uipipe, Draw::Pipeline *uipipenotex, Draw::Texture *uitexture, DrawBuffer *uidrawbuffer, DrawBuffer *uidrawbufferTop); void Init(Draw::DrawContext *thin3d, Draw::Pipeline *uipipe, Draw::Pipeline *uipipenotex, DrawBuffer *uidrawbuffer, DrawBuffer *uidrawbufferTop);
void FrameSetup(Draw::Texture *uiTexture);
void Begin(); void Begin();
void BeginNoTex(); void BeginNoTex();