/* Copyright 2018 flyinghead This file is part of reicast. reicast is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. reicast is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with reicast. If not, see . */ #pragma once #include "texconv.h" #include "custom_texture/CustomTextureTypes.h" #include "util/tsqueue.h" #include "types.h" #include #include #include #include #include #include #include #include #include #include class BaseTextureCacheData; struct Renderer; class WorkerThread; namespace config { enum class CustomTexturePreloadMode : int; } class CustomTextureException final : public FlycastException { public: enum class Error { FileRead, ImageDecode, CompressedSource, TextureTooLarge, Upload, AllocationFailed, DirectX9CompressedSource, }; CustomTextureException(Error error, const std::string& message) : FlycastException(message), error_(error) {} Error error() const { return error_; } private: Error error_; }; struct GpuPreloadedTexture { using Ptr = std::shared_ptr; explicit GpuPreloadedTexture(u8 mipLevels) : mipLevels(mipLevels) {} virtual ~GpuPreloadedTexture() = default; u8 mipLevels; }; class BaseCustomTextureSource { public: using TextureCallback = std::function; using CancellationCheck = std::function; virtual ~BaseCustomTextureSource() = default; virtual bool shouldReplace() const { return false; } virtual bool shouldPreload() const { return false; } virtual bool loadMap(const CustomTextureCapabilities& capabilities) = 0; virtual size_t getTextureCount() const { return 0; } virtual void terminate() { } virtual PreparedCustomTexture::Ptr loadCustomTexture(u32 hash, const CustomTextureCapabilities& capabilities, const CancellationCheck& cancelled) = 0; virtual bool isTextureReplaced(u32 hash) const = 0; virtual void preloadTextures(const CustomTextureCapabilities& capabilities, TextureCallback callback, std::atomic* stopFlag) {} }; class CustomTexture { public: using GpuTextureUploader = std::function; ~CustomTexture(); void init(); bool isInitialized() const; bool enabled() const; bool isPreloading() const; bool needsRefresh() const; void addSource(std::unique_ptr source); void loadCustomTextureAsync(BaseTextureCacheData *textureData); bool isRequestComplete(CustomTextureRequestId requestId) const; PreparedCustomTexture::Ptr takePreparedTexture(CustomTextureRequestId requestId, bool& failed); void cancelRequest(CustomTextureRequestId requestId); void setCapabilities(const CustomTextureCapabilities& capabilities); void invalidateGpuPreloads(); CustomTextureCapabilities getCapabilities() const; void dumpTexture(BaseTextureCacheData* texture, int w, int h, void *srcBuffer); void refresh(); void terminate(); void getPreloadProgress(int& completed, int& total, size_t& loadedSize) const; void processGpuPreloads(const GpuTextureUploader& uploader); void reportError(CustomTextureException::Error error); void showErrorNotification(); private: friend struct Renderer; struct GpuCleanupOperation {}; enum class State { Stopped, Active, RefreshPending, }; struct Request { PreparedCustomTexture::Ptr texture; bool complete = false; bool failed = false; }; PreparedCustomTexture::Ptr loadTexture(u32 currentHash, u32 oldVqHash, u32 oldHash, const CustomTextureCapabilities& capabilities, const BaseCustomTextureSource::CancellationCheck& cancelled); PreparedCustomTexture::Ptr findPreloaded(u32 currentHash, u32 oldVqHash, u32 oldHash) const; bool isTextureReplaced(BaseTextureCacheData* texture) const; std::string getGameId() const; void startSession(const std::string& gameId); void clearSessionResources(); void prepareSource(BaseCustomTextureSource* source, bool shouldPreload); void submitGpuPreload(u32 hash, PreparedCustomTexture::Ptr texture); bool consumeGpuCleanupOperations(); void resetPreloadProgress(); bool requestCancelled(CustomTextureRequestId requestId) const; State state = State::Stopped; std::string sessionGameId; bool sessionCustomTextures = false; config::CustomTexturePreloadMode sessionPreloadMode {}; std::vector> sources; std::unique_ptr loaderThread; mutable std::mutex stateMutex; std::unordered_map preloadedTextures; std::deque> pendingGpuPreloads; std::condition_variable gpuPreloadCondition; std::unordered_map requests; CustomTextureCapabilities capabilities = CustomTextureCapabilities::rgbaOnly(CustomTextureBackend::Unknown); std::atomic nextRequestId { 1 }; std::atomic preloadTotal { 0 }; std::atomic preloadLoaded { 0 }; std::atomic preloadLoadedSize { 0 }; std::atomic pendingPreloads { 0 }; std::atomic stopPreload { false }; TsQueue gpuCleanupOperations; std::optional pendingError; bool errorNotificationShown = false; }; extern CustomTexture custom_texture;