内存缓慢爬升,直到GPU崩溃

时间:2017-02-27 20:48:11

标签: three.js glsl webgl shader gpu

我正在使用着色器显示粒子云网格。每次用户点击云时,该云消失,新的云取代它。奇怪的是,每当新的云取代旧的云时,GPU中的内存使用量就会增加 - 无论新云是大还是小(并且缓冲区大小始终保持不变) - 未使用的点只显示在屏幕外没有颜色)。点击不到10次后,GPU最大化并崩溃。

这是我的物理着色器,其中新位置已更新 - 我通过更新tOffsets纹理中的某些值来传递新云的新位置值。之后是我的两个(vert和frag)视觉效果着色器。你能看到我的效率问题吗?或者这可能是垃圾收集问题? - 提前致谢!

物理着色器(仅限碎片):

// Physics shader: This shader handles the calculations to move the various points. The position values are rendered out to at texture that is passed to the next pair of shaders that add the sprites and opacity.

// the tPositions sampler is added to this shader by Three.js's GPUCompute script
uniform sampler2D tOffsets; 
uniform sampler2D tGridPositionsAndSeeds;
uniform sampler2D tSelectionFactors;
uniform float uPerMotifBufferDimension;
uniform float uTime;
uniform float uXOffW;

...noise functions omitted for brevity...

void main() {

        vec2 uv = gl_FragCoord.xy / resolution.xy;

        vec4 offsets = texture2D( tOffsets, uv ).xyzw;
        float alphaMass = offsets.z;
        float cellIndex = offsets.w;


        if (cellIndex >= 0.0) { // this point will be rendered on screen

            float damping = 0.98;

            float texelSize = 1.0 / uPerMotifBufferDimension;
            vec2 perMotifUV = vec2( mod(cellIndex, uPerMotifBufferDimension)*texelSize, floor(cellIndex / uPerMotifBufferDimension)*texelSize );
            perMotifUV += vec2(0.5*texelSize);

            vec4 selectionFactors = texture2D( tSelectionFactors, perMotifUV ).xyzw;
            float swapState = selectionFactors.x;
            vec4 gridPosition = texture2D( tGridPositionsAndSeeds, perMotifUV ).xyzw;
            vec2 noiseSeed = gridPosition.zw;
            vec4 nowPos;
            vec2 velocity;

            nowPos = texture2D( tPositions, uv ).xyzw;
            velocity = vec2(nowPos.z, nowPos.w);

            if ( swapState == 0.0 ) { // if no new position values are ready to be swapped in for this point
                nowPos = texture2D( tPositions, uv ).xyzw;
                velocity = vec2(nowPos.z, nowPos.w);
            } else { // if swapState == 1, this means new position values are ready to be swapped in for this point
                nowPos = vec4( -(uTime) + offsets.x, offsets.y, 0.0, 0.0 );
                velocity = vec2(0.0, 0.0);
            }

            ...physics calculations omitted for brevity...

            vec2 newPosition = vec2(nowPos.x - velocity.x, nowPos.y - velocity.y);

            // Write new position out to a texture for processing in the visual effects shader
            gl_FragColor = vec4(newPosition.x, newPosition.y, velocity.x, velocity.y);

        } else { // this point will not be rendered on screen
            // Write new position out off screen (all -1 cellIndexes have off-screen offset values)
            gl_FragColor = vec4( offsets.x, offsets.y, 0.0, 0.0);
        }

从物理着色器中,带有点'新动作的tPositions纹理被渲染出来并传递给视觉效果着色器:

视觉效果着色器(垂直):

uniform sampler2D tPositions; // passed in from the Physics Shader
uniform sampler2D tSelectionFactors;
uniform float uPerMotifBufferDimension;
uniform sampler2D uTextureSheet;
uniform float uPointSize;
uniform float uTextureCoordSizeX;
uniform float uTextureCoordSizeY;

attribute float aTextureIndex;
attribute float aAlpha;
attribute float aCellIndex;

varying float vCellIndex;
varying vec2 vTextureCoords;
varying vec2 vTextureSize;
varying float vAlpha;
varying vec3 vColor;

...omitted noise functions for brevity...

void main() {

        vec4 tmpPos = texture2D( tPositions, position.xy );
        vec2 pos = tmpPos.xy;
        vec2 vel = tmpPos.zw;

        vCellIndex = aCellIndex;

        if (vCellIndex >= 0.0) { // this point will be rendered onscreen

            float texelSize = 1.0 / uPerMotifBufferDimension;
            vec2 perMotifUV = vec2( mod(aCellIndex, uPerMotifBufferDimension)*texelSize, floor(aCellIndex / uPerMotifBufferDimension)*texelSize );
            perMotifUV += vec2(0.5*texelSize);

            vec4 selectionFactors = texture2D( tSelectionFactors, perMotifUV ).xyzw;
            float aSelectedMotif = selectionFactors.x;
            float aColor = selectionFactors.y;
            float fadeFactor = selectionFactors.z;

            vTextureCoords = vec2( aTextureIndex * uTextureCoordSizeX, 0 );
            vTextureSize = vec2( uTextureCoordSizeX, uTextureCoordSizeY );

            vAlpha = aAlpha * fadeFactor;

            vColor = vec3( 1.0, aColor, 1.0 );

            gl_PointSize = uPointSize;

        } else { // this point will not be rendered onscreen
            vAlpha = 0.0;
            vColor = vec3(0.0, 0.0, 0.0);
            gl_PointSize = 0.0;
        }
        gl_Position = projectionMatrix * modelViewMatrix * vec4( pos.x, pos.y, position.z, 1.0 );
    }

视觉效果着色器(frag):

uniform sampler2D tPositions;
    uniform sampler2D uTextureSheet;

    varying float vCellIndex;
    varying vec2 vTextureCoords;
    varying vec2 vTextureSize;
    varying float vAlpha;
    varying vec3 vColor;

    void main() {
        gl_FragColor = vec4( vColor, vAlpha );

        if (vCellIndex >= 0.0) { // this point will be rendered onscreen, so add the texture
            vec2 realTexCoord = vTextureCoords + ( gl_PointCoord * vTextureSize );
            gl_FragColor = gl_FragColor * texture2D( uTextureSheet, realTexCoord );
        }
    }

1 个答案:

答案 0 :(得分:1)

感谢@ Blindman67上面的评论,我解决了这个问题。它与着色器无关。在Javascript(Three.js)中,我需要发信号通知GPU在添加更新的纹理之前删除旧纹理。

每次我更新一个纹理(我的大多数都是DataTextures)我需要在创建和更新新纹理之前在现有纹理上调用dispose(),如下所示:

var textureHandle; // holds a reference to the current texture uniform value

textureHandle.dispose(); // ** deallocates GPU memory **
textureHandle = new THREE.DataTexture( textureData, dimension, dimension, THREE.RGBAFormat, THREE.FloatType );
textureHandle.needsUpdate = true;
uniforms.textureHandle.value = textureHandle;