1 #import "MTLTexturePool.h"
   2 #import "Trace.h"
   3 
   4 @implementation MTLTexturePoolItem
   5 
   6 @synthesize texture;
   7 @synthesize isBusy;
   8 
   9 - (id) initWithTexture:(id<MTLTexture>)tex {
  10     self = [super init];
  11     if (self == nil) return self;
  12     self.texture = tex;
  13     isBusy = NO;
  14     return self;
  15 }
  16 @end
  17 
  18 @implementation MTLTexturePool
  19 
  20 @synthesize device;
  21 @synthesize pool;
  22 
  23 - (id) initWithDevice:(id<MTLDevice>)dev {
  24     self = [super init];
  25     if (self == nil) return self;
  26 
  27     self.device = dev;
  28     self.pool = [NSMutableArray arrayWithCapacity:10];
  29     return self;
  30 }
  31 
  32 // NOTE: called from RQ-thread (on blit operations)
  33 - (id<MTLTexture>) getTexture:(int)width height:(int)height format:(MTLPixelFormat)format {
  34     @synchronized (self) {
  35         // 1. find free item
  36         // TODO: optimize search, use Map<(w,h,pf), TexPoolItem>
  37         const int count = [self.pool count];
  38         for (int c = 0; c < count; ++c) {
  39             MTLTexturePoolItem *tpi = [self.pool objectAtIndex:c];
  40             if (tpi == nil)
  41                 continue;
  42             // TODO: use checks tpi.texture.width <= width && tpi.texture.height <= height
  43             if (tpi.texture.width == width && tpi.texture.height == height && tpi.texture.pixelFormat == format &&
  44                 !tpi.isBusy) {
  45                 tpi.isBusy = YES;
  46                 return tpi.texture;
  47             }
  48         }
  49 
  50         // 2. create
  51         MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format width:width height:height mipmapped:NO];
  52         id <MTLTexture> tex = [self.device newTextureWithDescriptor:textureDescriptor];
  53         MTLTexturePoolItem *tpi = [[MTLTexturePoolItem alloc] initWithTexture:tex];
  54         [self.pool addObject:tpi];
  55         J2dTraceLn4(J2D_TRACE_VERBOSE, "MTLTexturePool: created pool item: tex=%p, w=%d h=%d, pf=%d", tex, width, height, format);
  56         return tpi.texture;
  57     }
  58 };
  59 
  60 // NOTE: called from completion-handler (pooled thread)
  61 - (void) markTextureFree:(id<MTLTexture>)texture {
  62     // TODO: optimize search, use Map<(w,h,pf), TexPoolItem>
  63     @synchronized (self) {
  64         const int count = [self.pool count];
  65         for (int c = 0; c < count; ++c) {
  66             MTLTexturePoolItem * tpi = [self.pool objectAtIndex:c];
  67             if (tpi == nil)
  68                 continue;
  69             if (tpi.texture == texture) {
  70                 tpi.isBusy = NO;
  71                 return;
  72             }
  73         }
  74         J2dTraceLn1(J2D_TRACE_ERROR, "MTLTexturePool: can't find item with texture %p", texture);
  75     }
  76 }
  77 
  78 // NOTE: called from completion-handler (pooled thread)
  79 - (void) markAllTexturesFree {
  80     @synchronized (self) {
  81         const int count = [self.pool count];
  82         for (int c = 0; c < count; ++c) {
  83             MTLTexturePoolItem *tpi = [self.pool objectAtIndex:c];
  84             if (tpi == nil)
  85                 continue;
  86             tpi.isBusy = NO;
  87         }
  88     }
  89 }
  90 
  91 
  92 @end