@@ -111,6 +111,12 @@ static void propsPutInt(CFMutableDictionaryRef props, const CFStringRef key, int
111111
112112// -- IOSurfacePool helpers --
113113
114+ #ifdef RLAWT_POOL_DEBUG
115+ #define POOL_STAT (pool, field ) ((pool)->stats.field++)
116+ #else
117+ #define POOL_STAT (pool, field ) ((void )0 )
118+ #endif
119+
114120static void poolInit (IOSurfacePool *pool) {
115121 memset (pool, 0 , sizeof (*pool));
116122 GLuint textures[RLAWT_MAX_POOL], framebuffers[RLAWT_MAX_POOL];
@@ -120,6 +126,9 @@ static void poolInit(IOSurfacePool *pool) {
120126 pool->entries [i].tex = textures[i];
121127 pool->entries [i].fbo = framebuffers[i];
122128 }
129+ #ifdef RLAWT_POOL_DEBUG
130+ pool->lastLogTime = CFAbsoluteTimeGetCurrent ();
131+ #endif
123132}
124133
125134static void poolDestroy (IOSurfacePool *pool) {
@@ -203,23 +212,56 @@ static int poolNextBack(IOSurfacePool *pool) {
203212 for (int i = 0 ; i < pool->count ; i++) {
204213 if (i == pool->front ) continue ;
205214 if (pool->entries [i].surface && !IOSurfaceIsInUse (pool->entries [i].surface )) {
215+ POOL_STAT (pool, reuses);
206216 return i;
207217 }
208218 }
209219
210220 // Grow pool if nothing was available
211221 if (pool->count < RLAWT_MAX_POOL) {
212- return pool->count ++;
222+ int idx = pool->count ++;
223+ POOL_STAT (pool, grows);
224+ #ifdef RLAWT_POOL_DEBUG
225+ if (pool->count > pool->stats .highWater ) {
226+ pool->stats .highWater = pool->count ;
227+ }
228+ #endif
229+ return idx;
213230 }
214231
215232 // Pool full, all in use -- evict first non-front entry.
216233 // count >= 2 is guaranteed here (pool grows on first swap), so this always finds one.
217234 for (int i = 0 ; i < pool->count ; i++) {
218- if (i != pool->front ) return i;
235+ if (i != pool->front ) {
236+ POOL_STAT (pool, stalls);
237+ return i;
238+ }
219239 }
220240 return 0 ; // unreachable
221241}
222242
243+ #ifdef RLAWT_POOL_DEBUG
244+ static void poolLogStats (IOSurfacePool *pool) {
245+ CFAbsoluteTime now = CFAbsoluteTimeGetCurrent ();
246+ if (now - pool->lastLogTime < 60.0 ) return ;
247+
248+ NSLog (@" IOSurfacePool: %d swaps, %d allocs, pool %d /%d (hw %d ), %d reuse, %d grow, %d stall, %d fail" ,
249+ pool->stats .swaps ,
250+ pool->stats .allocs ,
251+ pool->count ,
252+ RLAWT_MAX_POOL,
253+ pool->stats .highWater ,
254+ pool->stats .reuses ,
255+ pool->stats .grows ,
256+ pool->stats .stalls ,
257+ pool->stats .failures );
258+
259+ memset (&pool->stats , 0 , sizeof (pool->stats ));
260+ pool->stats .highWater = pool->count ;
261+ pool->lastLogTime = now;
262+ }
263+ #endif
264+
223265JNIEXPORT void JNICALL Java_net_runelite_rlawt_AWTContext_createGLContext (JNIEnv *env, jobject self) {
224266 AWTContext *ctx = rlawtGetContext (env, self);
225267 if (!ctx || !rlawtContextState (env, ctx, false )) {
@@ -361,6 +403,8 @@ JNIEXPORT void JNICALL Java_net_runelite_rlawt_AWTContext_swapBuffers(JNIEnv *en
361403 withObject: (id )(pool->entries[pool->front].surface)
362404 waitUntilDone: true ];
363405
406+ POOL_STAT (pool, swaps);
407+
364408 // Find a free surface for the next frame
365409 pool->back = poolNextBack (pool);
366410 IOSurfaceEntry *back = &pool->entries [pool->back];
@@ -369,9 +413,15 @@ JNIEXPORT void JNICALL Java_net_runelite_rlawt_AWTContext_swapBuffers(JNIEnv *en
369413 if (!poolEntryMatchesSize (back, ctx->layer )
370414 || IOSurfaceIsInUse (back->surface )) {
371415 if (!poolCreateSurface (env, back, ctx->layer , ctx->context )) {
416+ POOL_STAT (pool, failures);
372417 return ;
373418 }
419+ POOL_STAT (pool, allocs);
374420 }
421+
422+ #ifdef RLAWT_POOL_DEBUG
423+ poolLogStats (pool);
424+ #endif
375425}
376426
377427JNIEXPORT jint JNICALL Java_net_runelite_rlawt_AWTContext_getFramebuffer (JNIEnv *env, jobject self, jboolean front) {
0 commit comments