nux-1.14.0
IOpenGLVolume.cpp
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 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends