Я замечаю большую разницу в результативности между 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) ценились бы, я обновлю эти оценки.
Короткий ответ Классы текстур 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)
Я не уверен, что это полностью ликвидирует разрыв в производительности, но вы должны иметь возможность использовать метод 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);
Вы изучили JAI ( Java Advanced Imaging), так или иначе, он реализует собственное ускорение для таких задач, как сжатие / распаковка png. Здесь может возникнуть проблема с реализацией распаковки PNG в Java. Какую версию jvm вы используете?
Я работаю с приложениями, которые загружают и визуализируют тысячи текстур, для этого я использую чистую реализацию Java формата DDS, доступную в NASA WorldWind. Текстуры DDS загружаются в GL быстрее, так как они распознаются видеокартой.
Я ценю ваше тестирование и хотел бы использовать ваши эксперименты, чтобы проверить время загрузки DDS. Также настройте память, доступную для JAI и JVM, чтобы разрешить загрузку большего количества сегментов и распаковку.
На самом деле, я загружаю свои текстуры в jogl, как это:
TextureData data = TextureIO.newTextureData(stream, false, fileFormat);
Texture2D tex = new Texture2D(...); // contains glTexImage2D
tex.bind(g);
tex.uploadData(g, 0, data); // contains glTexSubImage2D
Текстуры нагрузки таким образом могут обойти дополнительную работу для преобразования буферизации и интерпретации. Это довольно быстро для меня. Вы можете профилировать его. Я жду вашего результата.