Подгрузка изображений вне основного потока

Версия Minecraft
1.12.2
214
11
59
Привет.
Стоит задача, регистрировать много изображений в разных потоках. При попытке сделать это, ловлю исключение: контекст opengl не задан.
Может кто-то помочь с этим ?

p.s.
В lwjgl 3 есть замечательный метод GlContext.createFromCurrent, который должен мне помочь, но я не знаю как правильно обновлять библиотеки майна
 
Краш-лог
java.lang.RuntimeException: No OpenGL context found in the current thread.
Краш-лог:
java.lang.RuntimeException: No OpenGL context found in the current thread.
Последнее редактирование:
214
11
59
@Agravaine Ты, кстати, не прав. Юзать lwjgl можно в нескольких потоках.
Вот тебе примеры:
LWJGL/lwjgl (с объектом Drawable)
OpenGL and multithreading - OpenGL Wiki (lwjgl 3.*.*)

Вопрос стоит не в том как скачивать изображения, а как их загружать в память/регистрировать.
 

CumingSoon

Местный стендапер
1,634
12
269
Почитав stackoverflow, я выяснил, что самая долгая операция - преобразование кратинки и чтение с диска. Загрузка же в ГПУ не такая уж и медленная - там шины в кучи Гигабит. Так что в одном потоке ты должен скачать картинки, преобразовать её; затем ты должен загрузить её в основном на ГПУ. Очень удобно такое делать через Future, а не через доисторические thread'ы.
 
214
11
59
@CoomingSoon Даже если разбить все это на мультипоток получится, я ведь все равно либо упрусь в 'RuntimeException: No OpenGL context found in the current thread.', либо не изменю ситуацию. Мне нужно как-то полностью избавиться от провисаний в игре, при подгрузке текстур
 

CumingSoon

Местный стендапер
1,634
12
269
Нет, ты не правильно меня понял. Из эвента какого-нибудь рендера (там уж точно будет прогрузка) запусти Future, который скачает текстуру и преобразует её, создаст в ByteBuffer. Ну а после уже грузи на ГПУ. Будет что-то типа if(future.isDone()) tex = load(future.get())
Я думаю, это оптимальный выбор в соотношении времени кодинга и времени исполнения
 
2,505
81
397
В worker-треде только читаешь картинку с диска. Достаешь сырой массив, подготовленный для загрузки на гпу. Дождавшись, в основном потоке загружаешь (делаешь gl вызовы). Т.е в worker-воркер треде у тебя не должно быть gl вызовов, поэтому и эксепшена там быть не может.
Thread в чистом виде лучше не использовать. Создай где-то ExecutorService и через него запускай таски. На выходе получишь Future, который позволит дождаться окончания таска через future.isDone().
 
214
11
59
@Dahaka @CoomingSoon Я все итак делаю через Executors и Future. Если я правильно понял, код выглядеть должен примерно так:

Код:
List<Future<int[]>> list = new ArrayList();
void a () {
    ExecutorService es = Executors.newCachedThreadPool();
    Future<int[]> future = es.submit(() -> {
        BufferedImage image = изображение с диска;
        int[] data = new int[] {}
        image.getRGB(0, 0, image.getWidth(), image.getHeight(),
                         data, 0, image.getWidth());
        return data;
    });
list.add(future);
}

void update() {
for(Future<int[]> future : list) {
if(future.isDone()) {
    int[] data = future.get();
    ResourceLocation rl = new ResourceLocation("ttt.png");
    DynamicTexture1 dt = new DynamicTexture1(data);
    Minecraft.getMinecraft().getTextureManager().loadTexture(rl, dt);
}
}
}

class DynamicTexture1 extends AbstractTexture {
        private final int[] dynamicTextureData;
    /** width of this icon in pixels */
    private final int width;
    /** height of this icon in pixels */
    private final int height;

    public DynamicTexture1(int[] data)
    {
        this.width = textureWidth;
        this.height = textureHeight;
        this.dynamicTextureData = data;
        this.updateDynamicTexture();
    }

    public void loadTexture(IResourceManager resourceManager) throws IOException
    {
    }

    public void updateDynamicTexture()
    {
        TextureUtil.uploadTexture(this.getGlTextureId(), this.dynamicTextureData, this.width, this.height);
    }

    public int[] getTextureData()
    {
        return this.dynamicTextureData;
    }
}
 
Последнее редактирование:
2,505
81
397
Чо за wait? Это вообще работает? А будит кто?
Я же сказал, что тебе нужно потом получить результат из future, а не сразу. Так ты просто блочишь мейн поток и никакого толку с этого нет.
 
214
11
59
@Dahaka Да я понимаю, что future нужно кидать в мапу и в update() где-нибудь проверять isDone. Я же написал, это пример кода...
Ты мне скажи, логически там все верно ?)
 
Последнее редактирование:
Сверху