想问一个关于全屏幕动画效率的问题

现在还是人类 2013-05-23 09:18:05
这段时间我在写一个图形动画引擎,是基于GDI来写的,但是感觉效果不是很好。我的这个引擎实现的方式大致是这样的。我创建了一个GDI设备(包括位图、刷子、字体什么的都设置好了),然后自己加载了几个位图数据到内存(这里的内存是指一个结构体数组,结构体包含图形资源的宽度、高度、具体符合GDI数据规范的数据指针等)。然后再添加图层(也是一个结构体数组),结构体包含图层的坐标、宽度、资源指针等。因为想引擎支持透明和半透明的资源,所以位图资源都采用32位的位图作为基础,分别是R、G、B、透明度这样的结构。因为涉及到运算,所以我就创建了一块与GDI设备数据大小相符的内存区域来实现这种图形运算,然后再用 SetBitmapBits 把处理好的内存数据设置到位图,然后再用Bitblt刷到窗口中。
我用了一个线程来专门轮询内存像素的每一个点,合并识别底图、以及每一个图层的数据,然后还用了一个线程来刷图。虽然最终效果是可以实现了,但是感觉速度上不能满足我的需求。在800*600的分辨率下,效果勉强可以接受,但在1366*768的情况下,动画效果就会很差,会卡。后来我就改了一下,采用了30个线程分块区运算,6*5个块区,虽然速度有所提升,但动画效果会根据块区线程的速度而脱节。之后我又改成了隔行扫描的方式,用了两个线程,一个处理单行数据,一个处理双行数据,效果还可以,速度上来一点,不过当动起来的时候,会有一条一条的扫描线影子。还有,我的程序是用VC写的,理论上循环运算效率应该是很快了的呀。
我想问一下,在这种全屏图形,有多个支持透明度调整的图层环境,用GDI作为基础,怎样才能更好的处理效果和效率方面呢?
...全文
485 23 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
Tiger_Zhao 2013-05-27
  • 打赏
  • 举报
回复
应该说GPU尚未在驱动级得到统一,只能在引擎级降低硬件差异性。 GPU高性能计算的前世今生
赵4老师 2013-05-27
  • 打赏
  • 举报
回复
提醒:动画效率再高,全屏白和全屏黑交替显示也会闪!
赵4老师 2013-05-27
  • 打赏
  • 举报
回复
处理图象有GPU不用非要用CPU?!
东方之珠 2013-05-27
  • 打赏
  • 举报
回复
VC++采用OpenGL编程比较合适。
PctGL 2013-05-26
  • 打赏
  • 举报
回复
多页缓存,画第一页的时候至少缓存2页以上 另加隔行贴图,只要帧速上来效果应该问题不大
嗷嗷叫的老马 2013-05-26
  • 打赏
  • 举报
回复
这个不知道了.....我猜测,DX的API应该也和GDI+一样吧,只不过最终一个是用GPU执行,一个是用CPU执行..... 这要问问对DX熟的哥们
现在还是人类 2013-05-25
  • 打赏
  • 举报
回复
引用 16 楼 myjian 的回复:
你看现在游行的DirectUI,本质上就是用显卡来处理图像,相当于实现了一个DirectX版本的GDI+. QQ那么多的图片量,在静态工作时CPU占用可以低到1%左右(我的CPU是N970/4核/2.2G) 而且QQ做了深度封装,可以直接利用XML来进行界面管理,使用与开发也方便了.
难道只有用现成的图形接口才能使用GPU运算?无法自己去用?那么那些图形接口又是如何做到的呢?
现在还是人类 2013-05-25
  • 打赏
  • 举报
回复
还有,运算部分是不是改为汇编会好一点?
现在还是人类 2013-05-25
  • 打赏
  • 举报
回复
那在Windows中如何自己调用GPU运算呢?
嗷嗷叫的老马 2013-05-25
  • 打赏
  • 举报
回复
我也觉得用DirectX吧. 毕竟GDI+多数是靠CPU,而DirectX却是由显卡来处理的,CPU与GPU在干图像处理方面硬件上就有天生的区别...
嗷嗷叫的老马 2013-05-25
  • 打赏
  • 举报
回复
你看现在游行的DirectUI,本质上就是用显卡来处理图像,相当于实现了一个DirectX版本的GDI+. QQ那么多的图片量,在静态工作时CPU占用可以低到1%左右(我的CPU是N970/4核/2.2G) 而且QQ做了深度封装,可以直接利用XML来进行界面管理,使用与开发也方便了.
Tiger_Zhao 2013-05-24
  • 打赏
  • 举报
回复
不是有 TransparentBlt 吗,为什么要自己处理图层合并? 你这哪里是写“基于GDI引擎”,而是写“GDI的替代品”了。
现在还是人类 2013-05-24
  • 打赏
  • 举报
回复
这是我简化过的线程合成数据的代码

void desktopui::Refresh(int ThreadIndex)
{
	int				x;
	int				y;
	long			gdiX,gdiY,gdiAddr;
	long			gdiXAddr,gdiYAddr;
	long			i,j;
	long			layerX,layerY;
	long			lbX,lbY,lbAddr;
	long			RYAddr,RXAddr;
	float			lwProportion,lhProportion;
	PALETTEENTRY	defColor,readColor,secondaryColor,colorA,colorB,colorC;
	int				zoomMode;
	int				nLOver;
	int				IsPix;
	int				InitRow;

	InitRow = ThreadIndex;

	for(y=InitRow;y<this->height;y=y+this->ThreadCount){
		gdiY = y;
		gdiYAddr = this->bytesWLength*gdiY;
		RYAddr = gdiYAddr;
		for(x=0;x<this->width;x++){
			gdiX = x;
			gdiXAddr = gdiX*4;
			RXAddr = gdiXAddr;
			gdiAddr = gdiXAddr+gdiYAddr;
			secondaryColor.peBlue	= this->Backs[gdiAddr];
			secondaryColor.peGreen	= this->Backs[gdiAddr+1];
			secondaryColor.peRed	= this->Backs[gdiAddr+2];

			for(i=0;i<this->LayerLength;i++){
				IsPix = 0;
				if(gdiX>=this->Layers[i].left)
				if(gdiX<(this->Layers[i].left+this->Layers[i].width))
				if(gdiY>=this->Layers[i].top)
				if(gdiY<(this->Layers[i].top+this->Layers[i].height)){
					IsPix = 1;
				}
				if(IsPix==1){
					lbX = gdiX-(this->Layers[i].left);
					lbY = gdiY-(this->Layers[i].top);
					lbAddr = (lbY*(this->Layers[i].img->wsize))+(lbX*4);

					readColor.peBlue	= this->Layers[i].img->bytes[lbAddr];
					readColor.peGreen	= this->Layers[i].img->bytes[lbAddr+1];
					readColor.peRed		= this->Layers[i].img->bytes[lbAddr+2];
					readColor.peFlags	= this->Layers[i].img->bytes[lbAddr+3];

					if(i==0||readColor.peFlags==255){
						secondaryColor.peBlue	= readColor.peBlue;
						secondaryColor.peGreen	= readColor.peGreen;
						secondaryColor.peRed	= readColor.peRed;
					}else{
						secondaryColor.peBlue	= secondaryColor.peBlue + Round(((float)(readColor.peBlue - secondaryColor.peBlue) / (float)255) * (float)readColor.peFlags);
						secondaryColor.peGreen	= secondaryColor.peGreen + Round(((float)(readColor.peGreen - secondaryColor.peGreen) / (float)255) * (float)readColor.peFlags);
						secondaryColor.peRed	= secondaryColor.peRed + Round(((float)(readColor.peRed - secondaryColor.peRed) / (float)255) * (float)readColor.peFlags);
					}

				}
			}

			this->bytes[RXAddr+RYAddr]		= secondaryColor.peBlue;
			this->bytes[RXAddr+RYAddr+1]	= secondaryColor.peGreen;
			this->bytes[RXAddr+RYAddr+2]	= secondaryColor.peRed;
			this->bytes[RXAddr+RYAddr+3]	= 0x00;
		}
	}
	SetBitmapBits(this->memBitmap,this->bytesLength,this->bytes);
}
现在还是人类 2013-05-24
  • 打赏
  • 举报
回复
引用 7 楼 Tiger_Zhao 的回复:
不知道你用什么方法实现缩放的?变换其实有现成函数可用的。 World space 到 Page space 的转换简介
缩放我是直接在数据里运算的,不过为了测试效率,我就把缩放部分屏蔽掉了,测试时也没有做缩放处理,但效率不高。
Tiger_Zhao 2013-05-24
  • 打赏
  • 举报
回复
不知道你用什么方法实现缩放的?变换其实有现成函数可用的。
World space 到 Page space 的转换简介
Tiger_Zhao 2013-05-24
  • 打赏
  • 举报
回复
那样性能就不能要求太高,毕竟 GDI+ 可以调用硬件实现的。
Round(((float)(readColor.peBlue - secondaryColor.peBlue) / (float)255) * (float)readColor.peFlags);
避免浮点运算,这个可以改成先乘再整除的运算。
现在还是人类 2013-05-24
  • 打赏
  • 举报
回复
引用 10 楼 Tiger_Zhao 的回复:
不是有 TransparentBlt 吗,为什么要自己处理图层合并? 你这哪里是写“基于GDI引擎”,而是写“GDI的替代品”了。
我这么做只是纯粹搞这种技术的研究而已,并不是不了解或不知道有什么现成的东西可用,只是想更深入更测底的去了解这种技术而已,当然,我更希望自己在这方面可以做到改良或创新,不过前提是更为深入的了解和运用。
worldy 2013-05-23
  • 打赏
  • 举报
回复
引用 2 楼 Tiger_Zhao 的回复:
动画分辨率≠屏幕分辨率 比如普通的网络电视,“片源”可能就是VCD的分辨率(352x288 或 352x240),全屏也只不过将该解码后的内容放大后进行显示,并不是屏幕有多大就需要片源分辨率有多大。 你也可以做成“小动画”,最后一步才放大到屏幕显示。
使用gdi,小动画放大后,速度肯定明细下降
Tiger_Zhao 2013-05-23
  • 打赏
  • 举报
回复
动画分辨率≠屏幕分辨率
比如普通的网络电视,“片源”可能就是VCD的分辨率(352x288 或 352x240),全屏也只不过将该解码后的内容放大后进行显示,并不是屏幕有多大就需要片源分辨率有多大。
你也可以做成“小动画”,最后一步才放大到屏幕显示。
worldy 2013-05-23
  • 打赏
  • 举报
回复
gdi需要经历复杂的转换和内存拷贝才能最终显示,作为动画,要得到满意的结果,估计很难,正如很好的车走在坑坑洼洼的路上,速度也上不来,动画还是是用directx,或者opengl比较合适
加载更多回复(3)

808

社区成员

发帖
与我相关
我的任务
社区描述
VB 多媒体
社区管理员
  • 多媒体
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧