无法加速像素修改的BufferedImage

4
很长一段时间(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。
提前感谢!

你期望从将你不断绘制像素的图像缓冲区移动到GPU中获得什么样的性能提升呢?你知道,将数据多次写入内存,然后一次性将整个数据传输到GPU中比多次单独调用GPU更快。 - John Dvorak
请查看以下链接:https://dev59.com/623Xa4cB1Zd3GeqPkOxU - nullptr
你试过我发布的例子了吗? - nullptr
1个回答

4

源代码来自: Java硬件加速与英特尔集成显卡不兼容

尝试这样做:

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% 的 CPU。700 FPS

然后我添加了系统变量:

Variable name: J2D_D3D_NO_HWCHECK
         Variable value: true

然后重新启动IDE并运行程序:

我得到了惊人的结果。我的计算机支持硬件加速,java.exe只占用了5%的CPU。帧率达到了1700 FPS,动画表现十分出色!

以上内容是为了检查您的系统是否支持硬件加速。

现在回答您的问题:

据我所知:使用BufferedImage无法获得真正的硬件加速。您应该使用VolatileImage来获得硬件加速。但是使用VolatileImage时,需要注意无法获取像素数据缓冲区以修改像素。而且,逐个像素地使用硬件渲染也没有意义。

我的建议:

1)设计您的逻辑,使用volatile image的Graphics和Graphics2D来渲染像素。但不要采用绘制1像素线条之类的hack。

2)使用缓冲策略,双/三倍缓冲。

3)如果您想使用BufferedImage来设置每个像素,请将BufferedImage用作数据模型,同时在volatile image上绘制缓冲图像。如果您需要对图像进行缩放,这将非常有帮助。

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()这样的耗时数学运算,可以缓存这些运算的结果并创建查找表来加速运算。


这确实加速了,但是OP在编辑像素时加速关闭的问题。 - arynaq
其实我也一直在寻找这个问题的答案,后来从其他帖子中得到了答案,感到非常兴奋,忍不住想要帮助其他人。 - nullptr
实际上,这将帮助 OP 知道系统是否支持硬件加速! - nullptr
调用硬件进行此类操作会有开销,但如果您告诉硬件在一次调用中渲染800*600的图像,则总体开销会更小。 - nullptr
1
像这样思考,你告诉硬件绘制100x100的矩形(更高效)。另一种方式是,你告诉硬件逐个绘制矩形的每个像素100x100次(非常低效)。 - nullptr
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接