2分钟带你了解什么是Vsync

了解Vsync,首先我们需要认知如下问题

  1. 什么是GPU
  2. CPU在渲染之前起到什么作用
  3. 什么是帧,帧率
  4. 什么是画面撕裂

什么是GPU

GPU为图形处理器,又称显示核心、视觉处理器、显示芯片。

在这里插入图片描述
是一种专门在个人电脑、工作站、游戏机和一些移动设备(如平板电脑、智能手机等)上做图像和图形相关运算工作的微处理器主要用于画面的渲染。

CPU在渲染之前起到什么作用?

在这里插入图片描述
在屏幕显示一个画面时候,他需要获取GPU合成的图层数据,进行渲染,而GPU进行图层合成时候,他的数据来自于CPU计算好的数据。
也就是说,一个画面的显示过程为,CPU通过程序的业务代码运算产生的数据,运输到GPU进行图层合成,发送到屏幕进行渲染显示。

什么是帧,帧率

帧(fps)是一个画面的显示,屏幕一秒显示多少个帧(画面),称为帧率。平时看到的60fps,代表一秒绘制60帧,反过来可以知道,60fps的渲染,一帧大概是需要16.66毫秒。人眼的正常帧率范围是30到60帧之间,如果在程序运行时候产生的画面帧率比这范围更低,视觉看到的画面会出现卡顿,也就是人们说的掉帧。通常手机屏幕的渲染帧数为60fps,高性能的手机为120fps。因此,显示画面的fps越高,意味,画面越流畅

在这里插入图片描述

什么是屏幕撕裂?

通过上面的了解我们已经知道,一个画面的绘制流程,如下图
在这里插入图片描述
每一个帧在显示器上绘制都需要从buffer缓冲区上拿去数据,进行刷新屏幕。在早期,只有一个缓冲区,并没有绘制同步概念,如果一个画面一边读取一边绘制还没完全完毕时候,突然缓冲区的数据被GPU合成的数据替换,就会造成画面有多重画面叠层效果,如下图,

在这里插入图片描述
这种情况称之为画面撕裂。GPU写入过快或写入过慢都会导致画面撕裂。后来为了解决这个问题,人们用了双或多缓冲区来解决这个问题
在这里插入图片描述
提供一个缓冲区提供给GPU写入,提供一个给显示器读取。当GPU写入完毕时候,下一次显示器读取时候,只需要将这两个数据交换即可。这就避免了GPU生产和显示器读取数据时间问题。那么问题又来了, 那么什么时候是写的缓冲区的数据交换到读的buffer缓冲区的最佳时期?答案是,显示器刚好绘制完一帧的时候。显示器绘制完一帧时候会发送一个信号给GPU,如果此时GPU已经写入完成,就会把这个数据与读Buffer缓冲区交换数据。这个信号称之为Vsync,也就是垂直信号,这就是Vsync的由来。如果下个次Vsync来时候,只写的buffer缓冲区没写完的话,显示器不会执行数据交换,而是再等一次Vsync信号来才进行交换。这个没有能成为被屏幕利用的数据,被成为Jank。后面为了减少Jank产生,就有了多缓冲Buffer区域。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然可以,以下是一个简单的Verilog代码,用于控制Nexys4 DDR板子的VGA显示和实现一个简单的CPU: ``` module VGA_CPU ( input clk, // 输入时钟信号 input rst, // 复位信号 output reg vga_hsync, // VGA水平同步信号 output reg vga_vsync, // VGA垂直同步信号 output reg [3:0] vga_r, // VGA红色信号 output reg [3:0] vga_g, // VGA绿色信号 output reg [3:0] vga_b // VGA蓝色信号 ); // 垂直同步计数器 reg [9:0] v_cnt; // 水平同步计数器 reg [9:0] h_cnt; // VGA分辨率 parameter WIDTH = 640; parameter HEIGHT = 480; // 垂直同步时序 parameter V_SYNC_START = 1; parameter V_SYNC_END = 10; parameter V_BACK_PORCH = 33; parameter V_ACTIVE = 480; parameter V_FRONT_PORCH = 10; // 水平同步时序 parameter H_SYNC_START = 1; parameter H_SYNC_END = 96; parameter H_BACK_PORCH = 48; parameter H_ACTIVE = 640; parameter H_FRONT_PORCH = 16; // CPU寄存器 reg [7:0] reg_a; reg [7:0] reg_b; reg [7:0] reg_c; reg [7:0] reg_d; reg [7:0] reg_e; reg [7:0] reg_f; reg [7:0] reg_g; reg [7:0] reg_h; // CPU指令存储器 reg [7:0] mem [255:0]; // CPU指令计数器 reg [7:0] pc; // CPU指令 parameter LOAD_A = 8'h00; parameter LOAD_B = 8'h01; parameter ADD_AB = 8'h02; parameter SUB_AB = 8'h03; parameter MOV_AB = 8'h04; parameter JMP = 8'h05; always @(posedge clk) begin // 复位信号 if (rst) begin v_cnt <= 0; h_cnt <= 0; vga_hsync <= 1; vga_vsync <= 1; vga_r <= 0; vga_g <= 0; vga_b <= 0; reg_a <= 0; reg_b <= 0; reg_c <= 0; reg_d <= 0; reg_e <= 0; reg_f <= 0; reg_g <= 0; reg_h <= 0; pc <= 0; end else begin // 垂直同步计数器 if (v_cnt >= HEIGHT + V_SYNC_START + V_SYNC_END + V_BACK_PORCH + V_ACTIVE + V_FRONT_PORCH - 1) begin v_cnt <= 0; end else begin v_cnt <= v_cnt + 1; end // 水平同步计数器 if (h_cnt >= WIDTH + H_SYNC_START + H_SYNC_END + H_BACK_PORCH + H_ACTIVE + H_FRONT_PORCH - 1) begin h_cnt <= 0; end else begin h_cnt <= h_cnt + 1; end // 垂直同步信号 if (v_cnt < V_SYNC_START || v_cnt >= HEIGHT + V_SYNC_START + V_SYNC_END) begin vga_vsync <= 1; end else begin vga_vsync <= 0; end // 水平同步信号 if (h_cnt < H_SYNC_START || h_cnt >= WIDTH + H_SYNC_START + H_SYNC_END) begin vga_hsync <= 1; end else begin vga_hsync <= 0; end // 红色信号 if (h_cnt >= H_SYNC_START + H_BACK_PORCH && h_cnt < H_SYNC_START + H_BACK_PORCH + H_ACTIVE && v_cnt >= V_SYNC_START + V_BACK_PORCH && v_cnt < V_SYNC_START + V_BACK_PORCH + V_ACTIVE) begin vga_r <= 8'hFF; end else begin vga_r <= 0; end // 绿色信号 if (h_cnt >= H_SYNC_START + H_BACK_PORCH && h_cnt < H_SYNC_START + H_BACK_PORCH + H_ACTIVE && v_cnt >= V_SYNC_START + V_BACK_PORCH && v_cnt < V_SYNC_START + V_BACK_PORCH + V_ACTIVE) begin vga_g <= 8'hFF; end else begin vga_g <= 0; end // 蓝色信号 if (h_cnt >= H_SYNC_START + H_BACK_PORCH && h_cnt < H_SYNC_START + H_BACK_PORCH + H_ACTIVE && v_cnt >= V_SYNC_START + V_BACK_PORCH && v_cnt < V_SYNC_START + V_BACK_PORCH + V_ACTIVE) begin vga_b <= 8'hFF; end else begin vga_b <= 0; end // CPU指令执行 case(mem[pc]) LOAD_A: reg_a <= mem[pc+1]; LOAD_B: reg_b <= mem[pc+1]; ADD_AB: reg_c <= reg_a + reg_b; SUB_AB: reg_c <= reg_a - reg_b; MOV_AB: reg_b <= reg_a; JMP: pc <= mem[pc+1]; default: // do nothing endcase // 更新PC if (mem[pc] == JMP) begin // 跳转指令 pc <= pc + 2; end else begin // 非跳转指令 pc <= pc + 1; end end end endmodule ``` 这个代码使用了一个简单的CPU,通过指令存储器和指令计数器来执行指令。你可以根据需要添加更多指令和CPU寄存器。注意在使用之前需要先了解Nexys4 DDR板子的VGA接口规格和CPU架构。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值