CPU到底是怎么操作独立显卡的?

您所在的位置:网站首页 windows10独立显卡怎么开 CPU到底是怎么操作独立显卡的?

CPU到底是怎么操作独立显卡的?

#CPU到底是怎么操作独立显卡的?| 来源: 网络整理| 查看: 265

问题1:

设备管理器属性里:

内存范围,表示的是MMIO(内存映射)的范围,这个范围是通过PCI配置寄存器读出来的,Windows里,在驱动里用HalGetBusData可以获得,用户态好像没有直接访问的方法。

关于PCI寄存器的描述,详见:

PCI configuration space

鉴于篇幅原因,只贴一个图:

其中你能看到的属性里的那些描述,都是Base Address Registers里的东西。

I/O范围,表示的是I/O端口号,如果你熟悉汇编,你就知道汇编里有IN/OUT指令,这个I/O范围指的就是操作这个设备使用IN/OUT指令时的端口范围,这个范围跟内存就没什么关系了。有些I/O范围也写在PCI配置里,但是没有严格的规定。

这段MMIO映射的内存大小代表什么意思呢?如果准确点说,我也不知道。

因为显卡厂商一般不太愿意公开这方面的信息,从我看到的一些资料上看,各个厂商对MMIO映射的地址空间的描述也完全不同,没有任何规范可言。

如果能拿到厂商的白皮书的话,也许还好办,但显卡厂商出于保密原因一般不给这方面的资料。

一般来说,这里包含的内容有:

1) 操作显卡的寄存器映射,用于发送控制命令,你的图里的那128K可能就是这个用途,这类地址一般都可以直接读写;

2) 映射显卡的一部分显存(注意不是全部),你的图里的那256M可能就是这个用途,这类地址读写的特性不确定。

问题2:

Linux一般是向Frame Buffer(

Framebuffer

)里写数据,然后显卡会周期性的取走数据。

写之前可能会通过I/O端口或者其它MMIO地址去操作显卡寄存器发送一部分控制命令,具体是什么就不清楚了,厂商一般都保密。

Windows应该采取的是类似的动作,Frame Buffer就是你截图里的那256M的一部分。

问题3:

你截图肯定不全,滚动条向下,你还能找到更多的MMIO内存地址范围,但一般情况下,不会把全部显存都映射过去。

原因是显存可能很大,这么做太浪费地址空间,对于32位系统来说,地址空间实在有限。

那么CPU是如何通过256M地址空间访问1G的显存的?原因是256M只是一个窗口,它可以把显存的某一段映射到内存中去,如果CPU要操作其它的位置,就发送控制命令改变映射的范围即可。

这个技术有点类似于:

Bank switching

问题4:

MMIO映射空间小于实际显卡显存,有些时候是为了刷新更多帧的需要,以题主你自己的显卡为例,可以先映射1G空间里的第一个256M,把要显示的图像写进去,再映射第二个256M,把后面要显示的图像写进去……以此类推,这样就能操作完整的显存了,甚至这么做可以提前把未来要绘制的图像先写到显存里。

不同的显卡每次能映射的最大显存数是不同的,可能是显卡本身DMA的限制,或者显卡本身处理能力有限,毕竟一次传输完一个完整显存大小的数据对于显卡来说负担还是太大了。

问题5:

你可以去了解一下PCI驱动的开发,但这方面真的没有书可以推荐,因为显卡技术涉及到的保密内容太多,其中很多东西甚至没有专利,只有一些小厂商公开了一部分2D加速的技术资料,但具体如何操作寄存器,如何渲染图像,资料实在太难找。

-----------------------------------

@Toe Z

的一些解释我不是特别认同,说CPU不能直接访问显存这个问题,我觉得说法不太严谨。

一般来说,Linux里都是用Frame Buffer驱动来向显卡写数据的,Frame Buffer最终是把数据送到显存里,这个过程是可以直接操作显存的,只不过这个“操作”的概念很模糊,因为有些是用DMA把数据传走的,如果说不能直接访问,也不对,至少DMA控制器是看见这部分显存了,只不过直接用CPU的指令MOV肯定会失败。

通常情况下操作显卡的动作是:

第一步:准备一个命令字,通过I/O端口或者MMIO映射的寄存器发送;

第二步:利用MMIO做DMA把内存里的东西送到显存里;

第三步:如果有返回命令,这里可能要等待DMA中断完成之类的动作;

如果是频繁的刷新图像,可能会有一个专门的线程不停的向MMIO映射的那部分显存里做DMA,目的就是不停的刷新显存,让显卡那边图像更新。

统一编址的用途是给DMA控制器做DMA的时候用的,否则DMA操作起来会很麻烦。所以,严格的说,看具体什么样的显卡,有些显卡的显存是可以被CPU直接访问的,有些是不能的,但所有显存都是可以被DMA的

-----------------------------------

题外话:

显卡的具体操作技术都是保密的,很多显卡驱动也都是闭源的,包括在Linux上(有办法可以规避GPL),显卡的3D加速之类的具体如何操作硬件,基本上不会有厂商公布,所以对外表现出来的这些特性只能猜。

一些有合作的企业会公布一些代码,但看代码有时候很难理解它的行为,所以不要指望说看几本书就会写显卡驱动,很不现实,要做显卡驱动最好是到显卡厂商那边去。

-----------------------------------

睡不着,做了一个比较有意思的实验:

在虚拟机里写一个简单的驱动,工作在内核态,然后找到显卡的MMIO的第一段地址,在驱动里加一段代码去读这个地址,结果发现这段地址上的数据正好就是屏幕上显示的像素信息。

VOID ReadGPUMem() { LARGE_INTEGER p; int * np; p.QuadPart = 0xE8000000; np = MmMapIoSpace(p, PAGE_SIZE, MmNonCached); if (np != NULL) { KdPrint(("%08x %08X %08X %08X %08X\n", np, np[0], np[1], np[2], np[3])); } else KdPrint(("Map fail\n")); return ; }

因为是读的前4个int,所以用截图键(print screen)截图比较了一下,像素点像素值完全等于我通过debug打印的数值,这说明0xE8000000这个地址就是我虚拟机上的显存地址。

然后我又在打印的后面加了一句:

RtlZeroMemory(np, PAGE_SIZE);

屏幕显示似乎没有变化,但通过截图键截图发现,屏幕的上面有一条黑线,正好是我ZeroMemory的位置:

这说明至少虚拟机里显卡映射的这部分是肯定可以读写的,甚至会影响系统截图的效果。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3