From 6a7d3a3910633e703178be36a3f07360fe550a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 27 Dec 2016 22:26:49 +0100 Subject: [PATCH] Break out image file management from DrawContext (thin3d) --- GPU/Software/SoftGpu.cpp | 2 +- UI/GameInfoCache.cpp | 5 +- UI/GameInfoCache.h | 9 +- UI/GameScreen.cpp | 2 +- UI/MainScreen.cpp | 6 +- UI/MiscScreens.cpp | 4 +- UI/NativeApp.cpp | 14 +-- UI/PauseScreen.cpp | 10 +- UI/PauseScreen.h | 3 +- UI/SavedataScreen.cpp | 4 +- UI/Store.cpp | 9 +- UI/TextureUtil.cpp | 142 ++++++++++++++++++++++++++ UI/TextureUtil.h | 54 ++++++++++ UI/UI.vcxproj | 3 +- UI/UI.vcxproj.filters | 4 +- ext/native/gfx_es2/draw_text.cpp | 2 +- ext/native/thin3d/thin3d.cpp | 151 ---------------------------- ext/native/thin3d/thin3d.h | 18 +--- ext/native/thin3d/thin3d_d3d11.cpp | 22 +++- ext/native/thin3d/thin3d_d3d9.cpp | 2 +- ext/native/thin3d/thin3d_gl.cpp | 21 +--- ext/native/thin3d/thin3d_vulkan.cpp | 6 +- ext/native/ui/ui_context.cpp | 7 +- ext/native/ui/ui_context.h | 4 +- 24 files changed, 275 insertions(+), 229 deletions(-) create mode 100644 UI/TextureUtil.cpp create mode 100644 UI/TextureUtil.h diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 2ee1773785..1240eb60c9 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -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]); u1 = 1.0f; } - fbTex->Finalize(0); + fbTex->Finalize(); float x, y, w, h; CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, dstwidth, dstheight, ROTATION_LOCKED_HORIZONTAL); diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 99a175a96e..b041211099 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -40,6 +40,7 @@ #include "Core/Util/GameManager.h" #include "Core/Config.h" #include "UI/GameInfoCache.h" +#include "UI/TextureUtil.h" GameInfoCache *g_gameInfoCache; @@ -781,11 +782,11 @@ again: 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; if (textureData.size()) { 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) { loadTime = time_now_d(); } diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index 57d1b3dd75..f0d1d073e2 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -24,6 +24,7 @@ #include "file/file_util.h" #include "Core/ELF/ParamSFO.h" #include "Core/Loaders.h" +#include "UI/TextureUtil.h" namespace Draw { class DrawContext; @@ -142,11 +143,11 @@ public: // Pre read the data, create a texture the next time (GL thread..) std::string iconTextureData; - Draw::Texture *iconTexture; + ManagedTexture *iconTexture; std::string pic0TextureData; - Draw::Texture *pic0Texture; + ManagedTexture *pic0Texture; std::string pic1TextureData; - Draw::Texture *pic1Texture; + ManagedTexture *pic1Texture; std::string sndFileData; @@ -202,7 +203,7 @@ public: private: void Init(); 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. std::map info_; diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index 032888a2c7..9eb72ce0fd 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -192,7 +192,7 @@ void GameScreen::update(InputState &input) { if (tvTitle_) tvTitle_->SetText(info->GetTitle() + " (" + info->id + ")"); if (info->iconTexture && texvGameIcon_) { - texvGameIcon_->SetTexture(info->iconTexture); + texvGameIcon_->SetTexture(info->iconTexture->GetTexture()); // Fade the icon with the background. double loadTime = info->timeIconWasLoaded; if (info->pic1Texture) { diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 5a46f6c9ae..2bbd840464 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -179,7 +179,7 @@ void GameButton::Draw(UIContext &dc) { using namespace UI; if (ginfo->iconTexture) { - texture = ginfo->iconTexture; + texture = ginfo->iconTexture->GetTexture(); } int x = bounds_.x; @@ -1013,9 +1013,9 @@ bool MainScreen::DrawBackgroundFor(UIContext &dc, const std::string &gamePath, f } if (ginfo->pic1Texture) { - dc.GetThin3DContext()->BindTexture(0, ginfo->pic1Texture); + dc.GetThin3DContext()->BindTexture(0, ginfo->pic1Texture->GetTexture()); } else if (ginfo->pic0Texture) { - dc.GetThin3DContext()->BindTexture(0, ginfo->pic0Texture); + dc.GetThin3DContext()->BindTexture(0, ginfo->pic0Texture->GetTexture()); } uint32_t color = whiteAlpha(ease(progress)) & 0xFFc0c0c0; diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index c71efc5b7c..4242c69b25 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -110,11 +110,11 @@ void DrawGameBackground(UIContext &dc, const std::string &gamePath) { bool hasPic = false; double loadTime; if (ginfo->pic1Texture) { - dc.GetThin3DContext()->BindTexture(0, ginfo->pic1Texture); + dc.GetThin3DContext()->BindTexture(0, ginfo->pic1Texture->GetTexture()); loadTime = ginfo->timePic1WasLoaded; hasPic = true; } else if (ginfo->pic0Texture) { - dc.GetThin3DContext()->BindTexture(0, ginfo->pic0Texture); + dc.GetThin3DContext()->BindTexture(0, ginfo->pic0Texture->GetTexture()); loadTime = ginfo->timePic0WasLoaded; hasPic = true; } diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 5f698798e6..eac524efae 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -90,6 +90,7 @@ #include "UI/MiscScreens.h" #include "UI/TiltEventProcessor.h" #include "UI/BackgroundAudio.h" +#include "UI/TextureUtil.h" #if !defined(MOBILE_DEVICE) #include "Common/KeyMap.h" @@ -117,7 +118,7 @@ static UI::Theme ui_theme; #include "android/android-ndk-profiler/prof.h" #endif -Draw::Texture *uiTexture; +ManagedTexture *uiTexture; ScreenManager *screenManager; std::string config_filename; @@ -578,7 +579,7 @@ void NativeInitGraphics(GraphicsContext *graphicsContext) { ui_theme.popupTitle.fgColor = 0xFF59BEE3; #endif - uiTexture = thin3d->CreateTextureFromFile("ui_atlas.zim", ImageFileType::ZIM); + uiTexture = CreateTextureFromFile(thin3d, "ui_atlas.zim", ImageFileType::ZIM); if (!uiTexture) { 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"); @@ -618,7 +619,7 @@ void NativeInitGraphics(GraphicsContext *graphicsContext) { ui_draw2d.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; desc.cull = CullMode::NONE; desc.frontFace = Facing::CCW; @@ -648,9 +649,8 @@ void NativeShutdownGraphics() { delete g_gameInfoCache; g_gameInfoCache = nullptr; - if (uiTexture->Release()) { - uiTexture = nullptr; - } + delete uiTexture; + uiTexture = nullptr; delete uiContext; uiContext = NULL; @@ -737,6 +737,8 @@ void DrawDownloadsOverlay(UIContext &dc) { void NativeRender(GraphicsContext *graphicsContext) { g_GameManager.Update(); + // If uitexture gets reloaded, make sure we use the latest one. + uiContext->FrameSetup(uiTexture->GetTexture()); float xres = dp_xres; float yres = dp_yres; diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 10c2b221e6..a925d59a95 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -69,7 +69,7 @@ void AsyncImageFileView::SetFilename(std::string filename) { textureFailed_ = false; filename_ = filename; if (texture_) { - texture_->Release(); + delete texture_; texture_ = nullptr; } } @@ -78,11 +78,11 @@ void AsyncImageFileView::SetFilename(std::string filename) { void AsyncImageFileView::Draw(UIContext &dc) { using namespace Draw; if (!texture_ && !textureFailed_ && !filename_.empty()) { - texture_ = dc.GetThin3DContext()->CreateTextureFromFile(filename_.c_str(), DETECT); + texture_ = CreateTextureFromFile(dc.GetThin3DContext(), filename_.c_str(), DETECT); if (!texture_) textureFailed_ = true; - else if (textureAutoGen_) - texture_->AutoGenMipmaps(); + else if (textureAutoGen_) // TODO: Iffy + texture_->GetTexture()->AutoGenMipmaps(); } if (HasFocus()) { @@ -92,7 +92,7 @@ void AsyncImageFileView::Draw(UIContext &dc) { // TODO: involve sizemode if (texture_) { 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.Flush(); dc.RebindTexture(); diff --git a/UI/PauseScreen.h b/UI/PauseScreen.h index 3781943c43..206d1c2554 100644 --- a/UI/PauseScreen.h +++ b/UI/PauseScreen.h @@ -22,6 +22,7 @@ #include "ui/ui_screen.h" #include "ui/viewgroup.h" #include "UI/MiscScreens.h" +#include "UI/TextureUtil.h" class GamePauseScreen : public UIDialogScreenWithGameBackground { public: @@ -95,7 +96,7 @@ private: uint32_t color_; UI::ImageSizeMode sizeMode_; - Draw::Texture *texture_; + ManagedTexture *texture_; bool textureFailed_; bool textureAutoGen_; float fixedSizeW_; diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index dcb81c94cb..b9eb10b087 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -80,7 +80,7 @@ public: std::string savedata_title = ginfo->paramSFO.GetValueString("SAVEDATA_TITLE"); 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)); topright->SetSpacing(1.0f); @@ -159,7 +159,7 @@ void SavedataButton::Draw(UIContext &dc) { using namespace UI; if (ginfo->iconTexture) { - texture = ginfo->iconTexture; + texture = ginfo->iconTexture->GetTexture(); } int x = bounds_.x; diff --git a/UI/Store.cpp b/UI/Store.cpp index 3d68e48fd2..f8b467aff1 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -33,6 +33,7 @@ #include "Core/Util/GameManager.h" #include "UI/EmuScreen.h" #include "UI/Store.h" +#include "UI/TextureUtil.h" const std::string storeBaseUrl = "http://store.ppsspp.org/"; @@ -84,7 +85,7 @@ private: std::shared_ptr download_; std::string textureData_; - Draw::Texture *texture_; + ManagedTexture *texture_; bool textureFailed_; float fixedSizeW_; float fixedSizeH_; @@ -116,7 +117,7 @@ void HttpImageFileView::SetFilename(std::string filename) { textureFailed_ = false; path_ = filename; if (texture_) { - texture_->Release(); + delete texture_; texture_ = nullptr; } } @@ -142,7 +143,7 @@ void HttpImageFileView::Draw(UIContext &dc) { } 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_) textureFailed_ = true; textureData_.clear(); @@ -156,7 +157,7 @@ void HttpImageFileView::Draw(UIContext &dc) { // TODO: involve sizemode if (texture_) { 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.Flush(); dc.RebindTexture(); diff --git a/UI/TextureUtil.cpp b/UI/TextureUtil.cpp new file mode 100644 index 0000000000..ab19946297 --- /dev/null +++ b/UI/TextureUtil.cpp @@ -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; +} \ No newline at end of file diff --git a/UI/TextureUtil.h b/UI/TextureUtil.h new file mode 100644 index 0000000000..9a6f8e1cea --- /dev/null +++ b/UI/TextureUtil.h @@ -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); diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index 3a12bb046f..dbe660a792 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -41,6 +41,7 @@ + @@ -71,6 +72,7 @@ + @@ -125,7 +127,6 @@ - diff --git a/UI/UI.vcxproj.filters b/UI/UI.vcxproj.filters index dec781d42a..8332d11762 100644 --- a/UI/UI.vcxproj.filters +++ b/UI/UI.vcxproj.filters @@ -69,6 +69,7 @@ Screens + @@ -139,10 +140,11 @@ Screens + {faee5dce-633b-4ba6-b19d-ea70ee3c1c38} - + \ No newline at end of file diff --git a/ext/native/gfx_es2/draw_text.cpp b/ext/native/gfx_es2/draw_text.cpp index 088a9c09af..b5dc16c86d 100644 --- a/ext/native/gfx_es2/draw_text.cpp +++ b/ext/native/gfx_es2/draw_text.cpp @@ -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->Finalize(0); + entry->texture->Finalize(); delete [] bitmapData; cache_[entryHash] = std::unique_ptr(entry); diff --git a/ext/native/thin3d/thin3d.cpp b/ext/native/thin3d/thin3d.cpp index b2c7ef7199..b6e9ff5781 100644 --- a/ext/native/thin3d/thin3d.cpp +++ b/ext/native/thin3d/thin3d.cpp @@ -2,10 +2,6 @@ #include #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 { @@ -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 \ No newline at end of file diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 7005941b32..d71711e005 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -281,14 +281,6 @@ enum class ShaderLanguage { METAL_BYTECODE = 1024, }; -enum ImageFileType { - PNG, - JPEG, - ZIM, - DETECT, - TYPE_UNKNOWN, -}; - enum InfoField { APINAME, APIVERSION, @@ -340,19 +332,15 @@ public: class Texture : public RefCountedObject { 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 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 Finalize(int zim_flags) = 0; // TODO: Tidy up + virtual void Finalize() = 0; // TODO: Tidy up int Width() { return width_; } int Height() { return height_; } int Depth() { return depth_; } protected: - std::string filename_; // Textures that are loaded from files can reload themselves automatically. int width_, height_, depth_; }; @@ -497,10 +485,6 @@ public: // virtual ComputePipeline CreateComputePipeline(const ComputePipelineDesc &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. ShaderModule *GetVshaderPreset(VertexShaderPreset preset) { return fsPresets_[preset]; } ShaderModule *GetFshaderPreset(FragmentShaderPreset preset) { return vsPresets_[preset]; } diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 3e31c9338a..54994bb7b5 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -6,6 +6,10 @@ namespace Draw { #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 D3D11DrawContext : public DrawContext { @@ -308,7 +312,7 @@ public: std::vector 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; @@ -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) { ApplyCurrentState(); } diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index 5291cfb676..e339cbfa54 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -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 AutoGenMipmaps() override {} void SetToSampler(LPDIRECT3DDEVICE9 device, int sampler); - void Finalize(int zim_flags) override {} + void Finalize() override {} private: LPDIRECT3DDEVICE9 device_; diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 108722bdd0..ba334f55e1 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -4,7 +4,6 @@ #include #include "base/logging.h" -#include "image/zim_load.h" #include "math/dataconv.h" #include "math/lin/matrix4x4.h" #include "thin3d/thin3d.h" @@ -542,7 +541,7 @@ public: } 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); #if defined(USING_GLES2) glDepthRangef(viewports[0].MinDepth, viewports[0].MaxDepth); @@ -702,20 +701,9 @@ public: } 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: GLuint tex_; @@ -784,11 +772,10 @@ bool isPowerOf2(int n) { return n == 1 || (n & (n - 1)) == 0; } -void Thin3DGLTexture::Finalize(int zim_flags) { - canWrap_ = (zim_flags & ZIM_CLAMP) || !isPowerOf2(width_) || !isPowerOf2(height_); +void Thin3DGLTexture::Finalize() { + canWrap_ = !isPowerOf2(width_) || !isPowerOf2(height_); } - OpenGLInputLayout::~OpenGLInputLayout() { if (id_) { glDeleteVertexArrays(1, &id_); diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 9008aee50a..eff53ec077 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -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 Finalize(int zim_flags) override; + void Finalize() override {} void AutoGenMipmaps() override {} 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(); } -void VKTexture::Finalize(int zim_flags) { - // TODO -} - inline void CopySide(VkStencilOpState &dest, const StencilSide &src) { dest.compareMask = src.compareMask; dest.reference = src.reference; diff --git a/ext/native/ui/ui_context.cpp b/ext/native/ui/ui_context.cpp index 2d00935284..6073bbbe58 100644 --- a/ext/native/ui/ui_context.cpp +++ b/ext/native/ui/ui_context.cpp @@ -18,13 +18,12 @@ UIContext::~UIContext() { 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; thin3d_ = thin3d; sampler_ = thin3d_->CreateSamplerState({ TextureFilter::LINEAR, TextureFilter::LINEAR, TextureFilter::LINEAR }); ui_pipeline_ = uipipe; ui_pipeline_notex_ = uipipenotex; - uitexture_ = uitexture; uidrawbuffer_ = uidrawbuffer; uidrawbufferTop_ = uidrawbufferTop; #if defined(_WIN32) || defined(USING_QT_UI) @@ -34,6 +33,10 @@ void UIContext::Init(Draw::DrawContext *thin3d, Draw::Pipeline *uipipe, Draw::Pi #endif } +void UIContext::FrameSetup(Draw::Texture *uiTexture) { + uitexture_ = uiTexture; +} + void UIContext::Begin() { thin3d_->BindSamplerStates(0, 1, &sampler_); thin3d_->BindTexture(0, uitexture_); diff --git a/ext/native/ui/ui_context.h b/ext/native/ui/ui_context.h index 7b34ba2626..558c74bb9e 100644 --- a/ext/native/ui/ui_context.h +++ b/ext/native/ui/ui_context.h @@ -36,7 +36,9 @@ public: 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 BeginNoTex();