gpu.go 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592
  1. // SPDX-License-Identifier: Unlicense OR MIT
  2. /*
  3. Package gpu implements the rendering of Gio drawing operations. It
  4. is used by package app and package app/headless and is otherwise not
  5. useful except for integrating with external window implementations.
  6. */
  7. package gpu
  8. import (
  9. "encoding/binary"
  10. "errors"
  11. "fmt"
  12. "image"
  13. "image/color"
  14. "math"
  15. "reflect"
  16. "time"
  17. "unsafe"
  18. "gioui.org/gpu/internal/driver"
  19. "gioui.org/internal/byteslice"
  20. "gioui.org/internal/f32"
  21. "gioui.org/internal/f32color"
  22. "gioui.org/internal/ops"
  23. "gioui.org/internal/scene"
  24. "gioui.org/internal/stroke"
  25. "gioui.org/layout"
  26. "gioui.org/op"
  27. "gioui.org/shader"
  28. "gioui.org/shader/gio"
  29. // Register backends.
  30. _ "gioui.org/gpu/internal/d3d11"
  31. _ "gioui.org/gpu/internal/metal"
  32. _ "gioui.org/gpu/internal/opengl"
  33. _ "gioui.org/gpu/internal/vulkan"
  34. )
  35. type GPU interface {
  36. // Release non-Go resources. The GPU is no longer valid after Release.
  37. Release()
  38. // Clear sets the clear color for the next Frame.
  39. Clear(color color.NRGBA)
  40. // Frame draws the graphics operations from op into a viewport of target.
  41. Frame(frame *op.Ops, target RenderTarget, viewport image.Point) error
  42. }
  43. type gpu struct {
  44. cache *textureCache
  45. profile string
  46. timers *timers
  47. frameStart time.Time
  48. stencilTimer, coverTimer, cleanupTimer *timer
  49. drawOps drawOps
  50. ctx driver.Device
  51. renderer *renderer
  52. }
  53. type renderer struct {
  54. ctx driver.Device
  55. blitter *blitter
  56. pather *pather
  57. packer packer
  58. intersections packer
  59. layers packer
  60. layerFBOs fboSet
  61. }
  62. type drawOps struct {
  63. reader ops.Reader
  64. states []f32.Affine2D
  65. transStack []f32.Affine2D
  66. layers []opacityLayer
  67. opacityStack []int
  68. vertCache []byte
  69. viewport image.Point
  70. clear bool
  71. clearColor f32color.RGBA
  72. imageOps []imageOp
  73. pathOps []*pathOp
  74. pathOpCache []pathOp
  75. qs quadSplitter
  76. pathCache *opCache
  77. }
  78. type opacityLayer struct {
  79. opacity float32
  80. parent int
  81. // depth of the opacity stack. Layers of equal depth are
  82. // independent and may be packed into one atlas.
  83. depth int
  84. // opStart and opEnd denote the range of drawOps.imageOps
  85. // that belong to the layer.
  86. opStart, opEnd int
  87. // clip of the layer operations.
  88. clip image.Rectangle
  89. place placement
  90. }
  91. type drawState struct {
  92. t f32.Affine2D
  93. cpath *pathOp
  94. matType materialType
  95. // Current paint.ImageOp
  96. image imageOpData
  97. // Current paint.ColorOp, if any.
  98. color color.NRGBA
  99. // Current paint.LinearGradientOp.
  100. stop1 f32.Point
  101. stop2 f32.Point
  102. color1 color.NRGBA
  103. color2 color.NRGBA
  104. }
  105. type pathOp struct {
  106. off f32.Point
  107. // rect tracks whether the clip stack can be represented by a
  108. // pixel-aligned rectangle.
  109. rect bool
  110. // clip is the union of all
  111. // later clip rectangles.
  112. clip image.Rectangle
  113. bounds f32.Rectangle
  114. // intersect is the intersection of bounds and all
  115. // previous clip bounds.
  116. intersect f32.Rectangle
  117. pathKey opKey
  118. path bool
  119. pathVerts []byte
  120. parent *pathOp
  121. place placement
  122. }
  123. type imageOp struct {
  124. path *pathOp
  125. clip image.Rectangle
  126. material material
  127. clipType clipType
  128. // place is either a placement in the path fbos or intersection fbos,
  129. // depending on clipType.
  130. place placement
  131. // layerOps is the number of operations this
  132. // operation replaces.
  133. layerOps int
  134. }
  135. func decodeStrokeOp(data []byte) float32 {
  136. _ = data[4]
  137. bo := binary.LittleEndian
  138. return math.Float32frombits(bo.Uint32(data[1:]))
  139. }
  140. type quadsOp struct {
  141. key opKey
  142. aux []byte
  143. }
  144. type opKey struct {
  145. outline bool
  146. strokeWidth float32
  147. sx, hx, sy, hy float32
  148. ops.Key
  149. }
  150. type material struct {
  151. material materialType
  152. opaque bool
  153. // For materialTypeColor.
  154. color f32color.RGBA
  155. // For materialTypeLinearGradient.
  156. color1 f32color.RGBA
  157. color2 f32color.RGBA
  158. opacity float32
  159. // For materialTypeTexture.
  160. data imageOpData
  161. tex driver.Texture
  162. uvTrans f32.Affine2D
  163. }
  164. const (
  165. filterLinear = 0
  166. filterNearest = 1
  167. )
  168. // imageOpData is the shadow of paint.ImageOp.
  169. type imageOpData struct {
  170. src *image.RGBA
  171. handle interface{}
  172. filter byte
  173. }
  174. type linearGradientOpData struct {
  175. stop1 f32.Point
  176. color1 color.NRGBA
  177. stop2 f32.Point
  178. color2 color.NRGBA
  179. }
  180. func decodeImageOp(data []byte, refs []interface{}) imageOpData {
  181. handle := refs[1]
  182. if handle == nil {
  183. return imageOpData{}
  184. }
  185. return imageOpData{
  186. src: refs[0].(*image.RGBA),
  187. handle: handle,
  188. filter: data[1],
  189. }
  190. }
  191. func decodeColorOp(data []byte) color.NRGBA {
  192. data = data[:ops.TypeColorLen]
  193. return color.NRGBA{
  194. R: data[1],
  195. G: data[2],
  196. B: data[3],
  197. A: data[4],
  198. }
  199. }
  200. func decodeLinearGradientOp(data []byte) linearGradientOpData {
  201. data = data[:ops.TypeLinearGradientLen]
  202. bo := binary.LittleEndian
  203. return linearGradientOpData{
  204. stop1: f32.Point{
  205. X: math.Float32frombits(bo.Uint32(data[1:])),
  206. Y: math.Float32frombits(bo.Uint32(data[5:])),
  207. },
  208. stop2: f32.Point{
  209. X: math.Float32frombits(bo.Uint32(data[9:])),
  210. Y: math.Float32frombits(bo.Uint32(data[13:])),
  211. },
  212. color1: color.NRGBA{
  213. R: data[17+0],
  214. G: data[17+1],
  215. B: data[17+2],
  216. A: data[17+3],
  217. },
  218. color2: color.NRGBA{
  219. R: data[21+0],
  220. G: data[21+1],
  221. B: data[21+2],
  222. A: data[21+3],
  223. },
  224. }
  225. }
  226. type resource interface {
  227. release()
  228. }
  229. type texture struct {
  230. src *image.RGBA
  231. tex driver.Texture
  232. }
  233. type blitter struct {
  234. ctx driver.Device
  235. viewport image.Point
  236. pipelines [2][3]*pipeline
  237. colUniforms *blitColUniforms
  238. texUniforms *blitTexUniforms
  239. linearGradientUniforms *blitLinearGradientUniforms
  240. quadVerts driver.Buffer
  241. }
  242. type blitColUniforms struct {
  243. blitUniforms
  244. _ [128 - unsafe.Sizeof(blitUniforms{}) - unsafe.Sizeof(colorUniforms{})]byte // Padding to 128 bytes.
  245. colorUniforms
  246. }
  247. type blitTexUniforms struct {
  248. blitUniforms
  249. }
  250. type blitLinearGradientUniforms struct {
  251. blitUniforms
  252. _ [128 - unsafe.Sizeof(blitUniforms{}) - unsafe.Sizeof(gradientUniforms{})]byte // Padding to 128 bytes.
  253. gradientUniforms
  254. }
  255. type uniformBuffer struct {
  256. buf driver.Buffer
  257. ptr []byte
  258. }
  259. type pipeline struct {
  260. pipeline driver.Pipeline
  261. uniforms *uniformBuffer
  262. }
  263. type blitUniforms struct {
  264. transform [4]float32
  265. uvTransformR1 [4]float32
  266. uvTransformR2 [4]float32
  267. opacity float32
  268. fbo float32
  269. _ [2]float32
  270. }
  271. type colorUniforms struct {
  272. color f32color.RGBA
  273. }
  274. type gradientUniforms struct {
  275. color1 f32color.RGBA
  276. color2 f32color.RGBA
  277. }
  278. type clipType uint8
  279. const (
  280. clipTypeNone clipType = iota
  281. clipTypePath
  282. clipTypeIntersection
  283. )
  284. type materialType uint8
  285. const (
  286. materialColor materialType = iota
  287. materialLinearGradient
  288. materialTexture
  289. )
  290. // New creates a GPU for the given API.
  291. func New(api API) (GPU, error) {
  292. d, err := driver.NewDevice(api)
  293. if err != nil {
  294. return nil, err
  295. }
  296. return NewWithDevice(d)
  297. }
  298. // NewWithDevice creates a GPU with a pre-existing device.
  299. //
  300. // Note: for internal use only.
  301. func NewWithDevice(d driver.Device) (GPU, error) {
  302. d.BeginFrame(nil, false, image.Point{})
  303. defer d.EndFrame()
  304. feats := d.Caps().Features
  305. switch {
  306. case feats.Has(driver.FeatureFloatRenderTargets) && feats.Has(driver.FeatureSRGB):
  307. return newGPU(d)
  308. }
  309. return nil, errors.New("no available GPU driver")
  310. }
  311. func newGPU(ctx driver.Device) (*gpu, error) {
  312. g := &gpu{
  313. cache: newTextureCache(),
  314. }
  315. g.drawOps.pathCache = newOpCache()
  316. if err := g.init(ctx); err != nil {
  317. return nil, err
  318. }
  319. return g, nil
  320. }
  321. func (g *gpu) init(ctx driver.Device) error {
  322. g.ctx = ctx
  323. g.renderer = newRenderer(ctx)
  324. return nil
  325. }
  326. func (g *gpu) Clear(col color.NRGBA) {
  327. g.drawOps.clear = true
  328. g.drawOps.clearColor = f32color.LinearFromSRGB(col)
  329. }
  330. func (g *gpu) Release() {
  331. g.renderer.release()
  332. g.drawOps.pathCache.release()
  333. g.cache.release()
  334. if g.timers != nil {
  335. g.timers.Release()
  336. }
  337. g.ctx.Release()
  338. }
  339. func (g *gpu) Frame(frameOps *op.Ops, target RenderTarget, viewport image.Point) error {
  340. g.collect(viewport, frameOps)
  341. return g.frame(target)
  342. }
  343. func (g *gpu) collect(viewport image.Point, frameOps *op.Ops) {
  344. g.renderer.blitter.viewport = viewport
  345. g.renderer.pather.viewport = viewport
  346. g.drawOps.reset(viewport)
  347. g.drawOps.collect(frameOps, viewport)
  348. if false && g.timers == nil && g.ctx.Caps().Features.Has(driver.FeatureTimers) {
  349. g.frameStart = time.Now()
  350. g.timers = newTimers(g.ctx)
  351. g.stencilTimer = g.timers.newTimer()
  352. g.coverTimer = g.timers.newTimer()
  353. g.cleanupTimer = g.timers.newTimer()
  354. }
  355. }
  356. func (g *gpu) frame(target RenderTarget) error {
  357. viewport := g.renderer.blitter.viewport
  358. defFBO := g.ctx.BeginFrame(target, g.drawOps.clear, viewport)
  359. defer g.ctx.EndFrame()
  360. g.drawOps.buildPaths(g.ctx)
  361. for _, img := range g.drawOps.imageOps {
  362. expandPathOp(img.path, img.clip)
  363. }
  364. g.stencilTimer.begin()
  365. g.renderer.packStencils(&g.drawOps.pathOps)
  366. g.renderer.stencilClips(g.drawOps.pathCache, g.drawOps.pathOps)
  367. g.renderer.packIntersections(g.drawOps.imageOps)
  368. g.renderer.prepareIntersections(g.drawOps.imageOps)
  369. g.renderer.intersect(g.drawOps.imageOps)
  370. g.stencilTimer.end()
  371. g.coverTimer.begin()
  372. g.renderer.uploadImages(g.cache, g.drawOps.imageOps)
  373. g.renderer.prepareDrawOps(g.drawOps.imageOps)
  374. g.drawOps.layers = g.renderer.packLayers(g.drawOps.layers)
  375. g.renderer.drawLayers(g.drawOps.layers, g.drawOps.imageOps)
  376. d := driver.LoadDesc{
  377. ClearColor: g.drawOps.clearColor,
  378. }
  379. if g.drawOps.clear {
  380. g.drawOps.clear = false
  381. d.Action = driver.LoadActionClear
  382. }
  383. g.ctx.BeginRenderPass(defFBO, d)
  384. g.ctx.Viewport(0, 0, viewport.X, viewport.Y)
  385. g.renderer.drawOps(false, image.Point{}, g.renderer.blitter.viewport, g.drawOps.imageOps)
  386. g.coverTimer.end()
  387. g.ctx.EndRenderPass()
  388. g.cleanupTimer.begin()
  389. g.cache.frame()
  390. g.drawOps.pathCache.frame()
  391. g.cleanupTimer.end()
  392. if false && g.timers.ready() {
  393. st, covt, cleant := g.stencilTimer.Elapsed, g.coverTimer.Elapsed, g.cleanupTimer.Elapsed
  394. ft := st + covt + cleant
  395. q := 100 * time.Microsecond
  396. st, covt = st.Round(q), covt.Round(q)
  397. frameDur := time.Since(g.frameStart).Round(q)
  398. ft = ft.Round(q)
  399. g.profile = fmt.Sprintf("draw:%7s gpu:%7s st:%7s cov:%7s", frameDur, ft, st, covt)
  400. }
  401. return nil
  402. }
  403. func (g *gpu) Profile() string {
  404. return g.profile
  405. }
  406. func (r *renderer) texHandle(cache *textureCache, data imageOpData) driver.Texture {
  407. key := textureCacheKey{
  408. filter: data.filter,
  409. handle: data.handle,
  410. }
  411. var tex *texture
  412. t, exists := cache.get(key)
  413. if !exists {
  414. t = &texture{
  415. src: data.src,
  416. }
  417. cache.put(key, t)
  418. }
  419. tex = t.(*texture)
  420. if tex.tex != nil {
  421. return tex.tex
  422. }
  423. var minFilter, magFilter driver.TextureFilter
  424. switch data.filter {
  425. case filterLinear:
  426. minFilter, magFilter = driver.FilterLinearMipmapLinear, driver.FilterLinear
  427. case filterNearest:
  428. minFilter, magFilter = driver.FilterNearest, driver.FilterNearest
  429. }
  430. handle, err := r.ctx.NewTexture(driver.TextureFormatSRGBA,
  431. data.src.Bounds().Dx(), data.src.Bounds().Dy(),
  432. minFilter, magFilter,
  433. driver.BufferBindingTexture,
  434. )
  435. if err != nil {
  436. panic(err)
  437. }
  438. driver.UploadImage(handle, image.Pt(0, 0), data.src)
  439. tex.tex = handle
  440. return tex.tex
  441. }
  442. func (t *texture) release() {
  443. if t.tex != nil {
  444. t.tex.Release()
  445. }
  446. }
  447. func newRenderer(ctx driver.Device) *renderer {
  448. r := &renderer{
  449. ctx: ctx,
  450. blitter: newBlitter(ctx),
  451. pather: newPather(ctx),
  452. }
  453. maxDim := ctx.Caps().MaxTextureSize
  454. // Large atlas textures cause artifacts due to precision loss in
  455. // shaders.
  456. if cap := 8192; maxDim > cap {
  457. maxDim = cap
  458. }
  459. d := image.Pt(maxDim, maxDim)
  460. r.packer.maxDims = d
  461. r.intersections.maxDims = d
  462. r.layers.maxDims = d
  463. return r
  464. }
  465. func (r *renderer) release() {
  466. r.pather.release()
  467. r.blitter.release()
  468. r.layerFBOs.delete(r.ctx, 0)
  469. }
  470. func newBlitter(ctx driver.Device) *blitter {
  471. quadVerts, err := ctx.NewImmutableBuffer(driver.BufferBindingVertices,
  472. byteslice.Slice([]float32{
  473. -1, -1, 0, 0,
  474. +1, -1, 1, 0,
  475. -1, +1, 0, 1,
  476. +1, +1, 1, 1,
  477. }),
  478. )
  479. if err != nil {
  480. panic(err)
  481. }
  482. b := &blitter{
  483. ctx: ctx,
  484. quadVerts: quadVerts,
  485. }
  486. b.colUniforms = new(blitColUniforms)
  487. b.texUniforms = new(blitTexUniforms)
  488. b.linearGradientUniforms = new(blitLinearGradientUniforms)
  489. pipelines, err := createColorPrograms(ctx, gio.Shader_blit_vert, gio.Shader_blit_frag,
  490. [3]interface{}{b.colUniforms, b.linearGradientUniforms, b.texUniforms},
  491. )
  492. if err != nil {
  493. panic(err)
  494. }
  495. b.pipelines = pipelines
  496. return b
  497. }
  498. func (b *blitter) release() {
  499. b.quadVerts.Release()
  500. for _, p := range b.pipelines {
  501. for _, p := range p {
  502. p.Release()
  503. }
  504. }
  505. }
  506. func createColorPrograms(b driver.Device, vsSrc shader.Sources, fsSrc [3]shader.Sources, uniforms [3]interface{}) (pipelines [2][3]*pipeline, err error) {
  507. defer func() {
  508. if err != nil {
  509. for _, p := range pipelines {
  510. for _, p := range p {
  511. if p != nil {
  512. p.Release()
  513. }
  514. }
  515. }
  516. }
  517. }()
  518. blend := driver.BlendDesc{
  519. Enable: true,
  520. SrcFactor: driver.BlendFactorOne,
  521. DstFactor: driver.BlendFactorOneMinusSrcAlpha,
  522. }
  523. layout := driver.VertexLayout{
  524. Inputs: []driver.InputDesc{
  525. {Type: shader.DataTypeFloat, Size: 2, Offset: 0},
  526. {Type: shader.DataTypeFloat, Size: 2, Offset: 4 * 2},
  527. },
  528. Stride: 4 * 4,
  529. }
  530. vsh, err := b.NewVertexShader(vsSrc)
  531. if err != nil {
  532. return pipelines, err
  533. }
  534. defer vsh.Release()
  535. for i, format := range []driver.TextureFormat{driver.TextureFormatOutput, driver.TextureFormatSRGBA} {
  536. {
  537. fsh, err := b.NewFragmentShader(fsSrc[materialTexture])
  538. if err != nil {
  539. return pipelines, err
  540. }
  541. defer fsh.Release()
  542. pipe, err := b.NewPipeline(driver.PipelineDesc{
  543. VertexShader: vsh,
  544. FragmentShader: fsh,
  545. BlendDesc: blend,
  546. VertexLayout: layout,
  547. PixelFormat: format,
  548. Topology: driver.TopologyTriangleStrip,
  549. })
  550. if err != nil {
  551. return pipelines, err
  552. }
  553. var vertBuffer *uniformBuffer
  554. if u := uniforms[materialTexture]; u != nil {
  555. vertBuffer = newUniformBuffer(b, u)
  556. }
  557. pipelines[i][materialTexture] = &pipeline{pipe, vertBuffer}
  558. }
  559. {
  560. var vertBuffer *uniformBuffer
  561. fsh, err := b.NewFragmentShader(fsSrc[materialColor])
  562. if err != nil {
  563. return pipelines, err
  564. }
  565. defer fsh.Release()
  566. pipe, err := b.NewPipeline(driver.PipelineDesc{
  567. VertexShader: vsh,
  568. FragmentShader: fsh,
  569. BlendDesc: blend,
  570. VertexLayout: layout,
  571. PixelFormat: format,
  572. Topology: driver.TopologyTriangleStrip,
  573. })
  574. if err != nil {
  575. return pipelines, err
  576. }
  577. if u := uniforms[materialColor]; u != nil {
  578. vertBuffer = newUniformBuffer(b, u)
  579. }
  580. pipelines[i][materialColor] = &pipeline{pipe, vertBuffer}
  581. }
  582. {
  583. var vertBuffer *uniformBuffer
  584. fsh, err := b.NewFragmentShader(fsSrc[materialLinearGradient])
  585. if err != nil {
  586. return pipelines, err
  587. }
  588. defer fsh.Release()
  589. pipe, err := b.NewPipeline(driver.PipelineDesc{
  590. VertexShader: vsh,
  591. FragmentShader: fsh,
  592. BlendDesc: blend,
  593. VertexLayout: layout,
  594. PixelFormat: format,
  595. Topology: driver.TopologyTriangleStrip,
  596. })
  597. if err != nil {
  598. return pipelines, err
  599. }
  600. if u := uniforms[materialLinearGradient]; u != nil {
  601. vertBuffer = newUniformBuffer(b, u)
  602. }
  603. pipelines[i][materialLinearGradient] = &pipeline{pipe, vertBuffer}
  604. }
  605. }
  606. return pipelines, nil
  607. }
  608. func (r *renderer) stencilClips(pathCache *opCache, ops []*pathOp) {
  609. if len(r.packer.sizes) == 0 {
  610. return
  611. }
  612. fbo := -1
  613. r.pather.begin(r.packer.sizes)
  614. for _, p := range ops {
  615. if fbo != p.place.Idx {
  616. if fbo != -1 {
  617. r.ctx.EndRenderPass()
  618. }
  619. fbo = p.place.Idx
  620. f := r.pather.stenciler.cover(fbo)
  621. r.ctx.BeginRenderPass(f.tex, driver.LoadDesc{Action: driver.LoadActionClear})
  622. r.ctx.BindPipeline(r.pather.stenciler.pipeline.pipeline.pipeline)
  623. r.ctx.BindIndexBuffer(r.pather.stenciler.indexBuf)
  624. }
  625. v, _ := pathCache.get(p.pathKey)
  626. r.pather.stencilPath(p.clip, p.off, p.place.Pos, v.data)
  627. }
  628. if fbo != -1 {
  629. r.ctx.EndRenderPass()
  630. }
  631. }
  632. func (r *renderer) prepareIntersections(ops []imageOp) {
  633. for _, img := range ops {
  634. if img.clipType != clipTypeIntersection {
  635. continue
  636. }
  637. fbo := r.pather.stenciler.cover(img.path.place.Idx)
  638. r.ctx.PrepareTexture(fbo.tex)
  639. }
  640. }
  641. func (r *renderer) intersect(ops []imageOp) {
  642. if len(r.intersections.sizes) == 0 {
  643. return
  644. }
  645. fbo := -1
  646. r.pather.stenciler.beginIntersect(r.intersections.sizes)
  647. for _, img := range ops {
  648. if img.clipType != clipTypeIntersection {
  649. continue
  650. }
  651. if fbo != img.place.Idx {
  652. if fbo != -1 {
  653. r.ctx.EndRenderPass()
  654. }
  655. fbo = img.place.Idx
  656. f := r.pather.stenciler.intersections.fbos[fbo]
  657. d := driver.LoadDesc{Action: driver.LoadActionClear}
  658. d.ClearColor.R = 1.0
  659. r.ctx.BeginRenderPass(f.tex, d)
  660. r.ctx.BindPipeline(r.pather.stenciler.ipipeline.pipeline.pipeline)
  661. r.ctx.BindVertexBuffer(r.blitter.quadVerts, 0)
  662. }
  663. r.ctx.Viewport(img.place.Pos.X, img.place.Pos.Y, img.clip.Dx(), img.clip.Dy())
  664. r.intersectPath(img.path, img.clip)
  665. }
  666. if fbo != -1 {
  667. r.ctx.EndRenderPass()
  668. }
  669. }
  670. func (r *renderer) intersectPath(p *pathOp, clip image.Rectangle) {
  671. if p.parent != nil {
  672. r.intersectPath(p.parent, clip)
  673. }
  674. if !p.path {
  675. return
  676. }
  677. uv := image.Rectangle{
  678. Min: p.place.Pos,
  679. Max: p.place.Pos.Add(p.clip.Size()),
  680. }
  681. o := clip.Min.Sub(p.clip.Min)
  682. sub := image.Rectangle{
  683. Min: o,
  684. Max: o.Add(clip.Size()),
  685. }
  686. fbo := r.pather.stenciler.cover(p.place.Idx)
  687. r.ctx.BindTexture(0, fbo.tex)
  688. coverScale, coverOff := texSpaceTransform(f32.FRect(uv), fbo.size)
  689. subScale, subOff := texSpaceTransform(f32.FRect(sub), p.clip.Size())
  690. r.pather.stenciler.ipipeline.uniforms.vert.uvTransform = [4]float32{coverScale.X, coverScale.Y, coverOff.X, coverOff.Y}
  691. r.pather.stenciler.ipipeline.uniforms.vert.subUVTransform = [4]float32{subScale.X, subScale.Y, subOff.X, subOff.Y}
  692. r.pather.stenciler.ipipeline.pipeline.UploadUniforms(r.ctx)
  693. r.ctx.DrawArrays(0, 4)
  694. }
  695. func (r *renderer) packIntersections(ops []imageOp) {
  696. r.intersections.clear()
  697. for i, img := range ops {
  698. var npaths int
  699. var onePath *pathOp
  700. for p := img.path; p != nil; p = p.parent {
  701. if p.path {
  702. onePath = p
  703. npaths++
  704. }
  705. }
  706. switch npaths {
  707. case 0:
  708. case 1:
  709. place := onePath.place
  710. place.Pos = place.Pos.Sub(onePath.clip.Min).Add(img.clip.Min)
  711. ops[i].place = place
  712. ops[i].clipType = clipTypePath
  713. default:
  714. sz := image.Point{X: img.clip.Dx(), Y: img.clip.Dy()}
  715. place, ok := r.intersections.add(sz)
  716. if !ok {
  717. panic("internal error: if the intersection fit, the intersection should fit as well")
  718. }
  719. ops[i].clipType = clipTypeIntersection
  720. ops[i].place = place
  721. }
  722. }
  723. }
  724. func (r *renderer) packStencils(pops *[]*pathOp) {
  725. r.packer.clear()
  726. ops := *pops
  727. // Allocate atlas space for cover textures.
  728. var i int
  729. for i < len(ops) {
  730. p := ops[i]
  731. if p.clip.Empty() {
  732. ops[i] = ops[len(ops)-1]
  733. ops = ops[:len(ops)-1]
  734. continue
  735. }
  736. place, ok := r.packer.add(p.clip.Size())
  737. if !ok {
  738. // The clip area is at most the entire screen. Hopefully no
  739. // screen is larger than GL_MAX_TEXTURE_SIZE.
  740. panic(fmt.Errorf("clip area %v is larger than maximum texture size %v", p.clip, r.packer.maxDims))
  741. }
  742. p.place = place
  743. i++
  744. }
  745. *pops = ops
  746. }
  747. func (r *renderer) packLayers(layers []opacityLayer) []opacityLayer {
  748. // Make every layer bounds contain nested layers; cull empty layers.
  749. for i := len(layers) - 1; i >= 0; i-- {
  750. l := layers[i]
  751. if l.parent != -1 {
  752. b := layers[l.parent].clip
  753. layers[l.parent].clip = b.Union(l.clip)
  754. }
  755. if l.clip.Empty() {
  756. layers = append(layers[:i], layers[i+1:]...)
  757. }
  758. }
  759. // Pack layers.
  760. r.layers.clear()
  761. depth := 0
  762. for i := range layers {
  763. l := &layers[i]
  764. // Only layers of the same depth may be packed together.
  765. if l.depth != depth {
  766. r.layers.newPage()
  767. }
  768. place, ok := r.layers.add(l.clip.Size())
  769. if !ok {
  770. // The layer area is at most the entire screen. Hopefully no
  771. // screen is larger than GL_MAX_TEXTURE_SIZE.
  772. panic(fmt.Errorf("layer size %v is larger than maximum texture size %v", l.clip.Size(), r.layers.maxDims))
  773. }
  774. l.place = place
  775. }
  776. return layers
  777. }
  778. func (r *renderer) drawLayers(layers []opacityLayer, ops []imageOp) {
  779. if len(r.layers.sizes) == 0 {
  780. return
  781. }
  782. fbo := -1
  783. r.layerFBOs.resize(r.ctx, driver.TextureFormatSRGBA, r.layers.sizes)
  784. for i := len(layers) - 1; i >= 0; i-- {
  785. l := layers[i]
  786. if fbo != l.place.Idx {
  787. if fbo != -1 {
  788. r.ctx.EndRenderPass()
  789. r.ctx.PrepareTexture(r.layerFBOs.fbos[fbo].tex)
  790. }
  791. fbo = l.place.Idx
  792. f := r.layerFBOs.fbos[fbo]
  793. r.ctx.BeginRenderPass(f.tex, driver.LoadDesc{Action: driver.LoadActionClear})
  794. }
  795. v := image.Rectangle{
  796. Min: l.place.Pos,
  797. Max: l.place.Pos.Add(l.clip.Size()),
  798. }
  799. r.ctx.Viewport(v.Min.X, v.Min.Y, v.Dx(), v.Dy())
  800. f := r.layerFBOs.fbos[fbo]
  801. r.drawOps(true, l.clip.Min.Mul(-1), l.clip.Size(), ops[l.opStart:l.opEnd])
  802. sr := f32.FRect(v)
  803. uvScale, uvOffset := texSpaceTransform(sr, f.size)
  804. uvTrans := f32.Affine2D{}.Scale(f32.Point{}, uvScale).Offset(uvOffset)
  805. // Replace layer ops with one textured op.
  806. ops[l.opStart] = imageOp{
  807. clip: l.clip,
  808. material: material{
  809. material: materialTexture,
  810. tex: f.tex,
  811. uvTrans: uvTrans,
  812. opacity: l.opacity,
  813. },
  814. layerOps: l.opEnd - l.opStart - 1,
  815. }
  816. }
  817. if fbo != -1 {
  818. r.ctx.EndRenderPass()
  819. r.ctx.PrepareTexture(r.layerFBOs.fbos[fbo].tex)
  820. }
  821. }
  822. func (d *drawOps) reset(viewport image.Point) {
  823. d.viewport = viewport
  824. d.imageOps = d.imageOps[:0]
  825. d.pathOps = d.pathOps[:0]
  826. d.pathOpCache = d.pathOpCache[:0]
  827. d.vertCache = d.vertCache[:0]
  828. d.transStack = d.transStack[:0]
  829. d.layers = d.layers[:0]
  830. d.opacityStack = d.opacityStack[:0]
  831. }
  832. func (d *drawOps) collect(root *op.Ops, viewport image.Point) {
  833. viewf := f32.Rectangle{
  834. Max: f32.Point{X: float32(viewport.X), Y: float32(viewport.Y)},
  835. }
  836. var ops *ops.Ops
  837. if root != nil {
  838. ops = &root.Internal
  839. }
  840. d.reader.Reset(ops)
  841. d.collectOps(&d.reader, viewf)
  842. }
  843. func (d *drawOps) buildPaths(ctx driver.Device) {
  844. for _, p := range d.pathOps {
  845. if v, exists := d.pathCache.get(p.pathKey); !exists || v.data.data == nil {
  846. data := buildPath(ctx, p.pathVerts)
  847. d.pathCache.put(p.pathKey, opCacheValue{
  848. data: data,
  849. bounds: p.bounds,
  850. })
  851. }
  852. p.pathVerts = nil
  853. }
  854. }
  855. func (d *drawOps) newPathOp() *pathOp {
  856. d.pathOpCache = append(d.pathOpCache, pathOp{})
  857. return &d.pathOpCache[len(d.pathOpCache)-1]
  858. }
  859. func (d *drawOps) addClipPath(state *drawState, aux []byte, auxKey opKey, bounds f32.Rectangle, off f32.Point) {
  860. npath := d.newPathOp()
  861. *npath = pathOp{
  862. parent: state.cpath,
  863. bounds: bounds,
  864. off: off,
  865. intersect: bounds.Add(off),
  866. rect: true,
  867. }
  868. if npath.parent != nil {
  869. npath.rect = npath.parent.rect
  870. npath.intersect = npath.parent.intersect.Intersect(npath.intersect)
  871. }
  872. if len(aux) > 0 {
  873. npath.rect = false
  874. npath.pathKey = auxKey
  875. npath.path = true
  876. npath.pathVerts = aux
  877. d.pathOps = append(d.pathOps, npath)
  878. }
  879. state.cpath = npath
  880. }
  881. func (d *drawOps) save(id int, state f32.Affine2D) {
  882. if extra := id - len(d.states) + 1; extra > 0 {
  883. d.states = append(d.states, make([]f32.Affine2D, extra)...)
  884. }
  885. d.states[id] = state
  886. }
  887. func (k opKey) SetTransform(t f32.Affine2D) opKey {
  888. sx, hx, _, hy, sy, _ := t.Elems()
  889. k.sx = sx
  890. k.hx = hx
  891. k.hy = hy
  892. k.sy = sy
  893. return k
  894. }
  895. func (d *drawOps) collectOps(r *ops.Reader, viewport f32.Rectangle) {
  896. var (
  897. quads quadsOp
  898. state drawState
  899. )
  900. reset := func() {
  901. state = drawState{
  902. color: color.NRGBA{A: 0xff},
  903. }
  904. }
  905. reset()
  906. loop:
  907. for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() {
  908. switch ops.OpType(encOp.Data[0]) {
  909. case ops.TypeTransform:
  910. dop, push := ops.DecodeTransform(encOp.Data)
  911. if push {
  912. d.transStack = append(d.transStack, state.t)
  913. }
  914. state.t = state.t.Mul(dop)
  915. case ops.TypePopTransform:
  916. n := len(d.transStack)
  917. state.t = d.transStack[n-1]
  918. d.transStack = d.transStack[:n-1]
  919. case ops.TypePushOpacity:
  920. opacity := ops.DecodeOpacity(encOp.Data)
  921. parent := -1
  922. depth := len(d.opacityStack)
  923. if depth > 0 {
  924. parent = d.opacityStack[depth-1]
  925. }
  926. lidx := len(d.layers)
  927. d.layers = append(d.layers, opacityLayer{
  928. opacity: opacity,
  929. parent: parent,
  930. depth: depth,
  931. opStart: len(d.imageOps),
  932. })
  933. d.opacityStack = append(d.opacityStack, lidx)
  934. case ops.TypePopOpacity:
  935. n := len(d.opacityStack)
  936. idx := d.opacityStack[n-1]
  937. d.layers[idx].opEnd = len(d.imageOps)
  938. d.opacityStack = d.opacityStack[:n-1]
  939. case ops.TypeStroke:
  940. quads.key.strokeWidth = decodeStrokeOp(encOp.Data)
  941. case ops.TypePath:
  942. encOp, ok = r.Decode()
  943. if !ok {
  944. break loop
  945. }
  946. quads.aux = encOp.Data[ops.TypeAuxLen:]
  947. quads.key.Key = encOp.Key
  948. case ops.TypeClip:
  949. var op ops.ClipOp
  950. op.Decode(encOp.Data)
  951. quads.key.outline = op.Outline
  952. bounds := f32.FRect(op.Bounds)
  953. trans, off := state.t.Split()
  954. if len(quads.aux) > 0 {
  955. // There is a clipping path, build the gpu data and update the
  956. // cache key such that it will be equal only if the transform is the
  957. // same also. Use cached data if we have it.
  958. quads.key = quads.key.SetTransform(trans)
  959. if v, ok := d.pathCache.get(quads.key); ok {
  960. // Since the GPU data exists in the cache aux will not be used.
  961. // Why is this not used for the offset shapes?
  962. bounds = v.bounds
  963. } else {
  964. var pathData []byte
  965. pathData, bounds = d.buildVerts(
  966. quads.aux, trans, quads.key.outline, quads.key.strokeWidth,
  967. )
  968. quads.aux = pathData
  969. // add it to the cache, without GPU data, so the transform can be
  970. // reused.
  971. d.pathCache.put(quads.key, opCacheValue{bounds: bounds})
  972. }
  973. } else {
  974. quads.aux, bounds, _ = d.boundsForTransformedRect(bounds, trans)
  975. quads.key = opKey{Key: encOp.Key}
  976. }
  977. d.addClipPath(&state, quads.aux, quads.key, bounds, off)
  978. quads = quadsOp{}
  979. case ops.TypePopClip:
  980. state.cpath = state.cpath.parent
  981. case ops.TypeColor:
  982. state.matType = materialColor
  983. state.color = decodeColorOp(encOp.Data)
  984. case ops.TypeLinearGradient:
  985. state.matType = materialLinearGradient
  986. op := decodeLinearGradientOp(encOp.Data)
  987. state.stop1 = op.stop1
  988. state.stop2 = op.stop2
  989. state.color1 = op.color1
  990. state.color2 = op.color2
  991. case ops.TypeImage:
  992. state.matType = materialTexture
  993. state.image = decodeImageOp(encOp.Data, encOp.Refs)
  994. case ops.TypePaint:
  995. // Transform (if needed) the painting rectangle and if so generate a clip path,
  996. // for those cases also compute a partialTrans that maps texture coordinates between
  997. // the new bounding rectangle and the transformed original paint rectangle.
  998. t, off := state.t.Split()
  999. // Fill the clip area, unless the material is a (bounded) image.
  1000. // TODO: Find a tighter bound.
  1001. inf := float32(1e6)
  1002. dst := f32.Rect(-inf, -inf, inf, inf)
  1003. if state.matType == materialTexture {
  1004. sz := state.image.src.Rect.Size()
  1005. dst = f32.Rectangle{Max: layout.FPt(sz)}
  1006. }
  1007. clipData, bnd, partialTrans := d.boundsForTransformedRect(dst, t)
  1008. cl := viewport.Intersect(bnd.Add(off))
  1009. if state.cpath != nil {
  1010. cl = state.cpath.intersect.Intersect(cl)
  1011. }
  1012. if cl.Empty() {
  1013. continue
  1014. }
  1015. if clipData != nil {
  1016. // The paint operation is sheared or rotated, add a clip path representing
  1017. // this transformed rectangle.
  1018. k := opKey{Key: encOp.Key}
  1019. k.SetTransform(t) // TODO: This call has no effect.
  1020. d.addClipPath(&state, clipData, k, bnd, off)
  1021. }
  1022. bounds := cl.Round()
  1023. mat := state.materialFor(bnd, off, partialTrans, bounds)
  1024. rect := state.cpath == nil || state.cpath.rect
  1025. if bounds.Min == (image.Point{}) && bounds.Max == d.viewport && rect && mat.opaque && (mat.material == materialColor) && len(d.opacityStack) == 0 {
  1026. // The image is a uniform opaque color and takes up the whole screen.
  1027. // Scrap images up to and including this image and set clear color.
  1028. d.imageOps = d.imageOps[:0]
  1029. d.clearColor = mat.color.Opaque()
  1030. d.clear = true
  1031. continue
  1032. }
  1033. img := imageOp{
  1034. path: state.cpath,
  1035. clip: bounds,
  1036. material: mat,
  1037. }
  1038. if n := len(d.opacityStack); n > 0 {
  1039. idx := d.opacityStack[n-1]
  1040. lb := d.layers[idx].clip
  1041. if lb.Empty() {
  1042. d.layers[idx].clip = img.clip
  1043. } else {
  1044. d.layers[idx].clip = lb.Union(img.clip)
  1045. }
  1046. }
  1047. d.imageOps = append(d.imageOps, img)
  1048. if clipData != nil {
  1049. // we added a clip path that should not remain
  1050. state.cpath = state.cpath.parent
  1051. }
  1052. case ops.TypeSave:
  1053. id := ops.DecodeSave(encOp.Data)
  1054. d.save(id, state.t)
  1055. case ops.TypeLoad:
  1056. reset()
  1057. id := ops.DecodeLoad(encOp.Data)
  1058. state.t = d.states[id]
  1059. }
  1060. }
  1061. }
  1062. func expandPathOp(p *pathOp, clip image.Rectangle) {
  1063. for p != nil {
  1064. pclip := p.clip
  1065. if !pclip.Empty() {
  1066. clip = clip.Union(pclip)
  1067. }
  1068. p.clip = clip
  1069. p = p.parent
  1070. }
  1071. }
  1072. func (d *drawState) materialFor(rect f32.Rectangle, off f32.Point, partTrans f32.Affine2D, clip image.Rectangle) material {
  1073. m := material{
  1074. opacity: 1.,
  1075. }
  1076. switch d.matType {
  1077. case materialColor:
  1078. m.material = materialColor
  1079. m.color = f32color.LinearFromSRGB(d.color)
  1080. m.opaque = m.color.A == 1.0
  1081. case materialLinearGradient:
  1082. m.material = materialLinearGradient
  1083. m.color1 = f32color.LinearFromSRGB(d.color1)
  1084. m.color2 = f32color.LinearFromSRGB(d.color2)
  1085. m.opaque = m.color1.A == 1.0 && m.color2.A == 1.0
  1086. m.uvTrans = partTrans.Mul(gradientSpaceTransform(clip, off, d.stop1, d.stop2))
  1087. case materialTexture:
  1088. m.material = materialTexture
  1089. dr := rect.Add(off).Round()
  1090. sz := d.image.src.Bounds().Size()
  1091. sr := f32.Rectangle{
  1092. Max: f32.Point{
  1093. X: float32(sz.X),
  1094. Y: float32(sz.Y),
  1095. },
  1096. }
  1097. dx := float32(dr.Dx())
  1098. sdx := sr.Dx()
  1099. sr.Min.X += float32(clip.Min.X-dr.Min.X) * sdx / dx
  1100. sr.Max.X -= float32(dr.Max.X-clip.Max.X) * sdx / dx
  1101. dy := float32(dr.Dy())
  1102. sdy := sr.Dy()
  1103. sr.Min.Y += float32(clip.Min.Y-dr.Min.Y) * sdy / dy
  1104. sr.Max.Y -= float32(dr.Max.Y-clip.Max.Y) * sdy / dy
  1105. uvScale, uvOffset := texSpaceTransform(sr, sz)
  1106. m.uvTrans = partTrans.Mul(f32.Affine2D{}.Scale(f32.Point{}, uvScale).Offset(uvOffset))
  1107. m.data = d.image
  1108. }
  1109. return m
  1110. }
  1111. func (r *renderer) uploadImages(cache *textureCache, ops []imageOp) {
  1112. for i := range ops {
  1113. img := &ops[i]
  1114. m := img.material
  1115. if m.material == materialTexture {
  1116. img.material.tex = r.texHandle(cache, m.data)
  1117. }
  1118. }
  1119. }
  1120. func (r *renderer) prepareDrawOps(ops []imageOp) {
  1121. for _, img := range ops {
  1122. m := img.material
  1123. switch m.material {
  1124. case materialTexture:
  1125. r.ctx.PrepareTexture(m.tex)
  1126. }
  1127. var fbo FBO
  1128. switch img.clipType {
  1129. case clipTypeNone:
  1130. continue
  1131. case clipTypePath:
  1132. fbo = r.pather.stenciler.cover(img.place.Idx)
  1133. case clipTypeIntersection:
  1134. fbo = r.pather.stenciler.intersections.fbos[img.place.Idx]
  1135. }
  1136. r.ctx.PrepareTexture(fbo.tex)
  1137. }
  1138. }
  1139. func (r *renderer) drawOps(isFBO bool, opOff, viewport image.Point, ops []imageOp) {
  1140. var coverTex driver.Texture
  1141. for i := 0; i < len(ops); i++ {
  1142. img := ops[i]
  1143. i += img.layerOps
  1144. m := img.material
  1145. switch m.material {
  1146. case materialTexture:
  1147. r.ctx.BindTexture(0, m.tex)
  1148. }
  1149. drc := img.clip.Add(opOff)
  1150. scale, off := clipSpaceTransform(drc, viewport)
  1151. var fbo FBO
  1152. fboIdx := 0
  1153. if isFBO {
  1154. fboIdx = 1
  1155. }
  1156. switch img.clipType {
  1157. case clipTypeNone:
  1158. p := r.blitter.pipelines[fboIdx][m.material]
  1159. r.ctx.BindPipeline(p.pipeline)
  1160. r.ctx.BindVertexBuffer(r.blitter.quadVerts, 0)
  1161. r.blitter.blit(m.material, isFBO, m.color, m.color1, m.color2, scale, off, m.opacity, m.uvTrans)
  1162. continue
  1163. case clipTypePath:
  1164. fbo = r.pather.stenciler.cover(img.place.Idx)
  1165. case clipTypeIntersection:
  1166. fbo = r.pather.stenciler.intersections.fbos[img.place.Idx]
  1167. }
  1168. if coverTex != fbo.tex {
  1169. coverTex = fbo.tex
  1170. r.ctx.BindTexture(1, coverTex)
  1171. }
  1172. uv := image.Rectangle{
  1173. Min: img.place.Pos,
  1174. Max: img.place.Pos.Add(drc.Size()),
  1175. }
  1176. coverScale, coverOff := texSpaceTransform(f32.FRect(uv), fbo.size)
  1177. p := r.pather.coverer.pipelines[fboIdx][m.material]
  1178. r.ctx.BindPipeline(p.pipeline)
  1179. r.ctx.BindVertexBuffer(r.blitter.quadVerts, 0)
  1180. r.pather.cover(m.material, isFBO, m.color, m.color1, m.color2, scale, off, m.uvTrans, coverScale, coverOff)
  1181. }
  1182. }
  1183. func (b *blitter) blit(mat materialType, fbo bool, col f32color.RGBA, col1, col2 f32color.RGBA, scale, off f32.Point, opacity float32, uvTrans f32.Affine2D) {
  1184. fboIdx := 0
  1185. if fbo {
  1186. fboIdx = 1
  1187. }
  1188. p := b.pipelines[fboIdx][mat]
  1189. b.ctx.BindPipeline(p.pipeline)
  1190. var uniforms *blitUniforms
  1191. switch mat {
  1192. case materialColor:
  1193. b.colUniforms.color = col
  1194. uniforms = &b.colUniforms.blitUniforms
  1195. case materialTexture:
  1196. t1, t2, t3, t4, t5, t6 := uvTrans.Elems()
  1197. uniforms = &b.texUniforms.blitUniforms
  1198. uniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0}
  1199. uniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0}
  1200. case materialLinearGradient:
  1201. b.linearGradientUniforms.color1 = col1
  1202. b.linearGradientUniforms.color2 = col2
  1203. t1, t2, t3, t4, t5, t6 := uvTrans.Elems()
  1204. uniforms = &b.linearGradientUniforms.blitUniforms
  1205. uniforms.uvTransformR1 = [4]float32{t1, t2, t3, 0}
  1206. uniforms.uvTransformR2 = [4]float32{t4, t5, t6, 0}
  1207. }
  1208. uniforms.fbo = 0
  1209. if fbo {
  1210. uniforms.fbo = 1
  1211. }
  1212. uniforms.opacity = opacity
  1213. uniforms.transform = [4]float32{scale.X, scale.Y, off.X, off.Y}
  1214. p.UploadUniforms(b.ctx)
  1215. b.ctx.DrawArrays(0, 4)
  1216. }
  1217. // newUniformBuffer creates a new GPU uniform buffer backed by the
  1218. // structure uniformBlock points to.
  1219. func newUniformBuffer(b driver.Device, uniformBlock interface{}) *uniformBuffer {
  1220. ref := reflect.ValueOf(uniformBlock)
  1221. // Determine the size of the uniforms structure, *uniforms.
  1222. size := ref.Elem().Type().Size()
  1223. // Map the uniforms structure as a byte slice.
  1224. ptr := unsafe.Slice((*byte)(unsafe.Pointer(ref.Pointer())), size)
  1225. ubuf, err := b.NewBuffer(driver.BufferBindingUniforms, len(ptr))
  1226. if err != nil {
  1227. panic(err)
  1228. }
  1229. return &uniformBuffer{buf: ubuf, ptr: ptr}
  1230. }
  1231. func (u *uniformBuffer) Upload() {
  1232. u.buf.Upload(u.ptr)
  1233. }
  1234. func (u *uniformBuffer) Release() {
  1235. u.buf.Release()
  1236. u.buf = nil
  1237. }
  1238. func (p *pipeline) UploadUniforms(ctx driver.Device) {
  1239. if p.uniforms != nil {
  1240. p.uniforms.Upload()
  1241. ctx.BindUniforms(p.uniforms.buf)
  1242. }
  1243. }
  1244. func (p *pipeline) Release() {
  1245. p.pipeline.Release()
  1246. if p.uniforms != nil {
  1247. p.uniforms.Release()
  1248. }
  1249. *p = pipeline{}
  1250. }
  1251. // texSpaceTransform return the scale and offset that transforms the given subimage
  1252. // into quad texture coordinates.
  1253. func texSpaceTransform(r f32.Rectangle, bounds image.Point) (f32.Point, f32.Point) {
  1254. size := f32.Point{X: float32(bounds.X), Y: float32(bounds.Y)}
  1255. scale := f32.Point{X: r.Dx() / size.X, Y: r.Dy() / size.Y}
  1256. offset := f32.Point{X: r.Min.X / size.X, Y: r.Min.Y / size.Y}
  1257. return scale, offset
  1258. }
  1259. // gradientSpaceTransform transforms stop1 and stop2 to [(0,0), (1,1)].
  1260. func gradientSpaceTransform(clip image.Rectangle, off f32.Point, stop1, stop2 f32.Point) f32.Affine2D {
  1261. d := stop2.Sub(stop1)
  1262. l := float32(math.Sqrt(float64(d.X*d.X + d.Y*d.Y)))
  1263. a := float32(math.Atan2(float64(-d.Y), float64(d.X)))
  1264. // TODO: optimize
  1265. zp := f32.Point{}
  1266. return f32.Affine2D{}.
  1267. Scale(zp, layout.FPt(clip.Size())). // scale to pixel space
  1268. Offset(zp.Sub(off).Add(layout.FPt(clip.Min))). // offset to clip space
  1269. Offset(zp.Sub(stop1)). // offset to first stop point
  1270. Rotate(zp, a). // rotate to align gradient
  1271. Scale(zp, f32.Pt(1/l, 1/l)) // scale gradient to right size
  1272. }
  1273. // clipSpaceTransform returns the scale and offset that transforms the given
  1274. // rectangle from a viewport into GPU driver device coordinates.
  1275. func clipSpaceTransform(r image.Rectangle, viewport image.Point) (f32.Point, f32.Point) {
  1276. // First, transform UI coordinates to device coordinates:
  1277. //
  1278. // [(-1, -1) (+1, -1)]
  1279. // [(-1, +1) (+1, +1)]
  1280. //
  1281. x, y := float32(r.Min.X), float32(r.Min.Y)
  1282. w, h := float32(r.Dx()), float32(r.Dy())
  1283. vx, vy := 2/float32(viewport.X), 2/float32(viewport.Y)
  1284. x = x*vx - 1
  1285. y = y*vy - 1
  1286. w *= vx
  1287. h *= vy
  1288. // Then, compute the transformation from the fullscreen quad to
  1289. // the rectangle at (x, y) and dimensions (w, h).
  1290. scale := f32.Point{X: w * .5, Y: h * .5}
  1291. offset := f32.Point{X: x + w*.5, Y: y + h*.5}
  1292. return scale, offset
  1293. }
  1294. // Fill in maximal Y coordinates of the NW and NE corners.
  1295. func fillMaxY(verts []byte) {
  1296. contour := 0
  1297. bo := binary.LittleEndian
  1298. for len(verts) > 0 {
  1299. maxy := float32(math.Inf(-1))
  1300. i := 0
  1301. for ; i+vertStride*4 <= len(verts); i += vertStride * 4 {
  1302. vert := verts[i : i+vertStride]
  1303. // MaxY contains the integer contour index.
  1304. pathContour := int(bo.Uint32(vert[int(unsafe.Offsetof(((*vertex)(nil)).MaxY)):]))
  1305. if contour != pathContour {
  1306. contour = pathContour
  1307. break
  1308. }
  1309. fromy := math.Float32frombits(bo.Uint32(vert[int(unsafe.Offsetof(((*vertex)(nil)).FromY)):]))
  1310. ctrly := math.Float32frombits(bo.Uint32(vert[int(unsafe.Offsetof(((*vertex)(nil)).CtrlY)):]))
  1311. toy := math.Float32frombits(bo.Uint32(vert[int(unsafe.Offsetof(((*vertex)(nil)).ToY)):]))
  1312. if fromy > maxy {
  1313. maxy = fromy
  1314. }
  1315. if ctrly > maxy {
  1316. maxy = ctrly
  1317. }
  1318. if toy > maxy {
  1319. maxy = toy
  1320. }
  1321. }
  1322. fillContourMaxY(maxy, verts[:i])
  1323. verts = verts[i:]
  1324. }
  1325. }
  1326. func fillContourMaxY(maxy float32, verts []byte) {
  1327. bo := binary.LittleEndian
  1328. for i := 0; i < len(verts); i += vertStride {
  1329. off := int(unsafe.Offsetof(((*vertex)(nil)).MaxY))
  1330. bo.PutUint32(verts[i+off:], math.Float32bits(maxy))
  1331. }
  1332. }
  1333. func (d *drawOps) writeVertCache(n int) []byte {
  1334. d.vertCache = append(d.vertCache, make([]byte, n)...)
  1335. return d.vertCache[len(d.vertCache)-n:]
  1336. }
  1337. // transform, split paths as needed, calculate maxY, bounds and create GPU vertices.
  1338. func (d *drawOps) buildVerts(pathData []byte, tr f32.Affine2D, outline bool, strWidth float32) (verts []byte, bounds f32.Rectangle) {
  1339. inf := float32(math.Inf(+1))
  1340. d.qs.bounds = f32.Rectangle{
  1341. Min: f32.Point{X: inf, Y: inf},
  1342. Max: f32.Point{X: -inf, Y: -inf},
  1343. }
  1344. d.qs.d = d
  1345. startLength := len(d.vertCache)
  1346. switch {
  1347. case strWidth > 0:
  1348. // Stroke path.
  1349. ss := stroke.StrokeStyle{
  1350. Width: strWidth,
  1351. }
  1352. quads := stroke.StrokePathCommands(ss, pathData)
  1353. for _, quad := range quads {
  1354. d.qs.contour = quad.Contour
  1355. quad.Quad = quad.Quad.Transform(tr)
  1356. d.qs.splitAndEncode(quad.Quad)
  1357. }
  1358. case outline:
  1359. decodeToOutlineQuads(&d.qs, tr, pathData)
  1360. }
  1361. fillMaxY(d.vertCache[startLength:])
  1362. return d.vertCache[startLength:], d.qs.bounds
  1363. }
  1364. // decodeOutlineQuads decodes scene commands, splits them into quadratic béziers
  1365. // as needed and feeds them to the supplied splitter.
  1366. func decodeToOutlineQuads(qs *quadSplitter, tr f32.Affine2D, pathData []byte) {
  1367. for len(pathData) >= scene.CommandSize+4 {
  1368. qs.contour = binary.LittleEndian.Uint32(pathData)
  1369. cmd := ops.DecodeCommand(pathData[4:])
  1370. switch cmd.Op() {
  1371. case scene.OpLine:
  1372. var q stroke.QuadSegment
  1373. q.From, q.To = scene.DecodeLine(cmd)
  1374. q.Ctrl = q.From.Add(q.To).Mul(.5)
  1375. q = q.Transform(tr)
  1376. qs.splitAndEncode(q)
  1377. case scene.OpGap:
  1378. var q stroke.QuadSegment
  1379. q.From, q.To = scene.DecodeGap(cmd)
  1380. q.Ctrl = q.From.Add(q.To).Mul(.5)
  1381. q = q.Transform(tr)
  1382. qs.splitAndEncode(q)
  1383. case scene.OpQuad:
  1384. var q stroke.QuadSegment
  1385. q.From, q.Ctrl, q.To = scene.DecodeQuad(cmd)
  1386. q = q.Transform(tr)
  1387. qs.splitAndEncode(q)
  1388. case scene.OpCubic:
  1389. from, ctrl0, ctrl1, to := scene.DecodeCubic(cmd)
  1390. qs.scratch = stroke.SplitCubic(from, ctrl0, ctrl1, to, qs.scratch[:0])
  1391. for _, q := range qs.scratch {
  1392. q = q.Transform(tr)
  1393. qs.splitAndEncode(q)
  1394. }
  1395. default:
  1396. panic("unsupported scene command")
  1397. }
  1398. pathData = pathData[scene.CommandSize+4:]
  1399. }
  1400. }
  1401. // create GPU vertices for transformed r, find the bounds and establish texture transform.
  1402. func (d *drawOps) boundsForTransformedRect(r f32.Rectangle, tr f32.Affine2D) (aux []byte, bnd f32.Rectangle, ptr f32.Affine2D) {
  1403. if isPureOffset(tr) {
  1404. // fast-path to allow blitting of pure rectangles
  1405. _, _, ox, _, _, oy := tr.Elems()
  1406. off := f32.Pt(ox, oy)
  1407. bnd.Min = r.Min.Add(off)
  1408. bnd.Max = r.Max.Add(off)
  1409. return
  1410. }
  1411. // transform all corners, find new bounds
  1412. corners := [4]f32.Point{
  1413. tr.Transform(r.Min), tr.Transform(f32.Pt(r.Max.X, r.Min.Y)),
  1414. tr.Transform(r.Max), tr.Transform(f32.Pt(r.Min.X, r.Max.Y)),
  1415. }
  1416. bnd.Min = f32.Pt(math.MaxFloat32, math.MaxFloat32)
  1417. bnd.Max = f32.Pt(-math.MaxFloat32, -math.MaxFloat32)
  1418. for _, c := range corners {
  1419. if c.X < bnd.Min.X {
  1420. bnd.Min.X = c.X
  1421. }
  1422. if c.Y < bnd.Min.Y {
  1423. bnd.Min.Y = c.Y
  1424. }
  1425. if c.X > bnd.Max.X {
  1426. bnd.Max.X = c.X
  1427. }
  1428. if c.Y > bnd.Max.Y {
  1429. bnd.Max.Y = c.Y
  1430. }
  1431. }
  1432. // build the GPU vertices
  1433. l := len(d.vertCache)
  1434. d.vertCache = append(d.vertCache, make([]byte, vertStride*4*4)...)
  1435. aux = d.vertCache[l:]
  1436. encodeQuadTo(aux, 0, corners[0], corners[0].Add(corners[1]).Mul(0.5), corners[1])
  1437. encodeQuadTo(aux[vertStride*4:], 0, corners[1], corners[1].Add(corners[2]).Mul(0.5), corners[2])
  1438. encodeQuadTo(aux[vertStride*4*2:], 0, corners[2], corners[2].Add(corners[3]).Mul(0.5), corners[3])
  1439. encodeQuadTo(aux[vertStride*4*3:], 0, corners[3], corners[3].Add(corners[0]).Mul(0.5), corners[0])
  1440. fillMaxY(aux)
  1441. // establish the transform mapping from bounds rectangle to transformed corners
  1442. var P1, P2, P3 f32.Point
  1443. P1.X = (corners[1].X - bnd.Min.X) / (bnd.Max.X - bnd.Min.X)
  1444. P1.Y = (corners[1].Y - bnd.Min.Y) / (bnd.Max.Y - bnd.Min.Y)
  1445. P2.X = (corners[2].X - bnd.Min.X) / (bnd.Max.X - bnd.Min.X)
  1446. P2.Y = (corners[2].Y - bnd.Min.Y) / (bnd.Max.Y - bnd.Min.Y)
  1447. P3.X = (corners[3].X - bnd.Min.X) / (bnd.Max.X - bnd.Min.X)
  1448. P3.Y = (corners[3].Y - bnd.Min.Y) / (bnd.Max.Y - bnd.Min.Y)
  1449. sx, sy := P2.X-P3.X, P2.Y-P3.Y
  1450. ptr = f32.NewAffine2D(sx, P2.X-P1.X, P1.X-sx, sy, P2.Y-P1.Y, P1.Y-sy).Invert()
  1451. return
  1452. }
  1453. func isPureOffset(t f32.Affine2D) bool {
  1454. a, b, _, d, e, _ := t.Elems()
  1455. return a == 1 && b == 0 && d == 0 && e == 1
  1456. }
  1457. func newShaders(ctx driver.Device, vsrc, fsrc shader.Sources) (vert driver.VertexShader, frag driver.FragmentShader, err error) {
  1458. vert, err = ctx.NewVertexShader(vsrc)
  1459. if err != nil {
  1460. return
  1461. }
  1462. frag, err = ctx.NewFragmentShader(fsrc)
  1463. if err != nil {
  1464. vert.Release()
  1465. }
  1466. return
  1467. }