WebKit新著色語言WHLSL

本文將介紹一門叫作Web High Level Shading Language(WHLSL啤挎,發(fā)音為“whistle”)的新Web圖形著色語言堪遂,它對HLSL進(jìn)行了擴(kuò)展,變得更安全检诗、更可靠甩鳄。

背景

在過去的幾十年中,3D圖形已經(jīng)發(fā)生了重大變化,程序員用來編寫3D應(yīng)用程序的 API也發(fā)生了相應(yīng)的變化渴逻。

五年前疾党,最先進(jìn)的圖形應(yīng)用程序使用OpenGL來執(zhí)行渲染。然而惨奕,在過去幾年中雪位,3D 圖形行業(yè)正朝著更新、更低級別的圖形框架轉(zhuǎn)變梨撞,這些框架與真實(shí)硬件的行為更加貼合雹洗。2014年,Apple推出了Metal框架卧波,讓iOS和macOS應(yīng)用程序可以充分利用GPU时肿。2015年,微軟推出了Direct3D 12港粱,這是Direct3D的一個重大更新螃成,帶來了控制臺級的渲染和計算效率。2016 年查坪,Khronos Group發(fā)布了Vulkan API寸宏,主要用于Android,也具備了類似的優(yōu)勢偿曙。

去年氮凝,Apple在W3C內(nèi)部成立了WebGPU社區(qū)組,致力于標(biāo)準(zhǔn)化新的3D圖形API遥昧,既要提供原生API的優(yōu)勢覆醇,同時也適用于Web環(huán)境。這個新的Web API可以在 Metal炭臭、Direct3D和Vulkan上實(shí)現(xiàn)永脓。所有主要的瀏覽器廠商都參與了標(biāo)準(zhǔn)化工作。

這些現(xiàn)代3D圖形API中的每一個都使用了著色器鞋仍,WebGPU也不例外常摧。著色器是一種利用GPU專門架構(gòu)的程序。在并行數(shù)值處理方面威创,GPU優(yōu)于CPU落午。為了利用這兩種架構(gòu),現(xiàn)代3D應(yīng)用程序使用了混合設(shè)計肚豺,使用CPU和GPU來完成不同的任務(wù)溃斋。通過利用每種架構(gòu)的最佳特性,現(xiàn)代圖形API為開發(fā)人員提供了一個強(qiáng)大的框架吸申,可以創(chuàng)建復(fù)雜梗劫、豐富享甸、快速的3D應(yīng)用程序。專為Metal設(shè)計的應(yīng)用程序使用的是 Metal Shading Language梳侨,為Direct3D 12設(shè)計的應(yīng)用程序使用的是 HLSL蛉威,為Vulkan設(shè)計的應(yīng)用程序使用的是SPIR-V或GLSL。

WHLSL

WHLSL是一門適用于Web平臺的新著色語言走哺。它由W3C的WebGPU社區(qū)組開發(fā)蚯嫌,這個開發(fā)組正忙于制定規(guī)范、開發(fā)編譯器和CPU端解釋器丙躏。

WHLSL以HLSL為基礎(chǔ)择示,并對其進(jìn)行了簡化和擴(kuò)展。WHLSL是一門功能強(qiáng)大且富有表現(xiàn)力的著色語言彼哼,帶來了安全性和其他好處对妄。

語言基礎(chǔ)

與HLSL中一樣,WHLSL的原始數(shù)據(jù)類型包括bool敢朱、int剪菱、uint、float和 half拴签。不支持Double孝常,因?yàn)樗贛etal中也不存在,并且會導(dǎo)致軟件模擬變慢蚓哩。Bool 沒有特定的位表示构灸,因此不能出現(xiàn)在著色器輸入/輸出或資源中。
SPIR-V中也存在同樣的限制岸梨,我們希望能夠在生成的SPIR-V代碼中使用 OpTypeBool喜颁。WHLSL還提供了較小的整數(shù)類型char、uchar曹阔、short和ushort半开,可以直接在Metal Shading Language中使用,在SPIR-V中可以將 OpTypeFloat指定為16赃份,并且可以在HLSL中進(jìn)行模擬寂拆。模擬這些類型比模擬 Double更快,因?yàn)檫@些類型更小并且它們的位表示不那么復(fù)雜抓韩。

WHLSL不提供C語言風(fēng)格的隱式轉(zhuǎn)換纠永。 我們發(fā)現(xiàn)隱式轉(zhuǎn)換是著色器中常見的錯誤來源。此外谒拴,避免隱式轉(zhuǎn)換使規(guī)范和編譯器變得更簡單尝江。

與HLSL中一樣,WHLSL也有矢量類型和矩陣類型英上,例如float4和int3x4茂装。我們盡量保持標(biāo)準(zhǔn)庫簡單怠蹂,所以沒有添加一堆“x1”單元素向量和矩陣,因?yàn)閱卧叵蛄恳呀?jīng)可以表示為標(biāo)量少态,單元素矩陣已經(jīng)可以表示為向量。這符合我們消除隱式轉(zhuǎn)換的愿望易遣,在float1和float之間進(jìn)行顯式轉(zhuǎn)換是件麻煩且不必要的事情彼妻。

以下是有效的著色器片段:

int a = 7;
a += 3;
float3 b = float3(float(a) * 5, 6, 7);
float3 c = b.xxy;
float3 d = b * c;

之前提到過,WHLSL不支持隱式轉(zhuǎn)換豆茫,但你可能已經(jīng)注意到侨歉,在上面的代碼片段中,5并未寫為5.0揩魂。這是因?yàn)樽置媪勘硎緸榭膳c其他數(shù)字類型統(tǒng)一的特殊類型幽邓。當(dāng)編譯器看到上面的代碼時,它知道乘法運(yùn)算符要求參數(shù)類型相同火脉,第一個參數(shù)顯然是浮點(diǎn)數(shù)牵舵。所以,當(dāng)編譯器看到float(a) * 5時倦挂,它說“好吧畸颅,我知道第一個參數(shù)是一個浮點(diǎn)數(shù),我必須使用(float, float)重載方援,所以讓我們把第二個參數(shù)也變?yōu)楦↑c(diǎn)數(shù)”没炒。即使兩個參數(shù)都是字面量也是一樣,因?yàn)樽置媪坑幸粋€首選類型犯戏。因此送火,5 * 5將對應(yīng) (int,int) 重載,5u *5u將對應(yīng)(uint,uint) 重載先匪,5.0 * 5.0將對應(yīng)(float,float) 重載种吸。

WHLSL和C語言之間的一個區(qū)別是WHLSL在聲明部分對所有未初始化的變量進(jìn)行零初始化。這可以避免跨操作系統(tǒng)和驅(qū)動程序的不可移植行為或者在著色器開始執(zhí)行之前讀取到任意值胚鸯。這也意味著WHLSL中的所有可構(gòu)造類型都具有零值骨稿。

枚舉

因?yàn)槊杜e不會產(chǎn)生任何運(yùn)行時成本并且非常有用,所以WHLSL原生支持枚舉姜钳。

enum Weekday {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    PizzaDay
}

枚舉的基礎(chǔ)類型默認(rèn)為int坦冠,但你可以進(jìn)行類型覆蓋,例如enum Weekday : uint哥桥。類似地辙浑,枚舉的值可以具有基礎(chǔ)值,例如Tuesday = 72拟糕。因?yàn)槊杜e已經(jīng)定義了類型和值判呕,因此它們可以被用在緩沖區(qū)中倦踢,并且可以在基礎(chǔ)類型和枚舉類型之間進(jìn)行轉(zhuǎn)換。當(dāng)你想在代碼中引用一個值時侠草,可以像 Weekday.PizzaDay 這樣辱挥。這意味著枚舉值不會污染全局命名空間,枚舉的值也不會發(fā)生沖突边涕。

結(jié)構(gòu)體

WHLSL中的結(jié)構(gòu)與HLSL和C語言類似晤碘。

struct Foo {
    int x;
    float y;
}

結(jié)構(gòu)體設(shè)計簡單,避免了繼承功蜓、虛擬方法和訪問控制园爷。結(jié)構(gòu)體沒有“私有”成員。因?yàn)榻Y(jié)構(gòu)體沒有訪問控制式撼,所以不需要成員函數(shù)童社。

數(shù)組

與其他著色語言一樣,數(shù)組是可以傳給函數(shù)或從函數(shù)中返回的值類型著隆。你可以使用以下語法創(chuàng)建一個數(shù)組:

int[3] x;

與任何變量聲明一樣扰楼,數(shù)組內(nèi)容將使用零進(jìn)行填充。我們將括號放在類型后面而不是變量名后面旅东,有兩個原因:

  • 將所有類型信息放在一個地方可以讓解析更簡單(避免順時針 / 螺旋規(guī)則);
  • 在單個語句中聲明多個變量時可以避免歧義(例如int[10] x灭抑,y;)。

數(shù)組是值類型抵代,而WHLSL使用另外兩種類型實(shí)現(xiàn)引用語義:安全指針和數(shù)組引用腾节。

安全指針

某種形式的引用語義,幾乎被用在每一種CPU端編程語言中荤牍。在WHLSL中包含指針將使開發(fā)人員更容易將現(xiàn)有的CPU端代碼遷移到GPU案腺,從而可以輕松移植機(jī)器學(xué)習(xí)、計算機(jī)視覺和信號處理應(yīng)用程序之類的東西康吵。

為了滿足安全要求劈榨,WHLSL使用了安全指針,保證指向有效的東西晦嵌,或者為 null同辣。與C語言一樣,你可以使用&運(yùn)算符創(chuàng)建指向lvalue的指針惭载,并可以使用* 運(yùn)算符取消引用旱函。與C語言不同的是,你不能像數(shù)組那樣對指針進(jìn)行索引描滔。你不能將其與標(biāo)量之間進(jìn)行轉(zhuǎn)換棒妨,也不能使用特定的位模式表示。因此含长,它不能出現(xiàn)在緩沖區(qū)中或作為著色器輸入/輸出券腔。

WHLSL有4種不同的堆:device伏穆、constant、threadgroup和thread纷纫。所有的引用類型都必須使用它們指向的地址空間進(jìn)行標(biāo)記枕扫。

device地址空間對應(yīng)于設(shè)備上的大部分內(nèi)存。內(nèi)存是可讀寫的涛酗,對應(yīng)于Direct3D中的無序訪問視圖以及Metal Shading Language中的device內(nèi)存铡原。constant地址空間對應(yīng)于內(nèi)存的只讀區(qū)域,通常針對廣播到每個線程的數(shù)據(jù)進(jìn)行優(yōu)化。最后,threadgroup 地址空間對應(yīng)于可讀寫的內(nèi)存區(qū)域窟却,該區(qū)域被線程組的每個線程共享软驰。它只能用于計算著色器。

默認(rèn)情況下请唱,值存在于thread地址空間中:

int i = 4;
thread int* j = &i;
*j = 7;
// i is now 7

因?yàn)樗凶兞慷际褂昧阒党跏蓟诌洌灾羔樖莕ull初始化的。因此十绑,以下的聲明是有效的:

thread int* i;

數(shù)組引用

數(shù)組引用類似于指針聚至,但它們可以與下標(biāo)運(yùn)算符一起使用,以訪問數(shù)組引用中的多個元素本橙。雖然數(shù)組的length在編譯時是已知的扳躬,并且必須在類型聲明中指明,但數(shù)組引用的length要在運(yùn)行時才能知道甚亭。與指針一樣贷币,它們必須與地址空間相關(guān)聯(lián),并且可能會是nullptr亏狰。與數(shù)組一樣役纹,它們使用uint進(jìn)行索引,以進(jìn)行單比較邊界檢查暇唾,并且不能是稀疏的促脉。

你可以使用@運(yùn)算符為lvalue創(chuàng)建數(shù)組引用:

int i = 4;
thread int[] j = @i;
j[0] = 7;
// i is 7
// j.length is 1

在指針j上使用@會創(chuàng)建一個指向與j相同的數(shù)組引用:

int i = 4;
thread int* j = &i;
thread int[] k = @j;
k[0] = 7;
// i is 7
// k.length is 1

在數(shù)組上使用 @使數(shù)組引用指向該數(shù)組:

int[3] i = int[3](4, 5, 6);
thread int[] j = @i;
j[1] = 7;
// i[1] is 7
// j.length is 3

函數(shù)

WHLSL的函數(shù)與C語言中的函數(shù)非常相似。例如策州,這是標(biāo)準(zhǔn)庫中的一個函數(shù):

float4 lit(float n_dot_l, float n_dot_h, float m) {
    float ambient = 1;
    float diffuse = max(0, n_dot_l);
    float specular = n_dot_l < 0 || n_dot_h < 0 ? 0 : n_dot_h * m;
    float4 result;
    result.x = ambient;
    result.y = diffuse;
    result.z = specular;
    result.w = 1;
    return result;
}

運(yùn)算符和運(yùn)算符重載

當(dāng)編譯器看到n_dot_h * m時瘸味,它并不知道如何執(zhí)行這個乘法。編譯器會將其轉(zhuǎn)換為對operator * ()的調(diào)用抽活。然后硫戈,通過標(biāo)準(zhǔn)函數(shù)重載決策算法選擇特定的operator * ()。這意味著你可以編寫自己的operator *()函數(shù)下硕,告訴 WHLSL 如何執(zhí)行自定義類型的乘法丁逝。

這同樣適用于像 ++ 這樣的操作汁胆。以下是標(biāo)準(zhǔn)庫中的一個示例:

int operator++(int value) {
    return value + 1;
}

生成屬性

但WHLSL并不僅僅停留在運(yùn)算符重載上。最開始的例子中有個b.xxy霜幼,其中b是 float3嫩码。這是一個表達(dá)式,意思是“創(chuàng)建一個包含3個元素的向量罪既,其中前兩個元素具有與b.x相同的值铸题,第三個元素具有與b.y相同的值”。這有點(diǎn)像是向量的成員琢感,只是沒有與任何存儲相關(guān)聯(lián)丢间。相反,它是在訪問期間計算生成的驹针。這些“混合運(yùn)算符”存在于每種實(shí)時著色語言中烘挫,WHLSL也不例外。這是通過生成屬性來實(shí)現(xiàn)的柬甥,就像在Swift中一樣饮六。

Getters

標(biāo)準(zhǔn)庫包含了很多以下形式的函數(shù):

float3 operator.xxy(float3 v) {
    float3 result;
    result.x = v.x;
    result.y = v.x;
    result.z = v.y;
    return result;
}

當(dāng)編譯器遇到訪問不存在的成員的屬性時,它可以調(diào)用這個運(yùn)算符苛蒲,并將對象作為第一個參數(shù)傳遞進(jìn)去卤橄。通俗地說,我們稱之為Getter臂外。

Setters

同樣的方法適用于Setter:

float4 operator.xyz=(float4 v, float3 c) {
    float4 result = v;
    result.x = c.x;
    result.y = c.y;
    result.z = c.z;
    return result;
}

Setter使用起來非常自然:

float4 a = float4(1, 2, 3, 4);
a.xyz = float3(7, 8, 9);

Setter使用新數(shù)據(jù)創(chuàng)建對象的副本窟扑。當(dāng)編譯器遇到對生成屬性進(jìn)行賦值時,它會調(diào)用Setter寄月,并將結(jié)果賦給原始變量辜膝。

Anders

Ander是Getter和Setter的泛化,可以與指針一起使用漾肮。它是對性能的一種優(yōu)化厂抖,這樣Setter就不必創(chuàng)建對象的副本。這是一個例子:

thread float* operator.r(thread Foo* value) {
    return &value->x;
}

Anders比Getter或Setter更強(qiáng)大克懊,因?yàn)榫幾g器可以使用Ander來實(shí)現(xiàn)讀取或賦值忱辅。當(dāng)通過Ander讀取生成屬性時,編譯器調(diào)用Ander谭溉,然后取消對結(jié)果的引用墙懂。在寫入時,編譯器也調(diào)用Ander扮念,取消對結(jié)果的引用损搬,并將結(jié)果分配給它。任何用戶定義的類型都可以包含Getter、Setter巧勤、Ander和Indexer的任意組合嵌灰。如果相同類型具有Ander以及Getter或Setter,編譯器將首選Ander颅悉。

Indexers

在大多數(shù)實(shí)時著色語言中沽瞭,不會使用與其列或行對應(yīng)的成員來訪問矩陣。相反剩瓶,它們使用數(shù)組語法來訪問驹溃,例如myMatrix的3。矢量類型通常也有這種語法:

float operator[](float2 v, uint index) {
    switch (index) {
        case 0:
            return v.x;
        case 1:
            return v.y;
        default:
            /* trap or clamp, more on this below */
    }
}

float2 operator[]=(float2 v, uint index, float a) {
    switch (index) {
        case 0:
            v.x = a;
            break;
        case 1:
            v.y = a;
            break;
        default:
            /* trap or clamp, more on this below */
    }
    return v;
}

可見延曙,索引也使用了運(yùn)算符豌鹤,因此可以被重載。向量也有“Indexer”枝缔,因此 myVector.x和myVector[0]是互為同義詞傍药。

標(biāo)準(zhǔn)庫

我們基于描述HLSL標(biāo)準(zhǔn)庫的Microsoft Docs設(shè)計了WHLSL標(biāo)準(zhǔn)庫。WHLSL標(biāo)準(zhǔn)庫主要包括數(shù)學(xué)運(yùn)算魂仍,既可以處理標(biāo)量值,也可以處理矢量和矩陣的元素拣挪。標(biāo)準(zhǔn)款定義了你期望的所有標(biāo)準(zhǔn)運(yùn)算符擦酌,包括邏輯運(yùn)算和按位運(yùn)算,如operator*()和 operator<<()菠劝。

WHLSL的設(shè)計原則之一是保持語言本身的小型化赊舶,所以盡可能多地在標(biāo)準(zhǔn)庫中定義其他內(nèi)容。當(dāng)然赶诊,并非標(biāo)準(zhǔn)庫中的所有函數(shù)都可以用WHLSL表示(如 bool operator*(float,float))笼平,但幾乎所有函數(shù)都可以使用WHLSL實(shí)現(xiàn)。例如舔痪,這個函數(shù)就是標(biāo)準(zhǔn)庫的一部分:

float smoothstep(float edge0, float edge1, float x) {
    float t = clamp((x - edge0) / (edge1 - edge0), 0, 1);
    return t * t * (3 - 2 * t);
}

由于標(biāo)準(zhǔn)庫旨在盡可能與HLSL相匹配寓调,因此其中的大多數(shù)函數(shù)已經(jīng)存在于HLSL 中。但不同的著色語言具有不同的內(nèi)置函數(shù)锄码,因此每個函數(shù)定義都允許進(jìn)行正確性測試夺英。WHLSL包含了一個CPU端解釋器,在執(zhí)行WHLSL程序時將使用這些函數(shù)的 WHLSL實(shí)現(xiàn)滋捶。

當(dāng)然痛悯,并非出現(xiàn)在HLSL標(biāo)準(zhǔn)庫中的每個函數(shù)在WHLSL中也都會有。例如重窟,HLSL支持printf()载萌,但要在Metal Shading Language或SPIR-V中實(shí)現(xiàn)這樣的函數(shù)會非常困難。

安全性

WHLSL是一門安全的語言,這意味著訪問網(wǎng)站以外的信息是不可能的扭仁。WHLSL通過消除未定義的行為來達(dá)到這個目的垮衷。

WHLSL實(shí)現(xiàn)安全性的另一種方式是進(jìn)行數(shù)組 / 指針訪問邊界檢查。邊界檢查有三種方式:

  • Trapping斋枢。當(dāng)程序中出現(xiàn)trap時帘靡,著色器階段會立即退出,將所有著色器階段的輸出填充為0瓤帚。繪制調(diào)用會繼續(xù)描姚,并運(yùn)行圖形管道的下一個階段。因?yàn)?Trapping引入了新的控制流程戈次,所以對程序的一致性有一定影響轩勘。trap是在邊界檢查內(nèi)發(fā)出的,這意味著它們必然存在于非一致的控制流程中怯邪。對于某些不使用一致性的程序可能沒問題绊寻,但一般來說這會導(dǎo)致trap難以使用。

  • Clamping悬秉。數(shù)組索引操作可以將索引限制為數(shù)組大小澄步。這不涉及新的控制流程,因此它對一致性沒有任何影響和泌。甚至可以通過忽略寫入并為讀取返回0 來“clamp”指針訪問或零長度陣列訪問村缸。這是可能的,因?yàn)槟憧梢杂肳HLSL中的指針做的事情是有限的武氓,所以我們可以簡單地讓每個操作用一個“clamp”指針做一些明確定義的事情梯皿。

  • 硬件和驅(qū)動程序支持。某些硬件和驅(qū)動程序已經(jīng)包含一種不會發(fā)生越界訪問的模式县恕。ARB_robustness OpenGL擴(kuò)展就是一個很好的例子东羹。可惜的是忠烛,WHLSL要在幾乎所有現(xiàn)代硬件上運(yùn)行属提,所以沒有足夠的API/設(shè)備支持這些模式。

無論編譯器使用哪種方法况木,都不應(yīng)影響著色器的一致性垒拢。換句話說,它不可能能將有效的程序變成無效的程序火惊。

為了確定邊界檢查的最佳行為求类,我們進(jìn)行了一些性能實(shí)驗(yàn)。我們采用了Metal Performance Shaders框架中的一些內(nèi)核屹耐,并創(chuàng)建了兩個新版本:一個使用 clamping尸疆,另一個使用traping椿猎。我們選擇的內(nèi)核是那些進(jìn)行大量數(shù)組訪問的內(nèi)核:例如,大型矩陣相乘寿弱。我們在各種設(shè)備上運(yùn)行這個基準(zhǔn)測試犯眠。

我們希望trapping能夠更快,因?yàn)橄掠尉幾g器可以消除冗余的trap症革。但我們發(fā)現(xiàn)筐咧,在某些設(shè)備上,trapping明顯快于clamping噪矛,而在其他設(shè)備上量蕊,卻是反過來的。這些結(jié)果表明艇挨,編譯器應(yīng)該能夠?yàn)樘囟ㄔO(shè)備選擇更合適的方法残炮,而不是被迫選擇一種給定的方法。

圖1

目前的工作

WebGPU社區(qū)小組正在使用OTT編寫正式語言規(guī)范缩滨。我們還在開發(fā)一個可以生成 Metal Shading Language势就、SPIR-V和HLSL的編譯器。此外脉漏,編譯器還包括了一個CPU端解釋器苞冯,可用于驗(yàn)證實(shí)現(xiàn)的正確性。

未來的發(fā)展方向

WHLSL還處于初級階段侧巨,在語言設(shè)計完成之前還有很長的路要走抱完。請隨時在GitHub(https://github.com/gpuweb/WHLSL)中提出你的想法和問題!

更多內(nèi)容刃泡,請參看英文原文。

英文原文:

https://webkit.org/blog/8482/web-high-level-shading-language/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末碉怔,一起剝皮案震驚了整個濱河市烘贴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌撮胧,老刑警劉巖桨踪,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異芹啥,居然都是意外死亡锻离,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門墓怀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汽纠,“玉大人,你說我怎么就攤上這事傀履∈洌” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長碴犬。 經(jīng)常有香客問我絮宁,道長,這世上最難降的妖魔是什么服协? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任绍昂,我火速辦了婚禮,結(jié)果婚禮上偿荷,老公的妹妹穿的比我還像新娘窘游。我一直安慰自己,他們只是感情好遭顶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布张峰。 她就那樣靜靜地躺著,像睡著了一般棒旗。 火紅的嫁衣襯著肌膚如雪喘批。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天铣揉,我揣著相機(jī)與錄音饶深,去河邊找鬼。 笑死逛拱,一個胖子當(dāng)著我的面吹牛敌厘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播朽合,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼俱两,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了曹步?” 一聲冷哼從身側(cè)響起宪彩,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎讲婚,沒想到半個月后尿孔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡筹麸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年活合,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片物赶。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡白指,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酵紫,到底是詐尸還是另有隱情侵续,我是刑警寧澤倔丈,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站状蜗,受9級特大地震影響需五,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜轧坎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一宏邮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缸血,春花似錦蜜氨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至笆豁,卻和暖如春郎汪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背闯狱。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工煞赢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人哄孤。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓照筑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瘦陈。 傳聞我的和親對象是個殘疾皇子凝危,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容