Archive

Posts Tagged ‘汇编’

最近都流行实现 Coroutine 么 ?

August 10th, 2019 No comments

这两天看着大家都在实现无栈的 coroutine 都挺好玩的,但无栈协程限制太多,工程实践上很少用,所以昨天手痒写了个有栈的 coroutine ,接口反照 ucontext 的接口,不比无栈的复杂多少:

int main(void)
{
    ctx_context_t r;
    int hr;
    volatile int mode = 0;

    hr = ctx_getcontext(&r);
    printf("ctx_getcontext() -> %d\n", hr);

    if (mode == 0) {
        mode++;
        printf("first run\n");
        ctx_setcontext(&r);
    }
    else {
        printf("second run\n");
    }
    printf("endup\n");

    return 0;
}

使用 ctx_getcontext / ctx_setcontext 可以实现保存现场,恢复现场的功能,该程序输出:

ctx_getcontext() -> 0
first run
ctx_getcontext() -> 6356604
second run
endup

继续使用 ctx_makecontext / ctx_swapcontext 可以实现初始化协程和切换上下文的功能:

char temp_stack[32768];
ctx_context_t mc, cc;

int raw_thread(void*p) {
    printf("remote: hello %s\n", (char*)p);
    ctx_swapcontext(&cc, &mc);

    printf("remote: back again\n");
    ctx_swapcontext(&cc, &mc);

    printf("remote: return\n");
    return 1024;
}

int main(void)
{
    cc.stack = temp_stack;
    cc.stack_size = sizeof(temp_stack);
    cc.link = &mc;

    ctx_getcontext(&cc);
    ctx_makecontext(&cc, raw_thread, (char*)"girl");

    printf("before switch: %d\n", cc.stack_size);
    ctx_swapcontext(&mc, &cc);

    printf("local: here\n");
    ctx_swapcontext(&mc, &cc);

    printf("local: again\n");
    ctx_swapcontext(&mc, &cc);

    printf("local: end\n");
    return 0;
}

这里创建了一个协程,接着主程序和协程互相切换,程序输出:

before switch: 32768
remote: hello girl
local: here
remote: back again
local: again
remote: return
local: end

关于实现

核心代码其实很简单,就 60 多行,没啥复杂的:

(点击 Read more 展开)

Read more…

Categories: 编程技术 Tags:

计算机底层是如何访问显卡的?

June 17th, 2016 1 comment

以前 DOS下做游戏,操作系统除了磁盘和文件管理外基本不管事情,所有游戏都是直接操作显卡和声卡的,用不了什么驱动。

虽然没有驱动,但是硬件标准还是放在那里,VGA, SVGA, VESA, VESA2.0 之类的硬件标准,最起码,你只做320x200x256c的游戏,或者 ModeX 下 320x240x256c 的游戏的话,需要用到VGA和部分 SVGA标准,而要做真彩高彩,更高分辨率的游戏的话,就必须掌握 VESA的各项规范了。

翻几段以前写的代码演示下:

例子1: 初始化 VGA/VESA 显示模式

基本是参考 VGA的编程手册来做:

INT 10,0 - Set Video Mode
    AH = 00
    AL = 00  40x25 B/W text (CGA,EGA,MCGA,VGA)
       = 01  40x25 16 color text (CGA,EGA,MCGA,VGA)
       = 02  80x25 16 shades of gray text (CGA,EGA,MCGA,VGA)
       = 03  80x25 16 color text (CGA,EGA,MCGA,VGA)
       = 04  320x200 4 color graphics (CGA,EGA,MCGA,VGA)
       = 05  320x200 4 color graphics (CGA,EGA,MCGA,VGA)
       = 06  640x200 B/W graphics (CGA,EGA,MCGA,VGA)
       = 07  80x25 Monochrome text (MDA,HERC,EGA,VGA)
       = 08  160x200 16 color graphics (PCjr)
       = 09  320x200 16 color graphics (PCjr)
       = 0A  640x200 4 color graphics (PCjr)
       = 0B  Reserved (EGA BIOS function 11)
       = 0C  Reserved (EGA BIOS function 11)
       = 0D  320x200 16 color graphics (EGA,VGA)
       = 0E  640x200 16 color graphics (EGA,VGA)
       = 0F  640x350 Monochrome graphics (EGA,VGA)
       = 10  640x350 16 color graphics (EGA or VGA with 128K)
         640x350 4 color graphics (64K EGA)
       = 11  640x480 B/W graphics (MCGA,VGA)
       = 12  640x480 16 color graphics (VGA)
       = 13  320x200 256 color graphics (MCGA,VGA)
       = 8x  EGA, MCGA or VGA ignore bit 7, see below
       = 9x  EGA, MCGA or VGA ignore bit 7, see below

    - if AL bit 7=1, prevents EGA,MCGA & VGA from clearing display
    - function updates byte at 40:49;  bit 7 of byte 40:87
      (EGA/VGA Display Data Area) is set to the value of AL bit 7

转换成代码的话,类似这样:

// enter standard graphic mode
int display_enter_graph(int mode)
{ 
    short hr = 0;
    union REGS r;
    memset(&r, 0, sizeof(r));
    if (mode < 0x100) { 
        r.w.ax = (short)mode;
        int386(0x10, &r, &r);
        r.h.ah = 0xf;
        int386(0x10, &r, &r);
        if (r.h.al != mode) hr = -1;
    }   
    else { 
        r.w.ax = 0x4f02;
        r.w.bx = (short)mode;
        int386(0x10, &r, &r);
        if (r.w.ax != 0x004f) hr = -1;
    }
    return hr;
}

Read more…

Categories: 图形编程 Tags: ,

超越 SDL/DirectDraw/GDI 性能的位图库

April 29th, 2016 2 comments

开源一个高性能位图库,之前对我的二维图形库 pixellib 进行了精简和重写,最终形成一个只包含两个文件(BasicBitmap.h, BasicBitmap.cpp)的图形基础库。

在今天 GPU 绘制横行天下的时候,任然有很多时候需要使用到纯 CPU实现的图形库,比如图像处理,视频预处理与合成,界面,以及GPU无法使用的情况(比如某个应用把gpu占满了,或者无法通过gpu做一些十分灵活的事情时),纹理处理,简单图片加载保存等。

支持 SSE2/AVX 优化,比 DirectDraw 快 40%(全系统内存绘制),比 SDL 快 10%,比GDI快 38%。如果你需要一个方便的高性能位图库,足够高性能的同时保证足够紧凑。

如果你有上述需求,那么你和我一样需要用到 BasicBitmap,只需要把 BasicBitmap.h/.cpp 两个文件拷贝到你的代码中即可。我正是为了这个目的编写了这两个文件。

特性介绍

  • 高度优化的 C++ 代码,可以在任意平台编译并运行
  • 多重像素格式,从8位到32位:A8R8G8B8, R8G8B8, A4R4G4B4, R5G6B5, A8, 等.
  • Blit (Bit Blt) ,包含透明和非透明的模式。
  • 像素格式快速转换
  • 使用不同的 Compositor 进行 Blending
  • 使用不同的过滤器进行缩放(nearest, linear, bilinear)
  • 高质量位图重采样(Bicubic/Box)
  • 支持从内存或者文件直接读取 BMP/TGA 文件
  • 支持从内存或者文件直接读取 PNG/JPEG 文件(Windows下)
  • 保存图片为 BMP/PPM 文件
  • 核心绘制函数可以被外部实现通过设置函数指针重载(比如 SSE2实现)
  • 比 DirectDraw 快 40% 的性能进行绘制(打开 AVX/SSE2支持)
  • 比 GDI 的 AlphaBlend 函数快34%的性能进行混色
  • Self-contained, 不依赖任何其他第三方库
  • 高度紧凑,只需要拷贝 BasicBitmap.h/.cpp 两个文件到你项目即可

项目地址

Blit 性能比较

Full window (800×600) blitting (both opacity and transparent), compare to GDI/SDL/DirectDraw:

32 Bits Blit Opacity Transparent
BasicBitmap C++ fps=2325 fps=1368
BasicBitmap AVX/SSE2 fps=2904 fps=2531
GDI fps=2333 fps=1167
SDL fps=2671 fps=1015
DirectDraw fps=2695 fps=2090

Note: use BltFast with DirectDrawSurface7 in System Memory to perform Opacity & Transparent blit. BitBlt and TransparentBlt(msimg32.dll) are used in the GDI testing case.

16 Bits Blit Opacity Transparent
BasicBitmap C++ fps=4494 fps=1253
BasicBitmap AVX/SSE2 fps=9852 fps=2909
DirectDraw BltFast fps=5889 fps=861

Blitting performance in SDL & GDI are slower than DirectDraw, just compare to ddraw as well.

8 Bits Blit Opacity Transparent
BasicBitmap C++ fps=11142 fps=1503
BasicBitmap AVX/SSE2 fps=18181 fps=5449
DirectDraw BltFast fps=14705 fps=4832

DirectDrawSurface in Video Memory takes the benefit of hardware acceleration which is definitely faster than BasicBitmap. If you really need hardware acceleration, use OpenGL/DX as well.

BasicBitmap is a software implementation which aims to achieve the best performance in all other software implementations: like GDI/GDI+, SDL/DirectDraw in System Memory, for examples.

So just compare to DirectDrawSurface in System Memory. Use it in the condition that you only need a lightweight software solution: GUI/Cross Platform/hardware unavailable/image processing/video compositing, etc.

混色性能比较

SRC OVER FPS
BasicBitmap C++ 594
BasicBitmap SSE2 1731
GDI (msimg32.dll) 1137

note: 800×600 full window src-over blending vs GDI’s AlphaBlend function (in msimg32.dll).

Categories: 图形编程 Tags: , ,

内存拷贝优化(3)-深入优化

December 20th, 2015 5 comments

今天继续在原来内存拷贝代码上优化:

1. 修改了小内存方案:由原来64字节扩大为128字节,由 int 改为 xmm,小内存性能提升 80%
2. 修改了中内存方案:从4个xmm寄存器并行拷贝改为8个并行拷贝+prefetch,提升20%左右
3. 去除目标地址头部对齐的分支判断,用一次xmm拷贝完成目标对齐,性能替升10%。
4. 增加测试用例:为贴近实际,增加了随机访问,10MB空间内(绝对大于L2尺寸)随机位置和长度的测试

为避免随机数生成影响结果,提前生成随机数,最终平均性能达到gcc4.9配套标准库的2倍以上:

https://github.com/skywind3000/FastMemcpy

最新代码测试结果(可以对比老的表看新版本性能是否有所提升):

Read more…

Categories: 编程技术 Tags: ,

内存拷贝优化(2)-全尺寸拷贝优化

December 18th, 2015 No comments

四年前写过一篇小内存拷贝优化:https://www.skywind.me/blog/archives/143

纠结了一下还是把全尺寸拷贝优化代码发布出来吧,没啥好保密的,

如今总结一下全尺寸内存拷贝优化的要点:

1. 策略区别:64字节以内用小内存方案,64K以内用中尺寸方案,大于64K用大内存拷贝方案。

2. 查表跳转:拷贝不同小尺寸内存,直接跳转到相应地址解除循环。

3. 目标对齐:64字节以上拷贝的先用普通方法拷贝几个字节让目标地址对齐,好做后面的事情。

4. 矢量拷贝:并行一次性读入N个矢量到 sse2 寄存器,再并行写出。

5. 缓存预取:使用 prefetchnta ,提前预取数据,等到真的要用时数据已经到位。

6. 内存直写:使用 movntdq 来直写内存,避免缓存污染。

 

部分理论,见论文:《Using Block Prefetch for Optimized Memory Performance

 

但论文考虑问题比较单一,所以实际代码写的比论文复杂不少,目前在各个尺寸上基本平均能够加速 40%,比较GCC 4.9, VS2012的 memcpy,不排除未来的 libc, crt库继续完善以后,能够达到下面代码的速度。但我看libc和crt的 memcpy代码已经很久没人更新了,不知道他们还愿意继续优化下去么?

行了,具体实现各位读代码吧,需要 SSE2 指令集支持,gcc编译时需要 –msse2 一下,点击(more)展开代码,测试结果附在源文件最后注释部分:

Read more…

Categories: 编程技术 Tags: ,

转换 Intel汇编格式到 AT&T汇编风格

April 10th, 2015 1 comment

常用 MSVC写内嵌汇编需要兼容 GCC是一件头疼的事情,不是说你不会写 GCC的 AT&T风格汇编,而是说同一份代码写两遍,还要调试两遍,是一件头疼的事情,特别是汇编写了上百行的时候。于是五年前写过一个小工具,可以方便的进行转换,能把 MSVC/MASM的汇编转成纯 AT&T风格汇编,或者 GCC Inline风格汇编,自动识别寄存器和变量,还有跳转地址,并且自动导出。今天把他放上来,或许有用到的人吧。

Read more…

[自制开源] 轻量级图形库 PixelLib

January 10th, 2010 6 comments

图像:64种不同的像素格式,色彩空间变换,多种图形图像变换。
质量:支持3种级别抗锯齿效果,高质量几何图形绘制。
实现:轻量级纯软件实现,100% C代码(仅700KB代码)。
优化:SSE2/MMX优化

地址:https://github.com/skywind3000/pixellib

1. 图像变换:

支持仿射变换和透视变换,提供大量图像变换操作接口。

Read more…

[业余土制] 实时汇编编译器

July 5th, 2009 3 comments

实时动态在内存中编译汇编代码,并返回函数调用指针,可用于JIT系统的后端:

项目地址:http://code.google.com/p/asmpure/

例子:

const char *AlphaBlendAsm =
"PROC C1:DWORD, C2:DWORD, A:DWORD\n"
"    movd mm0, A\n"
"    punpcklwd mm0, mm0\n"
"    punpckldq mm0, mm0\n"
"    pcmpeqb mm7, mm7\n"
"    psubw mm7, mm0\n"
"    \n"
"    punpcklbw mm1, C1\n"
"    psrlw mm1, 8\n"
"    punpcklbw mm2, C2\n"
"    psrlw mm2, 8\n"
"    \n"
"    pmullw mm1, mm7\n"
"    pmullw mm2, mm0\n"
"    paddw mm1, mm2\n"
"    \n"
"    psrlw mm1, 8\n"
"    packuswb mm1, mm1\n"
"    movd eax, mm1\n"
"    emms\n"
"    ret\n"
"ENDP\n";

void testAlphaBlend(void)
{
        CAssembler *casm;
        int c;

        int (*AlphaBlendPtr)(int, int, int);

        // create assembler
        casm = casm_create();

        // append assembly source
        casm_source(casm, AlphaBlendAsm);

        AlphaBlendPtr = (int (*)(int, int, int))casm_callable(casm, NULL);

        if (AlphaBlendPtr == NULL) {
                printf("error: %s\n", casm->error);
                casm_release(casm);
                return;
        }

        printf("==================== Alpha Blend ====================\n");

        casm_dumpinst(casm, stdout);

        printf("\nExecute code (y/n)?\n\n");

        do
        {
                c = getch();
        }
        while(c != 'y' && c != 'n');

        if(c == 'y')
        {
                int x = AlphaBlendPtr(0x00FF00FF, 0xFF00FF00, 128);
                printf("output: %.8X\n\n", x);
        }

        free(AlphaBlendPtr);
        casm_release(casm);
}

output: 7f7f7f7f

Wordpress Social Share Plugin powered by Ultimatelysocial