Место возникновения ошибки opengl (VBO)

Версия Minecraft
1.11.2
1,015
9
102
У меня майн начал флудить вот этим:
Код:
########## GL ERROR ##########
@ Post render
1282: Invalid operation

Это, кончено, очень информативно, но можно ли как-нибудь более подробнее узнать об ошибке? Например, откуда она исходит? У меня код довольно большой, и поэтому просматривать и тестить каждую строку желания нет
 
1,015
9
102
Опять у меня ничего не работает. Попробовал добавить в буффер цвет, а дальше UV
Код:
           float[] data = getData();
            FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
            buffer.put(data).flip();
            glBindBuffer(GL_ARRAY_BUFFER, vboID);
            glBufferData(GL_ARRAY_BUFFER, buffer, GL_DYNAMIC_DRAW);
            glBindBuffer(GL_ARRAY_BUFFER, 0);

Вот как строится массив data (coords, color и uv - листы, в которых лежат данные)
Код:
           float[] result = new float[coords.size()+color.size()+uv.size()];
            for (int i = 0; i < coords.size(); i++)
                result[i] = coords.get(i);
            for (int i = 0; i < color.size(); i++)
                result[i+coords.size()] = color.get(i);
            for (int i = 0; i < uv.size(); i++)
                result[i+color.size()+coords.size()] = uv.get(i);
            return result;

Потом применяя отступы, задаю цвет и UV при рендере
Код:
           mc.getTextureManager().bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
      mc.getTextureManager().getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).setBlurMipmap(false, false);
            glBindBuffer(GL_ARRAY_BUFFER, vboID);
            glEnableClientState( GL_VERTEX_ARRAY );
            glVertexPointer(3, GL_FLOAT, 0, 0);
            glEnableClientState(GL_COLOR_ARRAY);
            glColorPointer(3, GL_FLOAT, 0, vertexSize);
            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
            glTexCoordPointer(2, GL_FLOAT, 0, vertexSize+colorSize);
            glDrawArrays(GL_QUADS, 0, vertexSize);
            glDisableClientState(GL_VERTEX_ARRAY);
            glDisableClientState(GL_COLOR_ARRAY);
            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
            glBindBuffer(GL_ARRAY_BUFFER, 0);
            mc.getTextureManager().bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
            mc.getTextureManager().getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).restoreLastBlurMipmap();

Цвет и UV вычисляю верно и кладу в массив тоже верно (для цвета на каждую вершину по 3 значения, а для UV - по два), но вот в игре получается что-то типо того   :-/
9d02ac2bb8215d67112473b062f35b82-full.png


Такое чувство, что он применяет цвет и UV из буффера вообще к рандомной вершине
 
1,990
18
105
vertexSize и colorSize - размеры массивов данных с позициями\цветом, так? Должно быть так.
offset скорее всего указывается в байтах, так что попробуй умножать на 4.
Данные позиций выглядят адекватно, так что скорее всего поехал именно offset.
 
1,015
9
102
Да, над было на 4 умножить. Кстати странно, что в TextureMap.LOCATION_BLOCKS_TEXTURE нет текстур жидкостей


Agravaine написал(а):
А разве не по очереди нужно их? А ты сначала коорды все, потом весь цвет и ТД.

Разницы нет
 
1,990
18
105
Agravaine написал(а):
А разве не по очереди нужно их? А ты сначала коорды все, потом весь цвет и ТД.

Оно довольно гибко настраивается. Как запихнешь и какой формат укажешь - так и будет работать.
 
1,015
9
102
Ладно, забью пока. Надо в другом потоке заполнение буффера написать. Пробовал вот так, но были жесткие лаги с вершинами, UV и цветом
Код:
glBindBuffer(GL_ARRAY_BUFFER, vboID);
ByteBuffer mappedBuffer = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY, oldBuffer);
                new Thread(() -> {
                    float[] data = getData();
                    mappedBuffer.asFloatBuffer().put(data).flip();
                    oldBuffer = mappedBuffer;
                   glUnmapBuffer(GL_ARRAY_BUFFER);
                }).start();
                glBufferData(GL_ARRAY_BUFFER, oldBuffer, GL_DYNAMIC_DRAW);
                glBindBuffer(GL_ARRAY_BUFFER, 0);
 
2,505
81
397
Мне кажется, ты хрень сделал. Ты анбиндишь буфер перед тем, как произойдет glUnmapBuffer в другом потоке. Не думаю, что это законно. Вообще, в другом потоке тебе нужно только собирать данные. Хотя, думаю, что можно вообще без отдельного потока. Там же у тебя не должно быть сложного алгоритма. Просто пробежаться по вершинам и т.п. и положить их в буфер. Конструкция glMapBuffer - glBufferData сама по себе ассинхронна. CPU не будет ждать, пока данные отправятся на GPU.
 
1,990
18
105
Анбиндить буфер перед unmap, вернее, после map - абсолютно законно.
Другое дело, что нельзя делать (un)map в другом потоке, а перед самим unmap буфер нужно опять забиндить. К тому же, если оставить буфер забинженным, это может сломать что-нибудь другое, да и вообще майн версии 1.6.4 на такое ругается в тесселяторе :D
Грузить данные в map'нутый буфер можно из любого потока, это просто перекладывание байтиков из хипа в нативную память.

А ещё мне что-то подсказывает, что инициализировать буфер нужно перед вызовом map (я про стрёмный вызов glBufferData с каким-то oldBuffer) :V
 
1,015
9
102
Учел всё, что вы написали. Получился такой код. Лагов с UV и цветом нет, FPS в норме, но, иногда карта моргает. Как я понял, когда поток не успевает прогрузить, вместо карты ничего не рендрится
Код:
            glBindBuffer(GL_ARRAY_BUFFER, vboID);
            glBufferData(GL_ARRAY_BUFFER, radius*radius*radius*786, GL_DYNAMIC_DRAW);
            ByteBuffer mappedBuffer = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY, oldBuffer);
            glBindBuffer(GL_ARRAY_BUFFER, 0);
            new Thread(() -> {
                float[] data = getData();
                mappedBuffer.asFloatBuffer().put(data).flip();
                oldBuffer = mappedBuffer;
            }).start();
            glBindBuffer(GL_ARRAY_BUFFER, vboID);
            glUnmapBuffer(GL_ARRAY_BUFFER);
            glBindBuffer(GL_ARRAY_BUFFER, 0);
 
2,505
81
397
Ты кладешь байты в буфер после того, как заанмапил его. Как это вообще работает? Или поток успевает проработать до вызовава glUnmapBuffer? Дак тогда зачем вообще этот поток?
 
1,015
9
102
Dahaka написал(а):
Ты кладешь байты в буфер после того, как заанмапил его. Как это вообще работает? Или поток успевает проработать до вызовава glUnmapBuffer? Дак тогда зачем вообще этот поток?

Не всегда успевает. Подожди, а как тогда должно быть? Я думал, я буду буффер в другом потоке заполнять, а не до мапинга
 

CumingSoon

Местный стендапер
1,634
12
269
Извини за оффтоп. Возможно, видя сообщение в своей теме, ты подумал, что кто-то решил помочь тебе. Но тут появился я со своим оффтопом. А что ты вообще хочешь сделать? Можешь рассказать?
 
1,015
9
102
CoomingSoon написал(а):
Извини за оффтоп. Возможно, видя сообщение в своей теме, ты подумал, что кто-то решил помочь тебе. Но тут появился я со своим оффтопом. А что ты вообще хочешь сделать? Можешь рассказать?

Это тема - продолжение из середины этой
 
1,990
18
105
Minebot написал(а):
Не всегда успевает. Подожди, а как тогда должно быть? Я думал, я буду буффер в другом потоке заполнять, а не до мапинга

Алгоритм такой:
1) glMapBuffer
2) асинхронное перекидывание байтиков
3) тогда, и только тогда, когда мы уверены, что асинхронное копирование байтиков закончилось, из главного потока вызываем glUnmapBuffer
 
1,015
9
102
CoomingSoon написал(а):
Извините за вмешательство, Конь и майнбот, но это, вроде, можно сделать чем-то типа async/await. Да?

Ну да. По мне лучше wait/notify


Oldestkon написал(а):
Алгоритм такой:
1) glMapBuffer
2) асинхронное перекидывание байтиков
3) тогда, и только тогда, когда мы уверены, что асинхронное копирование байтиков закончилось, из главного потока вызываем glUnmapBuffer

Рендрить, не заанманапя буффер можно? Я решил вот так сделать, но ничё не поменялось. И ошибки пост рендера полетели
Код:
private Boolean isDone;

private void update(){
...
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, radius*radius*radius*786, GL_DYNAMIC_DRAW);
ByteBuffer mappedBuffer = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY, oldBuffer);
glBindBuffer(GL_ARRAY_BUFFER, 0);
new Thread(() -> {
    float[] data = getData();
    mappedBuffer.asFloatBuffer().put(data).flip();
    oldBuffer = mappedBuffer;
    isDone = true;
}).start();
}

private void render(){
glBindBuffer(GL_ARRAY_BUFFER, vboID);
if (isDone) {
    glUnmapBuffer(GL_ARRAY_BUFFER);
    isDone = false;
}
...
}
 

CumingSoon

Местный стендапер
1,634
12
269
Мне кажется, можно сделать так:
1) Создаём буфер, выделяя(glBufferData) памяти побольше. Как говорилось в статье про вулкан "выделяйте много, но редко". Думаю, здесь тот же случай.
2) Запускаешь поток. Он у тебя получает данные, загружая их в буфер. Загружай данные кусочками , а не всё сразу. Сделай какой-нибудь минимальный порог по кол-ву данных, после достижения которого загружать в буфер.
3) Блокируешь, если надо(а, скорее всего, надо), потом загружаешь данные через unmap.
4) А сам VBO просто рисуешь, будто б заполнен. Думаю, если данных хватать не будет, то ОпенГЛ пропустит их. Если нет - придумай что-нибудь.
===
Рендерить можно без мапинга. Мапинг нужен для загрузки данных. Он как бы берёт данные по указателю в памяти, перемещая в другой участок, откуда уже ОпенГЛ использует эти данные. Вроде так. Могу ошибаться
 
1,990
18
105
Minebot написал(а):
Рендрить, не заанманапя буффер можно? Я решил вот так сделать, но ничё не поменялось. И ошибки пост рендера полетели

Нет, нельзя. Вернее, технически можно - но, это, скорее всего undefined behaviour.

Если делаешь асинхронную загрузку данных - вперёд читать про асинхронность. Мне кажется, у тебя не очень хорошее представление о многопоточном программировании. Менять переменные, как это делаешь ты (isDone) нельзя. Нужна синхронизация, либо volatile переменная.

CoomingSoon написал(а):
1) Создаём буфер, выделяя(glBufferData) памяти побольше. Как говорилось в статье про вулкан "выделяйте много, но редко". Думаю, здесь тот же случай.
Выделять нужно ровно столько, сколько тебе потребуется. Ни больше, ни меньше.

CoomingSoon написал(а):
2) Загружай данные кусочками , а не всё сразу. Сделай какой-нибудь минимальный порог по кол-ву данных, после достижения которого загружать в буфер.
Никакого смысла в этом нет. ГЛ там не синхронизируется нигде и ничего не ждет. Ему абсолютно пофиг на эти данные, т.к. это просто ссылка, по которой ты загружаешь данные в память выделенную нативно.
... Пока ты это не рисуешь, а этого делать не надо, если процесс загрузки не закончился.
 
1,015
9
102
Oldestkon написал(а):
Нет, нельзя. Вернее, технически можно - но, это, скорее всего undefined behaviour.
... Пока ты это не рисуешь, а этого делать не надо, если процесс загрузки не закончился.

А смысл в асинхронном заполнении буффера, если карта во время заполнения не будет отрисовываться?
 
Сверху