Próbuję umieścić symulacji marszczyć na szczycie już bugs aplikacji. W tej chwili procesor działa na około 11 ms na najniższych procesorach. Cały dotychczasowy kod działa na głównym wątku.Optymalizacja kodu bez usuwania blokady wątku
Mam nadzieję, że możliwe jest umieszczenie symulacji marszruty w całości na innym wątku.
Symulacja jest oparta na jabłku GLCameraRipple project. Zasadniczo tworzy prostokąt tesselated i oblicza współrzędne tekstury. Tak więc w idealnym świecie tekstura jest współrzędna, a pulsujące symulacje tablic są na innym wątku.
Funkcja aktualizacji, nad którą pracuję teraz, wygląda następująco. Działa ona w sposób GCD, jednak nie zyskuje na szybkości z powodu synchronizacji. Jednak bez synchronizacji aplikacja zawiesiłaby się, ponieważ szybkie tablice nie są bezpieczne dla wątków.
var rippleTexCoords:[GLfloat] = []
var rippleSource:[GLfloat] = []
var rippleDest:[GLfloat] = []
func runSimulation()
{
if (firstUpdate)
{firstUpdate = false; Whirl.crashLog("First update")}
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
let block1: (y: size_t) -> Void = {
(y: size_t) -> Void in
objc_sync_enter(self)
defer { objc_sync_exit(self) } // */ This will actually run at the end
let pw = self.poolWidthi
for x in 1..<(pw - 1)
{
let ai:Int = (y ) * (pw + 2) + x + 1
let bi:Int = (y + 2) * (pw + 2) + x + 1
let ci:Int = (y + 1) * (pw + 2) + x
let di:Int = (y + 1) * (pw + 2) + x + 2
let me:Int = (y + 1) * (pw + 2) + x + 1
let a = self.rippleSource[ai]
let b = self.rippleSource[bi]
let c = self.rippleSource[ci]
let d = self.rippleSource[di]
var result = self.rippleDest[me]
result = (a + b + c + d)/2.0 - result
result -= result/32.0
self.rippleDest[me] = result
}
//Defer goes here
}
dispatch_apply(Int(poolHeighti), queue, block1);
/*for y in 0..<poolHeighti {
block1(y: y)
}*/
let hm1 = GLfloat(poolHeight - 1)
let wm1 = GLfloat(poolWidth - 1)
let block2: (y: size_t) -> Void = {
(y: size_t) -> Void in
objc_sync_enter(self)
defer { objc_sync_exit(self) } // */
let yy = GLfloat(y)
let pw = self.poolWidthi
for x in 1..<(pw - 1) {
let xx = GLfloat(x)
let ai:Int = (y ) * (pw + 2) + x + 1
let bi:Int = (y + 2) * (pw + 2) + x + 1
let ci:Int = (y + 1) * (pw + 2) + x
let di:Int = (y + 1) * (pw + 2) + x + 2
let a = self.rippleDest[ai]
let b = self.rippleDest[bi]
let c = self.rippleDest[ci]
let d = self.rippleDest[di]
var s_offset = ((b - a)/2048)
var t_offset = ((c - d)/2048)
s_offset = (s_offset < -0.5) ? -0.5 : s_offset;
t_offset = (t_offset < -0.5) ? -0.5 : t_offset;
s_offset = (s_offset > 0.5) ? 0.5 : s_offset;
t_offset = (t_offset > 0.5) ? 0.5 : t_offset;
let s_tc = yy/hm1
let t_tc = xx/wm1
let me = (y * pw + x) * 2
self.rippleTexCoords[me + 0] = s_tc + s_offset
self.rippleTexCoords[me + 1] = t_tc + t_offset
}
}
dispatch_apply(poolHeighti, queue, block2)
/* for y in 0..<poolHeighti {
block2(y: y)
} *///
let pTmp = rippleDest
rippleDest = rippleSource
rippleSource = pTmp
}
Czy istnieje sposób na wymuszenie ciągłego uruchamiania tego kodu na innym wątku? Albo jakoś go przyspieszyć?
dont konw czy to możliwe, ale jeśli jest to musiałbym te tablice na temat wątku:
główne:
- rippleVertices
- rippleIndices
wtórne: (Nie są one odczytywane ani zapisywane w głównym wątku)
- rippleSource
- rippleDest
na obu wątków:
- rippleTexCoords (czytaj na głównym wątku, napisane na wątku wtórny)
Jeśli te warunki są przestrzegane wtedy runSimulation metoda może być uruchomiona na drugim wątku bez problemu.
To jest naprawdę genialny pomysł! Nie wiem dokładnie, jak to osiągnąć, ale będę się z tym bawić. Dziękuję Ci! –
Być może możesz użyć semafora, aby rozpocząć obliczanie tętnienia, a następnie ustawić flagę, gdy to zrobisz. Następnie sprawdź/poczekaj na flagę przed renderowaniem z głównego wątku. Tego rodzaju rozwiązanie wyeliminowałoby konieczność użycia kopii roboczej w ogóle. –