0

I tried to create a MTLTexture(size is 1920x1080) and it costs lots of time when calling [replaceRegion:mipmapLevel:withBytes:bytesPerRow], more about 15ms on my iPhoneX. Is there any way to improve the performance?

Here's my test code, I found out that, if i make texture in [viewDidAppear] it only costs about 4ms. What's the difference?

#import "ViewController.h"
#import <Metal/Metal.h>
#define I_WIDTH 1920
#define I_HEIHG 1080

@interface ViewController ()
@property(strong, nonatomic) id<MTLDevice> device;
@property(strong, nonatomic) NSTimer* timer;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.device = MTLCreateSystemDefaultDevice();
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    //Method 1. This would run really slow, aboult 15ms per loop
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(mkTexture) userInfo:nil repeats:true];
    //Method 2. This would run really fast, aboult 3ms per loop
//    for (int i = 0; i < 3000; i++) {
//        [self mkTexture];
//    }
}

- (void)mkTexture {
    double start = CFAbsoluteTimeGetCurrent();
    MTLTextureDescriptor* desc = [[MTLTextureDescriptor alloc] init];
    desc.width = I_WIDTH;
    desc.height = I_HEIHG;
    desc.pixelFormat = MTLPixelFormatBGRA8Unorm;
    desc.usage = MTLTextureUsageShaderRead;
    id<MTLTexture> texture = [self.device newTextureWithDescriptor:desc];
    char* bytes = (char *)malloc(I_WIDTH * I_HEIHG * 4);
    [texture replaceRegion:MTLRegionMake3D(0, 0, 0, I_WIDTH, I_HEIHG, 1) mipmapLevel:0 withBytes:bytes bytesPerRow:I_WIDTH * 4];
    double end = CFAbsoluteTimeGetCurrent();
    NSLog(@"%.2fms", (end - start) * 1000);
    free(bytes);
}

@end

With [Method 1], the function mkTexture would cost about 15ms, with [Method 2], the function mkTexture only costs 4ms. It's really strange.

SXC
  • 1
  • 1
  • 1
    With method 1, is your app spawning any work on background threads after it returns from `viewDidAppear:`? What happens if you use sort of hybrid between methods 1 and 2: a non-repeating timer to invoke a method with a `for` loop around calls to `mkTexture`? In any case, my best suggestion is to use the Time Profile template of Instruments, with Record Waiting Threads set in its Record Options, to profile your program to see what's slow. – Ken Thomases Jan 20 '19 at 05:46
  • Wouldn't creating 3,000 textures that are 1920 x 1080 fail after a while? That's like 28 GB of memory. All iOS devices have [far less RAM than that](https://stackoverflow.com/questions/371107/how-much-ram-is-there-in-an-an-ios-iphone-ipad-ipod-touch-device). – user1118321 Jan 22 '19 at 04:25
  • @user1118321 ARC should be releasing them, since there's no strong reference remaining after the `mkTexture` method returns. – Ken Thomases Jan 22 '19 at 18:34
  • So, first off just don't create 3000 huge textures. That is only going to measure how fast you can crash your iOS device. Create a texture but do not call replaceRegion since all your are doing is a memcpy() of zeros into the texture. The texture already contains zeros when you allocated it. If you want to write into a texture then render into it as opposed to calling replaceRegion. Also, calling malloc() in this type of path is going to be very slow, just don't do that. – MoDJ Jan 30 '19 at 18:51

0 Answers0