Back to index

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