Не удается ускорить BufferedImages с измененными пикселями.

Довольно долго, 1-2 месяца, я пытался найти ответ именно на эту проблему:

Я не могу получить аппаратное ускорение моего изображения!

Я искал в сети, создал свои собственные методы, ударился головой о клавиатуру (до сих пор чувствую боль), но безуспешно.

Хотя я ненавижу другие библиотеки, кроме Java SDK, я попробовал LWJGL и JOGL, но по какой-то глупой причине они не работают на моем компьютере.

Я пытался использовать System.setProperty("Dsun.java2d.opengl", "True"), я использовал VolatileImage, но я не могу рисовать отдельные пиксели (я пытался использовать drawLine(x,y,x,y), но это медленно)

Теперь я в таком отчаянии. Я сделаю все, чтобы это исправить! Поэтому, пожалуйста, если вы знаете решение (я знаю, что некоторые из вас знают), скажите мне, чтобы я мог избавиться от этого.

Мой код:

   public static void render(int x, int y, int w, int h, ) {

            int a[] = new int[3]; // The array that contains RGB values for every pixel
            BufferedImage bImg = Launcher.contObj.getGraphicsConfiguration().createCompatibleImage(800, 600, Transparency.TRANSLUCENT); // Creates an image compatible to my JPanel (Runs at 20-24 FPS on 800x600 resolution)
            int[] wr = ((DataBufferInt) bImg.getRaster().getDataBuffer()).getData(); // Contains the image data, used for drawing pixels
            for (int i = 0; i < bImg.getWidth(); i++) {
                for (int j = 0; j < bImg.getHeight(); j++) {
                    a[0] = i % 256;
                    a[2] = j % 256;
                    a[1] = i * j % 256;
                    wr[i + j * bImg.getWidth()] = new Color(a[0], a[1], a[2]).getRGB(); // Sets the pixels from a[]
                }
            }
            bImg.flush();
            g.drawImage(bImg, x, y, w, h, null); // Draws the image on the JPanel
            g.dispose();
            System.out.println(bImg.getCapabilities(Launcher.contObj.getGraphicsConfiguration()).isAccelerated()); // Prints out whether I was successful and made the image accelerated or failed and made everything worse
        }

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

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

Кроме того, может ли быть так, что моя видеокарта не поддерживает ускорение? (потому что я видел сообщения, где аппаратное ускорение работает для других людей, но не для меня) Кстати, это GeForce 430 GT.

ЗАРАНЕЕ СПАСИБО!


person Sonjo Falce    schedule 17.10.2013    source источник
comment
Какого прироста производительности вы ожидаете от переноса на графический процессор буфера изображения, в который вы продолжаете рисовать пиксели? Вы знаете, быстрее записать в память много раз, а затем сразу сбросить все это в GPU, чем делать много отдельных обращений к GPU.   -  person John Dvorak    schedule 17.10.2013
comment
проверьте это: stackoverflow.com/questions/14635377/   -  person nullptr    schedule 17.10.2013
comment
Вы пробовали пример, который я разместил!   -  person nullptr    schedule 17.10.2013


Ответы (1)


Источник скопирован из: Аппаратное ускорение Java не работает с интегрированной графикой Intel< /а>

Попробуй это:

package graphicstest;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;

public class GraphicsTest extends JFrame {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new GraphicsTest();
            }
        });
    }

    GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
    BufferCapabilities bufferCapabilities;
    BufferStrategy bufferStrategy;

    int y = 0;
    int delta = 1;

    public GraphicsTest() {

        setTitle("Hardware Acceleration Test");
        setSize(500, 300);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        setVisible(true);

        createBufferStrategy(2);
        bufferStrategy = getBufferStrategy();

        bufferCapabilities = gc.getBufferCapabilities();

        new AnimationThread().start();
    }

    class AnimationThread extends Thread {
        @Override
        public void run() {

            while(true) {
                Graphics2D g2 = null;
                try {
                    g2 = (Graphics2D) bufferStrategy.getDrawGraphics();
                    draw(g2);
                } finally {
                    if(g2 != null) g2.dispose();
                }
                bufferStrategy.show();

                try {
                    // CHANGE HERE, DONT SLEEP
                    //Thread.sleep(16);
                } catch(Exception err) {
                    err.printStackTrace();
                }
            }
        }
    }

    public void draw(Graphics2D g2) {
        if(!bufferCapabilities.isPageFlipping() || bufferCapabilities.isFullScreenRequired()) {
            g2.setColor(Color.black);
            g2.fillRect(0, 0, getWidth(), getHeight());
            g2.setColor(Color.red);
            g2.drawString("Hardware Acceleration is not supported...", 100, 100);
            g2.setColor(Color.white);
            g2.drawString("Page Flipping: " + (bufferCapabilities.isPageFlipping() ? "Available" : "Not Supported"), 100, 130);
            g2.drawString("Full Screen Required: " + (bufferCapabilities.isFullScreenRequired() ? "Required" : "Not Required"), 100, 160);
            g2.drawString("Multiple Buffer Capable: " + (bufferCapabilities.isMultiBufferAvailable() ? "Yes" : "No"), 100, 190);
        } else {
            g2.setColor(Color.black);
            g2.fillRect(0, 0, getWidth(), getHeight());
            g2.setColor(Color.white);
            g2.drawString("Hardware Acceleration is Working...", 100, 100);
            g2.drawString("Page Flipping: " + (bufferCapabilities.isPageFlipping() ? "Available" : "Not Supported"), 100, 130);
            g2.drawString("Full Screen Required: " + (bufferCapabilities.isFullScreenRequired() ? "Required" : "Not Required"), 100, 160);
            g2.drawString("Multiple Buffer Capable: " + (bufferCapabilities.isMultiBufferAvailable() ? "Yes" : "No"), 100, 190);
        }

        y += delta;
        if((y + 50) > getHeight() || y < 0) {
            delta *= -1;
        }

        g2.setColor(Color.blue);
        g2.fillRect(getWidth()-50, y, 50, 50);
    }
}

Выходные данные Аппаратное ускорение недоступно. java.exe загружал процессор на 12%. 700 кадров в секунду

Затем я добавил системную переменную:

Variable name: J2D_D3D_NO_HWCHECK
         Variable value: true

затем перезапустил IDE и запустил программу:

Я получил потрясающий результат. У меня доступно аппаратное ускорение. java.exe загружал 5% ЦП. 1700 кадров в секунду. Анимация была великолепна!

Вышеуказанные вещи должны проверить, работает ли аппаратное ускорение в вашей системе.

Теперь ваш вопрос:

AFAIK: вы не можете получить реальное аппаратное ускорение с BufferedImage. Вы должны работать с VolatileImage, чтобы получить аппаратное ускорение. Но с VolatileImage вы не можете заставить буфер данных пикселей изменять пиксели. И рендеринг пиксель за пикселем с использованием аппаратного обеспечения не имеет смысла.

Что я предлагаю:

1) Разработайте свою логику, которая может отображать пиксели, используя Graphics и Graphics2D изменчивого изображения. Но не стоит заниматься халтурой вроде рисования линий в 1 пиксель.

2) Используйте буферные стратегии, двойную/тройную буферизацию.

3) Если вы хотите придерживаться BufferedImage для настройки каждого пикселя, используйте BufferedImage в качестве модели данных, а при рендеринге рисуйте буферизованное изображение на изменчивом изображении. Это очень поможет, если вы масштабируете изображение.

4) Кэшировать часто отображаемые изображения.

5) Лучше пишите код, например:

int wi = bImg.getWidth();
int he = bImg.getHeight();
for (int i = 0; i < wi; i++) {
    for (int j = 0; j < he; j++) {
        wr[i + j * wi] = ((i % 256) << 16) | ((i * j % 256) << 8) | (j % 256);
    }
}

6) Для трудоемких математических операций, таких как sqrt(), sin(), cos(), кэшируйте результаты этих операций и создавайте таблицы поиска.

person nullptr    schedule 17.10.2013
comment
Конечно, это ускорено, но у ОП есть проблема с отключением ускорения, когда он редактирует пиксель. - person arynaq; 17.10.2013
comment
На самом деле я тоже давно искал ответ на этот вопрос, я получил этот ответ из другого поста и возбудился, не мог удержаться от помощи другим. - person nullptr; 17.10.2013
comment
На самом деле это поможет OP узнать, работает ли аппаратное ускорение в системе или нет! - person nullptr; 17.10.2013
comment
Извините за мой поздний ответ. Переменная окружения прибавила вроде 5 FPS (по крайней мере, я думаю, что из-за этого), но все равно не ускоряется. Об использовании VolatileImage... Какой смысл иметь 200 кадров в секунду, если я не могу менять пиксели? По крайней мере, алгоритм рендеринга, который я имел в виду, должен иметь возможность изменять отдельные пиксели, чтобы работать. Кстати, я точно не знаю, что вы подразумеваете под «кешированием изображений». В любом случае, спасибо за усилия, и извините за беспокойство. - person Sonjo Falce; 18.10.2013
comment
У меня есть еще один вопрос. Как графика системной библиотеки JRE рисуетRect, fillRect или drawImage? Я не могу придумать другого способа, кроме изменения пикселей. Почему их рисование ускоряется? Какой метод fillRect() использует для рисования пикселей и почему этот метод недоступен для нас? (Мой компьютер имеет доступное аппаратное ускорение) - person Sonjo Falce; 18.10.2013
comment
Видите ли, настройка пикселей с помощью аппаратного ускорения не имеет смысла, потому что если вам нужно изменить пиксели, скажем, для изображения 800x600, будете ли вы вызывать аппаратное обеспечение 800x600x200 раз для отрисовки полной картинки с 200 FPS? - person nullptr; 18.10.2013
comment
Вызов оборудования для таких вещей имеет накладные расходы, но если вы указываете оборудованию отображать изображение 800 * 600 за один вызов, общие накладные расходы меньше. - person nullptr; 18.10.2013
comment
Насколько я знаю, вызов drawRect fillRect или drawImage преобразуется в вызов аппаратного обеспечения для таких вещей, и аппаратное обеспечение обработает этот полный вызов. Накладные расходы меньше, так как вы сообщаете так много пикселей, которые нужно изменить за один вызов. - person nullptr; 18.10.2013
comment
Представьте, что вы сказали оборудованию рисовать прямоугольник размером 100x100 (более эффективно). Другой способ: вы сказали аппаратному обеспечению 100x100 раз отрисовывать каждый пиксель прямоугольника (очень менее эффективно). - person nullptr; 18.10.2013