gl_PointCoord compiles and links, but crashes at runtime

289 Views Asked by At

I successfully wrote a standard basic transform feedback particle system with point-sprites. No flickering, the particles update from one buffer into the next, which is then rendered, then output buffer becomes input buffer on next iteration. All GPU-side, standard transform feedback. Wonderful! ONE BIG PROBLEM: It only works if I don't use gl_PointCoord. Using a flat color for my point sprites works fine. But I need gl_PointCoord to do anything meaningful. All my shaders, whether or not they use gl_PointCoord, compile and link just fine. However, at runtime, if the shader uses gl_PointCoord (whether or not gl_PointCoord is actually in the execution path), the program crashes. I explicitly glEnable(GL_POINT_SPRITE). This doesn't have any effect. Omitting gl_PointCoord, and setting glPointSize(100.0f), and using vec4(1.0,1.0,1.0,1.) the particle system renders just fine as large white blocky squares (as expected). But using gl_PointCoord in any way (as standard texture lookup coord or procedural color or anything else) will crash my shaders at runtime, after successfully compiling and linking. I simply don't understand why. It passed glShaderSource, glCompileShader,glAttachShader, glLinkProgram. I'm compiling my shaders as #version 430, and 440, and I even tried 300 es. All compile, link, and I checked the status of the compile and link. All good. I'm using a high-end microsoft surface book pro, visual studio 2015. NVIDIA GeForce GPU. I also made sure all my drivers are up to date. Unfortunately, with point sprites, I don't have billboard vertices from the vertex shader to use to interpolate into the fragment shader as texture coordinates. gl_FragCoord doesn't work either (as I would expect for point sprites). Does anyone know how to solve this or use another technique for texture coordinates for point sprites?

glBeginTransformFeedback(GL_POINTS);//if my fragment shader uses gl_PointCoord, it hard crashes here.

When replying, please understand I'm very experienced in writing shaders, Vertex Shaders, Pixel Shaders, Tessellation control, tessellation evaluation, and geometry shaders, in GLSL and HLSL. But I don't claim to know everything. I could have forgotten something simple; I just have no idea what that could be. I'm figuring it could be a state I don't have enabled. As far as transform feedback goes, I also set up the varying attribs correctly via glTransformFeedbackVaryings. C++ :

void Render(void* pData)
{
    auto pOwner = static_cast<CPointSpriteSystem*>(pData);
    glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
    glEnable(GL_POINT_SPRITE);
    glEnable(GL_POINT_SMOOTH);
    //glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
    m_Shader.Activate();
    auto num_particles = pOwner->m_NumPointSprites;
    FeedbackIndex = 0;
    while (true)
    {
        m_Shader.SetSubroutine(GL_VERTEX_SHADER, "RenderPass", 
            vssubroutines[FeedbackIndex], 
            vsprevSubLoc[FeedbackIndex], 
            vsupdateSub[FeedbackIndex]);
        m_Shader.SetSubroutine(GL_FRAGMENT_SHADER, "RenderPixelPass",
            pssubroutines[0],
            psprevSubLoc[0],
            psrenderSub[0]);
        if (!FeedbackIndex)
        {
            glEnable(GL_RASTERIZER_DISCARD);
            glBindVertexArray(m_vao[bufferIndex]);
            glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_Feedback[bufferIndex]);
            glBeginTransformFeedback(GL_POINTS);//if feedback fragment shader uses gl_PointCoord, will always hard-crash here 
            glDrawArrays(GL_POINTS, 0, num_particles);
            glEndTransformFeedback();
            glFlush();
        }
        else
        {
            m_Shader.SetSubroutine(GL_FRAGMENT_SHADER, "RenderPixelPass",
                pssubroutines[(int)pOwner->m_ParticleType],
                psprevSubLoc[(int)pOwner->m_ParticleType],
                psrenderSub[(int)pOwner->m_ParticleType]);
            glPointSize(100.0f);
            glDisable(GL_RASTERIZER_DISCARD);
            glDrawTransformFeedback(GL_POINTS, m_Feedback[bufferIndex]);
            bufferIndex = 1 - bufferIndex;
            break;
        }
        FeedbackIndex = 1 - FeedbackIndex;
    }
}

VS feedback:

#version 310 es
subroutine void RenderPassType();
subroutine uniform RenderPassType RenderPass;
layout(location=0) in vec3 VertexPosition;
layout(location=1) in vec3 VertexVelocity;
layout(location=2) in float VertexStartTime;
layout(location=3) in vec3 VertexInitialVelocity;
out vec3 Position;
out vec3 Velocity;
out float StartTime;
out float Transp;
uniform float g_fCurSeconds;
uniform float g_fElapsedSeconds;
uniform float Time;
uniform float H;
uniform vec3 Accel;

#ifdef USE_VIEW_BLOCK
layout(std140) uniform view_block{
    mat4 g_mView,
         g_mInvView,
         g_mPrevView,
         g_mPrevInvView,
         g_mProj,
         g_mInvProj;
};
uniform mat4 g_mWorld;
#endif

subroutine(RenderPassType) void UpdateSphere(){
    Position=VertexPosition+VertexVelocity*g_fElapsedSeconds;
    Velocity=VertexVelocity;
    StartTime=VertexStartTime;
}
subroutine(RenderPassType) void Render(){
    gl_Position=g_mProj*g_mInvView*vec4(VertexPosition,1.0);
}

void main(){
    RenderPass();"
}

PS feedback:

#version 310 es //version 430 and 440 same results
subroutine void RenderPixelType();
subroutine uniform RenderPixelType RenderPixelPass;
uniform sampler2D tex0;
layout(location=0) out vec4 g_FragColor;

subroutine(RenderPixelType) void Basic(){
    g_FragColor=vec4(1.0,1.0,1.0,1.0);
}

subroutine(RenderPixelType) void ProceduralSphere(){
#if 1
    vec2 coord=gl_PointCoord;//at runtime: BOOM!
    coord=coord*2.0-1.0;
    float len=length(coord);
    if(len>1.0) discard;
    g_FragColor=vec4(1.0-len,1.0-len,1.0-len,1.0);
#else
    g_FragColor=vec4(1.0,1.0,1.0,1.0);//always works
#endif
}

subroutine(RenderPixelType) void StandardImage(){
    g_FragColor=texture2D(tex0,gl_PointCoord); //boom!!
    g_FragColor=vec4(1.0,1.0,1.0,1.0);
}

void main(){
    RenderPixelPass();
}
1

There are 1 best solutions below

0
On

I solved the problem! The problem was actually that I didn't write a value to Transp (declared out float Transp;//in vs). I casually thought I didn't have to do this. But I started to trim some fat, and as soon as I wrote out a generic float (not actually being used by later shader stages: Transp=0.0f), and then compiled as #version 430, it all started to work as originally expected: little white spheres