summaryrefslogtreecommitdiff
path: root/indra/newview/lltexturecache.h
blob: faf722dc8f6b7899a3cf0f24e6dad204ac05aefa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/**
 * @file lltexturecache.h
 * @brief Object for managing texture cachees.
 *
 * $LicenseInfo:firstyear=2000&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#ifndef LL_LLTEXTURECACHE_H
#define LL_LLTEXTURECACHE_H

#include "lldir.h"
#include "llstl.h"
#include "llstring.h"
#include "lluuid.h"

#include "llworkerthread.h"

class LLImageFormatted;
class LLTextureCacheWorker;
class LLImageRaw;

class LLTextureCache : public LLWorkerThread
{
    friend class LLTextureCacheWorker;
    friend class LLTextureCacheRemoteWorker;
    friend class LLTextureCacheLocalFileWorker;

private:

#if LL_WINDOWS
#pragma pack(push,1)
#endif

    // Entries
    static const U32 sHeaderEncoderStringSize = 32;
    struct EntriesInfo
    {
        EntriesInfo() : mVersion(0.f), mAdressSize(0), mEntries(0) { memset(mEncoderVersion, 0, sHeaderEncoderStringSize); }
        F32 mVersion;
        U32 mAdressSize;
        char mEncoderVersion[sHeaderEncoderStringSize];
        U32 mEntries;
    };
    struct Entry
    {
            Entry() :
                mBodySize(0),
            mImageSize(0),
            mTime(0)
        {
        }
        Entry(const LLUUID& id, S32 imagesize, S32 bodysize, U32 time) :
            mID(id), mImageSize(imagesize), mBodySize(bodysize), mTime(time) {}
        void init(const LLUUID& id, U32 time) { mID = id, mImageSize = 0; mBodySize = 0; mTime = time; }
        Entry& operator=(const Entry& entry) {mID = entry.mID, mImageSize = entry.mImageSize; mBodySize = entry.mBodySize; mTime = entry.mTime; return *this;}
        LLUUID mID; // 16 bytes
        S32 mImageSize; // total size of image if known
        S32 mBodySize; // size of body file in body cache
        U32 mTime; // seconds since 1/1/1970
    };

#if LL_WINDOWS
#pragma pack(pop)
#endif

public:

    class Responder : public LLResponder
    {
    public:
        virtual void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, bool imagelocal) = 0;
    };

    class ReadResponder : public Responder
    {
    public:
        ReadResponder();
        void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, bool imagelocal);
        void setImage(LLImageFormatted* image) { mFormattedImage = image; }
    protected:
        LLPointer<LLImageFormatted> mFormattedImage;
        S32 mImageSize;
        bool mImageLocal;
    };

    class WriteResponder : public Responder
    {
        void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, bool imagelocal)
        {
            // not used
        }
    };

    LLTextureCache(bool threaded);
    ~LLTextureCache();

    /*virtual*/ size_t update(F32 max_time_ms);

    void purgeCache(ELLPath location, bool remove_dir = true);
    void setReadOnly(bool read_only) ;
    S64 initCache(ELLPath location, S64 maxsize, bool texture_cache_mismatch);

    handle_t readFromCache(const std::string& local_filename, const LLUUID& id, S32 offset, S32 size,
                           ReadResponder* responder);

    handle_t readFromCache(const LLUUID& id, S32 offset, S32 size,
                           ReadResponder* responder);
    bool readComplete(handle_t handle, bool abort);
    handle_t writeToCache(const LLUUID& id, const U8* data, S32 datasize, S32 imagesize, LLPointer<LLImageRaw> rawimage, S32 discardlevel,
                          WriteResponder* responder);
    LLPointer<LLImageRaw> readFromFastCache(const LLUUID& id, S32& discardlevel);
    bool writeComplete(handle_t handle, bool abort = false);
    void prioritizeWrite(handle_t handle);

    bool removeFromCache(const LLUUID& id);

    // For LLTextureCacheWorker::Responder
    LLTextureCacheWorker* getReader(handle_t handle);
    LLTextureCacheWorker* getWriter(handle_t handle);
    void lockWorkers() { mWorkersMutex.lock(); }
    void unlockWorkers() { mWorkersMutex.unlock(); }

    // debug
    S32 getNumReads() { return static_cast<S32>(mReaders.size()); }
    S32 getNumWrites() { return static_cast<S32>(mWriters.size()); }
    S64Bytes getUsage() { return S64Bytes(mTexturesSizeTotal); }
    S64Bytes getMaxUsage() { return S64Bytes(sCacheMaxTexturesSize); }
    U32 getEntries() { return mHeaderEntriesInfo.mEntries; }
    U32 getMaxEntries() { return sCacheMaxEntries; };
    bool isInCache(const LLUUID& id) ;
    bool isInLocal(const LLUUID& id) ; //not thread safe at the moment

protected:
    // Accessed by LLTextureCacheWorker
    std::string getLocalFileName(const LLUUID& id);
    std::string getTextureFileName(const LLUUID& id);
    void addCompleted(Responder* responder, bool success);

protected:
    //void setFileAPRPool(apr_pool_t* pool) { mFileAPRPool = pool ; }

private:
    void setDirNames(ELLPath location);
    void readHeaderCache();
    void clearCorruptedCache();
    void purgeAllTextures(bool purge_directories);
    void purgeTexturesLazy(F32 time_limit_sec);
    void purgeTextures(bool validate);
    LLAPRFile* openHeaderEntriesFile(bool readonly, S32 offset);
    void closeHeaderEntriesFile();
    void readEntriesHeader();
    void setEntriesHeader();
    void writeEntriesHeader();
    S32 openAndReadEntry(const LLUUID& id, Entry& entry, bool create);
    bool updateEntry(S32& idx, Entry& entry, S32 new_image_size, S32 new_body_size);
    void updateEntryTimeStamp(S32 idx, Entry& entry) ;
    U32 openAndReadEntries(std::vector<Entry>& entries);
    void writeEntriesAndClose(const std::vector<Entry>& entries);
    void readEntryFromHeaderImmediately(S32& idx, Entry& entry) ;
    void writeEntryToHeaderImmediately(S32& idx, Entry& entry, bool write_header = false) ;
    void removeEntry(S32 idx, Entry& entry, std::string& filename);
    void removeCachedTexture(const LLUUID& id) ;
    S32 getHeaderCacheEntry(const LLUUID& id, Entry& entry);
    S32 setHeaderCacheEntry(const LLUUID& id, Entry& entry, S32 imagesize, S32 datasize);
    void writeUpdatedEntries() ;
    void updatedHeaderEntriesFile() ;
    void lockHeaders() { mHeaderMutex.lock(); }
    void unlockHeaders() { mHeaderMutex.unlock(); }

    void openFastCache(bool first_time = false);
    void closeFastCache(bool forced = false);
    bool writeToFastCache(LLUUID image_id, S32 cache_id, LLPointer<LLImageRaw> raw, S32 discardlevel);

private:
    // Internal
    LLMutex mWorkersMutex;
    LLMutex mHeaderMutex;
    LLMutex mListMutex;
    LLMutex mFastCacheMutex;
    LLAPRFile* mHeaderAPRFile;
    LLVolatileAPRPool* mFastCachePoolp;

    // mLocalAPRFilePoolp is not thread safe and is meant only for workers
    // howhever mHeaderEntriesFileName is accessed not from workers' threads
    // so it needs own pool (not thread safe by itself, relies onto header's mutex)
    LLVolatileAPRPool*   mHeaderAPRFilePoolp;

    typedef std::map<handle_t, LLTextureCacheWorker*> handle_map_t;
    handle_map_t mReaders;
    handle_map_t mWriters;

    typedef std::vector<handle_t> handle_list_t;
    handle_list_t mPrioritizeWriteList;

    typedef std::vector<std::pair<LLPointer<Responder>, bool> > responder_list_t;
    responder_list_t mCompletedList;

    bool mReadOnly;

    // HEADERS (Include first mip)
    std::string mHeaderEntriesFileName;
    std::string mHeaderDataFileName;
    std::string mFastCacheFileName;
    EntriesInfo mHeaderEntriesInfo;
    std::set<S32> mFreeList; // deleted entries
    std::set<LLUUID> mLRU;
    typedef std::map<LLUUID, S32> id_map_t;
    id_map_t mHeaderIDMap;

    LLAPRFile*   mFastCachep;
    LLFrameTimer mFastCacheTimer;
    U8*          mFastCachePadBuffer;

    // BODIES (TEXTURES minus headers)
    std::string mTexturesDirName;
    typedef std::map<LLUUID,S32> size_map_t;
    size_map_t mTexturesSizeMap;
    S64 mTexturesSizeTotal;
    LLAtomicBool mDoPurge;

    typedef std::map<S32, Entry> idx_entry_map_t;
    idx_entry_map_t mUpdatedEntryMap;
    typedef std::vector<std::pair<S32, Entry> > idx_entry_vector_t;
    idx_entry_vector_t mPurgeEntryList;

    // Statics
    static F32 sHeaderCacheVersion;
    static U32 sHeaderCacheAddressSize;
    static std::string sHeaderCacheEncoderVersion;
    static U32 sCacheMaxEntries;
    static S64 sCacheMaxTexturesSize;
};

extern const S32 TEXTURE_CACHE_ENTRY_SIZE;

#endif // LL_LLTEXTURECACHE_H