昨天写了一篇文章:
使用Linux Framebuffer绘制32位真彩图形: https://blog.csdn.net/dog250/article/details/90113737
并发了朋友圈表示这件事结束了,玩了一天,玩恶心了。

但是我依然是想做出一个可以拖拽的不规则GUI界面(用皮鞋或者小小的照片做界面轮廓)来的。所以半夜就爬起来继续折腾。

无奈,没有找到获取鼠标焦点的好方法,都太复杂,要知道,我是希望在framebuffer上玩啊,不希望依赖那些已经集成在GUI里面的东西。

我不就想模拟个拖拽嘛,简单,用线程控制图片在屏幕上漂移,即:

// setPoint方法已经抽象独立了出来,成为一个static方法,以免main函数太长。
while(true) {setPoint(width, height, xoffset%200, yoffset%50);try {Thread.sleep(100);} catch (InterruptedException e) { }xoffset += 2;yoffset += 2;
}

这个代码测试下来, 闪烁太厉害了! 根本就没法看:

怎么办?如果简单的图片漂移都这么闪烁,那如果鼠标拖拽移动图片,结局注定令人遗憾。怎么办?

找根源!根源就是 画图的时间太久了! 我可是一个像素一个像素画的啊!

当然了,我知道,如果Java通过JNI将一个像素数组传递到本地代码,然后本地代码直接 memcpy,那将是令人赛里布瑞特的。可是我并不知道如何从Java往本地代码传递大数组…另外,我注意是想把事情做纯粹些。 我不想把事情交给库去解决,我要自己解决! (可能赚钱的经理们又要笑我了,但我就是这样,鄙视业务逻辑。)

利用双缓冲来解决问题。

意思就是说, 逐像素点画图这件耗时的操作,不要直接操作显存,而是操作一块预先分配好的和显存一样大小的缓冲区,等逐点画图完成之后,一次性将该缓冲区的内容memcpy到事先mmap好的显存地址空间。

关于 双缓冲 技术我就不多说了,这技术的解释已经烂大街了,诸如什么流水线相关的形而上解释,看着都烦了,不过确实是那么回事。

直接上代码吧,先看Java代码 Drawimage.java

import java.awt.image.*;
import java.io.*;
import javax.imageio.ImageIO;public class Drawimage {static File src = null;static BufferedImage img = null;native static void setFB(int x, int y, int rgb);native static void show(int x);static {System.loadLibrary("setFB");}static void setPoint(int width, int height, int xoffset, int yoffset) {int i, j, rgb, a1;for (i = 1; i < width - 1; i++) {for (j = 1; j < height-1; j++) {rgb = img.getRGB(i, j);a1 = (rgb>>24)&0xFF;if (a1 != 0) {Drawimage.setFB(i + xoffset, j + yoffset, rgb);}}}}public static void main(String[] args) throws IOException {int i, j, width, height, xoffset = 0, yoffset = 0;src = new File(args[0]);img = ImageIO.read(src);width = img.getWidth();height = img.getHeight();while(true) {setPoint(width, height, xoffset%200, yoffset%50);Drawimage.show(0);    // 清空之前的图形Drawimage.show(1);    // 显示当下的图形 try {Thread.sleep(100); // 这个时间频率最好和你的显示器刷新频率切合。} catch (InterruptedException e) { }xoffset += 2; // x漂移yoffset += 2; // y漂移}}
}

再看本地代码 setFB.c

#include <fcntl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <stdio.h>
#include <jni.h>unsigned int *mem = NULL;// 定义第二缓冲区
unsigned int *back_buffer = NULL;
static struct fb_var_screeninfo info;void setPixel(int x, int y, int c)
{int idx;if (x < 0 || x >= info.xres || y < 0 || y >= info.yres) {return;}idx = y*info.xres + x;// 操作第二缓冲区,而不是直接操作显存back_buffer[idx] = c;
}JNIEXPORT void JNICALL Java_Drawimage_show (JNIEnv *env, jclass class, int a)
{// show指令下达,说明画图操作已经完成,这里一次性替换显存的内容// 注意,替换的时机最好是显示器刷新的时机,完美契合!!if (a) {memcpy(mem, back_buffer, info.xres*info.yres*info.bits_per_pixel/8);memset(back_buffer, 0, info.xres*info.yres*info.bits_per_pixel/8);} else {memset(mem, 0, info.xres*info.yres*info.bits_per_pixel/8);}
}JNIEXPORT void JNICALL Java_Drawimage_setFB (JNIEnv *env, jclass class, jint x, jint y, int rgb)
{static int fd = -1;if (fd == -1) {fd = open("/dev/fb0", O_RDWR);if (ioctl(fd, FBIOGET_VSCREENINFO, &info)) {exit(1);}info.bits_per_pixel = 8;info.xres = 800;info.yres = 600;if (ioctl(fd, FBIOPUT_VSCREENINFO, &info)) {exit(1);}mem = (unsigned int *)mmap(NULL, info.xres*info.yres*info.bits_per_pixel/8, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if (mem == NULL) {printf("exit\n");exit(1);}back_buffer = (unsigned int *)mmap(NULL, info.xres*info.yres*info.bits_per_pixel/8, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);if (back_buffer == NULL) {printf("back_buffer exit\n");exit(1);}}setPixel(x, y, rgb);
}

动图不闪哦:

双缓冲的原理就是这么简单。10年前看的的那些冗长的Java代码,都是假的,及其虚假。


皮鞋?下雨进水,一定会湿,问题的关键不是会不会湿,而是皮鞋进水湿了之后, 会不会胖!

浙江温州皮鞋湿,下雨进水不会胖。

Linux framebuffer双缓冲防止闪烁相关推荐

  1. Qt组件中的双缓冲无闪烁绘图

    双缓冲绘图 在Qt4中,所有的窗口部件默认都使用双缓冲进行绘图.使用双缓冲,可以减轻绘制的闪烁感.在有些情况下,用户要关闭双缓冲,自己管理绘图.下面的语句设置了窗口部件的Qt::WA_PaintOnS ...

  2. java 坦克重叠_【Java】我所知道坦克大战(单机版)之画出坦克的实心圆、让圆动起来、双缓冲解决闪烁问题...

    28640发布于 今天 02:47 本篇文章目的 画出坦克的实心圆 让坦克圆动起来 双缓冲解决闪烁问题 一.画出代表坦克的实心圆 我们需要画出一个圆,那么可以使用fillOval方法 fillOval ...

  3. C++零食:WTL中使用双缓冲避免闪烁

    双缓冲的原理可以这样形象的理解:把电脑屏幕看作一块黑板.首先我们在内存环境中建立一个"虚拟"的黑板,然后在这块黑板上绘制复杂的图形,等图形全部绘制完毕的时候,再一次性的把内存中绘制 ...

  4. 控制台双缓冲防闪烁--功能封装

    使用时,将包括#define DATALEN 10000的语句以及整个类.全局变量scrbuf的定义都拷贝到你的代码文件中. 默认不开启双缓冲. 调用scrbuf.on()开始双缓冲模式 此模式下,输 ...

  5. directx 双缓冲 运动 闪烁_24期0利率 | BMW超值福袋开启“双11”购车狂欢节!!

    BMW超值福袋开启"双11"购车狂欢节 24期0利率 首付一半开宝马 又到一年"双11",华晨宝马以十足的诚意,携新BMW X1.创新BMW X2以及BMW 1 ...

  6. java闪烁_java双缓冲解决屏幕闪烁

    今天做实验,发现了屏幕闪烁问题,网上找到解决方法,在此谢谢原作者 转自http://blog.sina.com.cn/s/blog_611ca6300100ezfx.html Java的强大特性让其在 ...

  7. EGE基础入门篇(九):双缓冲与手动渲染

    EGE专栏:EGE专栏 上一篇:EGE基础入门篇(八):清屏与重绘 下一篇: 文章目录 一.双缓冲机制 1. 单缓冲绘图 1.1 单缓冲绘图的缺点 1.2 系统读取帧缓冲 2. 双缓冲绘图 2.1 双 ...

  8. framebuffer之overview/双缓冲/alpha与colorkey/窗口平移与virtual screen平移

    本文介绍了s3c6410中的framebuffer,参考代码为Linux2.6.28.网上介绍framebuffer的文章很多,内核代码中也有关于framebuffer的文档,所以本文只介绍一些其它文 ...

  9. Delphi 使用双缓冲解决图片切换时的闪烁问题 good

    Delphi 使用双缓冲解决图片切换时的闪烁问题 good 参考文章: (1)Delphi 使用双缓冲解决图片切换时的闪烁问题 good (2)https://www.cnblogs.com/find ...

最新文章

  1. Docker实践(6)—CentOS7上部署Kubernetes
  2. 震撼!15项世界互联网领先科技成果发布,将对你的生活产生什么影响?
  3. 构建高可靠hadoop集群之0-hadoop用户向导
  4. 【Python基础】科学计算库Scipy简易入门
  5. [zz]volatile
  6. DRBD+HeartBeat+NFS 架构
  7. c#中常用集合类和集合接口之接口系列【转】
  8. 没有bug队——加贝——Python 57,58
  9. 信息学奥赛C++语言:趣味整数2(亲密数)
  10. 4小时学会雅达利游戏,AI需要几台电脑?
  11. Hadoop tutorial - 3 Hello MapReduce- 2015-3-30
  12. 终结者:终止线程循环的方式
  13. 操作系统课设 Nachos 实验六、七、八:Nachos 用户程序与系统调用、地址空间的扩展、系统调用 Exec() 与 Exit()
  14. RGMII自适应网络数据的处理方式
  15. vue 使用qrcode生成二维码功能
  16. 新鲜事儿!只有AI作品的电影节;酷~AI纹身设计师;ChatGPT的接生婆RLHF;Wayve自动驾驶模型MILE… | ShowMeAI资讯日报
  17. 每日一皮:朋友圈集赞原来还可以这样...
  18. SETUP FACTORY安装完成后自动运行软件
  19. Hive的Metastore服务和Hiveserver2服务的详细说明
  20. input框如何设置框禁止输入

热门文章

  1. Java架构师视频+授课资料
  2. IT十年人生过客-二十三-不要情怀要生活
  3. 甲方乙方项目管理的差别
  4. Wi-Fi显示“无Internet,安全”是怎么回事?
  5. School:1靶机
  6. 互联网启示:从生命起源到智慧宇宙的进化全景图
  7. 当初的愿望实现了吗?
  8. 彝文计算机,计算机彝文信息处理主流技术的分析与探讨
  9. 人工智能概念站上风口
  10. 借用女性形象营销,微众银行为获客搞“擦边”,背后有何猫腻?