image.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. // Copyright 2019 The Ebiten Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package buffered
  15. import (
  16. "fmt"
  17. "image"
  18. "github.com/hajimehoshi/ebiten/v2/internal/atlas"
  19. "github.com/hajimehoshi/ebiten/v2/internal/graphics"
  20. "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
  21. "github.com/hajimehoshi/ebiten/v2/internal/restorable"
  22. )
  23. var whiteImage *Image
  24. func init() {
  25. whiteImage = NewImage(3, 3, atlas.ImageTypeRegular)
  26. pix := make([]byte, 4*3*3)
  27. for i := range pix {
  28. pix[i] = 0xff
  29. }
  30. whiteImage.WritePixels(pix, image.Rect(0, 0, 3, 3))
  31. }
  32. type Image struct {
  33. img *atlas.Image
  34. width int
  35. height int
  36. // dotsBuffer is a buffer for drawing a lot of dots.
  37. // An entry in this map is the primary data of pixels for ReadPixels.
  38. dotsBuffer map[image.Point][4]byte
  39. // pixels is cached pixels for ReadPixels.
  40. // pixels might be out of sync with GPU.
  41. // The data of pixels is the secondary data of pixels for ReadPixels.
  42. //
  43. // pixels is always nil when restorable.AlwaysReadPixelsFromGPU() returns false.
  44. pixels []byte
  45. // pixelsUnsynced represents whether the pixels in CPU and GPU are not synced.
  46. pixelsUnsynced bool
  47. }
  48. func NewImage(width, height int, imageType atlas.ImageType) *Image {
  49. return &Image{
  50. img: atlas.NewImage(width, height, imageType),
  51. width: width,
  52. height: height,
  53. }
  54. }
  55. func (i *Image) Deallocate() {
  56. i.img.Deallocate()
  57. i.dotsBuffer = nil
  58. i.pixels = nil
  59. i.pixelsUnsynced = false
  60. }
  61. func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byte, region image.Rectangle) (bool, error) {
  62. if region.Dx() == 1 && region.Dy() == 1 {
  63. if c, ok := i.dotsBuffer[region.Min]; ok {
  64. copy(pixels, c[:])
  65. return true, nil
  66. }
  67. }
  68. // If restorable.AlwaysReadPixelsFromGPU() returns false, the pixel data is cached in the restorable package.
  69. if !restorable.AlwaysReadPixelsFromGPU() {
  70. i.syncPixelsIfNeeded()
  71. ok, err := i.img.ReadPixels(graphicsDriver, pixels, region)
  72. if err != nil {
  73. return false, err
  74. }
  75. return ok, nil
  76. }
  77. // Do not call syncPixelsIfNeeded here. This would slow (image/draw).Draw.
  78. // See ebiten.TestImageDrawOver.
  79. if i.pixels == nil {
  80. pix := make([]byte, 4*i.width*i.height)
  81. ok, err := i.img.ReadPixels(graphicsDriver, pix, image.Rect(0, 0, i.width, i.height))
  82. if err != nil {
  83. return false, err
  84. }
  85. if !ok {
  86. return false, nil
  87. }
  88. i.pixels = pix
  89. }
  90. if len(i.dotsBuffer) > 0 {
  91. for pos, clr := range i.dotsBuffer {
  92. idx := 4 * (pos.Y*i.width + pos.X)
  93. i.pixels[idx] = clr[0]
  94. i.pixels[idx+1] = clr[1]
  95. i.pixels[idx+2] = clr[2]
  96. i.pixels[idx+3] = clr[3]
  97. delete(i.dotsBuffer, pos)
  98. }
  99. i.pixelsUnsynced = true
  100. }
  101. lineWidth := 4 * region.Dx()
  102. for j := 0; j < region.Dy(); j++ {
  103. dstX := 4 * j * region.Dx()
  104. srcX := 4 * ((region.Min.Y+j)*i.width + region.Min.X)
  105. copy(pixels[dstX:dstX+lineWidth], i.pixels[srcX:srcX+lineWidth])
  106. }
  107. return true, nil
  108. }
  109. func (i *Image) DumpScreenshot(graphicsDriver graphicsdriver.Graphics, name string, blackbg bool) (string, error) {
  110. i.syncPixelsIfNeeded()
  111. return i.img.DumpScreenshot(graphicsDriver, name, blackbg)
  112. }
  113. // WritePixels replaces the pixels at the specified region.
  114. func (i *Image) WritePixels(pix []byte, region image.Rectangle) {
  115. if l := 4 * region.Dx() * region.Dy(); len(pix) != l {
  116. panic(fmt.Sprintf("buffered: len(pix) was %d but must be %d", len(pix), l))
  117. }
  118. // Writing one pixel is a special case.
  119. // Do not write pixels in GPU, as (image/draw).Image's functions might call WritePixels with pixels one by one.
  120. if region.Dx() == 1 && region.Dy() == 1 {
  121. // If i.pixels exists, update this instead of adding an entry to dotsBuffer.
  122. if i.pixels != nil {
  123. idx := 4 * (region.Min.Y*i.width + region.Min.X)
  124. i.pixels[idx] = pix[0]
  125. i.pixels[idx+1] = pix[1]
  126. i.pixels[idx+2] = pix[2]
  127. i.pixels[idx+3] = pix[3]
  128. i.pixelsUnsynced = true
  129. delete(i.dotsBuffer, region.Min)
  130. return
  131. }
  132. if i.dotsBuffer == nil {
  133. i.dotsBuffer = map[image.Point][4]byte{}
  134. }
  135. var clr [4]byte
  136. copy(clr[:], pix)
  137. i.dotsBuffer[region.Min] = clr
  138. if len(i.dotsBuffer) >= 10000 {
  139. i.syncPixelsIfNeeded()
  140. }
  141. return
  142. }
  143. // If i.pixels is not nil, this indicates ReadPixels is called and might be called again later.
  144. // Keep and update the pixels data in this case.
  145. if i.pixels != nil {
  146. lineWidth := 4 * region.Dx()
  147. for j := 0; j < region.Dy(); j++ {
  148. dstX := 4 * ((region.Min.Y+j)*i.width + region.Min.X)
  149. srcX := 4 * j * region.Dx()
  150. copy(i.pixels[dstX:dstX+lineWidth], pix[srcX:srcX+lineWidth])
  151. }
  152. // pixelsUnsynced can NOT be set false as the outside pixels of the region is not written by WritePixels here.
  153. // See the test TestUnsyncedPixels.
  154. }
  155. // Even if i.pixels is nil, do not create a pixel cache.
  156. // It is in theroy possible to copy the argument pixels, but this tends to consume a lot of memory.
  157. // Avoid this unless ReadPixels is called.
  158. // Remove entries in the dots buffer that are overwritten by this WritePixels call.
  159. for pos := range i.dotsBuffer {
  160. if !pos.In(region) {
  161. continue
  162. }
  163. delete(i.dotsBuffer, pos)
  164. }
  165. i.img.WritePixels(pix, region)
  166. }
  167. // DrawTriangles draws the src image with the given vertices.
  168. //
  169. // Copying vertices and indices is the caller's responsibility.
  170. func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, hint restorable.Hint) {
  171. for _, src := range srcs {
  172. if i == src {
  173. panic("buffered: Image.DrawTriangles: source images must be different from the receiver")
  174. }
  175. if src != nil {
  176. // src's pixels have to be synced between CPU and GPU,
  177. // but doesn't have to be cleared since src is not modified in this function.
  178. src.syncPixelsIfNeeded()
  179. }
  180. }
  181. i.syncPixelsIfNeeded()
  182. var imgs [graphics.ShaderSrcImageCount]*atlas.Image
  183. for i, img := range srcs {
  184. if img == nil {
  185. continue
  186. }
  187. imgs[i] = img.img
  188. }
  189. i.img.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule, hint)
  190. // After rendering, the pixel cache is no longer valid.
  191. i.pixels = nil
  192. }
  193. // syncPixelsIfNeeded syncs the pixels between CPU and GPU.
  194. // After syncPixelsIfNeeded, dotsBuffer is cleared, but pixels might remain.
  195. func (i *Image) syncPixelsIfNeeded() {
  196. if i.pixelsUnsynced {
  197. // If this image already has pixels, use WritePixels instead of DrawTriangles for efficiency.
  198. for pos, clr := range i.dotsBuffer {
  199. idx := 4 * (pos.Y*i.width + pos.X)
  200. i.pixels[idx] = clr[0]
  201. i.pixels[idx+1] = clr[1]
  202. i.pixels[idx+2] = clr[2]
  203. i.pixels[idx+3] = clr[3]
  204. delete(i.dotsBuffer, pos)
  205. }
  206. i.img.WritePixels(i.pixels, image.Rect(0, 0, i.width, i.height))
  207. i.pixelsUnsynced = false
  208. return
  209. }
  210. if len(i.dotsBuffer) == 0 {
  211. return
  212. }
  213. l := len(i.dotsBuffer)
  214. vs := make([]float32, l*4*graphics.VertexFloatCount)
  215. is := make([]uint32, l*6)
  216. sx, sy := float32(1), float32(1)
  217. var idx int
  218. for p, c := range i.dotsBuffer {
  219. dx := float32(p.X)
  220. dy := float32(p.Y)
  221. crf := float32(c[0]) / 0xff
  222. cgf := float32(c[1]) / 0xff
  223. cbf := float32(c[2]) / 0xff
  224. caf := float32(c[3]) / 0xff
  225. vidx := 4 * idx
  226. iidx := 6 * idx
  227. vs[graphics.VertexFloatCount*vidx] = dx
  228. vs[graphics.VertexFloatCount*vidx+1] = dy
  229. vs[graphics.VertexFloatCount*vidx+2] = sx
  230. vs[graphics.VertexFloatCount*vidx+3] = sy
  231. vs[graphics.VertexFloatCount*vidx+4] = crf
  232. vs[graphics.VertexFloatCount*vidx+5] = cgf
  233. vs[graphics.VertexFloatCount*vidx+6] = cbf
  234. vs[graphics.VertexFloatCount*vidx+7] = caf
  235. vs[graphics.VertexFloatCount*(vidx+1)] = dx + 1
  236. vs[graphics.VertexFloatCount*(vidx+1)+1] = dy
  237. vs[graphics.VertexFloatCount*(vidx+1)+2] = sx + 1
  238. vs[graphics.VertexFloatCount*(vidx+1)+3] = sy
  239. vs[graphics.VertexFloatCount*(vidx+1)+4] = crf
  240. vs[graphics.VertexFloatCount*(vidx+1)+5] = cgf
  241. vs[graphics.VertexFloatCount*(vidx+1)+6] = cbf
  242. vs[graphics.VertexFloatCount*(vidx+1)+7] = caf
  243. vs[graphics.VertexFloatCount*(vidx+2)] = dx
  244. vs[graphics.VertexFloatCount*(vidx+2)+1] = dy + 1
  245. vs[graphics.VertexFloatCount*(vidx+2)+2] = sx
  246. vs[graphics.VertexFloatCount*(vidx+2)+3] = sy + 1
  247. vs[graphics.VertexFloatCount*(vidx+2)+4] = crf
  248. vs[graphics.VertexFloatCount*(vidx+2)+5] = cgf
  249. vs[graphics.VertexFloatCount*(vidx+2)+6] = cbf
  250. vs[graphics.VertexFloatCount*(vidx+2)+7] = caf
  251. vs[graphics.VertexFloatCount*(vidx+3)] = dx + 1
  252. vs[graphics.VertexFloatCount*(vidx+3)+1] = dy + 1
  253. vs[graphics.VertexFloatCount*(vidx+3)+2] = sx + 1
  254. vs[graphics.VertexFloatCount*(vidx+3)+3] = sy + 1
  255. vs[graphics.VertexFloatCount*(vidx+3)+4] = crf
  256. vs[graphics.VertexFloatCount*(vidx+3)+5] = cgf
  257. vs[graphics.VertexFloatCount*(vidx+3)+6] = cbf
  258. vs[graphics.VertexFloatCount*(vidx+3)+7] = caf
  259. is[iidx] = uint32(vidx)
  260. is[iidx+1] = uint32(vidx + 1)
  261. is[iidx+2] = uint32(vidx + 2)
  262. is[iidx+3] = uint32(vidx + 1)
  263. is[iidx+4] = uint32(vidx + 2)
  264. is[iidx+5] = uint32(vidx + 3)
  265. idx++
  266. }
  267. srcs := [graphics.ShaderSrcImageCount]*atlas.Image{whiteImage.img}
  268. dr := image.Rect(0, 0, i.width, i.height)
  269. sr := image.Rect(0, 0, whiteImage.width, whiteImage.height)
  270. blend := graphicsdriver.BlendCopy
  271. i.img.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone)
  272. clear(i.dotsBuffer)
  273. }