fps.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. //go:build darwin || linux || windows
  5. // +build darwin linux windows
  6. // Package debug provides GL-based debugging tools for apps.
  7. package debug // import "golang.org/x/mobile/exp/app/debug"
  8. import (
  9. "image"
  10. "image/color"
  11. "image/draw"
  12. "time"
  13. "golang.org/x/mobile/event/size"
  14. "golang.org/x/mobile/exp/gl/glutil"
  15. "golang.org/x/mobile/geom"
  16. )
  17. // FPS draws a count of the frames rendered per second.
  18. type FPS struct {
  19. sz size.Event
  20. images *glutil.Images
  21. m *glutil.Image
  22. lastDraw time.Time
  23. // TODO: store *gl.Context
  24. }
  25. // NewFPS creates an FPS tied to the current GL context.
  26. func NewFPS(images *glutil.Images) *FPS {
  27. return &FPS{
  28. lastDraw: time.Now(),
  29. images: images,
  30. }
  31. }
  32. // Draw draws the per second framerate in the bottom-left of the screen.
  33. func (p *FPS) Draw(sz size.Event) {
  34. const imgW, imgH = 7*(fontWidth+1) + 1, fontHeight + 2
  35. if sz.WidthPx == 0 && sz.HeightPx == 0 {
  36. return
  37. }
  38. if p.sz != sz {
  39. p.sz = sz
  40. if p.m != nil {
  41. p.m.Release()
  42. }
  43. p.m = p.images.NewImage(imgW, imgH)
  44. }
  45. display := [7]byte{
  46. 4: 'F',
  47. 5: 'P',
  48. 6: 'S',
  49. }
  50. now := time.Now()
  51. f := 0
  52. if dur := now.Sub(p.lastDraw); dur > 0 {
  53. f = int(time.Second / dur)
  54. }
  55. display[2] = '0' + byte((f/1e0)%10)
  56. display[1] = '0' + byte((f/1e1)%10)
  57. display[0] = '0' + byte((f/1e2)%10)
  58. draw.Draw(p.m.RGBA, p.m.RGBA.Bounds(), image.White, image.Point{}, draw.Src)
  59. for i, c := range display {
  60. glyph := glyphs[c]
  61. if len(glyph) != fontWidth*fontHeight {
  62. continue
  63. }
  64. for y := 0; y < fontHeight; y++ {
  65. for x := 0; x < fontWidth; x++ {
  66. if glyph[fontWidth*y+x] == ' ' {
  67. continue
  68. }
  69. p.m.RGBA.SetRGBA((fontWidth+1)*i+x+1, y+1, color.RGBA{A: 0xff})
  70. }
  71. }
  72. }
  73. p.m.Upload()
  74. p.m.Draw(
  75. sz,
  76. geom.Point{0, sz.HeightPt - imgH},
  77. geom.Point{imgW, sz.HeightPt - imgH},
  78. geom.Point{0, sz.HeightPt},
  79. p.m.RGBA.Bounds(),
  80. )
  81. p.lastDraw = now
  82. }
  83. func (f *FPS) Release() {
  84. if f.m != nil {
  85. f.m.Release()
  86. f.m = nil
  87. f.images = nil
  88. }
  89. }
  90. const (
  91. fontWidth = 5
  92. fontHeight = 7
  93. )
  94. // glyphs comes from the 6x10 fixed font from the plan9port:
  95. // https://github.com/9fans/plan9port/tree/master/font/fixed
  96. //
  97. // 6x10 becomes 5x7 because each glyph has a 1-pixel margin plus space for
  98. // descenders.
  99. //
  100. // Its README file says that those fonts were converted from XFree86, and are
  101. // in the public domain.
  102. var glyphs = [256]string{
  103. '0': "" +
  104. " X " +
  105. " X X " +
  106. "X X" +
  107. "X X" +
  108. "X X" +
  109. " X X " +
  110. " X ",
  111. '1': "" +
  112. " X " +
  113. " XX " +
  114. "X X " +
  115. " X " +
  116. " X " +
  117. " X " +
  118. "XXXXX",
  119. '2': "" +
  120. " XXX " +
  121. "X X" +
  122. " X" +
  123. " XX " +
  124. " X " +
  125. "X " +
  126. "XXXXX",
  127. '3': "" +
  128. "XXXXX" +
  129. " X" +
  130. " X " +
  131. " XX " +
  132. " X" +
  133. "X X" +
  134. " XXX ",
  135. '4': "" +
  136. " X " +
  137. " XX " +
  138. " X X " +
  139. "X X " +
  140. "XXXXX" +
  141. " X " +
  142. " X ",
  143. '5': "" +
  144. "XXXXX" +
  145. "X " +
  146. "X XX " +
  147. "XX X" +
  148. " X" +
  149. "X X" +
  150. " XXX ",
  151. '6': "" +
  152. " XX " +
  153. " X " +
  154. "X " +
  155. "X XX " +
  156. "XX X" +
  157. "X X" +
  158. " XXX ",
  159. '7': "" +
  160. "XXXXX" +
  161. " X" +
  162. " X " +
  163. " X " +
  164. " X " +
  165. " X " +
  166. " X ",
  167. '8': "" +
  168. " XXX " +
  169. "X X" +
  170. "X X" +
  171. " XXX " +
  172. "X X" +
  173. "X X" +
  174. " XXX ",
  175. '9': "" +
  176. " XXX " +
  177. "X X" +
  178. "X XX" +
  179. " XX X" +
  180. " X" +
  181. " X " +
  182. " XX ",
  183. 'F': "" +
  184. "XXXXX" +
  185. "X " +
  186. "X " +
  187. "XXXX " +
  188. "X " +
  189. "X " +
  190. "X ",
  191. 'P': "" +
  192. "XXXX " +
  193. "X X" +
  194. "X X" +
  195. "XXXX " +
  196. "X " +
  197. "X " +
  198. "X ",
  199. 'S': "" +
  200. " XXX " +
  201. "X X" +
  202. "X " +
  203. " XXX " +
  204. " X" +
  205. "X X" +
  206. " XXX ",
  207. }