From 2437ad8248fc01e1c0d193fab9be8376d47e9397 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 27 Oct 2024 00:21:15 +0900 Subject: [PATCH] ebiten: improve bulitinShader by reducing locks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit old.txt: 04c9a802a7ba86baed6f0dbce603d1adbf790d31 new.txt: this commit ``` % benchstat old.txt new.txt goos: darwin goarch: arm64 pkg: github.com/hajimehoshi/ebiten/v2 cpu: Apple M3 Pro │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ BuiltinShader-12 4.226n ± 2% 1.352n ± 2% -68.00% (p=0.000 n=10) ``` --- shader.go | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/shader.go b/shader.go index 93f4fa673..9b2d323c2 100644 --- a/shader.go +++ b/shader.go @@ -17,6 +17,7 @@ package ebiten import ( "fmt" "sync" + "sync/atomic" "github.com/hajimehoshi/ebiten/v2/internal/builtinshader" "github.com/hajimehoshi/ebiten/v2/internal/graphics" @@ -86,20 +87,29 @@ func (s *Shader) appendUniforms(dst []uint32, uniforms map[string]any) []uint32 } var ( - builtinShaders [builtinshader.FilterCount][builtinshader.AddressCount][2]*Shader - builtinShadersM sync.Mutex + builtinShadersForRead atomic.Pointer[[builtinshader.FilterCount][builtinshader.AddressCount][2]*Shader] + builtinShadersM sync.Mutex ) func builtinShader(filter builtinshader.Filter, address builtinshader.Address, useColorM bool) *Shader { - builtinShadersM.Lock() - defer builtinShadersM.Unlock() - var c int if useColorM { c = 1 } - if s := builtinShaders[filter][address][c]; s != nil { - return s + if read := builtinShadersForRead.Load(); read != nil { + if s := (*read)[filter][address][c]; s != nil { + return s + } + } + + builtinShadersM.Lock() + defer builtinShadersM.Unlock() + + // Double check in case another goroutine already created a shader. + if read := builtinShadersForRead.Load(); read != nil { + if s := (*read)[filter][address][c]; s != nil { + return s + } } var shader *Shader @@ -135,6 +145,11 @@ func builtinShader(filter builtinshader.Filter, address builtinshader.Address, u shader = s } - builtinShaders[filter][address][c] = shader + var shaders [builtinshader.FilterCount][builtinshader.AddressCount][2]*Shader + if ptr := builtinShadersForRead.Load(); ptr != nil { + shaders = *ptr + } + shaders[filter][address][c] = shader + builtinShadersForRead.Store(&shaders) return shader }