nux-1.14.0
|
00001 /* 00002 * Copyright 2010 Inalogic® Inc. 00003 * 00004 * This program is free software: you can redistribute it and/or modify it 00005 * under the terms of the GNU Lesser General Public License, as 00006 * published by the Free Software Foundation; either version 2.1 or 3.0 00007 * of the License. 00008 * 00009 * This program is distributed in the hope that it will be useful, but 00010 * WITHOUT ANY WARRANTY; without even the implied warranties of 00011 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR 00012 * PURPOSE. See the applicable version of the GNU Lesser General Public 00013 * License for more details. 00014 * 00015 * You should have received a copy of both the GNU Lesser General Public 00016 * License along with this program. If not, see <http://www.gnu.org/licenses/> 00017 * 00018 * Authored by: Jay Taoko <jaytaoko@inalogic.com> 00019 * 00020 */ 00021 00022 00023 #include "GLDeviceObjects.h" 00024 #include "IOpenGLVolume.h" 00025 #include "GraphicsDisplay.h" 00026 #include "GpuDevice.h" 00027 00028 namespace nux 00029 { 00030 00031 NUX_IMPLEMENT_OBJECT_TYPE (IOpenGLVolume); 00032 00033 IOpenGLVolume::~IOpenGLVolume() 00034 { 00035 00036 } 00037 00038 int IOpenGLVolume::RefCount() const 00039 { 00040 if (_VolumeTexture) 00041 return _VolumeTexture->RefCount(); 00042 00043 nuxAssert (0); // Surface with no underlying texture. That should not happen. 00044 return 0; 00045 } 00046 00047 int IOpenGLVolume::LockBox ( 00048 VOLUME_LOCKED_BOX *pLockedVolume, 00049 const VOLUME_BOX *pBox) 00050 00051 { 00052 // If _LockedRect.pBits or _LockedRect.Pitch are not equal to zero, then we have already Locked the buffer 00053 // Unlock it before locking again. 00054 nuxAssert (_LockedBox.pBits == 0); 00055 nuxAssert (_LockedBox.RowPitch == 0); 00056 //nuxAssert(_LockedBox.SlicePitch == 0); 00057 nuxAssert (_CompressedDataSize == 0); 00058 00059 if ( (_LockedBox.pBits != 0) || (_LockedBox.RowPitch != 0) || (_CompressedDataSize != 0) ) 00060 { 00061 // already locked; 00062 return OGL_INVALID_LOCK; 00063 } 00064 00065 _Box.Front = _Box.Back = _Box.Bottom = _Box.Left = _Box.Right = _Box.Top = 0; 00066 00067 //GLint unpack_alignment = GPixelFormats[_VolumeTexture->_PixelFormat].RowMemoryAlignment; 00068 00069 00070 CHECKGL ( glBindTexture (_STextureTarget, _VolumeTexture->_OpenGLID) ); 00071 00072 unsigned int surface_size = 0; 00073 00074 00075 IOpenGLVolumeTexture *texture = _VolumeTexture; 00076 00077 if (_VolumeTexture->_ResourceType != RTVOLUMETEXTURE) 00078 { 00079 nuxAssertMsg (0, TEXT ("Unknown resource type") ); 00080 } 00081 00082 int texwidth, texheight; 00083 texwidth = ImageSurface::GetLevelWidth (texture->_PixelFormat, texture->_Width, _SMipLevel); 00084 texheight = ImageSurface::GetLevelHeight (texture->_PixelFormat, texture->_Height, _SMipLevel); 00085 00086 if ( texture->_PixelFormat == BITFMT_DXT1 || 00087 texture->_PixelFormat == BITFMT_DXT2 || 00088 texture->_PixelFormat == BITFMT_DXT3 || 00089 texture->_PixelFormat == BITFMT_DXT4 || 00090 texture->_PixelFormat == BITFMT_DXT5) 00091 { 00092 if (texture->_PixelFormat == BITFMT_DXT1) 00093 { 00094 // We can conceive a 4x4 DXT1 block as if each texel uses 4 bits. 00095 // Actually, for DXT, we have 2 16-bits colors(5:6:5), and each texel uses 2 bits to interpolate 00096 // between the 2 colors. 00097 // --------------------- 00098 // | COLOR0 | 16 bits 00099 // --------------------- 00100 // | COLOR1 | 16 bits 00101 // --------------------- 00102 // | xx | xx | xx | xx | xx = 2 bits 00103 // --------------------- 00104 // | xx | xx | xx | xx | 00105 // --------------------- 00106 // | xx | xx | xx | xx | 00107 // --------------------- 00108 // | xx | xx | xx | xx | 00109 // --------------------- 00110 00111 // A line of n texel DXT1 data uses n/2 bytes (4 bits/texel). So the number of bytes used for a 00112 // texwidth texel, is texwidth/2 bytes. 00113 // Note that texwidth is divisible by 4(to to the upper rounding to 4), therefore, it is also divisible 00114 // by 2. 00115 00116 // glCompressedTexImage2DARB, glCompressedTexImage3DARB, 00117 // glCompressedTexSubImage2DARB, glCompressedTexSubImage3DARB are not affected by glPixelStorei. 00118 surface_size = ImageSurface::GetLevelSize (texture->_PixelFormat, texture->_Width, texture->_Height, _SMipLevel); 00119 _LockedBox.RowPitch = ImageSurface::GetLevelPitch (texture->_PixelFormat, texture->_Width, texture->_Height, _SMipLevel); 00120 00121 if (_Initialized == false) 00122 { 00123 InitializeLevel(); 00124 } 00125 } 00126 else 00127 { 00128 // A line of n texel DXT3/5 data uses n bytes (1 byte/texel). So the number of bytes used for a 00129 // texwidth texels, is texwidth bytes. 00130 00131 // glCompressedTexImage2DARB, glCompressedTexImage3DARB, 00132 // glCompressedTexSubImage2DARB, glCompressedTexSubImage3DARB are not affected by glPixelStorei. 00133 surface_size = ImageSurface::GetLevelSize (texture->_PixelFormat, texture->_Width, texture->_Height, _SMipLevel); 00134 _LockedBox.RowPitch = ImageSurface::GetLevelPitch (texture->_PixelFormat, texture->_Width, texture->_Height, _SMipLevel); 00135 00136 if (_Initialized == false) 00137 { 00138 InitializeLevel(); 00139 } 00140 } 00141 } 00142 else 00143 { 00144 _LockedBox.RowPitch = ImageSurface::GetLevelPitch (texture->_PixelFormat, texture->_Width, texture->_Height, _SMipLevel); 00145 surface_size = ImageSurface::GetLevelSize (texture->_PixelFormat, texture->_Width, texture->_Height, _SMipLevel); 00146 00147 if (_Initialized == false) 00148 { 00149 InitializeLevel(); 00150 } 00151 } 00152 00153 00154 _Box.Left = 0; 00155 _Box.Top = 0; 00156 _Box.Bottom = texheight; 00157 _Box.Right = texwidth; 00158 _Box.Front = 0; 00159 _Box.Back = ImageSurface::GetLevelDim (texture->_PixelFormat, texture->GetDepth(), _SMipLevel); 00160 00161 if (GetGraphicsDisplay()->GetGpuDevice()->UsePixelBufferObjects() ) 00162 { 00163 GetGraphicsDisplay()->GetGpuDevice()->AllocateUnpackPixelBufferIndex (&_AllocatedUnpackBuffer); 00164 } 00165 00166 if (pBox == 0) 00167 { 00168 _CompressedDataSize = GetDepth() * surface_size; 00169 00170 if (GetGraphicsDisplay()->GetGpuDevice()->UsePixelBufferObjects() ) 00171 { 00172 // Mapping the entire area of the surface 00173 if (1) 00174 { 00175 _LockedBox.pBits = GetGraphicsDisplay()->GetGpuDevice()->LockUnpackPixelBufferIndex (_AllocatedUnpackBuffer, _CompressedDataSize); 00176 } 00177 else 00178 { 00179 GetGraphicsDisplay()->GetGpuDevice()->BindUnpackPixelBufferIndex (_AllocatedUnpackBuffer); 00180 CHECKGL ( glBufferDataARB (GL_PIXEL_UNPACK_BUFFER_ARB, _CompressedDataSize, NULL, GL_STREAM_DRAW_ARB) ); 00181 _LockedBox.pBits = glMapBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB); 00182 CHECKGL_MSG (glMapBufferARB ); 00183 CHECKGL ( glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, 0) ); 00184 } 00185 00186 pLockedVolume->pBits = _LockedBox.pBits; 00187 pLockedVolume->RowPitch = _LockedBox.RowPitch; 00188 pLockedVolume->SlicePitch = surface_size; 00189 } 00190 else 00191 { 00192 //[DEBUGGING - NO PBO] 00193 // Mapping the entire area of the surface 00194 _LockedBox.pBits = new BYTE[_CompressedDataSize]; 00195 pLockedVolume->pBits = _LockedBox.pBits; 00196 pLockedVolume->RowPitch = _LockedBox.RowPitch; 00197 pLockedVolume->SlicePitch = surface_size; 00198 } 00199 } 00200 else 00201 { 00202 nuxAssert (pBox->Front >= 0); 00203 nuxAssert (pBox->Back <= GetDepth() ); 00204 nuxAssert (pBox->Front < pBox->Back); 00205 00206 int RectWidth = pBox->Right - pBox->Left; 00207 int RectHeight = pBox->Bottom - pBox->Top; 00208 int NumSlice = pBox->Back - pBox->Front; 00209 00210 nuxAssert (RectWidth >= 0); 00211 nuxAssert (RectHeight >= 0); 00212 nuxAssert (NumSlice >= 0); 00213 00214 00215 00216 unsigned int RectSize = ImageSurface::GetLevelSize (GetPixelFormat(), RectWidth, RectHeight, 0); //(((RectWidth * BytePerPixel + (unpack_alignment-1)) >> (halfUnpack)) << (halfUnpack)) * RectHeight; 00217 00218 if (RectSize == 0) 00219 { 00220 pLockedVolume->pBits = 0; 00221 pLockedVolume->RowPitch = 0; 00222 return OGL_INVALID_LOCK; 00223 } 00224 00225 _CompressedDataSize = NumSlice * RectSize; 00226 00227 if (GetGraphicsDisplay()->GetGpuDevice()->UsePixelBufferObjects() ) 00228 { 00229 _LockedBox.pBits = GetGraphicsDisplay()->GetGpuDevice()->LockUnpackPixelBufferIndex (_AllocatedUnpackBuffer, NumSlice * RectSize); 00230 00231 // GetGraphicsDisplay()->GetGpuDevice()->BindUnpackPixelBufferIndex(_AllocatedUnpackBuffer); 00232 // CHECKGL( glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, NumSlice * RectSize, NULL, GL_STATIC_DRAW_ARB) ); 00233 // _LockedBox.pBits = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY); 00234 // CHECKGL_MSG(glMapBufferARB ); 00235 // CHECKGL( glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0) ); 00236 00237 pLockedVolume->pBits = ( (BYTE *) _LockedBox.pBits); 00238 pLockedVolume->RowPitch = ImageSurface::GetLevelPitch (GetPixelFormat(), RectWidth, RectHeight, 0); //(((RectWidth * BytePerPixel + (unpack_alignment-1)) >> (halfUnpack)) << (halfUnpack)); 00239 pLockedVolume->SlicePitch = RectSize; 00240 } 00241 else 00242 { 00243 //[DEBUGGING - NO PBO] 00244 _LockedBox.pBits = new BYTE[_CompressedDataSize]; 00245 pLockedVolume->pBits = ( (BYTE *) _LockedBox.pBits); 00246 pLockedVolume->RowPitch = ImageSurface::GetLevelPitch (GetPixelFormat(), RectWidth, RectHeight, 0); //(((RectWidth * BytePerPixel + (unpack_alignment-1)) >> (halfUnpack)) << (halfUnpack)); 00247 pLockedVolume->SlicePitch = RectSize; 00248 } 00249 00250 _Box.Left = pBox->Left; 00251 _Box.Top = pBox->Top; 00252 _Box.Bottom = pBox->Bottom; 00253 _Box.Right = pBox->Right; 00254 _Box.Front = pBox->Front; 00255 _Box.Back = pBox->Back; 00256 } 00257 00258 return OGL_OK; 00259 } 00260 00261 int IOpenGLVolume::UnlockBox() 00262 { 00263 if (_LockedBox.pBits == 0) 00264 { 00265 return OGL_INVALID_UNLOCK; 00266 } 00267 00268 int MemAlignment = ImageSurface::GetMemAlignment (_VolumeTexture->_PixelFormat); 00269 CHECKGL ( glPixelStorei (GL_UNPACK_ALIGNMENT, MemAlignment) ); 00270 nuxAssert (MemAlignment == _VolumeTexture->GetFormatRowMemoryAlignment() ); 00271 00272 BYTE *DataPtr = 0; 00273 00274 if (_STextureTarget == GL_TEXTURE_3D) 00275 { 00276 CHECKGL ( glBindTexture (_STextureTarget, _VolumeTexture->_OpenGLID) ); 00277 00278 if (GetGraphicsDisplay()->GetGpuDevice()->UsePixelBufferObjects() ) 00279 { 00280 // Unmap the texture image buffer 00281 GetGraphicsDisplay()->GetGpuDevice()->BindUnpackPixelBufferIndex (_AllocatedUnpackBuffer); 00282 CHECKGL ( glUnmapBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB) ); 00283 DataPtr = NUX_BUFFER_OFFSET (0); 00284 } 00285 else 00286 { 00287 CHECKGL ( glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, 0) ); 00288 DataPtr = (BYTE *) _LockedBox.pBits; 00289 } 00290 00291 IOpenGLTexture2D *texture = (IOpenGLTexture2D *) _VolumeTexture; 00292 int width = _Box.Right - _Box.Left; 00293 int height = _Box.Bottom - _Box.Top; 00294 int depth = _Box.Back - _Box.Front; 00295 int xoffset = _Box.Left; 00296 int yoffset = _Box.Top; 00297 int zoffset = _Box.Front; 00298 00299 if ( texture->_PixelFormat == BITFMT_DXT1 || 00300 texture->_PixelFormat == BITFMT_DXT2 || 00301 texture->_PixelFormat == BITFMT_DXT3 || 00302 texture->_PixelFormat == BITFMT_DXT4 || 00303 texture->_PixelFormat == BITFMT_DXT5) 00304 { 00305 nuxAssert (_CompressedDataSize != 0); 00306 // This part does not work. The image is messed up. 00307 // Driver bug??? Tried glCompressedTexImage3DARB. Same result. 00308 // But I know the data that is loaded is correct. 00309 glCompressedTexSubImage3DARB (_SSurfaceTarget, 00310 _SMipLevel, // level 00311 xoffset, 00312 yoffset, 00313 zoffset, 00314 width, 00315 height, 00316 depth, 00317 GPixelFormats[texture->_PixelFormat].PlatformFormat, 00318 _CompressedDataSize, // image Size 00319 DataPtr // data 00320 ); 00321 CHECKGL_MSG (glCompressedTexSubImage3DARB); 00322 00323 // glCompressedTexImage3DARB(_SSurfaceTarget, 00324 // _SMipLevel, // level 00325 // GPixelFormats[texture->_PixelFormat].PlatformFormat, 00326 // width, 00327 // height, 00328 // depth, 00329 // 0, // border 00330 // _CompressedDataSize, // image Size 00331 // DataPtr // data 00332 // ); 00333 // CHECKGL_MSG(glCompressedTexImage2DARB); 00334 } 00335 else 00336 { 00337 CHECKGL ( glTexSubImage3D (_SSurfaceTarget, 00338 _SMipLevel, 00339 xoffset, 00340 yoffset, 00341 zoffset, // z offset 00342 width, 00343 height, 00344 depth, 00345 GPixelFormats[texture->_PixelFormat].Format, 00346 GPixelFormats[texture->_PixelFormat].type, 00347 DataPtr 00348 ) ); 00349 } 00350 } 00351 else 00352 { 00353 nuxAssertMsg (0, TEXT ("Incorrect Texture Target.") ); 00354 } 00355 00356 if (GetGraphicsDisplay()->GetGpuDevice()->UsePixelBufferObjects() ) 00357 { 00358 CHECKGL ( glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, 0) ); 00359 GetGraphicsDisplay()->GetGpuDevice()->FreeUnpackPixelBufferIndex (_AllocatedUnpackBuffer); 00360 } 00361 else 00362 { 00363 //[DEBUGGING - NO PBO] 00364 if (_LockedBox.pBits) 00365 { 00366 delete [] ( (BYTE *) _LockedBox.pBits); 00367 } 00368 } 00369 00370 CHECKGL ( glPixelStorei (GL_UNPACK_ALIGNMENT, GetGraphicsDisplay()->GetGpuDevice()->GetPixelStoreAlignment() ) ); 00371 00372 _LockedBox.pBits = 0; 00373 _LockedBox.RowPitch = 0; 00374 _CompressedDataSize = 0; 00375 00376 return OGL_OK; 00377 } 00378 00379 int IOpenGLVolume::InitializeLevel() 00380 { 00381 // Because we use SubImage when unlocking surfaces, we must first get some dummy data in the surface before we can make a lock. 00382 int volwidth = ImageSurface::GetLevelDim (_VolumeTexture->_PixelFormat, _VolumeTexture->_Width, _SMipLevel); 00383 int volheight = ImageSurface::GetLevelDim (_VolumeTexture->_PixelFormat, _VolumeTexture->_Height, _SMipLevel); 00384 int voldepth = ImageSurface::GetLevelDim (_VolumeTexture->_PixelFormat, _VolumeTexture->_Depth, _SMipLevel); 00385 int size = ImageSurface::GetLevelSize ( 00386 _VolumeTexture->_PixelFormat, 00387 _VolumeTexture->_Width, 00388 _VolumeTexture->_Height, 00389 _VolumeTexture->_Depth, 00390 _SMipLevel); 00391 00392 int MemAlignment = ImageSurface::GetMemAlignment (_VolumeTexture->_PixelFormat); 00393 00394 nuxAssert ( volwidth > 0 ); // Should never happen 00395 nuxAssert ( volheight > 0 ); // Should never happen 00396 nuxAssert ( voldepth > 0 ); // Should never happen 00397 nuxAssert ( size > 0 ); // Should never happen 00398 00399 BYTE *DummyBuffer = new BYTE[size]; 00400 Memset (DummyBuffer, 0, size); 00401 00402 CHECKGL ( glPixelStorei (GL_UNPACK_ALIGNMENT, MemAlignment) ); 00403 00404 if ( _VolumeTexture->_PixelFormat == BITFMT_DXT1 || 00405 _VolumeTexture->_PixelFormat == BITFMT_DXT2 || 00406 _VolumeTexture->_PixelFormat == BITFMT_DXT3 || 00407 _VolumeTexture->_PixelFormat == BITFMT_DXT4 || 00408 _VolumeTexture->_PixelFormat == BITFMT_DXT5) 00409 { 00410 { 00411 glCompressedTexImage3DARB ( 00412 _SSurfaceTarget, 00413 _SMipLevel, // level 00414 GPixelFormats[_VolumeTexture->_PixelFormat].PlatformFormat, 00415 volwidth, 00416 volheight, 00417 voldepth, 00418 0, // border 00419 size, // image Size 00420 DummyBuffer // data 00421 ); 00422 CHECKGL_MSG (glCompressedTexImage3DARB); 00423 } 00424 } 00425 else 00426 { 00427 glTexImage3D ( 00428 _SSurfaceTarget, 00429 _SMipLevel, // level 00430 GPixelFormats[_VolumeTexture->_PixelFormat].PlatformFormat, 00431 volwidth, 00432 volheight, 00433 voldepth, 00434 0, // border 00435 GPixelFormats[_VolumeTexture->_PixelFormat].Format, 00436 GPixelFormats[_VolumeTexture->_PixelFormat].type, 00437 DummyBuffer); 00438 CHECKGL_MSG (glTexImage3D); 00439 } 00440 00441 delete [] DummyBuffer; 00442 00443 00444 // { //[DEBUGGING - Red Texture] 00445 // // This is going to put some red in the texture. 00446 // // The texture is not compressed. 00447 // BYTE *color_array = new BYTE[texwidth*texheight*4]; 00448 // for(unsigned int i = 0; i < texwidth*texheight*4; i += 4) 00449 // { 00450 // color_array[i + 0] = 0xff; 00451 // color_array[i + 1] = _SMipLevel * 0x3F; 00452 // color_array[i + 2] = 0x0; 00453 // color_array[i + 3] = 0xFF; 00454 // } 00455 // glTexImage2D(GL_TEXTURE_2D, 00456 // _SMipLevel, 00457 // GL_RGBA8, texwidth, texheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, color_array); 00458 // CHECKGL_MSG(glTexImage2D); 00459 // delete [] color_array; 00460 // } 00461 00462 CHECKGL ( glPixelStorei (GL_UNPACK_ALIGNMENT, GetGraphicsDisplay()->GetGpuDevice()->GetPixelStoreAlignment() ) ); 00463 00464 _Initialized = true; 00465 return OGL_OK; 00466 } 00467 00468 BitmapFormat IOpenGLVolume::GetPixelFormat() const 00469 { 00470 if (_VolumeTexture == 0) 00471 return BITFMT_UNKNOWN; 00472 else 00473 return _VolumeTexture->GetPixelFormat(); 00474 } 00475 00476 int IOpenGLVolume::GetWidth() const 00477 { 00478 if (_VolumeTexture->_ResourceType == RTVOLUMETEXTURE) 00479 return ImageSurface::GetLevelDim (_VolumeTexture->_PixelFormat, _VolumeTexture->_Width, _SMipLevel); 00480 00481 nuxAssert (0); // Should not happen 00482 return 0; 00483 } 00484 00485 int IOpenGLVolume::GetHeight() const 00486 { 00487 if (_VolumeTexture->_ResourceType == RTVOLUMETEXTURE) 00488 return ImageSurface::GetLevelDim (_VolumeTexture->_PixelFormat, _VolumeTexture->_Height, _SMipLevel); 00489 00490 nuxAssert (0); // Should not happen 00491 return 0; 00492 } 00493 00494 int IOpenGLVolume::GetDepth() const 00495 { 00496 if (_VolumeTexture->_ResourceType == RTVOLUMETEXTURE) 00497 return ImageSurface::GetLevelDim (_VolumeTexture->_PixelFormat, _VolumeTexture->_Depth, _SMipLevel); 00498 00499 nuxAssert (0); // Should not happen 00500 return 0; 00501 } 00502 00503 }