Погрузка PNGs в проблемы работы OpenGL - Java & JOGL намного медленнее, чем C# & дао. OpenGL

Я замечаю большую разницу в результативности между Java & JOGL и C# & дао. OpenGL, когда и загружающий PNGs от хранения в память, и загружая, что BufferedImage (Ява) или Битовый массив (C# - оба - PNGs на жестком диске) 'в' OpenGL.

Эти различия довольно значительные, таким образом, я предположил, что делал что-то не так, однако после довольно большого поиска и попытки различных методов погрузки, я был неспособен уменьшить это различие.

С Явой я загрузил изображение в 248 мс и загруженный в OpenGL в 728 мс, то же на C# занимает 54 мс, чтобы загрузить изображение, и 34 мс, чтобы загрузить/создать структуру.

Рассматриваемое изображение выше - PNG, содержащий прозрачность, измеренную 7200x255, используемый для 2D оживленного эльфа. Я понимаю, что размер действительно довольно смешон и считает сокращение эльфом, однако значительные различия все еще там (и путающий).

На Явской стороне кодекс похож на это:

BufferedImage image = ImageIO.read(new File(fileName));
texture = TextureIO.newTexture(image, false);
texture.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
texture.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);

C# кодируют использование:

Bitmap t = new Bitmap(fileName);

t.RotateFlip(RotateFlipType.RotateNoneFlipY);
Rectangle r = new Rectangle(0, 0, t.Width, t.Height);

BitmapData bd = t.LockBits(r, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

Gl.glBindTexture(Gl.GL_TEXTURE_2D, tID);
Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, t.Width, t.Height, 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, bd.Scan0);
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);

t.UnlockBits(bd);
t.Dispose();

После довольно большого тестирования я могу только прийти к выводу, что Java/JOGL просто медленнее здесь - чтение PNG не могло бы быть столь же быстрым, или что я все еще делаю что-то не так.

Спасибо.

Edit2:

Я нашел, что, создавая новый BufferedImage с форматом TYPE_INT_ARGB_PRE уменьшает время загрузки структуры OpenGL почти на половину - это включает необходимость создать новый BufferedImage, получение Graphics2D от него и затем предоставление ранее нагруженного изображения к нему.

Edit3: Оценка заканчивается для 5 изменений. Я написал маленький инструмент сопоставительного анализа, следующие результаты прибывают из погрузки ряда 33 pngs, большинство очень широко, 5 раз.

testStart: ImageIO.read(file) -> TextureIO.newTexture(image)  
result: avg = 10250ms, total = 51251  
testStart: ImageIO.read(bis) -> TextureIO.newTexture(image)  
result: avg = 10029ms, total = 50147  
testStart: ImageIO.read(file) -> TextureIO.newTexture(argbImage)  
result: avg = 5343ms, total = 26717  
testStart: ImageIO.read(bis) -> TextureIO.newTexture(argbImage)  
result: avg = 5534ms, total = 27673  
testStart: TextureIO.newTexture(file)  
result: avg = 10395ms, total = 51979  

ImageIO.read (еще раз) относится к технике, описанной в ответе Джеймса Брэнигэна ниже. argbImage относится к технике, описанной в моем предыдущем, отредактируйте:

img = ImageIO.read(file);
argbImg = new BufferedImage(img.getWidth(), img.getHeight(), TYPE_INT_ARGB_PRE);
g = argbImg.createGraphics();
g.drawImage(img, 0, 0, null);
texture = TextureIO.newTexture(argbImg, false);

Больше методы погрузки (или изображения из файла или изображения к OpenGL) ценились бы, я обновлю эти оценки.

7
задан Ed Cresswell 20 December 2009 в 23:45
поделиться

4 ответа

Короткий ответ Классы текстур JOGL делают немного больше, чем нужно, и я полагаю, что именно поэтому они медленные. Я столкнулся с той же проблемой несколько дней назад, и теперь решил ее, загружая текстуру с помощью низкоуровневого API (glGenTextures, glBindTexture, glTexParameterf и glTexImage2D). Время загрузки уменьшилось примерно с 1 секунды до "без заметной задержки", но я не проводил систематического профилирования.

Длинный ответ. Если вы посмотрите документацию и исходный код классов JOGL TextureIO, TextureData и Texture, то заметите, что они делают гораздо больше, чем просто загрузка текстуры на GPU:

  • Работа с различными форматами изображений
  • Альфа-премультипликация

Я не уверен, что из этого занимает больше времени. Но во многих случаях вы знаете, какие данные изображения у вас есть, и вам не нужно делать никакого предварительного умножения.

Функция предварительного умножения альфа-файлов в любом случае совершенно неуместна в этом классе (с точки зрения архитектуры программного обеспечения), и я не нашел способа ее отключить. Несмотря на то, что в документации утверждается, что это "математически правильный способ" (на самом деле я в этом не уверен), существует множество случаев, когда вы не хотите использовать альфа-преумножение или сделали это заранее (например, по соображениям производительности).

В конце концов, загрузка текстуры с помощью низкоуровневого API довольно проста, если только вам не нужно, чтобы он обрабатывал различные форматы изображений. Вот код на scala, который отлично работает для всех моих RGBA текстурных изображений:

val textureIDList = new Array[Int](1)
gl.glGenTextures(1, textureIDList, 0)
gl.glBindTexture(GL.GL_TEXTURE_2D, textureIDList(0))
gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR)
gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR)
val dataBuffer = image.getRaster.getDataBuffer   // image is a java.awt.image.BufferedImage (loaded from a PNG file)
val buffer: Buffer = dataBuffer match {
  case b: DataBufferByte => ByteBuffer.wrap(b.getData)
  case _ => null
}
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, image.getWidth, image.getHeight, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, buffer)

...

gl.glDeleteTextures(1, textureIDList, 0)
7
ответ дан 7 December 2019 в 01:22
поделиться

Я не уверен, что это полностью ликвидирует разрыв в производительности, но вы должны иметь возможность использовать метод ImageIO.read, который принимает InputStream и передает BufferedInputStream, обертывающий FileInputStream. Это должно значительно уменьшить количество вызовов ввода-вывода собственных файлов, которые должна выполнять JVM. Это будет выглядеть так:

File file = new File(fileName);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis, 8192); //8K reads
BufferedImage image = ImageIO.read(bis);
1
ответ дан 7 December 2019 в 01:22
поделиться

Вы изучили JAI ( Java Advanced Imaging), так или иначе, он реализует собственное ускорение для таких задач, как сжатие / распаковка png. Здесь может возникнуть проблема с реализацией распаковки PNG в Java. Какую версию jvm вы используете?

Я работаю с приложениями, которые загружают и визуализируют тысячи текстур, для этого я использую чистую реализацию Java формата DDS, доступную в NASA WorldWind. Текстуры DDS загружаются в GL быстрее, так как они распознаются видеокартой.

Я ценю ваше тестирование и хотел бы использовать ваши эксперименты, чтобы проверить время загрузки DDS. Также настройте память, доступную для JAI и JVM, чтобы разрешить загрузку большего количества сегментов и распаковку.

1
ответ дан 7 December 2019 в 01:22
поделиться

На самом деле, я загружаю свои текстуры в jogl, как это:

TextureData data = TextureIO.newTextureData(stream, false, fileFormat);
Texture2D tex = new Texture2D(...);   // contains glTexImage2D
tex.bind(g);
tex.uploadData(g, 0, data);  // contains glTexSubImage2D

Текстуры нагрузки таким образом могут обойти дополнительную работу для преобразования буферизации и интерпретации. Это довольно быстро для меня. Вы можете профилировать его. Я жду вашего результата.

1
ответ дан 7 December 2019 в 01:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: