前面一篇blog里面描述了命令环缓冲区机制,在命令环机制下,驱动写入PM4(不知道为何会取这样一个名字)包格式的命令对显卡进行配置。这一篇blog将详细介绍命令包的格式。

  当前定义了4中命令包,分别是0型/1型/2型和3型命令包,命令包由两部分组成,第一部分是命令包头,第二部分是命令包主体,命令包头为请求GPU执行的具体操作,命令主体为执行该操作需要的数据。

  • 0型命令包

  0型命令包用于写连续N个寄存器。包主体部分是依次往这些寄存器写的值。包头各个部分的意义为:

域名称 描述
12:0 BASE_INDEX 要写的连续寄存器的第一个寄存器地址,最大地址0x7FFF
14:13 保留位  
15 ONE_REG_WR

0表示将包主体的数据依次写入寄存器中

1表示所有数据写入同一个寄存器

29:16 COUNT 要写的寄存器数目N-1
31:30 TYPE 包类型,0型命令包类型名为0

  Linux内核代码./drivers/gpu/drm/radeon/r600.c r600\_fence\_ring\_emit函数有如下语句:

  radeon_ring_write(rdev, PACKET0(CP_INT_STATUS, 0));

  radeon_ring_write(rdev, RB_INT_STAT);

  PACKET0定义如下:

    #define PACKET0(reg, n) ((PACKET_TYPE0 << 30) |  \     包类型 0型命令包

(((reg) >> 2) & 0xFFFF) |          \        寄存器偏移基地址

((n) & 0x3FFF) << 16)                     要写的寄存器数目

  所有类型的数据包31~30bit为包类型标识符,0型数据包的类型标识符为0,其30bit为PACKET_TYPE0(0x0),29~16bit为命令写的寄存器数量-1((n) & 0x3FFF) << 16),上面例子只写一个寄存器,其值为0。第14~132bit为保留位,12~0bit ((reg) >> 2) & 0xFFFF)为第一个寄存器偏移地址,由于使用0型包可以访问的所有寄存器都是4字节的,寄存器地址都是4字节对其的,所以低2位为0。

  • 1型命令包

  1型命令包用于写两个的寄存器,1型命令包包头定义如下:

域名称 描述
10:0 REG_INDEX1 第一个寄存器的地址
22:11 REG_INDEX2 第二个寄存器的地址
29:22 RESERVED 保留位
31:30 TYPE 1型命令包的类型为0x1

  由于1型命令包可以用0型命令包代替而且1型命令包并不能够访问到所有寄存器,在内核radeon驱动中并没有使用1型命令包。

  • 2型命令包

  2型命令包是一个空命令包,用于填充对齐命令。2型命令包没有包主体,其包头最高两位为0x2,其它位无意义。

  2型命令包不做任何操作,仅用于填充保证对齐用,填充ring buffer的时候有对齐要求,内核radeon驱动对齐要求是16个dword(16×4字节),在命令没有16 dword对齐的时候,就需要使用2型命令包填充。

  drivers/gpu/drm/radeon/radeon_ring.c radeon_ring_commit函数用于通知GPU从ring buffer中取数据并执行,该函数包含如下代码:

count_dw_pad = (rdev->cp.align_mask + 1) - (rdev->cp.wptr & rdev->cp.align_mask);

for (i = 0; i < count_dw_pad; i++) {

radeon_ring_write(rdev, 2 << 30);

}

  第一句用于计算对齐命令需要的dword数目,后面的for循环用于填充2型命令。2型命令仅有个命令头部,并且只有31~30bit有效。

  • 3型命令包

  3型命令包是最功能最丰富的包,图形的主要功能都是通过这类包实现的。3型命令包主体内容由包头的IT_OPCODE决定。

域名称 描述
7:0 reserved 保留位
15:8 IT_OPCODE 操作码
29:16 COUNT 包主题DWORDS数目-1
31:30 TYPE 3型包类型为0x3

  3型命令是主要的命令包,涵盖了寄存器设置/绘图命令/同步等主要操作。以下是一个使用3型命令包设置寄存器的例子,这段代码来自drivers/gpu/drm/radeon/r600.c 的r600_ib_test函数:

ib->ptr[0] = PACKET3(PACKET3_SET_CONFIG_REG, 1);

ib->ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);

ib->ptr[2] = 0xDEADBEEF;

ib->ptr[3] = PACKET2(0);

ib->ptr[4] = PACKET2(0);

......

ib->ptr[15] = PACKET2(0);

ib->length_dw = 16;

  这段代码使用了indirect buffer,但是填充的命令和ring buffer中填充的命令是一样的。

#define PACKET3(op, n)  ((PACKET_TYPE3 << 30) |             \

(((op) & 0xFF) << 8) |             \

((n) & 0x3FFF) << 16)

  3型命令头部包含了操作码op和数据数目(以dword计)。上面例子中PACKET3(PACKET3_SET_CONFIG_REG, 1) PACKET3_SET_CONFIG_REG表明这次命令包用于设置寄存器,1表明后面有2个dword数据,分别是(scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2(寄存器地址)和0xDEADBEEF(往寄存器中写的值)。后面是用于对齐的2型包。

  下面使用一个更加复杂的命令包来说明3型包的使用,下面的这个命令包用于执行一个简单的2D操作。r600显卡是ATI推出的第一款使用统一着色器的GPU,r600及其以后的显卡不包含单独的2D单元,而是使用3D部件执行2D操作。为了简单起见,这里我们使用r500显卡上的填充矩形的命令包。

radeon_ring_write(rdev, PACKET3(PACKET3_PAINT_MULTI, 6));

radeon_ring_write(rdev,

RADEON_GMC_DST_PITCH_OFFSET_CNTL |

RADEON_GMC_DST_CLIPPING | // important

RADEON_GMC_BRUSH_SOLID_COLOR |          // 13 << 4

(RADEON_COLOR_FORMAT_ARGB8888 << 8) |     // << 8

RADEON_GMC_SRC_DATATYPE_COLOR |         // 4 << 12

RADEON_ROP3_P |                              // << 16

RADEON_GMC_CLR_CMP_CNTL_DIS);           // 1 << 28

radeon_ring_write(rdev, ((pitch / 64) << 22) | (fb_offset>>10));

radeon_ring_write(rdev, 0 | (0 << 16));                                   // SC_TOP_LEFT

radeon_ring_write(rdev, (fb_w -1) | ((fb_h -1) << 16));    // SC_BOT_RITE

radeon_ring_write(rdev, color); // this is color

radeon_ring_write(rdev, (x << 16) | y);

radeon_ring_write(rdev, (w << 16) | h);

radeon_ring_write(rdev, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0));

radeon_ring_write(rdev, RADEON_RB2D_DC_FLUSH_ALL);

radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));

radeon_ring_write(rdev, RADEON_WAIT_2D_IDLECLEAN|

RADEON_WAIT_HOST_IDLECLEAN|

RADEON_WAIT_DMA_GUI_IDLE);

  3型包根据他们IT_OPCODE的不同,其IT_BODY差别很大,如果IT_OPCODE的最高位为1(通常是2D绘图命令),那么PACKET还需要加入GUI control。R500上的2D绘图命令有如下格式:

HEADER

GUI_CONTROL

SETUP_BODY

DATA_BLOCK

  其中Header部分对应3型命令包的头,GUI_CONTROL和SETUP_BODY共同构成了当前绘图环境的配置,这两部分加上DATA_BLOCK共同构成了3型包的IT_BODY部分。上面的代码第一句表明该命令包执行的是矩形绘制(PAINT_MULTI可以同时绘制多个矩形,这里我们只绘制了一个矩形)。第二句对应GUI_CONTROL,GUI_CONTROL为32bit,内容为当前绘制环境的标志,下表给出了代码中使用的一些标志(如果是blit操作,除了表中的DSTxx参数外,还需要设置对应的SRCxx参数),关于这些标志更详细的信息可以参考“R5xx Acceleration v1.5.pdf”35-36页相关内容。

域名称 描述
1 DST_PITCH_OFFSET 绘图目标区域的PITCH值和该区域在GPU虚拟地址空间中的偏移,如果该为被置为1,则需要在SETUP_BODY中指定该参数
3 DST_CLIPPING 设置绘图区域的裁剪参数,如果该位置为1,则需要在SETUP_BODY中设置SC_TOP_LEFT和SC_BOTTOM_RIGHT参数
7:4 BRUSH_TYPE 绘图时使用的brush类型,brush类型需要根据这里给出的类型在SETUP_BODY中填brush包,不同的BRUSH_TYPE对应的brush包不同
11:8 DST_TYPE

绘图目标区域的像素类型:

1 :- (reserved)

2 :- 8 bpp pseudocolor

3 :- 16 bpp aRGB 1555

4 :- 16 bpp RGB 565

5 :- reserved

6 :- 32 bpp aRGB 8888

7 :- 8 bpp RGB 332

8 :- Y8 greyscale

9 :- RGB8 greyscale (8 bit intensity, duplicated for all 3 channels. Green channel is used on writes)

10 :- (reserved)

11 :- YUV 422 packed (VYUY)

12 :- YUV 422 packed (YVYU)

13 :- (reserved)

在上面示例程序中,以上标志位均被设置,并且BRUSH\_TYPE被设置为14,DST_TYPE设为32位真彩色。

根据GUI_CONTROL的设置,SETUP_BODY中需要设置以下参数:

DST_PITCH_OFFSET

SC_TOP_LEFT

SC_BOTTOM_RIGHT

BRUSH_PACKET

上面代码中的3-6行即是对这些参数的设置。更多参数的可以参考“R5xx Acceleration v1.5.pdf”37页的内容。

下面对这些参数进行介绍:

  • DST_PITCH_OFFSET

  包括了三部分,31:30位是和tiling相关的标志位,29:22位是以64字节为单位的pitch值,21:0位是DST绘图区域(在xorg中称为pixmap)以1KB为单位在显存中的偏移,这里提示我们,在分配内存的时候必须是1K对齐的,否则在使用的时候会出问题,后面讨论directfb的时候将会碰到这个问题。对于这个参数,上面代码填的是

radeon_ring_write(rdev, ((pitch / 64) << 22) | (fb_offset>>10));

  • SC_TOP_LEFTSC_BOTTOM_RIGHT

  指定绘图区域的裁剪区域,裁剪区域是个矩形,SC_TOP_LEFT指定裁剪区域左上方坐标,2D绘图时以屏幕左上方的点为原点,从左往又为X轴正方向,从上往下为Y轴正方向。

radeon_ring_write(rdev, 0 | (0 << 16));                            // SC_TOP_LEFT

radeon_ring_write(rdev, (fb_w -1) | ((fb_h -1) << 16)); // SC_BOTTOM_RIGHT

  fb_w和fb_h为当前绘图区域的长和宽,这里我们指定的裁剪区域就是整个绘图区域。

  • BRUSH_PACKET

  在GUI_CONTROL中指定的brush type为RADEON_GMC_BRUSH_SOLID_COLOR,关于brush type 和对应的值请参考“R5xx Acceleration v1.5.pdf”38页的内容,这里指定的类型为13,对应的BRUSH\_PACKET格式为4字节,内容为绘图使用的前景色。

radeon_ring_write(rdev, color); // the foreground color

  后面两句代码是DATA_BLOCK部分,对应绘图使用的参数。

radeon_ring_write(rdev, (x << 16) | y);// 矩形左上角坐标

radeon_ring_write(rdev, (w << 16) | h);// 矩形宽和高

  PAINT_MULTI命令包的DATA_BLOCK部分定义如下表示:

顺序 域名称 描述
1 [DST_X1 | DST_Y1] 第1个矩形左上角的坐标,高16位为X轴坐标,低16位为Y轴坐标
2 [DST_W1 | DST_H1] 第1个矩形的宽和高
...    
2n-1 [DST_Xn | DST_Yn] 第n个矩形左上角的坐标
2n [DST_Wn | DST_Hn] 第n个矩形的宽和高

  

  下面给出了一些代码,读者根据前面的介绍并参考“R5xx Acceleration v1.5.pdf” 是很容易理解的,如果机器上有R500核心的显卡,将这些代码添加到drivers/gpu/drm/radeon/radeon_test.c文件中并调用这些函数,在开启radeon_testing的情况下就能在启动阶段看到效果。

  • 画线

  POLYLINE的op_code为0x95,用于绘制折线。

1 void r5xx_draw_line_2d(struct radeon_device *rdev, uint64_t fb_location,

2             int *points, int num ,int color, int fb_w, int fb_h)

3 {

4     int r;

5     struct radeon_fence *fence = NULL;

6     int ndw = 32 + 6 + num;// ?? 32 is enough

7     int i = 0;

8

9     r = radeon_fence_create(rdev, &fence);

10     if (r) {

11         DRM_ERROR("Failed to create fence\n");

12         goto out_cleanup;

13     }

14     r = radeon_ring_lock(rdev, ndw);

15     radeon_ring_write(rdev, PACKET3(PACKET3_POLYLINE, 4 + num));

16     radeon_ring_write(rdev,

17             RADEON_GMC_DST_PITCH_OFFSET_CNTL |

18             RADEON_GMC_DST_CLIPPING | // important

19             RADEON_GMC_BRUSH_SOLID_COLOR |        // 13 << 4

20             (RADEON_COLOR_FORMAT_ARGB8888 << 8) |   //  << 8

21             RADEON_GMC_SRC_DATATYPE_COLOR |      // ??  4 << 12

22             RADEON_ROP3_P |                      // << 16

23             RADEON_GMC_CLR_CMP_CNTL_DIS);

24     radeon_ring_write(rdev, ((fb_w * 4 / 64) << 22) | (fb_location >>10));

25     radeon_ring_write(rdev, 0 | (0 << 16));

26     radeon_ring_write(rdev, (fb_w -1) | ((fb_h -1) << 16));

27     radeon_ring_write(rdev, color);

28     for( i = 0; i < num; ++i){

29            radeon_ring_write(rdev, *points++);

30     }

31     radeon_ring_write(rdev, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0));

32     radeon_ring_write(rdev, RADEON_RB2D_DC_FLUSH_ALL);

33     radeon_ring_write(rdev,

34             RADEON_WAIT_2D_IDLECLEAN |

35             RADEON_WAIT_HOST_IDLECLEAN |

36             RADEON_WAIT_DMA_GUI_IDLE);

37

38     if(fence) {

39         r = radeon_fence_emit(rdev, fence);

40     }

41     radeon_ring_unlock_commit(rdev);

42     r = radeon_fence_wait(fence, false);

43     if (r) {

44         DRM_ERROR("Failed to wait for fence\n");

45         goto out_cleanup;

46     }

47

48 out_cleanup:

49     if(fence) {

50         radeon_fence_unref(&fence);

51     }

52 }

  注意到这里调用了三个函数处理fence:radeon_fence_create,创建一个fence;radeon_fence_emit,在提交ring buffer之前发送fence;radeon_fence_wait,等待fence。在下一篇blog“中断机制”中会介绍。

  •  画矩形

  使用PAINT_MULTI可以绘制矩形,可以在一次命令中绘制多个矩形,其IT_OPCODE为0x9a。

1 void r5xx_draw_rectangl_2d(struct radeon_device *rdev, uint64_t fb_location,

2                 int x, int y, int w, int h, int color, int fb_w, int fb_h)

3 {

4     int r;

5     int ndw = 32 + 6;// ?? 32 is enough

6     struct radeon_fence *fence = NULL;

7

8     r = radeon_fence_create(rdev, &fence);

......

13     r = radeon_ring_lock(rdev, ndw);

......

18     radeon_ring_write(rdev, PACKET3(PACKET3_PAINT_MULTI, 6));

19     radeon_ring_write(rdev,

20             RADEON_GMC_DST_PITCH_OFFSET_CNTL |

21             RADEON_GMC_DST_CLIPPING | // important

22             RADEON_GMC_BRUSH_SOLID_COLOR |        // 13 << 4

23             (RADEON_COLOR_FORMAT_ARGB8888 << 8) |   //  << 8

24             RADEON_GMC_SRC_DATATYPE_COLOR |      // ??  4 << 12

25             RADEON_ROP3_P |                      // << 16

26             RADEON_GMC_CLR_CMP_CNTL_DIS);          // 1 << 28

27

28     radeon_ring_write(rdev, ((fb_w * 4 / 64) << 22) | (fb_location >>10));

29     radeon_ring_write(rdev, 0 | (0 << 16));

30     radeon_ring_write(rdev, (fb_w -1) | ((fb_h -1) << 16));

31

32     radeon_ring_write(rdev, color); // this is color

33     radeon_ring_write(rdev, (x << 16) | y);

34     radeon_ring_write(rdev, (w << 16) | h);

35

36     radeon_ring_write(rdev, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0));

37     radeon_ring_write(rdev, RADEON_RB2D_DC_FLUSH_ALL);

38     radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));

39     radeon_ring_write(rdev,

40           RADEON_WAIT_2D_IDLECLEAN |

41           RADEON_WAIT_HOST_IDLECLEAN |

42           RADEON_WAIT_DMA_GUI_IDLE);

43

44     r = radeon_fence_emit(rdev, fence);

......

49     radeon_ring_unlock_commit(rdev);

50     r = radeon_fence_wait(fence, false);

......

55 out_cleanup:

......

59 }

  • BLT

1 void r6xx_blit_2d(struct radeon_device *rdev,

2             uint64_t src_ad, uint64_t dst_addr,

3             int src_x, int src_y, int dst_x, int dst_y,

4             int src_w, int src_h, int fb_w, int fb_h)

5 {

6     int r;

7     int ndw;

8     struct radeon_fence *fence = NULL;

9     ndw = 64 + 10;

10

......

21     radeon_ring_write(rdev, PACKET3(PACKET3_BITBLT_MULTI, 8));

22     radeon_ring_write(rdev,

23                 RADEON_GMC_SRC_PITCH_OFFSET_CNTL |

24                 RADEON_GMC_DST_PITCH_OFFSET_CNTL |

25                 RADEON_GMC_SRC_CLIPPING |

26                 RADEON_GMC_DST_CLIPPING |

27                 RADEON_GMC_BRUSH_NONE |

28                 (RADEON_COLOR_FORMAT_ARGB8888 << 8) |

29                 RADEON_GMC_SRC_DATATYPE_COLOR |

30                 RADEON_ROP3_S |

31                 RADEON_DP_SRC_SOURCE_MEMORY |

32                 RADEON_GMC_CLR_CMP_CNTL_DIS |

33                 RADEON_GMC_WR_MSK_DIS);

34 // SRC_PITCH_OFFSET

35     radeon_ring_write(rdev, ((fb_w * 4/64) << 22) | (src_addr >> 10));

36 // DST_PITCH_OFFSET

37     radeon_ring_write(rdev, ((fb_w * 4/64) << 22) | (dst_addr >> 10));

38 // SRC_SC_BOT_RITE

39 //  radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16));

40     radeon_ring_write(rdev, (fb_w -1) | ((fb_h -1) << 16));

41 // SC_TOP_LEFT

42     radeon_ring_write(rdev, 0 | (0 << 16));

43 // SC_BOT_RITE

44 //  radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16));

45     radeon_ring_write(rdev, (fb_w -1) | ((fb_h -1) << 16));

46 // [SRC_X1 | SRC_Y1]

47     radeon_ring_write(rdev, (src_x << 16) | src_y);

48 // [DST_X1 | DST_Y1]

49     radeon_ring_write(rdev, (dst_x << 16) | dst_y);

50 // [SRC_W1 | SRC_H1]

51     radeon_ring_write(rdev, (src_w << 16) | src_h);

......

}

参考资料:

  本节内容主要参考资料为“R5xx Acceleration v1.5.pdf”。

【原创】Linux环境下的图形系统和AMD R600显卡编程(6)——AMD显卡GPU命令格式的更多相关文章

  1. 【原创】Linux环境下的图形系统和AMD R600显卡编程(1)——Linux环境下的图形系统简介

    Linux/Unix环境下最早的图形系统是Xorg图形系统,Xorg图形系统通过扩展的方式以适应显卡和桌面图形发展的需要,然而随着软硬件的发展,特别是嵌入式系统的发展,Xorg显得庞大而落后.开源社区 ...

  2. Linux环境下的图形系统和AMD R600显卡编程(1)——Linux环境下的图形系统简介

    转:https://www.cnblogs.com/shoemaker/p/linux_graphics01.html Linux/Unix环境下最早的图形系统是Xorg图形系统,Xorg图形系统通过 ...

  3. 【原创】Linux环境下的图形系统和AMD R600显卡编程(2)——Framebuffer、DRM、EXA和Mesa简介【转】

    转自:http://www.cnblogs.com/shoemaker/p/linux_graphics02.html 1. Framebuffer Framebuffer驱动提供基本的显示,fram ...

  4. 【原创】Linux环境下的图形系统和AMD R600显卡编程(5)——AMD显卡显命令处理机制

    通常通过读写设备寄存器对设备进行编程,在X86系统上,有专门的IO指令进行编程,在其他诸如MIPS.SPARC这类系统上,通过将设备的寄存器映射到内存地址空间直接使用读写内存的方式对设备进行编程. R ...

  5. 【原创】Linux环境下的图形系统和AMD R600显卡编程(3)——AMD显卡简介

    早期的显卡仅用于显示,后来显卡中加入了2D加速部件,这些部件用于做拷屏,画点,画线等操作.随着游戏.三维模拟以及科学计算可视化等需要,对3D的需求逐渐增加,早期图形绘制工作由CPU来完成,要达到真实感 ...

  6. 【原创】Linux环境下的图形系统和AMD R600显卡编程(9)——R600显卡的3D引擎和图形流水线

    1. R600 3D引擎 R600核心是AMD一款非常重要的GPU核心,这个核心引入了统一处理器架构,其寄存器和指令集同以前的GPU 都完全不同,对其编程也有比较大的区别. 图1显示了R600 GPU ...

  7. 【原创】Linux环境下的图形系统和AMD R600显卡编程(10)——R600显卡的3D引擎编程

    3D图形处理流水线需要流经多个硬件单元才能得到最后的渲染结果,流水线上的所有的硬件单元必须被正确编程,才能得到正确的结果. 总体上看,从图形处理流水线的源头开始,需要准备好vertex和index,在 ...

  8. 【原创】Linux环境下的图形系统和AMD R600显卡编程(7)——AMD显卡的软件中断

    CPU上处理的中断可以分成“硬件中断”和“软件中断”两类,比如网卡产生的中断称为硬件中断,而如果是软件使用诸如"int 0x10"(X86平台上)这样的指令产生中断称为软件中断,硬 ...

  9. Linux环境下的图形系统和AMD R600显卡编程(2)——Framebuffer、DRM、EXA和Mesa简介

    转:https://www.cnblogs.com/shoemaker/p/linux_graphics02.html 1. Framebuffer Framebuffer驱动提供基本的显示,fram ...

随机推荐

  1. awk命令例子详解

    awk -F: '{print "Number of dields: "NF}' passwd 字段分隔符设为冒号,所以每条记录的字段数变成7: awk  '{print &quo ...

  2. Null / Loopback (Null)

    参考: http://www.cnblogs.com/caoguoping100/p/3654452.html https://wiki.wireshark.org/NullLoopback 抓包安装 ...

  3. Maven学习 (三) 使用m2eclipse创建web项目

    1.首先确认你的eclipse已经安装好m2eclipse的环境,可以参照上两篇Maven学习内容 2.新建一个maven的项目 3.下一步默认配置,使用默认的工作空间,或者你可以自己选择其他的空间 ...

  4. laravel5.5队列

    目录 简单实例 1. 简介和配置 1.1 好处 1.2 配置文件 1.3 队列驱动的必要配置 2. 创建任务 2.1 生成任务类 2.2 修改任务类 2.3 分发任务 2.4 自定义队列 & ...

  5. erlang节点互通查看

    在局域网内部,一般用短节点名来完成短节点的全联通.     全联通的前提之一是cookie要相同,cookie记录在一个文件中.     对于同一个物理机上的两个erlang节点,不用其他配置就可以全 ...

  6. 一道关于C++ 继承/虚函数 笔试题 [转]

    转自:http://www.cnblogs.com/yangyh/archive/2011/06/04/2072393.html 首先这位作者, 因为看了这篇简短的一个博文, 我相同了关于虚函数方面的 ...

  7. python2.7写入文件时指定编码为utf-8

    python3.0可以这样写 f = open('ufile.log', 'w', 'utf-8')   但在python2.7中open()没有编码参数,如上那样写会报错,可以使用如下模块 impo ...

  8. mac虚拟机上(centos系统)怎样实现共享本机文件

    首先加载vboxadditions,可以从https://download.virtualbox.org/virtualbox/下载,记得一定要跟virtualBox版本对应 然后打开virtualb ...

  9. Linux认知之旅【01 与Linux第一次亲密接触】!

    一.搜索LINUX,了解它的前世今生! linux很厉害,应用在很多方面,我知道有超算.IOT.树莓派. 而且好多开发人员都在用这个系统.linux作为服务器使用,常年不用重启,不宕机,很少受病毒影响 ...

  10. Grid 布局管理器

    Grid 布局管理器: Grid布局类wx.GridSizer,Grid布局以网格形式对子窗口或控件进行摆放,容器被分成大小相等的矩形,一个矩形中放置一个子窗口或控件. wx.GridSizer构造方 ...