2

ここで奇妙な問題が発生しました。1秒間に数回作成される潜在的に大きな(最大500mbのような)3Dテクスチャがあります。テクスチャのサイズが変更される可能性があるため、古いテクスチャを毎回再利用することはできません。メモリ消費を回避するための論理的な手順は、テクスチャが使用されなくなるたびに(glDeleteTextureを使用して)テクスチャを削除することですが、プログラムはすぐに読み取りまたは書き込みアクセス違反でクラッシュします。テクスチャを更新するために使用するバッファで呼び出された場合、glDeleteBufferでも同じことが起こります。

私の目には、glDelete *関数はかなりフェイルセーフであるため、これは起こり得ません。対応するオブジェクトではないglハンドルをそれらに与えると、それらは何もしません。

興味深いのは、テクスチャとバッファを削除しないと、最終的にグラフィックカードのメモリがなくなるまでプログラムが正常に実行されることです。

これは、Windows XP 32ビット、266.58erドライバーを搭載したNVIDIA Geforce 9500GTで実行され、プログラミング言語はVisualStudio2005ではc++です。

アップデート

明らかに、影響を受ける関数はglDeleteだけではありません。他のいくつかの方法で違反が発生しました(昨日はそうではありませんでした)...ここで何かが壊れているようです。

アップデート2

これは失敗するべきではありませんか?

template <> inline
Texture<GL_TEXTURE_3D>::Texture(
    GLint internalFormat,
    glm::ivec3 size,
    GLint border ) : Wrapper<detail::gl_texture>()
{
    glGenTextures(1,&object.t);

    std::vector<GLbyte> tmp(glm::compMul(size)*4);
    glTextureImage3DEXT(
        object,             // texture
        GL_TEXTURE_3D,          // target
        0,                      // level
        internalFormat,         // internal format
        size.x, size.y, size.z, // size
        border,                 // border
        GL_RGBA,                // format
        GL_BYTE,                // type
        &tmp[0]);               // don't load anything
}

失敗する:

Exception (first chance) at 0x072c35c0: 0xC0000005:  Access violoation while writing to position 0x00000004.
Unhandled exception at 0x072c35c0 in Project.exe: 0xC0000005: Access violatione while writing to position 0x00000004.

最良の推測:プログラムメモリを台無しにする何か?

4

2 に答える 2

4

glDeleteがクラッシュする理由はわかりませんが、とにかくそれを必要とせず、これを複雑にしすぎていると確信しています。

glGenTexturesは、テクスチャの「名前」を作成します。glTexImage3Dは、OpenGLにその名前に添付するデータを提供します。私の理解が正しければ、データが不要になったときに名前を削除する理由はありません

代わりに、同じテクスチャ名でもう一度glTexImage3Dを呼び出し、古いデータが不要になったことをドライバーが認識できることを信頼する必要があります。これにより、最初に最大サイズを指定してからglTexSubImage3Dを呼び出す代わりに、毎回新しいサイズを再指定できます。これにより、テクスチャが最大サイズを保持するため、実際にデータを使用することが困難になります。

以下は、大量のテクスチャを割り当て(GPU-ZでのGPUメモリ使用量測定が実際に機能することを確認するため)、フレームごとに新しいデータを同じテクスチャに再割り当てするpython(pygletが必要)でのばかげたテストです。ランダムな新しいサイズといくつかのランダムなデータは、データが一定のままである場合に存在する可能性のある最適化を回避するためのものです。

それは(明らかに)地獄のように遅いですが、少なくとも私のシステム(Windowsサーバー2003 x64、NVidia Quadro FX1800、ドライバー259.81)では、テクスチャの再割り当てをループしている間、GPUメモリ使用量が上がらないことを明確に示しています。

import pyglet
from pyglet.gl import *
import random

def toGLArray(input):
    return (GLfloat*len(input))(*input)

w, h = 800, 600
AR = float(h)/float(w)
window = pyglet.window.Window(width=w, height=h, vsync=False, fullscreen=False)


def init():
    glActiveTexture(GL_TEXTURE1)
    tst_tex = GLuint()
    some_data = [11.0, 6.0, 3.2, 2.8, 2.2, 1.90, 1.80, 1.80, 1.70, 1.70,  1.60, 1.60, 1.50, 1.50, 1.40, 1.40, 1.30, 1.20, 1.10, 1.00]
    some_data = some_data * 1000*500

    # allocate a few useless textures just to see GPU memory load go up in GPU-Z
    for i in range(10):
        dummy_tex = GLuint()
        glGenTextures(1, dummy_tex)
        glBindTexture(GL_TEXTURE_2D, dummy_tex)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 1000, 1000, 0, GL_RGBA, GL_FLOAT, toGLArray(some_data))
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

    # our real test texture
    glGenTextures(1, tst_tex)
    glBindTexture(GL_TEXTURE_2D, tst_tex)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 1000, 1000, 0, GL_RGBA, GL_FLOAT, toGLArray(some_data))
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

def world_update(dt):
    pass
pyglet.clock.schedule_interval(world_update, 0.015)

@window.event
def on_draw():
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
    # randomize texture size and data
    size = random.randint(1, 1000)
    data = [random.randint(0, 100) for i in xrange(size)]
    data = data*1000*4

    # just to see our draw calls 'tick'
    print pyglet.clock.get_fps()

    # reallocate texture every frame
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 1000, size, 0, GL_RGBA, GL_FLOAT, toGLArray(data))

def main():
    init()
    pyglet.app.run()

if __name__ == '__main__':
    main()
于 2011-03-03T10:13:11.613 に答える
0

コード全体にglGetError()を振りかけます。glDeleteが実際にオブジェクトを破壊しないという事実に、あなたが巻き込まれていることに賭けたいと思います。オブジェクトは、数フレーム長く使用されている可能性があります。そのため、メモリが不足していると思われます(つまり、glGetErrorがGL_OUT_OF_MEMORYを返しています)。

于 2011-03-03T10:14:02.947 に答える