Swiftshader简介

Swiftshader是Google推出的OpenGL的软件实现.
它的机制和VM差不多, 可以动态地将shader翻译成cpu指令.

下图是它的架构, 主要有三层:

  1. Renderer: 负责将Shader中的操作转化为Reactor的调用.
  2. Reactor: 一种中间语言,主要就是包装了一下LLVM的调用.
  3. LLVM: Swiftshader底层通过LLVM来生成machine code.


    Architecture.png

本文分为三个部分:

  • Reactor Layer Introduction
  • Renderer Layer Introduction
  • Debug Tips

Reactor Layer Introduction

Reactor是一种中间语言, 可以嵌入在C++中使用.
它的语法参见Reactor.md

Reactor里定义了很多数据类型:

// src/Reactor/Reactor.hpp
class Bool;
...
class Short8;
class UShort8;
...
class Int4;
class UInt4;
...
class Float4;

可以使用RR_WATCH(variable_name)的形式来print Reactor变量.
前提是在CMakeList.txt中定义ENABLE_RR_PRINT

// src/Reactor/Print.hpp

// RR_WATCH() is a helper that prints the name and value of all the supplied
// arguments.
// For example, if you had the Int and bool variables 'foo' and 'bar' that
// you want to print, you can simply write:
//    RR_WATCH(foo, bar)
// When this JIT compiled code is executed, it will print the string
// "foo: 1, bar: true" to stdout.
//
// RR_WATCH() is intended to be used for debugging JIT compiled code, and
// is not intended for production use.
#   define RR_WATCH(...) RR_LOG(RR_WATCH_FMT(__VA_ARGS__), __VA_ARGS__)

与LLVM的接口主要在src/Reactor/LLVMReactor.cpp

需要注意的是: Renderer Layer里对它的调用都会生成machine code, 但这些machine code并不会立刻执行, 而是作为data存在的. 只有当swiftshader将程序入口指到这些code的时候,它们才会执行.

Renderer Layer Introduciton

它处理图像的时候大致会经历三个步骤:

  1. VertexRoutine
  2. SetupRoutine
  3. PixelRoutine
// src/Render/Render.cpp
    void Renderer::draw(DrawType drawType, unsigned int indexOffset, unsigned int count, bool update)

VertexRoutine: 用于处理顶点变换.

SetupRoutine: 根据顶点建立平面方程. 比如说根据三角形的三点来构建一个三角形的平面方程. Pixel Routine会根据平面方程来分别处理不同的pixel.

PixelRoutine: 计算pixel color, 并写入frame buffer.
PixelRoutine可以细分为三个主要步骤:
(a) interpolate: 将pixel shader的输入参数根据平面方程做插值
(b) apply shader: 执行pixel shader中的算子
(c) write color: 将数据写入frame buffer

PixelRoutine的处理逻辑可以参见:

//  src/Shader/PixelRoutine.cpp
    void PixelRoutine::quad(Pointer<Byte> cBuffer[RENDERTARGETS], Pointer<Byte> &zBuffer, Pointer<Byte> &sBuffer, Int cMask[4], Int &x)
    {

...
        // 这里将1个pixel的x扩展成4个pixel的x
        Float4 xxxx = Float4(Float(x)) + *Pointer<Float4>(primitive + OFFSET(Primitive,xQuad), 16);

...
        If(depthPass || Bool(!earlyDepthTest))
        {
...
            // 这里将1个pixel的y扩展成4个pixel的y
            Float4 yyyy = Float4(Float(y)) + *Pointer<Float4>(primitive + OFFSET(Primitive,yQuad), 16);
...
            for(int interpolant = 0; interpolant < MAX_FRAGMENT_INPUTS; interpolant++)
            {
                for(int component = 0; component < 4; component++)
                {
                    if(state.interpolant[interpolant].component & (1 << component))
                    {
                        if(!state.interpolant[interpolant].centroid)
                        {
                            v[interpolant][component] = interpolate(xxxx, Dv[interpolant][component], rhw, primitive + OFFSET(Primitive, V[interpolant][component]), (state.interpolant[interpolant].flat & (1 << component)) != 0, state.perspective, false);
                        }
                        else
                        {
                            v[interpolant][component] = interpolateCentroid(XXXX, YYYY, rhwCentroid, primitive + OFFSET(Primitive, V[interpolant][component]), (state.interpolant[interpolant].flat & (1 << component)) != 0, state.perspective);
                        }
                    }
                }
...

            if(colorUsed())
            {
...
                applyShader(cMask);
...
            }

            If(alphaPass)
            {
...
                    if(colorUsed())
                    {
...
                        rasterOperation(f, cBuffer, x, sMask, zMask, cMask);
                    }
                }
...
            }
        }
...
    }

xQuad和yQuad会在SetupRoutine里进行初始化:

// src/Shader/SetupRoutine.cpp
            Float4 xQuad = Float4(0, 1, 0, 1) - Float4(dx);
            Float4 yQuad = Float4(0, 0, 1, 1) - Float4(dy);

Swiftshaer使用Vector4f存放4个pixel的rgba.
Float4里面存放了1个pixel的(r, r, r, r) or (g, g, g, g) or (b, b, b, b) or (a, a, a, a). 明白了这一点, code会容易理解很多.

Debug Tips:

  1. Profile switch of PixelRoutine
// src/Main/Config.hpp
#define PERF_PROFILE 0   // Profile various pipeline stages and display the timing in SwiftConfig
  1. Dump llvm's IR
// src/Reactor/LLVMReactor.cpp
        if(false)
        {
            std::error_code error;
            llvm::raw_fd_ostream file(std::string(name) + "-llvm-dump-unopt.txt", error);
            jit->module->print(file, 0);
        }
  1. Print shader
// src/OpenGL/libGLESv2/Shader.cpp
    if(false)
    {
        static int serial = 1;

        if(false)
        {
            char buffer[256];
            sprintf(buffer, "shader-input-%d-%d.txt", getName(), serial);
            FILE *file = fopen(buffer, "wt");
            fprintf(file, "%s", mSource);
            fclose(file);
        }

        getShader()->print("shader-output-%d-%d.txt", getName(), serial);

        serial++;
    }
  1. Settings of Swiftshader
    Swiftshader提供了很多配置, 包括图像质量/线程数量/优化等级等等, 这些都会极大地影响性能
// Swiftshader.ini
...

[Quality]
TextureSampleQuality=2
MipmapQuality=1
PerspectiveCorrection=1
TranscendentalPrecision=2
TransparencyAntialiasing=0

[Processor]
ThreadCount=0
EnableSSE3=1
EnableSSSE3=1
EnableSSE4_1=1

[Optimization]
OptimizationPass1=1
OptimizationPass2=0
OptimizationPass3=0
OptimizationPass4=0
OptimizationPass5=0
OptimizationPass6=0
OptimizationPass7=0
OptimizationPass8=0
OptimizationPass9=0
OptimizationPass10=0
...
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354