1
// test data brick
class Brick
{
public:
    Brick() { data = new U32[27]; }
    virtual ~Brick() { delete[] data; }

    U32* data;
};

Texture3D* OctreeMipmapper::GenerateBrickTexture()
{
    auto ret = new Texture3D();
    ret->Initialize();
    ret->Storage(GL_R32UI, SV3(g_brickSize)); // g_brickSize = 3u, SV3 is a 3d-signed-int-vec
    ret->SetScaleFilter(GL_LINEAR, GL_LINEAR);
    ret->SetWrapFilter(GL_CLAMP_TO_BORDER);
    ret->SetBorderColorIiv(SV4{ 0u, 0u, 0u, 0u });
    //ret->GenerateBindlessImageHandle(GL_R32UI);
    return ret;
}

void OctreeMipmapper::InitOctreeBrick()
{
    auto texNum = m_octree->GetTexNum(); // texNum = 600000u
    m_albedoBricks.resize(texNum);
    m_normalBricks.resize(texNum);
    m_bricks.resize(texNum);
    for (U32 i = 0u; i < texNum; ++i)
    {
        m_bricks[i] = new Brick();
        m_albedoBricks[i] = GenerateBrickTexture();
        //m_normalBricks[i] = GenerateBrickTexture();
    }
}


Above is my source code, as you can see, the amount of bricks vector is 600000, and the texture is a 3d-single-channel texture with 27 texel(3 * 3 * 3). So, the data size is 600000 * 27 * 4 bytes = 64MB. But when i run the code, the memory usage of these textures is over 3GB, it make me confused. I wanna what opengl has done in glTextureStorage3D function

pneuma
  • 11
  • 2

1 Answers1

1

the texture is a 3d-single-channel texture with 27 texel(3 * 3 * 3).

Technically, that is the minimum storage that could possibly be required for a system to store such a texture.

That doesn't mean that this is how much memory the texture actually consumes. Even ignoring any particular details that I will discuss presently, every single one of those 600,000 textures will need storage for information about those textures. Storage the GPU needs access to: filtering parameters, texture size, mipmap limits, etc. Because the GPU needs this data, that data needs to live (at least) in GPU accessible storage.

But there's more. In order to select texels from textures in an optimal fashion, hardware will employ what's known as swizzling. While different hardware does it in different ways, the basic idea is to improve locality of access. If a fragment accesses the texel at coordinate X, Y, Z, then a fragment is likely to access X, Y+1, Z, or something similar. So the system messes with the position of texels in allocated storage to make this work.

Swizzling typically requires some minimum alignment on the dimensions of the texture. This can be as small as 4 in each axis, or as big as 32-64.

Additionally, texture memory tends to have to be aligned in some way. That is, a texture's starting byte has to be aligned to some minimum alignment. This could be as little as 32-bytes, or as much as a full memory page (4K) or more, depending on the implementation.

So it is entirely possible that each of those textures takes up 4KB or more in actual storage. Which is pretty close to the amount of storage you're using up.

You should find ways of avoiding using tiny textures.

Note that Vulkan, being a lower-level API, lets you know about things like minimum alignments, sizes, and the like. So you would be able to tell just from trying to create one of these textures how much actual storage it requires.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Thank you so much! Maybe I need to pack up these small textures to bigger textures to reduce the memory wasting – pneuma Oct 15 '21 at 07:13