OSG data loading performance optimization: texture compression

Posted by ubuntu-user on Fri, 21 Jan 2022 19:30:20 +0100

1. Theoretical knowledge

  1. As we all know, texture storage is RGBA. If these four numbers are not compressed, the storage space occupied by them is quite large. Each channel is calculated by 0 ~ 255 bytes, a pixel RGBA is 4 bytes, and a picture as large as 1024x1024 will occupy 1024x1024x4=4M. If it is not compressed, a GPU can only store 1024 1024x1024 pictures with 4GB graphics card. This is obviously unreasonable. Sometimes when we specify not to use compression when processing tiff images, dozens of GB will come out of any size, that is, no graphics card can be saved.
  2. Therefore, both CPU and GPU support texture compression. Compression algorithms are also a large pile, which are used for different scenarios. After texture compression, we should effectively reduce the use of CPU memory and CPU video memory. The key is to effectively reduce the storage space occupied by the model.
  3. Theoretically, compression and decompression consume CPU and GPU utilization, so the use of compression will increase the amount of computation and reduce the utilization of memory and video memory. The following is the comparison of CPU/GPU utilization and video memory occupation before and after compression with 20x20=400 512x512 rgbs allocated. Theoretically, the storage occupied by such pictures and pixels is 300M.

2. Practical practice

We only need to use the following statement for texture to compress the function according to the algorithm:

     
   texture->setInternalFormatMode(osg::Texture2D::USE_S3TC_DXT1_COMPRESSION);
   texture->setUnRefImageDataAfterApply(true);

The first sentence set internal format mode is to set the compression format.
The second sentence setUnRefImageDataAfterApply is that after the picture is transmitted to the GPU, the CPU will release it. This is why many texture s have something, but the image is obtained to output, and it is found that the image is 0.

The specific codes are as follows:

// osgPro222.cpp: this file contains the "main" function. Program execution will begin and end here.
//
#include <windows.h>
#include <iostream>

#include <osg/Texture2D>
#include <osg/Geometry>
#include <osg/Group>
#include <osgDB/ReadFile>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/Viewer>

#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")


/* -*-c++-*- OpenSceneGraph Cookbook
 * Chapter 8 Recipe 2
 * Author: Wang Rui <wangray84 at gmail dot com>
*/



 #define COMPRESS_TEXTURE  // Comment this to disable compressing textures

float randomValue(float min, float max)
{
    return (min + (float)rand() / (RAND_MAX + 1.0f) * (max - min));
}

osg::Vec3 randomVector(float min, float max)
{
    return osg::Vec3(randomValue(min, max),
        randomValue(min, max),
        randomValue(min, max));
}

osg::Matrix randomMatrix(float min, float max)
{
    osg::Vec3 rot = randomVector(-osg::PI, osg::PI);
    osg::Vec3 pos = randomVector(min, max);
    return osg::Matrix::rotate(rot[0], osg::X_AXIS, rot[1], osg::Y_AXIS, rot[2], osg::Z_AXIS) *
        osg::Matrix::translate(pos);
}

osg::Image* createRandomImage(int width, int height)
{
    osg::ref_ptr<osg::Image> image = new osg::Image;
    image->allocateImage(width, height, 1, GL_RGB, GL_UNSIGNED_BYTE);

    unsigned char* data = image->data();
    for (int y = 0; y < height; ++y)
    {
        for (int x = 0; x < width; ++x)
        {
            *(data++) = randomValue(0.0f, 255.0f);
            *(data++) = randomValue(0.0f, 255.0f);
            *(data++) = randomValue(0.0f, 255.0f);
        }
    }
    return image.release();
}

osg::Node* createQuads(unsigned int cols, unsigned int rows)
{
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    for (unsigned int y = 0; y < rows; ++y)
    {
        for (unsigned int x = 0; x < cols; ++x)
        {
            osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
            texture->setImage(createRandomImage(512, 512));
#ifdef COMPRESS_TEXTURE
            texture->setInternalFormatMode(osg::Texture2D::USE_S3TC_DXT1_COMPRESSION);
            texture->setUnRefImageDataAfterApply(true);
#endif

            osg::Vec3 center((float)x, 0.0f, (float)y);
            osg::ref_ptr<osg::Drawable> quad = osg::createTexturedQuadGeometry(
                center, osg::Vec3(0.9f, 0.0f, 0.0f), osg::Vec3(0.0f, 0.0f, 0.9f));
            quad->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get());
            geode->addDrawable(quad.get());
        }
    }
    return geode.release();
}

int main(int argc, char** argv)
{
	//Create Viewer objects, scene browser
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();

	osg::ref_ptr<osg::Group> root = new osg::Group();

	//Add to scene
	root->addChild(createQuads(20, 20));

	viewer->setSceneData(root.get());

	viewer->addEventHandler(new osgViewer::StatsHandler);
	viewer->addEventHandler(new osgViewer::WindowSizeHandler());

	viewer->realize();

	viewer->run();

	return 0;
}

Topics: osg