// genshaders is a tool to generate fragment shaders that implement the // X11 GC operations, and to generate fragment shaders that implement // (some of) the RENDER extension blend operations. // // Note that some of the generated shaders are much more complex than // they need to be; genshaders relies on the fxc optimizer to elimiate // dead code. For example, the entire noop set contains generated code // for the rest of the GC operations, but fxc optimizes it all to a // single discard instruction. // // Also generated are a few useful vertex and geometry shaders. package main import ( "bytes" "flag" "fmt" "os" "os/exec" "runtime" "sync" "text/template" ) type compInfo struct { name string suffix string } var compile = flag.Bool("compile", false, "Invoke the fxc compiler on each shader") func compiler(wg *sync.WaitGroup, log chan string, in chan compInfo) { var errorBuf bytes.Buffer for { ci := <-in if *compile { model := ci.suffix + "_4_0" out, err := os.Create(ci.name + ".asm") if err != nil { panic(err) } cmd := exec.Command("fxc", "/T"+model, "/O3", ci.name+".hl"+ci.suffix) cmd.Stdout = out errorBuf.Reset() cmd.Stderr = &errorBuf err = cmd.Run() if err != nil { fmt.Fprintln(os.Stderr, "\nFatal Error while creating asm file", ci.name) fmt.Fprintln(os.Stderr, err.Error()) errorBuf.WriteTo(os.Stderr) os.Exit(1) } out.Close() cmd = exec.Command("fxc", "/T"+model, "/O3", ci.name+".hl"+ci.suffix, "/Fo"+ci.name+"."+ci.suffix) cmd.Run() out, err = os.Create(ci.name + ".h") if err != nil { panic(err) } cmd = exec.Command("xxd", "-i", ci.name+"."+ci.suffix) cmd.Stdout = out errorBuf.Reset() cmd.Stderr = &errorBuf err = cmd.Run() if err != nil { fmt.Fprintln(os.Stderr, "\n Fatal Error while xxding", ci.name) fmt.Fprintln(os.Stderr, err.Error()) errorBuf.WriteTo(os.Stderr) os.Exit(1) } out.Close() log <- ci.name + " Compiled." } wg.Done() } } type GlyphS struct { Cbuf string TilePos string GlyphPos string OutPos string } func doVert(wg *sync.WaitGroup, log chan string, comp chan compInfo) { wg.Add(3) vt, err := template.ParseFiles("vertex.template") if err != nil { panic(err) } out, err := os.Create("size_calc.hlvs") if err != nil { panic(err) } err = vt.Execute(out, nil) if err != nil { panic(err) } out.Close() comp <- compInfo{"size_calc", "vs"} glypht, err := template.ParseFiles("glyphs.template") if err != nil { panic(err) } out, err = os.Create("render_glyphs.hlvs") if err != nil { panic(err) } render := GlyphS{"", "input.glyph_pos", "0", "0"} err = glypht.Execute(out, &render) if err != nil { panic(err) } out.Close() comp <- compInfo{"render_glyphs", "vs"} out, err = os.Create("core_glyphs.hlvs") if err != nil { panic(err) } core := GlyphS{` cbuffer output_info :register(b1) { uint2 out_offset; } `, "input.pos - tile_offset", "input.glyph_pos / (float2)clip_size", "input.pos - out_offset"} err = glypht.Execute(out, &core) if err != nil { panic(err) } out.Close() comp <- compInfo{"core_glyphs", "vs"} log <- "Vertex shaders done." wg.Done() } func doGeom(wg *sync.WaitGroup, log chan string, comp chan compInfo) { gt, err := template.ParseFiles("geometry.template") if err != nil { panic(err) } out, err := os.Create("line2rect.hlgs") if err != nil { panic(err) } err = gt.Execute(out, nil) if err != nil { panic(err) } out.Close() wg.Add(1) comp <- compInfo{"line2rect", "gs"} log <- "Geometry shader done." wg.Done() } type pixelInfo struct { Rop string Style string PlaneMask string ClipMask string Tex string ClipMaskBlock string Load string RopBlock string PlaneMaskBlock string } var rop = [...]string{"clear", "and", "andreverse", "copy", "andinverted", "noop", "xor", "or", "nor", "equiv", "invert", "orreverse", "copyinverted", "orinverted", "nand", "set"} var style = [...]string{"solid", "tile", "stipple", "opaquestip"} var planemask = [...]string{"fullmask", "planemask"} var clipmask = [...]string{"unclipped", "clipmask"} func forEachCore(cb func(r, s, p, c string)) { for _, c := range clipmask { for _, p := range planemask { for _, s := range style { for _, r := range rop { cb(r, s, p, c) } } } } } func forEachCopyPlane(cb func(r, s, p, c string)) { for _, c := range clipmask { for _, p := range planemask { for _, r := range rop { cb(r, "copyplane", p, c) } } } } func doPixel(wg *sync.WaitGroup, log chan string, comp chan compInfo) { pt, err := template.ParseFiles("pixel.template") if err != nil { panic(err) } cmask := map[string]string{ "unclipped": "", "clipmask": ` // Test clip mask float4 cm = clipmask.Sample(point_sample, input.clip_pos); if (cm.r < 0.5) { discard; return 0; } `} pmask := map[string]string{ "fullmask": "", "planemask": ` // planemask color = (color & planemask) | (out_color & ~planemask); `} style := map[string]string{ "solid": " color = foreground;", "tile": ` int3 tp; tp.xy = input.tile_pos.xy % tile_wh.xy; tp.z = 0; color = tile.Load(tp);`, "stipple": ` float4 pt = stipple.Sample(point_sample, input.tile_pos); if (pt.r < 0.5) { discard; return 0; } color = foreground;`, "opaquestip": ` float4 pt = stipple.Sample(point_sample, input.tile_pos); color = foreground; if (pt.r < 0.5) color = background;`, "copyplane": ` int3 tp; tp.xy = input.tile_pos.xy % tile_wh.xy; tp.z = 0; color = tile.Load(tp); if (any(color & plane)) color = foreground; else color = background;`, } rop := map[string]string{ "clear": "color = 0", "and": "color = color & out_color", "andreverse": "color = color & ~out_color", "copy": "color = color", "andinverted": "color = ~color & out_color", "noop": "discard", "xor": "color = color ^ out_color", "or": "color = color | out_color", "nor": "color = ~color & ~out_color", "equiv": "color = ~color ^ out_color", "invert": "color = ~out_color", "orreverse": "color = color | ~out_color", "copyinverted": "color = ~color", "orinverted": "color = ~color | out_color", "nand": "color = ~color | ~out_color", "set": "color = 255", } var pi pixelInfo for pi.ClipMask, pi.ClipMaskBlock = range cmask { for pi.PlaneMask, pi.PlaneMaskBlock = range pmask { for pi.Style, pi.Load = range style { for pi.Rop, pi.RopBlock = range rop { name := pi.Rop + "_" + pi.Style + "_" + pi.PlaneMask + "_" + pi.ClipMask pi.Tex = "" switch pi.Style { case "stipple", "opaquestip": pi.Tex = "\nTexture2D stipple : register(t0);" case "tile", "copyplane": pi.Tex = "\nTexture2D tile : register(t0);" } if pi.ClipMask == "clipmask" { pi.Tex += "\nTexture2D clipmask : register(t1);" } out, err := os.Create(name + ".hlps") if err != nil { panic(err) } err = pt.Execute(out, &pi) if err != nil { panic(err) } out.Close() wg.Add(1) comp <- compInfo{name, "ps"} } } } } pix_h, err := os.Create("pixel_shaders.h") if err != nil { panic(err) } fmt.Fprintln(pix_h, "/* Automatically generated file; do not edit */") fmt.Fprintln(pix_h) include := func(rop, style, planemask, clipmask string) { name := rop + "_" + style + "_" + planemask + "_" + clipmask fmt.Fprintln(pix_h, `#include "`+name+`.h"`) } ps := func(rop, style, planemask, clipmask string) { name := " " + rop + "_" + style + "_" + planemask + "_" + clipmask + "_ps," fmt.Fprintln(pix_h, name) } ps_len := func(rop, style, planemask, clipmask string) { name := " " + rop + "_" + style + "_" + planemask + "_" + clipmask + "_ps_len," fmt.Fprintln(pix_h, name) } forEachCore(include) forEachCopyPlane(include) fmt.Fprintln(pix_h) fmt.Fprintln(pix_h, "static const unsigned char *core_ps[] = {") forEachCore(ps) fmt.Fprintln(pix_h, "};") fmt.Fprintln(pix_h) fmt.Fprintln(pix_h, "static const unsigned int core_ps_len[] = {") forEachCore(ps_len) fmt.Fprintln(pix_h, "};") fmt.Fprintln(pix_h) fmt.Fprintln(pix_h, "static const unsigned char *copyplane_ps[] = {") forEachCopyPlane(ps) fmt.Fprintln(pix_h, "};") fmt.Fprintln(pix_h) fmt.Fprintln(pix_h, "static const unsigned int copyplane_ps_len[] = {") forEachCopyPlane(ps_len) fmt.Fprintln(pix_h, "};") pix_h.Close() log <- "Pixel shaders done." wg.Done() } func foreachRenderSimple(cb func(name string, hasmask, srcswiz, dstswiz, maskswiz, compalpha, skip bool)) { falsetrue := [...]bool{false, true} for _, srcswizzle := range falsetrue { for _, dstswizzle := range falsetrue { for _, hasmask := range falsetrue { for _, maskswizzle := range falsetrue { for _, componentalpha := range falsetrue { skip := maskswizzle && !hasmask skip = skip || (componentalpha && !hasmask) name := "render_simple" + map[bool]string{true: "_sswiz"}[srcswizzle] + map[bool]string{true: "_dswiz"}[dstswizzle] + map[bool]string{true: "_mask"}[hasmask] + map[bool]string{true: "_swiz"}[maskswizzle] + map[bool]string{true: "_ca"}[componentalpha] cb(name, hasmask, srcswizzle, dstswizzle, maskswizzle, componentalpha, skip) } } } } } } type simpleRender struct { Description string SrcSwiz, Mask, MaskSwiz, CompAlpha string Return string } func doRender(wg *sync.WaitGroup, log chan string, comp chan compInfo) { rt, err := template.ParseFiles("simple.template") if err != nil { panic(err) } simple_h, err := os.Create("render_simple_shaders.h") if err != nil { panic(err) } fmt.Fprintln(simple_h, "/* Automatically generated file; do not edit */") fmt.Fprintln(simple_h) foreachRenderSimple(func(name string, hasmask, srcswiz, dstswiz, maskswiz, compalpha, skip bool) { if skip { return } fmt.Fprintln(simple_h, `#include "`+name+`.h"`) var sr simpleRender if srcswiz { sr.Description += " for source swizzled" } if hasmask { sr.Description += " with mask" } if maskswiz { sr.Description += " swizzled" } if compalpha { sr.Description += ", component alpha" } if srcswiz { sr.SrcSwiz = ` s.a = s.r; s.rgb = 0;` } if hasmask { sr.Mask = "\n float4 m = mask.Sample(mask_sample, input.mask_pos);" if maskswiz { sr.MaskSwiz = "\n m.a = m.r;" } sr.CompAlpha = "\n s *= m.a;" if compalpha { sr.CompAlpha = "\n s *= m;" } } sr.Return = "s" if dstswiz { sr.Return = "s.a" } out, err := os.Create(name + ".hlps") if err != nil { panic(err) } err = rt.Execute(out, &sr) if err != nil { panic(err) } out.Close() wg.Add(1) comp <- compInfo{name, "ps"} }) fmt.Fprintln(simple_h) fmt.Fprintln(simple_h, "static const unsigned char *render_simple[] = {") foreachRenderSimple(func(name string, hasmask, srcswiz, dstswiz, maskswiz, compalpha, skip bool) { if skip { fmt.Fprintln(simple_h, " NULL,") } else { fmt.Fprintln(simple_h, " "+name+"_ps,") } }) fmt.Fprintln(simple_h, "};") fmt.Fprintln(simple_h) fmt.Fprintln(simple_h, "static const unsigned int render_simple_len[] = {") foreachRenderSimple(func(name string, hasmask, srcswiz, dstswiz, maskswiz, compalpha, skip bool) { if skip { fmt.Fprintln(simple_h, " 0,") } else { fmt.Fprintln(simple_h, " "+name+"_ps_len,") } }) fmt.Fprintln(simple_h, "};") simple_h.Close() log <- "Render shaders done." wg.Done() } func logger(wg *sync.WaitGroup, in chan string) { for { msg := <-in if msg == "" { wg.Done() return } fmt.Println(msg) } } func main() { flag.Parse() var wg sync.WaitGroup log := make(chan string) go logger(&wg, log) // Limit number of concurrent compiles compile := make(chan compInfo) for i := 0; i < runtime.NumCPU(); i++ { go compiler(&wg, log, compile) } wg.Add(4) go doVert(&wg, log, compile) go doGeom(&wg, log, compile) go doPixel(&wg, log, compile) go doRender(&wg, log, compile) wg.Wait() wg.Add(1) log <- "Done." log <- "" wg.Wait() }