void GlyphTexture::apply(osg::State& state) const { // get the contextID (user defined ID of 0 upwards) for the // current OpenGL context. const unsigned int contextID = state.getContextID(); if (contextID>=_glyphsToSubload.size()) { OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); // graphics context is beyond the number of glyphsToSubloads, so // we must now copy the glyph list across, this is a potential // threading issue though is multiple applies are happening the // same time on this object - to avoid this condition number of // graphics contexts should be set before create text. for(unsigned int i=_glyphsToSubload.size();i<=contextID;++i) { GlyphPtrList& glyphPtrs = _glyphsToSubload[i]; for(GlyphRefList::const_iterator itr=_glyphs.begin(); itr!=_glyphs.end(); ++itr) { glyphPtrs.push_back(itr->get()); } } } const Extensions* extensions = getExtensions(contextID,true); bool generateMipMapSupported = extensions->isGenerateMipMapSupported(); // get the texture object for the current contextID. TextureObject* textureObject = getTextureObject(contextID); bool newTextureObject = (textureObject == 0); if (newTextureObject) { GLint maxTextureSize = 256; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); if (maxTextureSize < getTextureWidth() || maxTextureSize < getTextureHeight()) { OSG_WARN<<"Warning: osgText::Font texture size of ("<<getTextureWidth()<<", "<<getTextureHeight()<<") too large, unable to create font texture."<<std::endl; OSG_WARN<<" Maximum supported by hardward by native OpenGL implementation is ("<<maxTextureSize<<","<<maxTextureSize<<")."<<std::endl; OSG_WARN<<" Please set OSG_MAX_TEXTURE_SIZE lenvironment variable to "<<maxTextureSize<<" and re-run application."<<std::endl; return; } // being bound for the first time, need to allocate the texture _textureObjectBuffer[contextID] = textureObject = osg::Texture::generateTextureObject( this, contextID,GL_TEXTURE_2D,1,GL_ALPHA,getTextureWidth(), getTextureHeight(),1,0); textureObject->bind(); applyTexParameters(GL_TEXTURE_2D,state); // need to look at generate mip map extension if mip mapping required. switch(_min_filter) { case NEAREST_MIPMAP_NEAREST: case NEAREST_MIPMAP_LINEAR: case LINEAR_MIPMAP_NEAREST: case LINEAR_MIPMAP_LINEAR: if (generateMipMapSupported) { glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE); } else glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, LINEAR); break; default: // not mip mapping so no problems. break; } unsigned int imageDataSize = getTextureHeight()*getTextureWidth(); unsigned char* imageData = new unsigned char[imageDataSize]; for(unsigned int i=0; i<imageDataSize; ++i) { imageData[i] = 0; } // allocate the texture memory. glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, getTextureWidth(), getTextureHeight(), 0, GL_ALPHA, GL_UNSIGNED_BYTE, imageData ); delete [] imageData; } else { // reuse texture by binding. textureObject->bind(); if (getTextureParameterDirty(contextID)) { applyTexParameters(GL_TEXTURE_2D,state); } } static const GLubyte* s_renderer = 0; static bool s_subloadAllGlyphsTogether = false; if (!s_renderer) { OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); s_renderer = glGetString(GL_RENDERER); OSG_INFO<<"glGetString(GL_RENDERER)=="<<s_renderer<<std::endl; if (s_renderer && strstr((const char*)s_renderer,"IMPACT")!=0) { // we're running on an Octane, so need to work around its // subloading bugs by loading all at once. s_subloadAllGlyphsTogether = true; } if (s_renderer && ((strstr((const char*)s_renderer,"Radeon")!=0) || (strstr((const char*)s_renderer,"RADEON")!=0) || (strstr((const char*)s_renderer,"ALL-IN-WONDER")!=0))) { // we're running on an ATI, so need to work around its // subloading bugs by loading all at once. s_subloadAllGlyphsTogether = true; } if (s_renderer && strstr((const char*)s_renderer,"Sun")!=0) { // we're running on an solaris x server, so need to work around its // subloading bugs by loading all at once. s_subloadAllGlyphsTogether = true; } const char* str = getenv("OSG_TEXT_INCREMENTAL_SUBLOADING"); if (str) { s_subloadAllGlyphsTogether = strcmp(str,"OFF")==0 || strcmp(str,"Off")==0 || strcmp(str,"off")==0; } } // now subload the glyphs that are outstanding for this graphics context. GlyphPtrList& glyphsWereSubloading = _glyphsToSubload[contextID]; if (!glyphsWereSubloading.empty() || newTextureObject) { OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); if (!s_subloadAllGlyphsTogether) { if (newTextureObject) { for(GlyphRefList::const_iterator itr=_glyphs.begin(); itr!=_glyphs.end(); ++itr) { (*itr)->subload(); } } else // just subload the new entries. { // default way of subloading as required. //std::cout<<"subloading"<<std::endl; for(GlyphPtrList::iterator itr=glyphsWereSubloading.begin(); itr!=glyphsWereSubloading.end(); ++itr) { (*itr)->subload(); } } // clear the list since we have now subloaded them. glyphsWereSubloading.clear(); } else { OSG_INFO<<"osgText::Font loading all glyphs as a single subload."<<std::endl; // Octane has bugs in OGL driver which mean that subloads smaller // than 32x32 produce errors, and also cannot handle general alignment, // so to get round this copy all glyphs into a temporary image and // then subload the whole lot in one go. int tsize = getTextureHeight() * getTextureWidth(); unsigned char *local_data = new unsigned char[tsize]; memset( local_data, 0L, tsize); for(GlyphRefList::const_iterator itr=_glyphs.begin(); itr!=_glyphs.end(); ++itr) { //(*itr)->subload(); // Rather than subloading to graphics, we'll write the values // of the glyphs into some intermediate data and subload the // whole thing at the end for( int t = 0; t < (*itr)->t(); t++ ) { for( int s = 0; s < (*itr)->s(); s++ ) { int sindex = (t*(*itr)->s()+s); int dindex = ((((*itr)->getTexturePositionY()+t) * getTextureWidth()) + ((*itr)->getTexturePositionX()+s)); const unsigned char *sptr = &(*itr)->data()[sindex]; unsigned char *dptr = &local_data[dindex]; (*dptr) = (*sptr); } } } // clear the list since we have now subloaded them. glyphsWereSubloading.clear(); // Subload the image once glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, getTextureWidth(), getTextureHeight(), GL_ALPHA, GL_UNSIGNED_BYTE, local_data ); delete [] local_data; } } else { // OSG_INFO << "no need to subload "<<std::endl; } // if (generateMipMapTurnedOn) // { // glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE); // } }
void SparseTexture2DArray::apply( osg::State& state ) const { // get the contextID (user defined ID of 0 upwards) for the // current OpenGL context. const unsigned int contextID = state.getContextID(); Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID).get(); //ElapsedTime elapsedTime(&(tom->getApplyTime())); tom->getNumberApplied()++; const Extensions* extensions = getExtensions(contextID,true); // if not supported, then return if (!extensions->isTexture2DArraySupported() || !extensions->isTexture3DSupported()) { OSG_WARN<<"Warning: Texture2DArray::apply(..) failed, 2D texture arrays are not support by OpenGL driver."<<std::endl; return; } // get the texture object for the current contextID. TextureObject* textureObject = getTextureObject(contextID); if (textureObject && _textureDepth>0) { const osg::Image* image = firstValidImage(); if (image && getModifiedCount(0, contextID) != image->getModifiedCount()) { // compute the internal texture format, this set the _internalFormat to an appropriate value. computeInternalFormat(); GLsizei new_width, new_height, new_numMipmapLevels; // compute the dimensions of the texture. computeRequiredTextureDimensions(state, *image, new_width, new_height, new_numMipmapLevels); if (!textureObject->match(GL_TEXTURE_2D_ARRAY_EXT, new_numMipmapLevels, _internalFormat, new_width, new_height, 1, _borderWidth)) { Texture::releaseTextureObject(contextID, _textureObjectBuffer[contextID].get()); _textureObjectBuffer[contextID] = 0; textureObject = 0; } } } // if we already have an texture object, then if (textureObject) { // bind texture object textureObject->bind(); // if texture parameters changed, then reset them if (getTextureParameterDirty(state.getContextID())) applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT,state); // if subload is specified, then use it to subload the images to GPU memory //if (_subloadCallback.valid()) //{ // _subloadCallback->subload(*this,state); //} //else { // for each image of the texture array do for (GLsizei n=0; n < _textureDepth; n++) { osg::Image* image = _images[n].get(); // if image content is modified, then upload it to the GPU memory // GW: this means we have to "dirty" an image before setting it! if (image && getModifiedCount(n,contextID) != image->getModifiedCount()) { applyTexImage2DArray_subload(state, image, _textureWidth, _textureHeight, n, _internalFormat, _numMipmapLevels); getModifiedCount(n,contextID) = image->getModifiedCount(); } } } } // nothing before, but we have valid images, so do manual upload and create texture object manually else if ( firstValidImage() != 0L ) // if (imagesValid()) { // compute the internal texture format, this set the _internalFormat to an appropriate value. computeInternalFormat(); // compute the dimensions of the texture. osg::Image* firstImage = firstValidImage(); computeRequiredTextureDimensions(state, *firstImage, _textureWidth, _textureHeight, _numMipmapLevels); // create texture object textureObject = generateTextureObject( this, contextID,GL_TEXTURE_2D_ARRAY_EXT,_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0); // bind texture textureObject->bind(); applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT, state); _textureObjectBuffer[contextID] = textureObject; // First we need to allocate the texture memory int sourceFormat = _sourceFormat ? _sourceFormat : _internalFormat; if( isCompressedInternalFormat( sourceFormat ) && sourceFormat == _internalFormat && extensions->isCompressedTexImage3DSupported() ) { extensions->glCompressedTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, _internalFormat, _textureWidth, _textureHeight, _textureDepth, _borderWidth, firstImage->getImageSizeInBytes() * _textureDepth, 0); } else { // Override compressed source format with safe GL_RGBA value which not generate error // We can safely do this as source format is not important when source data is NULL if( isCompressedInternalFormat( sourceFormat ) ) sourceFormat = GL_RGBA; extensions->glTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, _internalFormat, _textureWidth, _textureHeight, _textureDepth, _borderWidth, sourceFormat, _sourceType ? _sourceType : GL_UNSIGNED_BYTE, 0); } // For certain we have to manually allocate memory for mipmaps if images are compressed // if not allocated OpenGL will produce errors on mipmap upload. // I have not tested if this is neccessary for plain texture formats but // common sense suggests its required as well. if( _min_filter != LINEAR && _min_filter != NEAREST && firstImage->isMipmap() ) allocateMipmap( state ); // now for each layer we upload it into the memory for (GLsizei n=0; n<_textureDepth; n++) { // if image is valid then upload it to the texture memory osg::Image* image = _images[n].get(); if (image) { // now load the image data into the memory, this will also check if image do have valid properties applyTexImage2DArray_subload(state, image, _textureWidth, _textureHeight, n, _internalFormat, _numMipmapLevels); getModifiedCount(n,contextID) = image->getModifiedCount(); } } const Texture::Extensions* texExtensions = Texture::getExtensions(contextID,true); // source images have no mipmamps but we could generate them... if( _min_filter != LINEAR && _min_filter != NEAREST && !firstImage->isMipmap() && _useHardwareMipMapGeneration && texExtensions->isGenerateMipMapSupported() ) { _numMipmapLevels = osg::Image::computeNumberOfMipmapLevels( _textureWidth, _textureHeight ); generateMipmap( state ); } textureObject->setAllocated(_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0); // unref image data? if (isSafeToUnrefImageData(state)) { SparseTexture2DArray* non_const_this = const_cast<SparseTexture2DArray*>(this); for (int n=0; n<_textureDepth; n++) { if (_images[n].valid() && _images[n]->getDataVariance()==STATIC) { non_const_this->_images[n] = NULL; } } } } // No images present, but dimensions are set. So create empty texture else if ( (_textureWidth > 0) && (_textureHeight > 0) && (_textureDepth > 0) && (_internalFormat!=0) ) { // generate texture _textureObjectBuffer[contextID] = textureObject = generateTextureObject( this, contextID, GL_TEXTURE_2D_ARRAY_EXT,_numMipmapLevels,_internalFormat,_textureWidth,_textureHeight,_textureDepth,0); textureObject->bind(); applyTexParameters(GL_TEXTURE_2D_ARRAY_EXT,state); extensions->glTexImage3D( GL_TEXTURE_2D_ARRAY_EXT, 0, _internalFormat, _textureWidth, _textureHeight, _textureDepth, _borderWidth, _sourceFormat ? _sourceFormat : _internalFormat, _sourceType ? _sourceType : GL_UNSIGNED_BYTE, 0); } // nothing before, so just unbind the texture target else { glBindTexture( GL_TEXTURE_2D_ARRAY_EXT, 0 ); } // if texture object is now valid and we have to allocate mipmap levels, then if (textureObject != 0 && _texMipmapGenerationDirtyList[contextID]) { generateMipmap(state); } }