Для инстенсинга использую TBO, дополнительно делаю отсечение по фрустуму на GPU используя FeedBackBuffer. Соответственно использую VAO для TBO. Точки которые попадают в фрустум помещаю в другой TBO, который идет на рендер.
Собственно алгоритм  выглядит примерно так(более подробно Ссылка):

Код:
initInstanced()
{
glGenBuffers(1, &this->grassTBO);
    glBindBuffer(GL_TEXTURE_BUFFER, *geom->getTBO());
    glBufferData(GL_TEXTURE_BUFFER, sizeof(InstanceData)*geom->numGrass, NULL, GL_STATIC_DRAW);

    // generate the grass instance data
    InstanceData* instance = (InstanceData*)glMapBufferRange(GL_TEXTURE_BUFFER, 0, sizeof(InstanceData)*geom->numGrass,
                 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
    int size = (int)sqrt((float)this->numGrass);
    for (int i=0; i<size; i++) {
    	for (int j=0; j<size; j++) {
        instance[i+j*size].position = vec4( (i-size/2)*4.0f+sf::Randomizer::Random(-0.05f, 0.05f), -5.5f, (j-size/2)*4.0f+sf::Randomizer::Random(-0.05f, 0.05f), 0.0f );
    	}
    }
    glUnmapBuffer(GL_TEXTURE_BUFFER);

    // create the vertex array for culling
    glGenVertexArrays(1, *geom->getVertexArray());
    glBindVertexArray(geom->getVertexArray());
    glBindBuffer(GL_ARRAY_BUFFER, geom->getTBO());
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, (void*)0);

}

render()
{
glEnable(GL_RASTERIZER_DISCARD);
    
    
    extensions->glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, geom->getCulledTbo()->getBufferId());
    geom->getVertexArray()->bind();
    extensions->glBeginTransformFeedback(GL_POINTS);
	 	extensions->glBeginQueryIndexed(GL_PRIMITIVES_GENERATED, 0, *geom->getCulledQuery());
    	extensions->glDrawArrays(GL_POINTS, 0, (GLsizei)geom->getMaxNumInstanced());
    extensions->glEndQueryIndexed(GL_PRIMITIVES_GENERATED, 0);
    extensions->glEndTransformFeedback();
    glDisable(GL_RASTERIZER_DISCARD);
    geom->getVertexArray()->unbind();
    while(true)
    {
    	// Apparently, must actually sleep here to avoid issues w/ NVIDIA Quadro.
    	extensions->glGetQueryObjectiv( geom->getCulledQueryAsValue(), GL_QUERY_RESULT_AVAILABLE, &ready );
    	if (!ready) OpenThreads::Thread::microSleep(1000);
    	else break;
    }	

    numVisible = 0;
    unsigned int sum = 0;
    for(unsigned int i = 0; i < lodCount; i++)
    {
    	extensions->glGetQueryObjectiv(geom->getCulledQueryAsValue(i), GL_QUERY_RESULT, &numVisible);
    	geom->drawInstanced(numVisible)
    }

}

Ситуация такая : если видимых объектов больше 0, то все нормально, если 0, то начинают валится ошибки invalid operation. Путем медитаций удалось сузить вероятное проблемное место до VAO. Т.е. инициализация объекта VAO происходит только один раз, вроде и glEnableVertexAttribArray(0) делаю, а получается, что VAO влияет на состояние рендера? Если я делаю инстанс без VAO и соответственно без отсечения невидимых объектов, все проходит нормально даже если принудительно выставить кол-во видимых объектов = 0.  Предполагал, что VAO может быть сколько угодно и соответственно его можно свободно создать и если нет необходимости его использовать в данный момент, то можно отрубить через glEnableVertexAttribArray(0), теперь уже не знаю.
Железо :
GeForce GTX 550Ti (драйверы пробовал и последние 296  и 285), использую некоторые инструкции OpenGL4.2