shader.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // Copyright 2020 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 ebiten
  15. import (
  16. "fmt"
  17. "sync"
  18. "github.com/hajimehoshi/ebiten/v2/internal/builtinshader"
  19. "github.com/hajimehoshi/ebiten/v2/internal/graphics"
  20. "github.com/hajimehoshi/ebiten/v2/internal/shaderir"
  21. "github.com/hajimehoshi/ebiten/v2/internal/ui"
  22. )
  23. // Shader represents a compiled shader program.
  24. //
  25. // For the details about the shader, see https://ebitengine.org/en/documents/shader.html.
  26. type Shader struct {
  27. shader *ui.Shader
  28. unit shaderir.Unit
  29. }
  30. // NewShader compiles a shader program in the shading language Kage, and returns the result.
  31. //
  32. // If the compilation fails, NewShader returns an error.
  33. //
  34. // For the details about the shader, see https://ebitengine.org/en/documents/shader.html.
  35. func NewShader(src []byte) (*Shader, error) {
  36. return newShader(src, "")
  37. }
  38. func newShader(src []byte, name string) (*Shader, error) {
  39. ir, err := graphics.CompileShader(src)
  40. if err != nil {
  41. return nil, err
  42. }
  43. return &Shader{
  44. shader: ui.NewShader(ir, name),
  45. unit: ir.Unit,
  46. }, nil
  47. }
  48. // Dispose disposes the shader program.
  49. // After disposing, the shader is no longer available.
  50. //
  51. // Deprecated: as of v2.7. Use Deallocate instead.
  52. func (s *Shader) Dispose() {
  53. s.shader.Deallocate()
  54. s.shader = nil
  55. }
  56. func (s *Shader) isDisposed() bool {
  57. return s.shader == nil
  58. }
  59. // Deallocate deallocates the internal state of the shader.
  60. // Even after Deallocate is called, the shader is still available.
  61. // In this case, the shader's internal state is allocated again.
  62. //
  63. // Usually, you don't have to call Deallocate since the internal state is automatically released by GC.
  64. // However, if you are sure that the shader is no longer used but not sure how this shader object is referred,
  65. // you can call Deallocate to make sure that the internal state is deallocated.
  66. //
  67. // If the shader is disposed, Deallocate does nothing.
  68. func (s *Shader) Deallocate() {
  69. if s.shader == nil {
  70. return
  71. }
  72. s.shader.Deallocate()
  73. }
  74. func (s *Shader) appendUniforms(dst []uint32, uniforms map[string]any) []uint32 {
  75. return s.shader.AppendUniforms(dst, uniforms)
  76. }
  77. var (
  78. builtinShaders [builtinshader.FilterCount][builtinshader.AddressCount][2]*Shader
  79. builtinShadersM sync.Mutex
  80. )
  81. func builtinShader(filter builtinshader.Filter, address builtinshader.Address, useColorM bool) *Shader {
  82. builtinShadersM.Lock()
  83. defer builtinShadersM.Unlock()
  84. var c int
  85. if useColorM {
  86. c = 1
  87. }
  88. if s := builtinShaders[filter][address][c]; s != nil {
  89. return s
  90. }
  91. var shader *Shader
  92. if address == builtinshader.AddressUnsafe && !useColorM {
  93. switch filter {
  94. case builtinshader.FilterNearest:
  95. shader = &Shader{shader: ui.NearestFilterShader}
  96. case builtinshader.FilterLinear:
  97. shader = &Shader{shader: ui.LinearFilterShader}
  98. }
  99. } else {
  100. src := builtinshader.ShaderSource(filter, address, useColorM)
  101. var name string
  102. switch filter {
  103. case builtinshader.FilterNearest:
  104. name = "nearest"
  105. case builtinshader.FilterLinear:
  106. name = "linear"
  107. }
  108. switch address {
  109. case builtinshader.AddressClampToZero:
  110. name += "-clamptozero"
  111. case builtinshader.AddressRepeat:
  112. name += "-repeat"
  113. }
  114. if useColorM {
  115. name += "-colorm"
  116. }
  117. s, err := newShader(src, name)
  118. if err != nil {
  119. panic(fmt.Sprintf("ebiten: NewShader for a built-in shader failed: %v", err))
  120. }
  121. shader = s
  122. }
  123. builtinShaders[filter][address][c] = shader
  124. return shader
  125. }