aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llrender/llimagegl.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llrender/llimagegl.cpp
parentREADME.txt (diff)
downloadmeta-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.cpp1224
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
43const F32 MIN_TEXTURE_LIFETIME = 10.f;
44
45//statics
46LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 };
47
48S32 LLImageGL::sGlobalTextureMemory = 0;
49S32 LLImageGL::sBoundTextureMemory = 0;
50S32 LLImageGL::sCurBoundTextureMemory = 0;
51S32 LLImageGL::sCount = 0;
52
53BOOL LLImageGL::sGlobalUseAnisotropic = FALSE;
54F32 LLImageGL::sLastFrameTime = 0.f;
55
56std::set<LLImageGL*> LLImageGL::sImageList;
57
58//----------------------------------------------------------------------------
59
60//static
61S32 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
83S32 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
97S32 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
120void 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
129void 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
138void LLImageGL::updateStats(F32 current_time)
139{
140 sLastFrameTime = current_time;
141 sBoundTextureMemory = sCurBoundTextureMemory;
142 sCurBoundTextureMemory = 0;
143}
144
145//static
146S32 LLImageGL::updateBoundTexMem(const S32 delta)
147{
148 LLImageGL::sCurBoundTextureMemory += delta;
149 return LLImageGL::sCurBoundTextureMemory;
150}
151
152//----------------------------------------------------------------------------
153
154//static
155void 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
179void 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
200BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, BOOL usemipmaps)
201{
202 dest = new LLImageGL(usemipmaps);
203 return TRUE;
204}
205
206BOOL 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
212BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps)
213{
214 dest = new LLImageGL(imageraw, usemipmaps);
215 return TRUE;
216}
217
218//----------------------------------------------------------------------------
219
220LLImageGL::LLImageGL(BOOL usemipmaps)
221 : mSaveData(0)
222{
223 init(usemipmaps);
224 setSize(0, 0, 0);
225 sImageList.insert(this);
226 sCount++;
227}
228
229LLImageGL::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
239LLImageGL::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
249LLImageGL::~LLImageGL()
250{
251 LLImageGL::cleanup();
252 sImageList.erase(this);
253 sCount--;
254}
255
256void 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
290void LLImageGL::cleanup()
291{
292 if (!gGLManager.mIsDisabled)
293 {
294 destroyGLTexture();
295 }
296 mSaveData = NULL; // deletes data
297}
298
299//----------------------------------------------------------------------------
300
301static 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
315bool LLImageGL::checkSize(S32 width, S32 height)
316{
317 return check_power_of_two(width) && check_power_of_two(height);
318}
319
320void 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
359void 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
386BOOL 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
434BOOL 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
445void 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
461void 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
470void 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
656BOOL 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
740BOOL 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
746BOOL 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
760BOOL 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
819BOOL 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
899BOOL 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
950BOOL 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
1007void 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
1034void 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
1046void 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
1090BOOL 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
1107S32 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
1118S32 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
1129S32 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
1142S32 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
1163BOOL LLImageGL::getBoundRecently() const
1164{
1165 return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME);
1166}
1167
1168void 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*/