diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llrender/llimagegl.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llrender/llimagegl.cpp')
-rw-r--r-- | linden/indra/llrender/llimagegl.cpp | 1224 |
1 files changed, 1224 insertions, 0 deletions
diff --git a/linden/indra/llrender/llimagegl.cpp b/linden/indra/llrender/llimagegl.cpp new file mode 100644 index 0000000..5ea7322 --- /dev/null +++ b/linden/indra/llrender/llimagegl.cpp | |||
@@ -0,0 +1,1224 @@ | |||
1 | /** | ||
2 | * @file llimagegl.cpp | ||
3 | * @brief Generic GL image handler | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | |||
29 | // TODO: create 2 classes for images w/ and w/o discard levels? | ||
30 | |||
31 | #include "linden_common.h" | ||
32 | |||
33 | #include "llimagegl.h" | ||
34 | |||
35 | #include "llerror.h" | ||
36 | #include "llimage.h" | ||
37 | |||
38 | #include "llmath.h" | ||
39 | #include "llgl.h" | ||
40 | |||
41 | //---------------------------------------------------------------------------- | ||
42 | |||
43 | const F32 MIN_TEXTURE_LIFETIME = 10.f; | ||
44 | |||
45 | //statics | ||
46 | LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 }; | ||
47 | |||
48 | S32 LLImageGL::sGlobalTextureMemory = 0; | ||
49 | S32 LLImageGL::sBoundTextureMemory = 0; | ||
50 | S32 LLImageGL::sCurBoundTextureMemory = 0; | ||
51 | S32 LLImageGL::sCount = 0; | ||
52 | |||
53 | BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; | ||
54 | F32 LLImageGL::sLastFrameTime = 0.f; | ||
55 | |||
56 | std::set<LLImageGL*> LLImageGL::sImageList; | ||
57 | |||
58 | //---------------------------------------------------------------------------- | ||
59 | |||
60 | //static | ||
61 | S32 LLImageGL::dataFormatBits(S32 dataformat) | ||
62 | { | ||
63 | switch (dataformat) | ||
64 | { | ||
65 | case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4; | ||
66 | case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8; | ||
67 | case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 8; | ||
68 | case GL_LUMINANCE: return 8; | ||
69 | case GL_ALPHA: return 8; | ||
70 | case GL_COLOR_INDEX: return 8; | ||
71 | case GL_LUMINANCE_ALPHA: return 16; | ||
72 | case GL_RGB: return 24; | ||
73 | case GL_RGB8: return 24; | ||
74 | case GL_RGBA: return 32; | ||
75 | case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac | ||
76 | default: | ||
77 | llerrs << "LLImageGL::Unknown format: " << dataformat << llendl; | ||
78 | return 0; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | //static | ||
83 | S32 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height) | ||
84 | { | ||
85 | if (dataformat >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT && | ||
86 | dataformat <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) | ||
87 | { | ||
88 | if (width < 4) width = 4; | ||
89 | if (height < 4) height = 4; | ||
90 | } | ||
91 | S32 bytes ((width*height*dataFormatBits(dataformat)+7)>>3); | ||
92 | S32 aligned = (bytes+3)&~3; | ||
93 | return aligned; | ||
94 | } | ||
95 | |||
96 | //static | ||
97 | S32 LLImageGL::dataFormatComponents(S32 dataformat) | ||
98 | { | ||
99 | switch (dataformat) | ||
100 | { | ||
101 | case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 3; | ||
102 | case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 4; | ||
103 | case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 4; | ||
104 | case GL_LUMINANCE: return 1; | ||
105 | case GL_ALPHA: return 1; | ||
106 | case GL_COLOR_INDEX: return 1; | ||
107 | case GL_LUMINANCE_ALPHA: return 2; | ||
108 | case GL_RGB: return 3; | ||
109 | case GL_RGBA: return 4; | ||
110 | case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac | ||
111 | default: | ||
112 | llerrs << "LLImageGL::Unknown format: " << dataformat << llendl; | ||
113 | return 0; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | //---------------------------------------------------------------------------- | ||
118 | |||
119 | // static | ||
120 | void LLImageGL::bindExternalTexture(LLGLuint gl_name, S32 stage, LLGLenum bind_target ) | ||
121 | { | ||
122 | glActiveTextureARB(GL_TEXTURE0_ARB + stage); | ||
123 | glClientActiveTextureARB(GL_TEXTURE0_ARB + stage); | ||
124 | glBindTexture(bind_target, gl_name); | ||
125 | sCurrentBoundTextures[stage] = gl_name; | ||
126 | } | ||
127 | |||
128 | // static | ||
129 | void LLImageGL::unbindTexture(S32 stage, LLGLenum bind_target) | ||
130 | { | ||
131 | glActiveTextureARB(GL_TEXTURE0_ARB + stage); | ||
132 | glClientActiveTextureARB(GL_TEXTURE0_ARB + stage); | ||
133 | glBindTexture(bind_target, 0); | ||
134 | sCurrentBoundTextures[stage] = 0; | ||
135 | } | ||
136 | |||
137 | // static | ||
138 | void LLImageGL::updateStats(F32 current_time) | ||
139 | { | ||
140 | sLastFrameTime = current_time; | ||
141 | sBoundTextureMemory = sCurBoundTextureMemory; | ||
142 | sCurBoundTextureMemory = 0; | ||
143 | } | ||
144 | |||
145 | //static | ||
146 | S32 LLImageGL::updateBoundTexMem(const S32 delta) | ||
147 | { | ||
148 | LLImageGL::sCurBoundTextureMemory += delta; | ||
149 | return LLImageGL::sCurBoundTextureMemory; | ||
150 | } | ||
151 | |||
152 | //---------------------------------------------------------------------------- | ||
153 | |||
154 | //static | ||
155 | void LLImageGL::destroyGL(BOOL save_state) | ||
156 | { | ||
157 | for (S32 stage = 0; stage < gGLManager.mNumTextureUnits; stage++) | ||
158 | { | ||
159 | LLImageGL::unbindTexture(stage, GL_TEXTURE_2D); | ||
160 | } | ||
161 | for (std::set<LLImageGL*>::iterator iter = sImageList.begin(); | ||
162 | iter != sImageList.end(); iter++) | ||
163 | { | ||
164 | LLImageGL* glimage = *iter; | ||
165 | if (glimage->mTexName && glimage->mComponents) | ||
166 | { | ||
167 | if (save_state) | ||
168 | { | ||
169 | glimage->mSaveData = new LLImageRaw; | ||
170 | glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData); | ||
171 | } | ||
172 | glimage->destroyGLTexture(); | ||
173 | stop_glerror(); | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | |||
178 | //static | ||
179 | void LLImageGL::restoreGL() | ||
180 | { | ||
181 | for (std::set<LLImageGL*>::iterator iter = sImageList.begin(); | ||
182 | iter != sImageList.end(); iter++) | ||
183 | { | ||
184 | LLImageGL* glimage = *iter; | ||
185 | if (glimage->mSaveData.notNull() && glimage->mSaveData->getComponents()) | ||
186 | { | ||
187 | if (glimage->getComponents()) | ||
188 | { | ||
189 | glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData); | ||
190 | stop_glerror(); | ||
191 | } | ||
192 | glimage->mSaveData = NULL; // deletes data | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | |||
197 | //---------------------------------------------------------------------------- | ||
198 | |||
199 | //static | ||
200 | BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, BOOL usemipmaps) | ||
201 | { | ||
202 | dest = new LLImageGL(usemipmaps); | ||
203 | return TRUE; | ||
204 | } | ||
205 | |||
206 | BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, U32 width, U32 height, U8 components, BOOL usemipmaps) | ||
207 | { | ||
208 | dest = new LLImageGL(width, height, components, usemipmaps); | ||
209 | return TRUE; | ||
210 | } | ||
211 | |||
212 | BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps) | ||
213 | { | ||
214 | dest = new LLImageGL(imageraw, usemipmaps); | ||
215 | return TRUE; | ||
216 | } | ||
217 | |||
218 | //---------------------------------------------------------------------------- | ||
219 | |||
220 | LLImageGL::LLImageGL(BOOL usemipmaps) | ||
221 | : mSaveData(0) | ||
222 | { | ||
223 | init(usemipmaps); | ||
224 | setSize(0, 0, 0); | ||
225 | sImageList.insert(this); | ||
226 | sCount++; | ||
227 | } | ||
228 | |||
229 | LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps) | ||
230 | : mSaveData(0) | ||
231 | { | ||
232 | llassert( components <= 4 ); | ||
233 | init(usemipmaps); | ||
234 | setSize(width, height, components); | ||
235 | sImageList.insert(this); | ||
236 | sCount++; | ||
237 | } | ||
238 | |||
239 | LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps) | ||
240 | : mSaveData(0) | ||
241 | { | ||
242 | init(usemipmaps); | ||
243 | setSize(0, 0, 0); | ||
244 | sImageList.insert(this); | ||
245 | sCount++; | ||
246 | createGLTexture(0, imageraw); | ||
247 | } | ||
248 | |||
249 | LLImageGL::~LLImageGL() | ||
250 | { | ||
251 | LLImageGL::cleanup(); | ||
252 | sImageList.erase(this); | ||
253 | sCount--; | ||
254 | } | ||
255 | |||
256 | void LLImageGL::init(BOOL usemipmaps) | ||
257 | { | ||
258 | #ifdef DEBUG_MISS | ||
259 | mMissed = FALSE; | ||
260 | #endif | ||
261 | |||
262 | mTextureMemory = 0; | ||
263 | mLastBindTime = 0.f; | ||
264 | |||
265 | mTarget = GL_TEXTURE_2D; | ||
266 | mBindTarget = GL_TEXTURE_2D; | ||
267 | mUseMipMaps = usemipmaps; | ||
268 | mHasMipMaps = FALSE; | ||
269 | mAutoGenMips = FALSE; | ||
270 | mTexName = 0; | ||
271 | mIsResident = 0; | ||
272 | mClampS = FALSE; | ||
273 | mClampT = FALSE; | ||
274 | mMipFilterNearest = FALSE; | ||
275 | mWidth = 0; | ||
276 | mHeight = 0; | ||
277 | mComponents = 0; | ||
278 | |||
279 | mMaxDiscardLevel = MAX_DISCARD_LEVEL; | ||
280 | mCurrentDiscardLevel = -1; | ||
281 | mDontDiscard = FALSE; | ||
282 | |||
283 | mFormatInternal = -1; | ||
284 | mFormatPrimary = (LLGLenum) 0; | ||
285 | mFormatType = GL_UNSIGNED_BYTE; | ||
286 | mFormatSwapBytes = FALSE; | ||
287 | mHasExplicitFormat = FALSE; | ||
288 | } | ||
289 | |||
290 | void LLImageGL::cleanup() | ||
291 | { | ||
292 | if (!gGLManager.mIsDisabled) | ||
293 | { | ||
294 | destroyGLTexture(); | ||
295 | } | ||
296 | mSaveData = NULL; // deletes data | ||
297 | } | ||
298 | |||
299 | //---------------------------------------------------------------------------- | ||
300 | |||
301 | static bool check_power_of_two(S32 dim) | ||
302 | { | ||
303 | while(dim > 1) | ||
304 | { | ||
305 | if (dim & 1) | ||
306 | { | ||
307 | return false; | ||
308 | } | ||
309 | dim >>= 1; | ||
310 | } | ||
311 | return true; | ||
312 | } | ||
313 | |||
314 | //static | ||
315 | bool LLImageGL::checkSize(S32 width, S32 height) | ||
316 | { | ||
317 | return check_power_of_two(width) && check_power_of_two(height); | ||
318 | } | ||
319 | |||
320 | void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents) | ||
321 | { | ||
322 | if (width != mWidth || height != mHeight || ncomponents != mComponents) | ||
323 | { | ||
324 | // Check if dimensions are a power of two! | ||
325 | if (!checkSize(width,height)) | ||
326 | { | ||
327 | llerrs << llformat("Texture has non power of two dimention: %dx%d",width,height) << llendl; | ||
328 | } | ||
329 | |||
330 | if (mTexName) | ||
331 | { | ||
332 | // llwarns << "Setting Size of LLImageGL with existing mTexName = " << mTexName << llendl; | ||
333 | destroyGLTexture(); | ||
334 | } | ||
335 | |||
336 | mWidth = width; | ||
337 | mHeight = height; | ||
338 | mComponents = ncomponents; | ||
339 | if (ncomponents > 0) | ||
340 | { | ||
341 | mMaxDiscardLevel = 0; | ||
342 | while (width > 1 && height > 1 && mMaxDiscardLevel < MAX_DISCARD_LEVEL) | ||
343 | { | ||
344 | mMaxDiscardLevel++; | ||
345 | width >>= 1; | ||
346 | height >>= 1; | ||
347 | } | ||
348 | } | ||
349 | else | ||
350 | { | ||
351 | mMaxDiscardLevel = MAX_DISCARD_LEVEL; | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | |||
356 | //---------------------------------------------------------------------------- | ||
357 | |||
358 | // virtual | ||
359 | void LLImageGL::dump() | ||
360 | { | ||
361 | llinfos << "mMaxDiscardLevel " << S32(mMaxDiscardLevel) | ||
362 | << " mLastBindTime " << mLastBindTime | ||
363 | << " mTarget " << S32(mTarget) | ||
364 | << " mBindTarget " << S32(mBindTarget) | ||
365 | << " mUseMipMaps " << S32(mUseMipMaps) | ||
366 | << " mHasMipMaps " << S32(mHasMipMaps) | ||
367 | << " mCurrentDiscardLevel " << S32(mCurrentDiscardLevel) | ||
368 | << " mFormatInternal " << S32(mFormatInternal) | ||
369 | << " mFormatPrimary " << S32(mFormatPrimary) | ||
370 | << " mFormatType " << S32(mFormatType) | ||
371 | << " mFormatSwapBytes " << S32(mFormatSwapBytes) | ||
372 | << " mHasExplicitFormat " << S32(mHasExplicitFormat) | ||
373 | #if DEBUG_MISS | ||
374 | << " mMissed " << mMissed | ||
375 | #endif | ||
376 | << llendl; | ||
377 | |||
378 | llinfos << " mTextureMemory " << mTextureMemory | ||
379 | << " mTexNames " << mTexName | ||
380 | << " mIsResident " << S32(mIsResident) | ||
381 | << llendl; | ||
382 | } | ||
383 | |||
384 | //---------------------------------------------------------------------------- | ||
385 | |||
386 | BOOL LLImageGL::bindTextureInternal(const S32 stage) const | ||
387 | { | ||
388 | if (gGLManager.mIsDisabled) | ||
389 | { | ||
390 | llwarns << "Trying to bind a texture while GL is disabled!" << llendl; | ||
391 | } | ||
392 | |||
393 | stop_glerror(); | ||
394 | |||
395 | glActiveTextureARB(GL_TEXTURE0_ARB + stage); | ||
396 | //glClientActiveTextureARB(GL_TEXTURE0_ARB + stage); | ||
397 | |||
398 | stop_glerror(); | ||
399 | |||
400 | if (sCurrentBoundTextures[stage] && sCurrentBoundTextures[stage] == mTexName) | ||
401 | { | ||
402 | // already set! | ||
403 | return TRUE; | ||
404 | } | ||
405 | |||
406 | if (mTexName != 0) | ||
407 | { | ||
408 | #ifdef DEBUG_MISS | ||
409 | mMissed = ! getIsResident(TRUE); | ||
410 | #endif | ||
411 | |||
412 | glBindTexture(mBindTarget, mTexName); | ||
413 | sCurrentBoundTextures[stage] = mTexName; | ||
414 | stop_glerror(); | ||
415 | |||
416 | if (mLastBindTime != sLastFrameTime) | ||
417 | { | ||
418 | // we haven't accounted for this texture yet this frame | ||
419 | updateBoundTexMem(mTextureMemory); | ||
420 | mLastBindTime = sLastFrameTime; | ||
421 | } | ||
422 | |||
423 | return TRUE; | ||
424 | } | ||
425 | else | ||
426 | { | ||
427 | glBindTexture(mBindTarget, 0); | ||
428 | sCurrentBoundTextures[stage] = 0; | ||
429 | return FALSE; | ||
430 | } | ||
431 | } | ||
432 | |||
433 | //virtual | ||
434 | BOOL LLImageGL::bind(const S32 stage) const | ||
435 | { | ||
436 | if (stage == -1) | ||
437 | { | ||
438 | return FALSE; | ||
439 | } | ||
440 | BOOL res = bindTextureInternal(stage); | ||
441 | //llassert(res); | ||
442 | return res; | ||
443 | } | ||
444 | |||
445 | void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes ) | ||
446 | { | ||
447 | // Note: must be called before createTexture() | ||
448 | // Note: it's up to the caller to ensure that the format matches the number of components. | ||
449 | mHasExplicitFormat = TRUE; | ||
450 | mFormatInternal = internal_format; | ||
451 | mFormatPrimary = primary_format; | ||
452 | if(type_format == 0) | ||
453 | mFormatType = GL_UNSIGNED_BYTE; | ||
454 | else | ||
455 | mFormatType = type_format; | ||
456 | mFormatSwapBytes = swap_bytes; | ||
457 | } | ||
458 | |||
459 | //---------------------------------------------------------------------------- | ||
460 | |||
461 | void LLImageGL::setImage(const LLImageRaw* imageraw) | ||
462 | { | ||
463 | llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) && | ||
464 | (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) && | ||
465 | (imageraw->getComponents() == getComponents())); | ||
466 | const U8* rawdata = imageraw->getData(); | ||
467 | setImage(rawdata, FALSE); | ||
468 | } | ||
469 | |||
470 | void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) | ||
471 | { | ||
472 | // LLFastTimer t1(LLFastTimer::FTM_TEMP1); | ||
473 | |||
474 | bool is_compressed = false; | ||
475 | if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) | ||
476 | { | ||
477 | is_compressed = true; | ||
478 | } | ||
479 | |||
480 | { | ||
481 | // LLFastTimer t2(LLFastTimer::FTM_TEMP2); | ||
482 | llverify(bindTextureInternal(0)); | ||
483 | } | ||
484 | |||
485 | if (mUseMipMaps) | ||
486 | { | ||
487 | // LLFastTimer t2(LLFastTimer::FTM_TEMP3); | ||
488 | if (data_hasmips) | ||
489 | { | ||
490 | // NOTE: data_in points to largest image; smaller images | ||
491 | // are stored BEFORE the largest image | ||
492 | for (S32 d=mCurrentDiscardLevel; d<=mMaxDiscardLevel; d++) | ||
493 | { | ||
494 | S32 w = getWidth(d); | ||
495 | S32 h = getHeight(d); | ||
496 | S32 gl_level = d-mCurrentDiscardLevel; | ||
497 | if (d > mCurrentDiscardLevel) | ||
498 | { | ||
499 | data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment | ||
500 | } | ||
501 | if (is_compressed) | ||
502 | { | ||
503 | // LLFastTimer t2(LLFastTimer::FTM_TEMP4); | ||
504 | S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); | ||
505 | glCompressedTexImage2DARB(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); | ||
506 | stop_glerror(); | ||
507 | } | ||
508 | else | ||
509 | { | ||
510 | // LLFastTimer t2(LLFastTimer::FTM_TEMP4); | ||
511 | |||
512 | if(mFormatSwapBytes) | ||
513 | { | ||
514 | glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); | ||
515 | stop_glerror(); | ||
516 | } | ||
517 | |||
518 | glTexImage2D(mTarget, gl_level, mFormatInternal, w, h, 0, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in); | ||
519 | |||
520 | if(mFormatSwapBytes) | ||
521 | { | ||
522 | glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); | ||
523 | stop_glerror(); | ||
524 | } | ||
525 | |||
526 | stop_glerror(); | ||
527 | } | ||
528 | stop_glerror(); | ||
529 | } | ||
530 | } | ||
531 | else if (!is_compressed) | ||
532 | { | ||
533 | if (mAutoGenMips) | ||
534 | { | ||
535 | glTexParameteri(mBindTarget, GL_GENERATE_MIPMAP_SGIS, TRUE); | ||
536 | stop_glerror(); | ||
537 | { | ||
538 | // LLFastTimer t2(LLFastTimer::FTM_TEMP4); | ||
539 | |||
540 | if(mFormatSwapBytes) | ||
541 | { | ||
542 | glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); | ||
543 | stop_glerror(); | ||
544 | } | ||
545 | |||
546 | glTexImage2D(mTarget, 0, mFormatInternal, | ||
547 | getWidth(mCurrentDiscardLevel), getHeight(mCurrentDiscardLevel), 0, | ||
548 | mFormatPrimary, mFormatType, | ||
549 | data_in); | ||
550 | stop_glerror(); | ||
551 | |||
552 | if(mFormatSwapBytes) | ||
553 | { | ||
554 | glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); | ||
555 | stop_glerror(); | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | else | ||
560 | { | ||
561 | // Create mips by hand | ||
562 | // about 30% faster than autogen on ATI 9800, 50% slower on nVidia 4800 | ||
563 | // ~4x faster than gluBuild2DMipmaps | ||
564 | S32 width = getWidth(mCurrentDiscardLevel); | ||
565 | S32 height = getHeight(mCurrentDiscardLevel); | ||
566 | S32 nummips = mMaxDiscardLevel - mCurrentDiscardLevel + 1; | ||
567 | S32 w = width, h = height; | ||
568 | const U8* prev_mip_data = 0; | ||
569 | const U8* cur_mip_data = 0; | ||
570 | for (int m=0; m<nummips; m++) | ||
571 | { | ||
572 | if (m==0) | ||
573 | { | ||
574 | cur_mip_data = data_in; | ||
575 | } | ||
576 | else | ||
577 | { | ||
578 | S32 bytes = w * h * mComponents; | ||
579 | U8* new_data = new U8[bytes]; | ||
580 | LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents); | ||
581 | cur_mip_data = new_data; | ||
582 | } | ||
583 | llassert(w > 0 && h > 0 && cur_mip_data); | ||
584 | { | ||
585 | // LLFastTimer t1(LLFastTimer::FTM_TEMP4); | ||
586 | if(mFormatSwapBytes) | ||
587 | { | ||
588 | glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); | ||
589 | stop_glerror(); | ||
590 | } | ||
591 | |||
592 | glTexImage2D(mTarget, m, mFormatInternal, w, h, 0, mFormatPrimary, mFormatType, cur_mip_data); | ||
593 | stop_glerror(); | ||
594 | |||
595 | if(mFormatSwapBytes) | ||
596 | { | ||
597 | glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); | ||
598 | stop_glerror(); | ||
599 | } | ||
600 | } | ||
601 | if (prev_mip_data && prev_mip_data != data_in) | ||
602 | { | ||
603 | delete[] prev_mip_data; | ||
604 | } | ||
605 | prev_mip_data = cur_mip_data; | ||
606 | w >>= 1; | ||
607 | h >>= 1; | ||
608 | } | ||
609 | if (prev_mip_data && prev_mip_data != data_in) | ||
610 | { | ||
611 | delete[] prev_mip_data; | ||
612 | } | ||
613 | } | ||
614 | } | ||
615 | else | ||
616 | { | ||
617 | llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl; | ||
618 | } | ||
619 | mHasMipMaps = TRUE; | ||
620 | } | ||
621 | else | ||
622 | { | ||
623 | // LLFastTimer t2(LLFastTimer::FTM_TEMP5); | ||
624 | S32 w = getWidth(); | ||
625 | S32 h = getHeight(); | ||
626 | if (is_compressed) | ||
627 | { | ||
628 | S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); | ||
629 | glCompressedTexImage2DARB(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); | ||
630 | stop_glerror(); | ||
631 | } | ||
632 | else | ||
633 | { | ||
634 | if(mFormatSwapBytes) | ||
635 | { | ||
636 | glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); | ||
637 | stop_glerror(); | ||
638 | } | ||
639 | |||
640 | glTexImage2D(mTarget, 0, mFormatInternal, w, h, 0, | ||
641 | mFormatPrimary, mFormatType, (GLvoid *)data_in); | ||
642 | stop_glerror(); | ||
643 | |||
644 | if(mFormatSwapBytes) | ||
645 | { | ||
646 | glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); | ||
647 | stop_glerror(); | ||
648 | } | ||
649 | |||
650 | } | ||
651 | mHasMipMaps = FALSE; | ||
652 | } | ||
653 | stop_glerror(); | ||
654 | } | ||
655 | |||
656 | BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height) | ||
657 | { | ||
658 | if (!width || !height) | ||
659 | { | ||
660 | return TRUE; | ||
661 | } | ||
662 | if (mTexName == 0) | ||
663 | { | ||
664 | llwarns << "Setting subimage on image without GL texture" << llendl; | ||
665 | return FALSE; | ||
666 | } | ||
667 | |||
668 | if (x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight()) | ||
669 | { | ||
670 | setImage(datap, FALSE); | ||
671 | } | ||
672 | else | ||
673 | { | ||
674 | if (mUseMipMaps) | ||
675 | { | ||
676 | dump(); | ||
677 | llerrs << "setSubImage called with mipmapped image (not supported)" << llendl; | ||
678 | } | ||
679 | llassert(mCurrentDiscardLevel == 0); | ||
680 | if (((x_pos + width) > getWidth()) || | ||
681 | (y_pos + height) > getHeight()) | ||
682 | { | ||
683 | dump(); | ||
684 | llerrs << "Subimage not wholly in target image!" | ||
685 | << " x_pos " << x_pos | ||
686 | << " y_pos " << y_pos | ||
687 | << " width " << width | ||
688 | << " height " << height | ||
689 | << " getWidth() " << getWidth() | ||
690 | << " getHeight() " << getHeight() | ||
691 | << llendl; | ||
692 | } | ||
693 | |||
694 | if ((x_pos + width) > data_width || | ||
695 | (y_pos + height) > data_height) | ||
696 | { | ||
697 | dump(); | ||
698 | llerrs << "Subimage not wholly in source image!" | ||
699 | << " x_pos " << x_pos | ||
700 | << " y_pos " << y_pos | ||
701 | << " width " << width | ||
702 | << " height " << height | ||
703 | << " source_width " << data_width | ||
704 | << " source_height " << data_height | ||
705 | << llendl; | ||
706 | } | ||
707 | |||
708 | |||
709 | glPixelStorei(GL_UNPACK_ROW_LENGTH, data_width); | ||
710 | stop_glerror(); | ||
711 | |||
712 | if(mFormatSwapBytes) | ||
713 | { | ||
714 | glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); | ||
715 | stop_glerror(); | ||
716 | } | ||
717 | |||
718 | datap += (y_pos * data_width + x_pos) * getComponents(); | ||
719 | // Update the GL texture | ||
720 | llverify(bindTextureInternal(0)); | ||
721 | stop_glerror(); | ||
722 | |||
723 | glTexSubImage2D(mTarget, 0, x_pos, y_pos, | ||
724 | width, height, mFormatPrimary, mFormatType, datap); | ||
725 | stop_glerror(); | ||
726 | |||
727 | if(mFormatSwapBytes) | ||
728 | { | ||
729 | glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); | ||
730 | stop_glerror(); | ||
731 | } | ||
732 | |||
733 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||
734 | stop_glerror(); | ||
735 | } | ||
736 | |||
737 | return TRUE; | ||
738 | } | ||
739 | |||
740 | BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height) | ||
741 | { | ||
742 | return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height); | ||
743 | } | ||
744 | |||
745 | // Copy sub image from frame buffer | ||
746 | BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height) | ||
747 | { | ||
748 | if (bindTextureInternal(0)) | ||
749 | { | ||
750 | glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height); | ||
751 | stop_glerror(); | ||
752 | return TRUE; | ||
753 | } | ||
754 | else | ||
755 | { | ||
756 | return FALSE; | ||
757 | } | ||
758 | } | ||
759 | |||
760 | BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/) | ||
761 | { | ||
762 | if (gGLManager.mIsDisabled) | ||
763 | { | ||
764 | llwarns << "Trying to create a texture while GL is disabled!" << llendl; | ||
765 | return FALSE; | ||
766 | } | ||
767 | llassert(gGLManager.mInited || gNoRender); | ||
768 | stop_glerror(); | ||
769 | |||
770 | if (discard_level < 0) | ||
771 | { | ||
772 | llassert(mCurrentDiscardLevel >= 0); | ||
773 | discard_level = mCurrentDiscardLevel; | ||
774 | } | ||
775 | discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); | ||
776 | |||
777 | // Actual image width/height = raw image width/height * 2^discard_level | ||
778 | S32 w = imageraw->getWidth() << discard_level; | ||
779 | S32 h = imageraw->getHeight() << discard_level; | ||
780 | |||
781 | // setSize may call destroyGLTexture if the size does not match | ||
782 | setSize(w, h, imageraw->getComponents()); | ||
783 | |||
784 | if( !mHasExplicitFormat ) | ||
785 | { | ||
786 | switch (mComponents) | ||
787 | { | ||
788 | case 1: | ||
789 | // Use luminance alpha (for fonts) | ||
790 | mFormatInternal = GL_LUMINANCE8; | ||
791 | mFormatPrimary = GL_LUMINANCE; | ||
792 | mFormatType = GL_UNSIGNED_BYTE; | ||
793 | break; | ||
794 | case 2: | ||
795 | // Use luminance alpha (for fonts) | ||
796 | mFormatInternal = GL_LUMINANCE8_ALPHA8; | ||
797 | mFormatPrimary = GL_LUMINANCE_ALPHA; | ||
798 | mFormatType = GL_UNSIGNED_BYTE; | ||
799 | break; | ||
800 | case 3: | ||
801 | mFormatInternal = GL_RGB8; | ||
802 | mFormatPrimary = GL_RGB; | ||
803 | mFormatType = GL_UNSIGNED_BYTE; | ||
804 | break; | ||
805 | case 4: | ||
806 | mFormatInternal = GL_RGBA8; | ||
807 | mFormatPrimary = GL_RGBA; | ||
808 | mFormatType = GL_UNSIGNED_BYTE; | ||
809 | break; | ||
810 | default: | ||
811 | llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl; | ||
812 | } | ||
813 | } | ||
814 | |||
815 | const U8* rawdata = imageraw->getData(); | ||
816 | return createGLTexture(discard_level, rawdata, FALSE, usename); | ||
817 | } | ||
818 | |||
819 | BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) | ||
820 | { | ||
821 | llassert(data_in); | ||
822 | |||
823 | if (discard_level < 0) | ||
824 | { | ||
825 | llassert(mCurrentDiscardLevel >= 0); | ||
826 | discard_level = mCurrentDiscardLevel; | ||
827 | } | ||
828 | discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); | ||
829 | |||
830 | if (mTexName != 0 && discard_level == mCurrentDiscardLevel) | ||
831 | { | ||
832 | // This will only be true if the size has not changed | ||
833 | setImage(data_in, data_hasmips); | ||
834 | return TRUE; | ||
835 | } | ||
836 | |||
837 | GLuint old_name = mTexName; | ||
838 | // S32 old_discard = mCurrentDiscardLevel; | ||
839 | |||
840 | if (usename != 0) | ||
841 | { | ||
842 | mTexName = usename; | ||
843 | } | ||
844 | else | ||
845 | { | ||
846 | glGenTextures(1, (GLuint*)&mTexName); | ||
847 | stop_glerror(); | ||
848 | { | ||
849 | // LLFastTimer t1(LLFastTimer::FTM_TEMP6); | ||
850 | llverify(bindTextureInternal(0)); | ||
851 | glTexParameteri(mBindTarget, GL_TEXTURE_BASE_LEVEL, 0); | ||
852 | glTexParameteri(mBindTarget, GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel-discard_level); | ||
853 | } | ||
854 | } | ||
855 | if (!mTexName) | ||
856 | { | ||
857 | llerrs << "LLImageGL::createGLTexture failed to make texture" << llendl; | ||
858 | } | ||
859 | |||
860 | if (mUseMipMaps) | ||
861 | { | ||
862 | mAutoGenMips = gGLManager.mHasMipMapGeneration; | ||
863 | #if LL_DARWIN | ||
864 | // On the Mac GF2 and GF4MX drivers, auto mipmap generation doesn't work right with alpha-only textures. | ||
865 | if(gGLManager.mIsGF2or4MX && (mFormatInternal == GL_ALPHA8) && (mFormatPrimary == GL_ALPHA)) | ||
866 | { | ||
867 | mAutoGenMips = FALSE; | ||
868 | } | ||
869 | #endif | ||
870 | } | ||
871 | |||
872 | mCurrentDiscardLevel = discard_level; | ||
873 | |||
874 | setImage(data_in, data_hasmips); | ||
875 | |||
876 | setClamp(mClampS, mClampT); | ||
877 | setMipFilterNearest(mMipFilterNearest); | ||
878 | |||
879 | // things will break if we don't unbind after creation | ||
880 | unbindTexture(0, mBindTarget); | ||
881 | stop_glerror(); | ||
882 | |||
883 | if (old_name != 0) | ||
884 | { | ||
885 | sGlobalTextureMemory -= mTextureMemory; | ||
886 | glDeleteTextures(1, &old_name); | ||
887 | stop_glerror(); | ||
888 | } | ||
889 | |||
890 | mTextureMemory = getMipBytes(discard_level); | ||
891 | sGlobalTextureMemory += mTextureMemory; | ||
892 | |||
893 | // mark this as bound at this point, so we don't throw it out immediately | ||
894 | mLastBindTime = sLastFrameTime; | ||
895 | |||
896 | return TRUE; | ||
897 | } | ||
898 | |||
899 | BOOL LLImageGL::setDiscardLevel(S32 discard_level) | ||
900 | { | ||
901 | llassert(discard_level >= 0); | ||
902 | llassert(mCurrentDiscardLevel >= 0); | ||
903 | |||
904 | discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); | ||
905 | |||
906 | if (mDontDiscard) | ||
907 | { | ||
908 | // don't discard! | ||
909 | return FALSE; | ||
910 | } | ||
911 | else if (discard_level == mCurrentDiscardLevel) | ||
912 | { | ||
913 | // nothing to do | ||
914 | return FALSE; | ||
915 | } | ||
916 | else if (discard_level < mCurrentDiscardLevel) | ||
917 | { | ||
918 | // larger image | ||
919 | dump(); | ||
920 | llerrs << "LLImageGL::setDiscardLevel() called with larger discard level; use createGLTexture()" << llendl; | ||
921 | return FALSE; | ||
922 | } | ||
923 | else if (mUseMipMaps) | ||
924 | { | ||
925 | LLPointer<LLImageRaw> imageraw = new LLImageRaw; | ||
926 | while(discard_level > mCurrentDiscardLevel) | ||
927 | { | ||
928 | if (readBackRaw(discard_level, imageraw)) | ||
929 | { | ||
930 | break; | ||
931 | } | ||
932 | discard_level--; | ||
933 | } | ||
934 | if (discard_level == mCurrentDiscardLevel) | ||
935 | { | ||
936 | // unable to increase the discard level | ||
937 | return FALSE; | ||
938 | } | ||
939 | return createGLTexture(discard_level, imageraw); | ||
940 | } | ||
941 | else | ||
942 | { | ||
943 | #ifndef LL_LINUX // *FIX: This should not be skipped for the linux client. | ||
944 | llerrs << "LLImageGL::setDiscardLevel() called on image without mipmaps" << llendl; | ||
945 | #endif | ||
946 | return FALSE; | ||
947 | } | ||
948 | } | ||
949 | |||
950 | BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw) | ||
951 | { | ||
952 | if (discard_level < 0) | ||
953 | { | ||
954 | discard_level = mCurrentDiscardLevel; | ||
955 | } | ||
956 | |||
957 | if (mTexName == 0 || discard_level < mCurrentDiscardLevel) | ||
958 | { | ||
959 | return FALSE; | ||
960 | } | ||
961 | |||
962 | S32 gl_discard = discard_level - mCurrentDiscardLevel; | ||
963 | |||
964 | llverify(bindTextureInternal(0)); | ||
965 | |||
966 | LLGLint glwidth = 0; | ||
967 | glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth); | ||
968 | if (glwidth == 0) | ||
969 | { | ||
970 | // No mip data smaller than current discard level | ||
971 | return FALSE; | ||
972 | } | ||
973 | |||
974 | S32 width = getWidth(discard_level); | ||
975 | S32 height = getHeight(discard_level); | ||
976 | S32 ncomponents = getComponents(); | ||
977 | if (ncomponents == 0) | ||
978 | { | ||
979 | return FALSE; | ||
980 | } | ||
981 | |||
982 | if (width <= 0 || width > 2048 || height <= 0 || height > 2048 || ncomponents < 1 || ncomponents > 4) | ||
983 | { | ||
984 | llerrs << llformat("LLImageGL::readBackRaw: bogus params: %d x %d x %d",width,height,ncomponents) << llendl; | ||
985 | } | ||
986 | |||
987 | LLGLint is_compressed = 0; | ||
988 | glGetTexLevelParameteriv(mTarget, is_compressed, GL_TEXTURE_COMPRESSED, (GLint*)&is_compressed); | ||
989 | if (is_compressed) | ||
990 | { | ||
991 | LLGLint glbytes; | ||
992 | glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint*)&glbytes); | ||
993 | imageraw->allocateDataSize(width, height, ncomponents, glbytes); | ||
994 | glGetCompressedTexImageARB(mTarget, gl_discard, (GLvoid*)(imageraw->getData())); | ||
995 | stop_glerror(); | ||
996 | } | ||
997 | else | ||
998 | { | ||
999 | imageraw->allocateDataSize(width, height, ncomponents); | ||
1000 | glGetTexImage(GL_TEXTURE_2D, gl_discard, mFormatPrimary, mFormatType, (GLvoid*)(imageraw->getData())); | ||
1001 | stop_glerror(); | ||
1002 | } | ||
1003 | |||
1004 | return TRUE; | ||
1005 | } | ||
1006 | |||
1007 | void LLImageGL::destroyGLTexture() | ||
1008 | { | ||
1009 | stop_glerror(); | ||
1010 | |||
1011 | if (mTexName != 0) | ||
1012 | { | ||
1013 | for (int i = 0; i < gGLManager.mNumTextureUnits; i++) | ||
1014 | { | ||
1015 | if (sCurrentBoundTextures[i] == mTexName) | ||
1016 | { | ||
1017 | unbindTexture(i, GL_TEXTURE_2D); | ||
1018 | stop_glerror(); | ||
1019 | } | ||
1020 | } | ||
1021 | |||
1022 | sGlobalTextureMemory -= mTextureMemory; | ||
1023 | mTextureMemory = 0; | ||
1024 | |||
1025 | glDeleteTextures(1, (GLuint*)&mTexName); | ||
1026 | mTexName = 0; | ||
1027 | |||
1028 | stop_glerror(); | ||
1029 | } | ||
1030 | } | ||
1031 | |||
1032 | //---------------------------------------------------------------------------- | ||
1033 | |||
1034 | void LLImageGL::setClamp(BOOL clamps, BOOL clampt) | ||
1035 | { | ||
1036 | mClampS = clamps; | ||
1037 | mClampT = clampt; | ||
1038 | if (mTexName != 0) | ||
1039 | { | ||
1040 | glTexParameteri(mBindTarget, GL_TEXTURE_WRAP_S, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT); | ||
1041 | glTexParameteri(mBindTarget, GL_TEXTURE_WRAP_T, clampt ? GL_CLAMP_TO_EDGE : GL_REPEAT); | ||
1042 | } | ||
1043 | stop_glerror(); | ||
1044 | } | ||
1045 | |||
1046 | void LLImageGL::setMipFilterNearest(BOOL nearest, BOOL min_nearest) | ||
1047 | { | ||
1048 | mMipFilterNearest = nearest; | ||
1049 | |||
1050 | if (mTexName != 0) | ||
1051 | { | ||
1052 | if (min_nearest) | ||
1053 | { | ||
1054 | glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||
1055 | } | ||
1056 | else if (mHasMipMaps) | ||
1057 | { | ||
1058 | glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | ||
1059 | } | ||
1060 | else | ||
1061 | { | ||
1062 | glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||
1063 | } | ||
1064 | if (mMipFilterNearest) | ||
1065 | { | ||
1066 | glTexParameteri(mBindTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||
1067 | } | ||
1068 | else | ||
1069 | { | ||
1070 | glTexParameteri(mBindTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||
1071 | } | ||
1072 | if (gGLManager.mHasAnisotropic) | ||
1073 | { | ||
1074 | if (sGlobalUseAnisotropic && !mMipFilterNearest) | ||
1075 | { | ||
1076 | F32 largest_anisotropy; | ||
1077 | glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_anisotropy); | ||
1078 | glTexParameterf(mBindTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_anisotropy); | ||
1079 | } | ||
1080 | else | ||
1081 | { | ||
1082 | glTexParameterf(mBindTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f); | ||
1083 | } | ||
1084 | } | ||
1085 | } | ||
1086 | |||
1087 | stop_glerror(); | ||
1088 | } | ||
1089 | |||
1090 | BOOL LLImageGL::getIsResident(BOOL test_now) | ||
1091 | { | ||
1092 | if (test_now) | ||
1093 | { | ||
1094 | if (mTexName != 0) | ||
1095 | { | ||
1096 | glAreTexturesResident(1, (GLuint*)&mTexName, &mIsResident); | ||
1097 | } | ||
1098 | else | ||
1099 | { | ||
1100 | mIsResident = FALSE; | ||
1101 | } | ||
1102 | } | ||
1103 | |||
1104 | return mIsResident; | ||
1105 | } | ||
1106 | |||
1107 | S32 LLImageGL::getHeight(S32 discard_level) const | ||
1108 | { | ||
1109 | if (discard_level < 0) | ||
1110 | { | ||
1111 | discard_level = mCurrentDiscardLevel; | ||
1112 | } | ||
1113 | S32 height = mHeight >> discard_level; | ||
1114 | if (height < 1) height = 1; | ||
1115 | return height; | ||
1116 | } | ||
1117 | |||
1118 | S32 LLImageGL::getWidth(S32 discard_level) const | ||
1119 | { | ||
1120 | if (discard_level < 0) | ||
1121 | { | ||
1122 | discard_level = mCurrentDiscardLevel; | ||
1123 | } | ||
1124 | S32 width = mWidth >> discard_level; | ||
1125 | if (width < 1) width = 1; | ||
1126 | return width; | ||
1127 | } | ||
1128 | |||
1129 | S32 LLImageGL::getBytes(S32 discard_level) const | ||
1130 | { | ||
1131 | if (discard_level < 0) | ||
1132 | { | ||
1133 | discard_level = mCurrentDiscardLevel; | ||
1134 | } | ||
1135 | S32 w = mWidth>>discard_level; | ||
1136 | S32 h = mHeight>>discard_level; | ||
1137 | if (w == 0) w = 1; | ||
1138 | if (h == 0) h = 1; | ||
1139 | return dataFormatBytes(mFormatPrimary, w, h); | ||
1140 | } | ||
1141 | |||
1142 | S32 LLImageGL::getMipBytes(S32 discard_level) const | ||
1143 | { | ||
1144 | if (discard_level < 0) | ||
1145 | { | ||
1146 | discard_level = mCurrentDiscardLevel; | ||
1147 | } | ||
1148 | S32 w = mWidth>>discard_level; | ||
1149 | S32 h = mHeight>>discard_level; | ||
1150 | S32 res = dataFormatBytes(mFormatPrimary, w, h); | ||
1151 | if (mUseMipMaps) | ||
1152 | { | ||
1153 | while (w > 1 && h > 1) | ||
1154 | { | ||
1155 | w >>= 1; if (w == 0) w = 1; | ||
1156 | h >>= 1; if (h == 0) h = 1; | ||
1157 | res += dataFormatBytes(mFormatPrimary, w, h); | ||
1158 | } | ||
1159 | } | ||
1160 | return res; | ||
1161 | } | ||
1162 | |||
1163 | BOOL LLImageGL::getBoundRecently() const | ||
1164 | { | ||
1165 | return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME); | ||
1166 | } | ||
1167 | |||
1168 | void LLImageGL::setTarget(const LLGLenum target, const LLGLenum bind_target) | ||
1169 | { | ||
1170 | mTarget = target; | ||
1171 | mBindTarget = bind_target; | ||
1172 | } | ||
1173 | |||
1174 | //---------------------------------------------------------------------------- | ||
1175 | |||
1176 | // Manual Mip Generation | ||
1177 | /* | ||
1178 | S32 width = getWidth(discard_level); | ||
1179 | S32 height = getHeight(discard_level); | ||
1180 | S32 w = width, h = height; | ||
1181 | S32 nummips = 1; | ||
1182 | while (w > 4 && h > 4) | ||
1183 | { | ||
1184 | w >>= 1; h >>= 1; | ||
1185 | nummips++; | ||
1186 | } | ||
1187 | stop_glerror(); | ||
1188 | w = width, h = height; | ||
1189 | const U8* prev_mip_data = 0; | ||
1190 | const U8* cur_mip_data = 0; | ||
1191 | for (int m=0; m<nummips; m++) | ||
1192 | { | ||
1193 | if (m==0) | ||
1194 | { | ||
1195 | cur_mip_data = rawdata; | ||
1196 | } | ||
1197 | else | ||
1198 | { | ||
1199 | S32 bytes = w * h * mComponents; | ||
1200 | U8* new_data = new U8[bytes]; | ||
1201 | LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents); | ||
1202 | cur_mip_data = new_data; | ||
1203 | } | ||
1204 | llassert(w > 0 && h > 0 && cur_mip_data); | ||
1205 | U8 test = cur_mip_data[w*h*mComponents-1]; | ||
1206 | { | ||
1207 | glTexImage2D(mTarget, m, mFormatInternal, w, h, 0, mFormatPrimary, mFormatType, cur_mip_data); | ||
1208 | stop_glerror(); | ||
1209 | } | ||
1210 | if (prev_mip_data && prev_mip_data != rawdata) | ||
1211 | { | ||
1212 | delete prev_mip_data; | ||
1213 | } | ||
1214 | prev_mip_data = cur_mip_data; | ||
1215 | w >>= 1; | ||
1216 | h >>= 1; | ||
1217 | } | ||
1218 | if (prev_mip_data && prev_mip_data != rawdata) | ||
1219 | { | ||
1220 | delete prev_mip_data; | ||
1221 | } | ||
1222 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); | ||
1223 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, nummips); | ||
1224 | */ | ||