`
regular
  • 浏览: 77617 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java2D: 硬件加速 - 第一部分 - 非恒定图像类:Volatile Image

    博客分类:
  • Java
阅读更多
原文地址:Java2D: Hareware Accelerating - Part1 - Volatile Images

Java 1.4在Java 2D的功能方面引入了对硬件加速的支持。毫无疑问,硬件加速非常有用——不过有效的使用java.awt.image.VolatileImage至少要比使用传统的“图像缓冲”机制要复杂一些。仅当你在自行实现复杂的Java 2D渲染的时候,使用低级的“硬件加速”功能才是的确很重要的。如果你只是在使用比方说Swing里预编译的控件的话,那么这个技巧的大部分都不太合适。但是对那些Java的2D游戏编程的人,或者那些操作大量图形,如图表、图解的人来说,就非常有用了。

我假设这个技巧的读者至少熟悉双缓冲的概念——如果你不熟悉,请读这里。简短地说,双缓冲就是把渲染的过程推迟在“画面外”的缓冲里,然后快速地把缓冲复制到画面设备上,从而提高了画质(画面渲染得更柔和)。标准双缓冲的简单实现方式(没有硬件加速),代码基本如下:
// 也可以扩展其它类 - 不过通常会选择Canvas。
public class CustomGUI extends Canvas {
 
    private Image offscreenImage;
    private Graphics offscreenGraphics;
    private Dimension offscreenDimension;
 
    // ...
    public void paint(Graphics g) {
        Dimension currentSize = getSize();
        if(offscreenImage == null || !currentSize.equals(offscreenDimension)) {
            // 调用java.awt.Component.createImage(...)方法以获得Image对象
            offscreenImage = createImage(currentSize.width, currentSize.height);
            offscreenGraphics = offscreenImage.getGraphics();
            offscreenDimension = currentSize;   
        }

        // 渲染代码放在这里(使用offscreenGraphics的Graphics对象)
        // 算法假设背景会被重新填充因为这里重用了Image对象
        // (否则的话要从之前的渲染中取回背景)
        offscreenGraphics.setColor(Color.WHITE);
        offscreenGraphics.fillRect(0, 0, offscreenDimension.width, offscreenDimension.height);
        offscreenGraphics.setColor(Color.BLACK);
        offscreenGraphics.drawLine(0, 0, 10, 10); // 任意的渲染逻辑
  
        // 把缓冲画回主Graphics对象
        g.drawImage(offscreenImage, 0, 0, this);
    }

    public void update(Graphics g) {
        paint(g);
    }
}


这类“双缓冲”的情况是使用硬件加速最好的例子。然而现在问题变成了,如何使用java.awt.image.VolatileImage类来加速这里的代码?哦,以下的是改编自VolatileImage的Javadoc和Java关于volatile image的白皮书(深入理解阅读的强烈推荐)——上面那个类的新版本使用了VolatileImage做渲染——不用着急,我稍后会解释这段“离奇”的代码:
// 也可以扩展其它类 - 不过通常会选择Canvas。
public class CustomGUI extends Canvas {
    private VolatileImage volatileImg;

    // ...

    public void paint(Graphics g) {
        // 创建硬件加速图像
        createBackBuffer();

        // 主渲染循环。VolatileImage对象可能失去内容。 
        // 这个循环会不断渲染(如果需要的话并制造)VolatileImage对象
        // 直到渲染过程圆满完成。
        do {

            // 为该控件的Graphics配置验证VolatileImage的有效性。
            // 如果VolatileImage对象不能匹配GraphicsConfiguration
            // (换句话说,硬件加速不能应用在新设备上)
            // 那我们就重建它。
            GraphicsConfiguration gc = this.getGraphicsConfiguration();
            int valCode = volatileImg.validate(gc);

            // 以下说明设备不匹配这个硬件加速Image对象。
            if(valCode==VolatileImage.IMAGE_INCOMPATIBLE){
                createBackBuffer(); // 重建硬件加速Image对象。
            }

            Graphics offscreenGraphics = volatileImg.getGraphics();   
            offscreenGraphics.setColor(Color.WHITE);
            offscreenGraphics.fillRect(0, 0, getWidth(), getHeight());
            offscreenGraphics.setColor(Color.BLACK);
            offscreenGraphics.drawLine(0, 0, 10, 10); // 任意的渲染逻辑
   
            // 把缓冲画回主Graphics对象
            g.drawImage(volatileImg, 0, 0, this);
            // 检查内容是否丢失  
        } while(volatileImg.contentsLost());
    }
 
    // 以下创建新的VolatileImage对象
    private void createBackBuffer() {
        GraphicsConfiguration gc = getGraphicsConfiguration();
        volatileImg = gc.createCompatibleVolatileImage(getWidth(), getHeight());
    }

    public void update(Graphics g) {
        paint(g);
    }
}

呼——越来越复杂了。长话短说,VolatileImage只不过就是像名字所暗示的那样——易变化。VolatileImage可以被认为是在非标准内存(就是说显卡内存)中表达图像。这使得它们依赖于下层的硬件(显卡)特征,不是所有的时候都被激活,所以图像也可能或可能不被应用(表现在显卡没有使用的内存上)。这正是执行VolatileImage.IMAGE_INCOMPATIBLE检查的原因。我们要求VolatileImage对象验证自身在当前控件的GraphicsConfiguration中的有效性(请记住GraphicsConfiguration其核心代表了我们控件的目标“设备”),如果不匹配,我们就为当前GraphicsConfiguration(也就是当前显卡实例)重建VolatileImage。

除了外部的“有效性”检测之外,我们还恶心地(并罕见地)使用了do-while循环。有两个理由可以说明为何所有的逻辑被包裹在do-while循环中。第一,在我们已经开始渲染VolatileImage对象之后,图像可能再次变得不匹配。这种情况下,contentsLost()方法将返回true以让我们知道出问题了。第二,某些平台(我不指名)可能会出现显示内存“丢失”(BIU!哪去了?),这种情况需要你重写这块内存的所有数据。这种情况下VolatileImage.validate(...)返回的valCode实际上是VolatileImage.IMAGE_RESTORED(一共有三种结果——IMAGE_OK,IMAGE_RESTORED,IMAGE_INCOMPATIBLE)。而上面的代码的方案中,这个返回类型不需要显式地处理。通常,如果图像内容在上一次调用VolatileImage.validate(...)之后因为上述原因丢失,那么VolatileImage.contentsLost()返回true。也由于我强调的这种区别,我们的代码仅仅在每次循环中执行两次检验:在渲染逻辑之前调用VolatileImage.validate()(确保我们的图像对象可用),以及渲染逻辑之后的VolatileImage.contentsLost()调用,以确定我们上一次验证之后的图像都还在(表明我们调用validate之后所有的渲染逻辑都如预期所致)。

不要转台,我明天将秀给你看如何使用java.awt.image.BufferStrategy类隐藏这些疯狂的代码。
2
0
分享到:
评论
1 楼 fineqtbull 2009-10-30  
正在学习Java2D,期待下文!文中没有提到VolatileImage对渲染性能提高有多大影响,因该是与实际硬件有关吧,但如果能有个大概映像的话也能判断何时需要用该类,毕竟代码还是复杂了一点。

相关推荐

    Java多线程编程总结

    Java线程:概念与原理 Java线程:创建与启动 Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:线程的调度-...

    java线程详解

    Java线程:概念与原理 Java线程:创建与启动 Java线程:线程状态的转换 Java线程:线程的同步与锁 一、同步问题提出 二、同步和锁定 三、静态方法同步 四、如果线程不能不能获得锁会怎么样 五、何时需要同步...

    AEC-Q100-005D1:2012 Non-Volatile Memory Program-Erase Endurance,

    AEC-Q100-005D1:2012 Non-Volatile Memory Program-Erase Endurance, Data Retention, and Operational Life Test - 完整英文电子版(14页).zip

    C、C、Java语言的常用符号.doc

    - `continue`:跳过循环中剩余部分,进入下一次迭代 - `default`:switch语句的默认分支 - `extern`:外部链接属性 - `break`:退出循环或switch语句 - `case`:switch语句的分支 - `char`:字符型变量 - `...

    Java线程:volatile关键字

    与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。 volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说...

    OCA Java SE 7 Programmer I Certification Guide

    ### OCA Java SE 7 Programmer I 认证指南知识点概览 #### 一、认证考试简介 - **考试编号:** 1Z0-803 - **目标人群:** 对于希望获得 Oracle Certified Associate (OCA) Java SE 7 Programmer I 认证的专业人士。...

    2023最新 Java面试:1-100期Java面试题及答案整理合集

    这份“2023最新 Java面试:1-100期Java面试题及答案整理合集”涵盖了Java开发人员在求职过程中可能会遇到的各种问题,旨在帮助求职者全面准备面试,提升自己的竞争力。 1. **Java基础知识** - 类与对象:理解面向...

    Java并发编程:volatile关键字解析

    1. **通过在总线加LOCK#锁的方式**:这是一种较早的技术,在某个处理器正在修改共享数据时,通过锁住总线阻止其他处理器访问这部分数据。然而这种方法降低了系统的整体性能,因为它限制了其他处理器的工作。 2. **...

    图灵图书:图解JAVA多线程设计模式

    ### 图灵图书:图解JAVA多线程设计模式 #### 关键知识点概览 - **Java多线程基础** - 线程的概念与创建方式 - 线程的状态及其转换 - 线程生命周期 - **Java并发编程** - 同步机制(synchronized关键字) - ...

    Java后端技术面试基础汇总

    ### Java后端技术面试基础汇总 #### 一、Java基础知识 **1.1 Java基础** - **面向对象的特征:** - 继承:子类可以继承父类的属性和方法。 - 封装:将数据和行为封装在一起,提高数据安全性。 - 多态:同一...

    AEC-Q100-005D1:2012 非易失性存储器写入/擦除耐久性、数据保留和操作寿命测试 - 完整英文电子版(14页)

    完整英文电子版 AEC-Q100-005D1:2012 Non-Volatile Memory Program/Erase Endurance, Data Retention, and Operational Life Test (非易失性存储器程序-擦除耐久性、数据保留和操作寿命测试 )。本测试旨在评估...

    java面试题-java-interview-questions-master.zip

    java面试题_java-interview-questions-master.zip2、在 Java 程序中怎么保证多线程的运行安全? 出现线程安全问题的原因一般都是三个原因: 1、 线程切换带来的原子性问题 解决办法:使用多线程之间同步...

    JAVA核心技术--高级特征(第八版)--第三部分

    《JAVA核心技术--高级特征(第八版)--第三部分》是一本深入探讨Java编程高级特性的权威指南,涵盖了Java语言的精髓和最新发展。本书分为四部分,确保全面且系统地讲解了Java开发中的关键知识点,而这里我们将聚焦于第...

    JAVA修饰符总结.pdf

    - **说明:** 属于类而非实例,即所有实例共享同一份数据。 - **备注:** 可用于创建类变量(静态变量),在没有创建类实例的情况下即可访问。 - **transient:** - **说明:** 标记不需要序列化的变量。 - **...

    Java基础:volatile详解.pdf

    Java基础:volatile详解 Java基础:volatile详解问:谈谈你对volatile的理解? volatile是Java虚拟机提供的轻量级的同步机制,它有三个特性:保证可见性、不保证原子性、禁止指令重排。 1、volatile保证可见性 ...

    Java面试常见问题总结(2024最新版)

    - 内部类是定义在一个类内部的类,它可以访问外部类的成员变量和方法。 - 匿名内部类是没有名称的内部类,通常用于简化代码,特别是当内部类只被使用一次时。 13. **BIO、NIO和AIO的区别:** - BIO (Blocking I/...

    MultithreadingJava:来自Cave of Programming http的John Purcell的Java多线程课程代码

    1- Java 多线程:启动线程 2- Java 多线程:Volatile – 基本线程通信 3- Java 多线程:同步 4- Java 多线程:锁定对象 5- Java 多线程:线程池 6- Java 多线程:倒计时锁存器 7- Java 多线程:生产者-消费者 8- ...

    Java线程入门大全

    ### Java线程入门大全知识点详解 #### 一、线程基础概述 - **定义与特点:** - **线程**是一种比进程更细粒度的执行单元,它允许在一个进程中并发执行多个任务。 - **多线程**能够提高程序的效率和响应速度,...

    华为Java面试题目

    1. **Java基础知识:** - 类与对象:理解面向对象编程的基本概念,包括封装、继承和多态。 - 异常处理:掌握如何使用try-catch-finally语句,理解和应用异常类型。 - 内存管理:理解JVM内存模型,包括堆、栈、...

Global site tag (gtag.js) - Google Analytics