Профайлинг и управление памятью в Unity iOS

Научился сам? Помоги начинающему.

Профайлинг и управление памятью в Unity iOS

Сообщение Wozik 20 мар 2012, 19:44

Записал пару скринкастов для русскоязычных пользователей.

1. Как профайлить Unity игры на iOS (Unity iOS profiling)



2. Как профайлить память в iOS играх (iOS memory profiling)



3. Как менеджить дополнительные ассеты (asset management)



Записывал в пятницу вечером, без репетиций и чернового текста. Пытался ответить на самые частые пользователей Unity iOS.

Мэйкс сэнс?
На какие еще вопросы ответить надо?
Работаю в Unity Technologies
Веду блог про Юнити (иногда на русском)
Аватара пользователя
Wozik
Unity Technologies
 
Сообщения: 299
Зарегистрирован: 31 авг 2009, 17:54
Откуда: http://drinkandcode.com
  • Сайт

Re: Профайлинг и управление памятью в Unity iOS

Сообщение Neodrop 20 мар 2012, 23:23

(3A4OT)

Огромное спасибо и низкий поклон от лица сообщества.
Часто спрашивают про :

[V] Лайтмапинг
[V] Лайтпробы
[V] Навмеши
[V] Можно добавить про ЛОД (сырая система пока ещё (имхо). Дописал бы, но руки пока не доходят.)
[V] Работа с префабами и их новые фишки (кажется очень много глюков в 3.5)
Добавить neodrop в Skype
Изображение
"Спасибо!" нашему порталу, вы сможете сказать ЗДЕСЬ.
Если проблема не решается честно, нужно её обмануть! || Per stupiditas at Astra!
Страх порождает слабость. Бесстрашных поражают пули.
Протратившись на блядях байтах, на битах не экономят.
Аватара пользователя
Neodrop
Админ
 
Сообщения: 8480
Зарегистрирован: 08 окт 2008, 15:42
Откуда: Питер
Skype: neodrop
  • Сайт

Re: Профайлинг и управление памятью в Unity iOS

Сообщение Syberex 21 мар 2012, 00:21

Спасибо, спасибо, спасибо ^:)^
Аватара пользователя
Syberex
Адепт
 
Сообщения: 2292
Зарегистрирован: 14 янв 2011, 20:35
Откуда: Кострома
  • Сайт

Re: Профайлинг и управление памятью в Unity iOS

Сообщение Wozik 21 мар 2012, 13:38

Neodrop писал(а):(3A4OT)

Огромное спасибо и низкий поклон от лица сообщества.
Часто спрашивают про :

[V] Лайтмапинг
[V] Лайтпробы
[V] Навмеши
[V] Можно добавить про ЛОД (сырая система пока ещё (имхо). Дописал бы, но руки пока не доходят.)
[V] Работа с префабами и их новые фишки (кажется очень много глюков в 3.5)


На все эти вопросы легко найти ответы в мануале или видео-туториалы вот есть: http://video.unity3d.com/channel/1649856/tutorials
Или вражеский язык мешает? =)

Я бы скорее хотел ответить на вопросы, которые требуют определенного опыта и ноу-хау, а не переводить один кусок мануала. Впрочем, и это возможно, в принципе. Посмотрим на фидбэк :)
Работаю в Unity Technologies
Веду блог про Юнити (иногда на русском)
Аватара пользователя
Wozik
Unity Technologies
 
Сообщения: 299
Зарегистрирован: 31 авг 2009, 17:54
Откуда: http://drinkandcode.com
  • Сайт

Re: Профайлинг и управление памятью в Unity iOS

Сообщение artk 21 мар 2012, 21:55

Перезалейте видео
Аватара пользователя
artk
Старожил
 
Сообщения: 749
Зарегистрирован: 22 май 2011, 12:22

Re: Профайлинг и управление памятью в Unity iOS

Сообщение Neodrop 21 мар 2012, 23:51

Олег, я просто перечислил наиболее частые вопросы.
Лично для меня важен такие вопросы :

[V] Почему iOS сборка всегда толще Android и как это уменьшить ?
[V] На Android есть дефолтный прелоадер, а на iOS нету, хотя галки в PlayerSettings существуют и там и там.
[V] Разница в графической производительности между iPad -> iPad2 -> iPad New (3) крайне незначительна. Это проблема Unity, кривых рук или наглого маркетинга Apple ?
Добавить neodrop в Skype
Изображение
"Спасибо!" нашему порталу, вы сможете сказать ЗДЕСЬ.
Если проблема не решается честно, нужно её обмануть! || Per stupiditas at Astra!
Страх порождает слабость. Бесстрашных поражают пули.
Протратившись на блядях байтах, на битах не экономят.
Аватара пользователя
Neodrop
Админ
 
Сообщения: 8480
Зарегистрирован: 08 окт 2008, 15:42
Откуда: Питер
Skype: neodrop
  • Сайт

Re: Профайлинг и управление памятью в Unity iOS

Сообщение Wozik 22 мар 2012, 15:57

Почему iOS сборка всегда толще Android и как это уменьшить ?
Может потому что включаешь бинарники и для ифона и для ипада? Байнари сайз должен быть примерно равен.
Построй пустую сцену для ифона и для ондроеда и сравнии бинарники.

На Android есть дефолтный прелоадер, а на iOS нету, хотя галки в PlayerSettings существуют и там и там.
Крутящаяся херня, т.е. лоадинг индикатор при загрузке сцены? Должен работать и там и там.

Разница в графической производительности между iPad -> iPad2 -> iPad New (3) крайне незначительна. Это проблема Unity, кривых рук или наглого маркетинга Apple ?
kFPS в appcontroller.mm настроен на 30 по умолчанию. Т.е. больше фпсов юнити просто не рендерит. Поставь хоть 120 там и получи пустую батарейку через два часа :)
Второй вариант - твой эпп cpu bound, т.е. более мощная видеокарта тебе не помогает (или разрешение экрана убивает все приросты производительности), а проц более-менее одинаков во всех трёх.

еще? :)
Работаю в Unity Technologies
Веду блог про Юнити (иногда на русском)
Аватара пользователя
Wozik
Unity Technologies
 
Сообщения: 299
Зарегистрирован: 31 авг 2009, 17:54
Откуда: http://drinkandcode.com
  • Сайт

Re: Профайлинг и управление памятью в Unity iOS

Сообщение Syberex 22 мар 2012, 21:00

В одном из видео упоминается ролик про оптимизацию Shadowgun-а, было бы круто увидеть с переводом, или просто осветите основные моменты от туда :)
Аватара пользователя
Syberex
Адепт
 
Сообщения: 2292
Зарегистрирован: 14 янв 2011, 20:35
Откуда: Кострома
  • Сайт

Re: Профайлинг и управление памятью в Unity iOS

Сообщение Neodrop 23 мар 2012, 13:05

Wozik писал(а): Почему iOS сборка всегда толще Android и как это уменьшить ?
Может потому что включаешь бинарники и для ифона и для ипада? Байнари сайз должен быть примерно равен.
Построй пустую сцену для ифона и для ондроеда и сравнии бинарники.


Конечно же я собираю только под iPad или iPhone. Но размер сборки всегда выше, чем для Андроида.

Wozik писал(а): На Android есть дефолтный прелоадер, а на iOS нету, хотя галки в PlayerSettings существуют и там и там.
Крутящаяся херня, т.е. лоадинг индикатор при загрузке сцены? Должен работать и там и там.


Херня крутится на андроиде и при загрузке уровней, на iOS нет. Меня это совсем не беспокоит, просто сообщаю наблюдение ;)

Wozik писал(а):Разница в графической производительности между iPad -> iPad2 -> iPad New (3) крайне незначительна. Это проблема Unity, кривых рук или наглого маркетинга Apple ?
kFPS в appcontroller.mm настроен на 30 по умолчанию. Т.е. больше фпсов юнити просто не рендерит. Поставь хоть 120 там и получи пустую батарейку через два часа :)
Второй вариант - твой эпп cpu bound, т.е. более мощная видеокарта тебе не помогает (или разрешение экрана убивает все приросты производительности), а проц более-менее одинаков во всех трёх.


Фиксированный FPS тут ни при чём, конечно. В принципе, ты ответил на вопрос, спасибо - я про то, что CPU одинаков и разрешение отъедает возможный прирост производительности. Спасибо.
Добавить neodrop в Skype
Изображение
"Спасибо!" нашему порталу, вы сможете сказать ЗДЕСЬ.
Если проблема не решается честно, нужно её обмануть! || Per stupiditas at Astra!
Страх порождает слабость. Бесстрашных поражают пули.
Протратившись на блядях байтах, на битах не экономят.
Аватара пользователя
Neodrop
Админ
 
Сообщения: 8480
Зарегистрирован: 08 окт 2008, 15:42
Откуда: Питер
Skype: neodrop
  • Сайт

Re: Профайлинг и управление памятью в Unity iOS

Сообщение xcube 16 июл 2012, 21:10

kFPS в appcontroller.mm настроен на 30 по умолчанию. Т.е. больше фпсов юнити просто не рендерит. Поставь хоть 120 там и получи пустую батарейку через два часа :)


Можно поподробнее как это сделать ? что именно нужно изменить в файле AppController.mm ?
Изображение
Аватара пользователя
xcube
UNITрон
 
Сообщения: 304
Зарегистрирован: 23 сен 2011, 12:20
Откуда: Spb

Re: Профайлинг и управление памятью в Unity iOS

Сообщение gnoblin 16 июл 2012, 21:36

значение 30 в строчке с kFPS поменять на 60 )
skypeid: madkust
Мои крайние проекты:
Убойный Хоккей
Cube Day Z (альфа)
Аватара пользователя
gnoblin
Адепт
 
Сообщения: 4633
Зарегистрирован: 08 окт 2008, 17:23
Откуда: Минск, Беларусь
Skype: madkust
  • Сайт

Re: Профайлинг и управление памятью в Unity iOS

Сообщение xcube 16 июл 2012, 21:39

gnoblin писал(а):значение 30 в строчке с kFPS поменять на 60 )

Нет такой строчки, может в новых версиях что-то изменили а в хелпе инфу не обновили (

вот файл AppController.mm
Синтаксис:
Используется csharp
#import "AppController.h"

#import <CoreGraphics/CoreGraphics.h>
#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIKit.h>
#import <Availability.h>

#import <OpenGLES/EAGL.h>
#import <OpenGLES/EAGLDrawable.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
#import <OpenGLES/ES2/glext.h>

#include <mach/mach_time.h>

// USE_DISPLAY_LINK_IF_AVAILABLE
//
// Use of the CADisplayLink class is the preferred method for controlling your
// rendering loop. CADisplayLink will link to the main display and fire every
// vsync when added to a given run-loop. Other main loop types (NSTimer, Thread,
// EventPump) are used only as fallback when running on a pre 3.1 device where
// CADisplayLink is not available.
//
// NOTE: some developers reported problems with input lag while using
// CADisplayLink, so try to disable it if this is the case for you.
//
// Note that OS version and CADisplayLink support will be determined at the
// run-time automatically and you CAN compile your application using ANY SDK.
// Your application will work succesfully on pre 3.1 device too.
//


// Fallback types (for pre 3.1 devices):

// NSTIMER_BASED_LOOP
//
// It is a common approach to use NSTimer for scheduling rendering on a pre 3.1
// device NSTimer approach is perfect for non-performance critical applications
// which favours battery life and scrupulous correct events processing over the
// rendering performance.
//
// Constants supported by this method: kThrottleFPS


// THREAD_BASED_LOOP
//
// However number of games might prefer frame-rate over battery life,
// therefore Unity provide alternate methods which allows you to run in a
// tighter rendering loop.

// Thread based loop allows to get best of two worlds - fast rendering and
// guaranteed event processing.
//


// EVENT_PUMP_BASED_LOOP
//
// Following method allows you to specify explicit time limit for OS to process
// events. Though it might lend you best rendering performance some input events
// maybe missing, therefore you must carefully tweak
// kMillisecondsPerFrameToProcessEvents to achieve desired responsivness.
//
// Constants supported by this method: kMillisecondsPerFrameToProcessEvents


// Constants:
//
// kThrottleFPS - usually you need to boost NSTimer approach a bit to get any
// decent performance. Set to 2 by default. Meaningful only if
// NSTIMER_BASED_LOOP method is used.

// kMillisecondsPerFrameToProcessEvents - allows you to specify how much time
// you allow to process events if OS event pump method is used. Set to 3ms by
// default. Settings kMillisecondsPerFrameToProcessEvents to 0 will make main
// loop to wait for OS to pump all events.
// Meaningful only if EVENT_PUMP_BASED_LOOP method is used.

#define USE_OPENGLES20_IF_AVAILABLE 1
#define USE_DISPLAY_LINK_IF_AVAILABLE 1
// MSAA_DEFAULT_SAMPLE_COUNT was moved to iPhone_GlesSupport.h

//#define FALLBACK_LOOP_TYPE NSTIMER_BASED_LOOP
#define FALLBACK_LOOP_TYPE THREAD_BASED_LOOP
//#define FALLBACK_LOOP_TYPE EVENT_PUMP_BASED_LOOP


#include "iPhone_Common.h"
#include "iPhone_GlesSupport.h"

// ENABLE_INTERNAL_PROFILER and related defines were moved to iPhone_Profiler.h
#include "iPhone_Profiler.h"


// --- CONSTANTS ---------------------------------------------------------------
//

#if FALLBACK_LOOP_TYPE == NSTIMER_BASED_LOOP
#define kThrottleFPS                                                    2.0
#endif

#if FALLBACK_LOOP_TYPE == EVENT_PUMP_BASED_LOOP
#define kMillisecondsPerFrameToProcessEvents    3
#endif

// kFPS define for removed
// you can use Application.targetFrameRate (30 fps by default)

// Time to process events in seconds.
// Only used when display link loop is enabled.
#define kInputProcessingTime                                    0.001

extern "C" __attribute__((visibility ("default"))) NSString * const kUnityViewWillRotate = @"kUnityViewWillRotate";
extern "C" __attribute__((visibility ("default"))) NSString * const kUnityViewDidRotate = @"kUnityViewDidRotate";

// --- Unity ------------------------------------------------------------------
//

enum EnabledOrientation
{
        kAutorotateToPortrait = 1,
        kAutorotateToPortraitUpsideDown = 2,
        kAutorotateToLandscapeLeft = 4,
        kAutorotateToLandscapeRight = 8
};


enum ScreenOrientation
{
        kScreenOrientationUnknown,
        portrait,
        portraitUpsideDown,
        landscapeLeft,
        landscapeRight,
        autorotation,
        kScreenOrientationCount
};


void UnityPlayerLoop();
void UnityFinishRendering();
void UnityInitApplication(const char* appPathName);
void UnityLoadApplication();
void UnityPause(bool pause);
void UnityReloadResources();
void UnitySetAudioSessionActive(bool active);
void UnityCleanup();

void UnitySendTouchesBegin(NSSet* touches, UIEvent* event);
void UnitySendTouchesEnded(NSSet* touches, UIEvent* event);
void UnitySendTouchesCancelled(NSSet* touches, UIEvent* event);
void UnitySendTouchesMoved(NSSet* touches, UIEvent* event);
void UnitySendLocalNotification(UILocalNotification* notification);
void UnitySendRemoteNotification(NSDictionary* notification);
void UnitySendDeviceToken(NSData* deviceToken);
void UnitySendRemoteNotificationError(NSError* error);
void UnityDidAccelerate(float x, float y, float z, NSTimeInterval timestamp);
void UnityInputProcess();
bool UnityIsRenderingAPISupported(int renderingApi);
void UnitySetInputScaleFactor(float scale);
float UnityGetInputScaleFactor();
int  UnityGetTargetFPS();

bool UnityIsOrientationEnabled(EnabledOrientation orientation);
void UnitySetScreenOrientation(ScreenOrientation orientation);
ScreenOrientation UnityRequestedScreenOrientation();
ScreenOrientation ConvertToUnityScreenOrientation(UIInterfaceOrientation hwOrient, EnabledOrientation* outAutorotOrient);
bool UnityUseOSAutorotation();

bool UnityUse32bitDisplayBuffer();

void    UnityKeyboardOrientationStep1();
void    UnityKeyboardOrientationStep2();

int     UnityGetDesiredMSAASampleCount(int defaultSampleCount);
int     UnityGetShowActivityIndicatorOnLoading();
int             UnityGetAccelerometerFrequency();

enum TargetResolution
{
    kTargetResolutionNative = 0,
    kTargetResolutionStandard = 1,
    kTargetResolutionHD = 2
};

int UnityGetTargetResolution();


static UIViewController *sGLViewController = nil;

UIViewController *UnityGetGLViewController()
{
        return sGLViewController;
}


bool    _ios30orNewer           = false;
bool    _ios31orNewer           = false;
bool    _ios43orNewer           = false;

bool    _supportsDiscard        = false;
bool    _supportsMSAA           = false;

EAGLSurfaceDesc _surface;

ScreenOrientation       _curOrientation                 = portrait;
ScreenOrientation       _autorotOrientation             = kScreenOrientationUnknown;
bool                            _autorotEnableHandling  = false;
bool                            _glesContextCreated             = false;
bool                            _skipPresent                    = false;
bool                            _allowOrientationDetection = false;

void UnitySetAllowOrientationDetection(bool allow)
{
        _allowOrientationDetection = allow;
}


UIActivityIndicatorView*        _activityIndicator      = nil;
UIImageView*                            _splashView                     = nil;


class KeyboardOnScreen
{
public:
        static void Init();
};


// --- OpenGLES --------------------------------------------------------------------
//



//extern GLint gDefaultGLES2FBO;
extern GLint gDefaultFBO;


// Forward declaration of CADisplayLink for pre-3.1 SDKS
@interface NSObject(CADisplayLink)
+ (id) displayLinkWithTarget:(id)arg1 selector:(SEL)arg2;
- (void) addToRunLoop:(id)arg1 forMode:(id)arg2;
- (void) setFrameInterval:(int)interval;
- (void) invalidate;
@end


typedef EAGLContext*    MyEAGLContext;

@interface EAGLView : UIView {}
@end

@interface UnityViewController : UIViewController {}
@end


MyEAGLContext                   _context;
UIWindow *                              _window;

NSTimer*                                _timer;
bool                                    _need_recreate_timer = false;
id                                              _displayLink;
BOOL                                    _accelerometerIsActive = NO;
// This is set to true when applicationWillResignActive gets called. It is here
// to prevent calling SetPause(false) from applicationDidBecomeActive without
// previous call to applicationWillResignActive
BOOL                                    _didResignActive = NO;

bool CreateSurface(EAGLView *view, EAGLSurfaceDesc* surface);
void DestroySurface(EAGLSurfaceDesc* surface);

bool CreateWindowSurface(EAGLView *view, GLuint format, GLuint depthFormat, GLuint msaaSamples, bool retained, EAGLSurfaceDesc* surface)
{

    CAEAGLLayer* eaglLayer = (CAEAGLLayer*)[view layer];

        surface->format = format;
        surface->depthFormat = depthFormat;

        surface->depthbuffer = 0;
        surface->renderbuffer = 0;
        surface->framebuffer = 0;

        surface->msaaFramebuffer = 0;
        surface->msaaRenderbuffer = 0;
        surface->msaaDepthbuffer = 0;
        surface->msaaSamples = _supportsMSAA ? msaaSamples : 0;
        surface->use32bitColor = UnityUse32bitDisplayBuffer();

        surface->eaglLayer = eaglLayer;

        return CreateSurface(view, &_surface);
}

extern "C" void InitEAGLLayer(void* eaglLayer, bool use32bitColor)
{
        CAEAGLLayer* layer = (CAEAGLLayer*)eaglLayer;

        const NSString* colorFormat = use32bitColor ? kEAGLColorFormatRGBA8 : kEAGLColorFormatRGB565;

        layer.opaque = YES;
        layer.drawableProperties =      [NSDictionary dictionaryWithObjectsAndKeys:
                                                                        [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking,
                                                                        colorFormat, kEAGLDrawablePropertyColorFormat,
                                                                        nil
                                                                ];
}
extern "C" bool AllocateRenderBufferStorageFromEAGLLayer(void* eaglLayer)
{
        return [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)eaglLayer];
}
extern "C" void DeallocateRenderBufferStorageFromEAGLLayer()
{
        [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:nil];
}

bool CreateSurface(EAGLView *view, EAGLSurfaceDesc* surface)
{
        CAEAGLLayer* eaglLayer = (CAEAGLLayer*)surface->eaglLayer;
        assert(eaglLayer == [view layer]);

        CGSize newSize = [eaglLayer bounds].size;
        newSize.width  = roundf(newSize.width);
        newSize.height = roundf(newSize.height);

#ifdef __IPHONE_4_0
    int resolution = UnityGetTargetResolution();

    if (    (resolution == kTargetResolutionNative || resolution == kTargetResolutionHD)
         && [view respondsToSelector:@selector(setContentScaleFactor:)]
         && [[UIScreen mainScreen] respondsToSelector:@selector(scale)]
       )
    {
                        CGFloat scaleFactor = [UIScreen mainScreen].scale;
                        [view setContentScaleFactor:scaleFactor];
                        newSize.width = roundf(newSize.width * scaleFactor);
                        newSize.height = roundf(newSize.height * scaleFactor);
                        UnitySetInputScaleFactor(scaleFactor);
    }
#endif

        surface->w = newSize.width;
        surface->h = newSize.height;

        UNITY_DBG_LOG ("CreateWindowSurface: FBO\n");
        CreateSurfaceGLES(surface);
        GLES_CHK( glBindRenderbufferOES(GL_RENDERBUFFER_OES, surface->renderbuffer) );

        return true;
}


void DestroySurface(EAGLSurfaceDesc* surface)
{
        EAGLContext *oldContext = [EAGLContext currentContext];

        if (oldContext != _context)
                [EAGLContext setCurrentContext:_context];

        UnityFinishRendering();
        DestroySurfaceGLES(surface);

        if (oldContext != _context)
                [EAGLContext setCurrentContext:oldContext];
}

void PresentSurface(EAGLSurfaceDesc* surface)
{
        if(_skipPresent)
        {
                UNITY_DBG_LOG ("SKIP PresentSurface:\n");
                return;
        }
        UNITY_DBG_LOG ("PresentSurface:\n");

        EAGLContext *oldContext = [EAGLContext currentContext];
        if (oldContext != _context)
                [EAGLContext setCurrentContext:_context];

        PreparePresentSurfaceGLES(surface);

        // presentRenderbuffer presents currently bound RB, so make sure we have the correct one bound
        GLES_CHK( glBindRenderbufferOES(GL_RENDERBUFFER_OES, surface->renderbuffer) );
        if(![_context presentRenderbuffer:GL_RENDERBUFFER_OES])
                printf_console("failed to present renderbuffer (%s:%i)\n", __FILE__, __LINE__ );

        AfterPresentSurfaceGLES(surface);

        if(oldContext != _context)
                [EAGLContext setCurrentContext:oldContext];
}

void PresentContext_UnityCallback(struct UnityFrameStats const* unityFrameStats)
{
        Profiler_FrameEnd();

        PresentSurface(&_surface);

        Profiler_FrameUpdate(unityFrameStats);
        Profiler_FrameStart();
}


void CreateSplashView( UIView* parentView )
{
        NSString* launchImageName = nil;
        if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPhone)
        {
                bool devicePortrait  = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]);
                bool deviceLandscape = UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]);

                NSArray* supportedOrientation = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UISupportedInterfaceOrientations"];
                bool rotateToPortrait  =   [supportedOrientation containsObject: @"UIInterfaceOrientationPortrait"]
                                                                || [supportedOrientation containsObject: @"UIInterfaceOrientationPortraitUpsideDown"];
                bool rotateToLandscape =   [supportedOrientation containsObject: @"UIInterfaceOrientationLandscapeLeft"]
                                                                || [supportedOrientation containsObject: @"UIInterfaceOrientationLandscapeRight"];


                if (devicePortrait && rotateToPortrait)
                        launchImageName = @"Default-Portrait.png";
                else if (deviceLandscape && rotateToLandscape)
                        launchImageName = @"Default-Landscape.png";
                else if (rotateToPortrait)
                        launchImageName = @"Default-Portrait.png";
                else
                        launchImageName = @"Default-Landscape.png";
        }
        else
        {
#ifdef __IPHONE_4_0
                if ( [[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [UIScreen mainScreen].scale > 1.0 )
                        launchImageName = @"Default@2x.png";
                else
#endif
                        launchImageName = @"Default.png";
        }

        _splashView = [ [UIImageView alloc] initWithFrame: [[UIScreen mainScreen] bounds] ];
        _splashView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _splashView.autoresizesSubviews = YES;
        _splashView.image = [UIImage imageNamed:launchImageName];

        [parentView addSubview:_splashView];
}

void RemoveSplashScreen()
{
        [_splashView removeFromSuperview];
        [_splashView release];
        _splashView = nil;
}

void CreateActivityIndicator(UIView* parentView)
{
        int activityIndicatorStyle = UnityGetShowActivityIndicatorOnLoading();
        if( activityIndicatorStyle >= 0)
        {
                _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyle)activityIndicatorStyle];
                [parentView addSubview:_activityIndicator];
        }
}



int OpenEAGL_UnityCallback(UIWindow** window, int* screenWidth, int* screenHeight,  int* openglesVersion)
{
        CGRect rect = [[UIScreen mainScreen] bounds];

        // Create a full-screen window
        _window = [[UIWindow alloc] initWithFrame:rect];
        EAGLView* view = [[EAGLView alloc] initWithFrame:rect];
        UnityViewController *controller = [[UnityViewController alloc] init];
        sGLViewController = controller;

#if defined(__IPHONE_3_0)
        if( _ios30orNewer )
                controller.wantsFullScreenLayout = TRUE;
#endif

        controller.view = view;

        CreateSplashView( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ? (UIView*)_window : (UIView*)view );
        CreateActivityIndicator(_splashView);

        // add only now so controller have chance to reorient *all* added views
        [_window addSubview:view];
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
                [_window bringSubviewToFront:_splashView];

        if( !UnityUseOSAutorotation() )
        {
                _autorotEnableHandling = true;
                [[NSNotificationCenter defaultCenter] postNotificationName: UIDeviceOrientationDidChangeNotification object: [UIDevice currentDevice]];
        }

        // reposition activity indicator after we rotated views
        if (_activityIndicator)
                _activityIndicator.center = CGPointMake([_splashView bounds].size.width/2, [_splashView bounds].size.height/2);

        int openglesApi =
#if defined(__IPHONE_3_0) && USE_OPENGLES20_IF_AVAILABLE
        kEAGLRenderingAPIOpenGLES2;
#else
        kEAGLRenderingAPIOpenGLES1;
#endif

        for (; openglesApi >= kEAGLRenderingAPIOpenGLES1 && !_context; --openglesApi)
        {
                if (!UnityIsRenderingAPISupported(openglesApi))
                        continue;

                _context = [[EAGLContext alloc] initWithAPI:openglesApi];
        }

        if (!_context)
                return false;

        if (![EAGLContext setCurrentContext:_context]) {
                _context = 0;
                return false;
        }

        const GLuint colorFormat = UnityUse32bitDisplayBuffer() ? GL_RGBA8_OES : GL_RGB565_OES;

        if (!CreateWindowSurface(view, colorFormat, GL_DEPTH_COMPONENT16_OES, UnityGetDesiredMSAASampleCount(MSAA_DEFAULT_SAMPLE_COUNT), NO, &_surface)) {
                return false;
        }

        glViewport(0, 0, _surface.w, _surface.h);
        [_window makeKeyAndVisible];
        [view release];

        *window = _window;
        *screenWidth = _surface.w;
        *screenHeight = _surface.h;
        *openglesVersion = _context.API;

        _glesContextCreated = true;

        return true;
}

UIInterfaceOrientation
ConvertToIosScreenOrientation(ScreenOrientation orient)
{
        switch( orient )
        {
                case portrait:                          return UIInterfaceOrientationPortrait;
                case portraitUpsideDown:        return UIInterfaceOrientationPortraitUpsideDown;
                // landscape left/right have switched values in device/screen orientation
                // though unity docs are adjusted with device orientation values, so swap here
                case landscapeLeft:                     return UIInterfaceOrientationLandscapeRight;
                case landscapeRight:            return UIInterfaceOrientationLandscapeLeft;

                // shouldn't got there, just shutting up compiler
                default:                                        return UIInterfaceOrientationPortrait;
        }

        return UIInterfaceOrientationPortrait;
}

bool
OrientationWillChangeSurfaceExtents( ScreenOrientation prevOrient, ScreenOrientation targetOrient )
{
        bool prevLandscape   = ( prevOrient == landscapeLeft || prevOrient == landscapeRight );
        bool targetLandscape = ( targetOrient == landscapeLeft || targetOrient == landscapeRight );

        return( prevLandscape != targetLandscape );
}

CGAffineTransform TransformForOrientation( ScreenOrientation orient )
{
        static CGAffineTransform        transform[kScreenOrientationCount];
        static bool                                     inited = false;

        if( !inited )
        {
                transform[portrait]                             = CGAffineTransformIdentity;
                transform[portraitUpsideDown]   = CGAffineTransformMakeRotation(M_PI);
                transform[landscapeLeft]                = CGAffineTransformMakeRotation(M_PI_2);
                transform[landscapeRight]               = CGAffineTransformMakeRotation(-M_PI_2);

                inited = true;
        }

        return transform[orient];
}

CGRect ContentRectForOrientation( ScreenOrientation orient )
{
        static CGRect   contentRect[kScreenOrientationCount];
        static bool             inited = false;

        if( !inited )
        {
                CGRect screenRect               = [[UIScreen mainScreen] bounds];
                CGRect flipScreenRect   = CGRectMake(screenRect.origin.y, screenRect.origin.x, screenRect.size.height, screenRect.size.width);

                contentRect[portrait]                   = screenRect;
                contentRect[portraitUpsideDown] = screenRect;
                contentRect[landscapeLeft]              = flipScreenRect;
                contentRect[landscapeRight]             = flipScreenRect;

                inited = true;
        }

        return contentRect[orient];
}

bool
ShouldHandleRotation( ScreenOrientation* outTargetOrient )
{
        ScreenOrientation requestedOrient       = UnityRequestedScreenOrientation();
        ScreenOrientation targetOrient          = requestedOrient == autorotation ? _autorotOrientation : requestedOrient;

        if( outTargetOrient )
                *outTargetOrient = targetOrient;

        return targetOrient != kScreenOrientationUnknown && targetOrient != _curOrientation;
}

void
HandleOrientationRequest()
{
        UnityViewController*    controller      = (UnityViewController*)UnityGetGLViewController();
        EAGLView*                               view            = (EAGLView*)[controller view];

        ScreenOrientation targetOrient = portrait;
        if( ShouldHandleRotation(&targetOrient) )
        {
                UnityFinishRendering();

                [CATransaction begin];

                UnityKeyboardOrientationStep1();
                view.transform  = TransformForOrientation(targetOrient);
                view.bounds             = ContentRectForOrientation(targetOrient);

                [UIApplication sharedApplication].statusBarOrientation = ConvertToIosScreenOrientation(targetOrient);

                UnitySetScreenOrientation(targetOrient);
                if( OrientationWillChangeSurfaceExtents(_curOrientation, targetOrient) )
                {
                        DestroySurface(&_surface);
                        CreateSurface(view, &_surface);

                        // seems like ios sometimes got confused about abrupt swap chain destroy
                        // draw 2 times to fill both buffers
                        // present only once to make sure correct image goes to CA
                        _skipPresent = true;
                        {
                                UnityPlayerLoop();
                                UnityPlayerLoop();
                                UnityFinishRendering();
                        }
                        _skipPresent = false;

                        PresentSurface(&_surface);
                }
                [CATransaction commit];

                [CATransaction begin];
                UnityKeyboardOrientationStep2();
                [CATransaction commit];

                _curOrientation = targetOrient;
        }
}

void NotifyFramerateChange(int targetFPS)
{
        if( targetFPS <= 0 )
                return;

#if USE_DISPLAY_LINK_IF_AVAILABLE
        if (_displayLink)
        {
                int animationFrameInterval = (60.0 / (targetFPS));
                if (animationFrameInterval < 1)
                        animationFrameInterval = 1;

                [_displayLink setFrameInterval:animationFrameInterval];
        }
#endif
#if FALLBACK_LOOP_TYPE == NSTIMER_BASED_LOOP
        if (_displayLink == 0 && _timer)
                _need_recreate_timer = true;
#endif
}



// --- AppController --------------------------------------------------------------------
//


@implementation AppController

- (void) registerAccelerometer
{
        // NOTE: work-around for accelerometer sometimes failing to register (presumably on older devices)
        // set accelerometer delegate to nil first
        // work-around reported by Brian Robbins

        [[UIAccelerometer sharedAccelerometer] setDelegate:nil];
        int frequency = UnityGetAccelerometerFrequency();

        if (frequency > 0)
        {
                const float accelerometerFrequency = frequency;
                [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / accelerometerFrequency)];
                [[UIAccelerometer sharedAccelerometer] setDelegate:self];
        }
}

- (void) RepaintDisplayLink
{
#if USE_DISPLAY_LINK_IF_AVAILABLE
        [_displayLink setPaused: YES];

        while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, kInputProcessingTime, TRUE) == kCFRunLoopRunHandledSource)
                ;

        [_displayLink setPaused: NO];
        [self Repaint];
#endif
}

- (void) Repaint
{
        if( _surface.renderbuffer == 0 )
        {
                CreateSurface( (EAGLView*)[UnityGetGLViewController() view], &_surface);

                // to avoid black screen creeping in - redraw once (second time + present will be in normal Repaint flow)
                _skipPresent = true;
                UnityPlayerLoop();
                UnityFinishRendering();
                _skipPresent = false;
        }

        Profiler_UnityLoopStart();

        UnityInputProcess();
        UnityPlayerLoop();

        Profiler_UnityLoopEnd();

        // TODO: maybe repaint is not the best place?
        HandleOrientationRequest();

        if (UnityGetAccelerometerFrequency() > 0 && (!_accelerometerIsActive || ([UIAccelerometer sharedAccelerometer].delegate == nil)))
        {
                static int frameCounter = 0;
                if (frameCounter <= 0)
                {
                        // NOTE: work-around for accelerometer sometimes failing to register (presumably on older devices)
                        // sometimes even Brian Robbins work-around doesn't help
                        // then we will try to register accelerometer every N frames until we succeed

                        printf_console("-> force accelerometer registration\n");
                        [self registerAccelerometer];
                        frameCounter = 90; // try every ~3 seconds
                }
                --frameCounter;
        }

#if FALLBACK_LOOP_TYPE == NSTIMER_BASED_LOOP
        if (_displayLink == 0 && _timer && _need_recreate_timer)
        {
                [_timer invalidate];
                _timer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / (UnityGetTargetFPS() * kThrottleFPS)) target:self selector:@selector(Repaint) userInfo:nil repeats:YES];

                _need_recreate_timer = false;
        }
#endif

}

- (void) startRendering
{
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

#if FALLBACK_LOOP_TYPE == THREAD_BASED_LOOP
        const double OneMillisecond = 1.0 / 1000.0;
        for (;;)
        {
                const double SecondsPerFrame = 1.0 / (float)UnityGetTargetFPS();
                const double frameStartTime  = (double)CFAbsoluteTimeGetCurrent();
                [self performSelectorOnMainThread:@selector(Repaint) withObject:nil waitUntilDone:YES];

                double secondsToProcessEvents = SecondsPerFrame - (((double)CFAbsoluteTimeGetCurrent()) - frameStartTime);
                // if we run considerably slower than desired framerate anyhow
                // then we should sleep for a while leaving OS some room to process events
                if (secondsToProcessEvents < -OneMillisecond)
                        secondsToProcessEvents = OneMillisecond;
                if (secondsToProcessEvents > 0)
                        [NSThread sleepForTimeInterval:secondsToProcessEvents];
        }

#elif FALLBACK_LOOP_TYPE == EVENT_PUMP_BASED_LOOP

        int eventLoopTimeOuts = 0;
        const double SecondsPerFrameToProcessEvents = 0.001 * (double)kMillisecondsPerFrameToProcessEvents;
        for (;;)
        {
                const double SecondsPerFrame = 1.0 / (float)UnityGetTargetFPS();
                const double frameStartTime  = (double)CFAbsoluteTimeGetCurrent();
                [self Repaint];

                if (kMillisecondsPerFrameToProcessEvents <= 0)
                {
                        while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource);
                }
                else
                {
                        double secondsToProcessEvents = SecondsPerFrame - (((double)CFAbsoluteTimeGetCurrent()) - frameStartTime);
                        if(secondsToProcessEvents < SecondsPerFrameToProcessEvents)
                                secondsToProcessEvents = SecondsPerFrameToProcessEvents;

                        if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, secondsToProcessEvents, FALSE) == kCFRunLoopRunTimedOut)
                                ++eventLoopTimeOuts;
                }
        }

#endif

        [pool release];
}

- (void) prepareRunLoop
{
        UnityLoadApplication();
        Profiler_InitProfiler();
        InitGLES();

        _displayLink = nil;
#if USE_DISPLAY_LINK_IF_AVAILABLE
        // A system version of 3.1 or greater is required to use CADisplayLink. The NSTimer
        // class is used as fallback when it isn't available.
        if (_ios31orNewer)
        {
                // Frame interval defines how many display frames must pass between each time the
                // display link fires.
                int animationFrameInterval = 60.0 / (float)UnityGetTargetFPS();
                assert(animationFrameInterval >= 1);

                _displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(RepaintDisplayLink)];
                [_displayLink setFrameInterval:animationFrameInterval];
                [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        }
#endif

        if (_displayLink == nil)
        {
#if FALLBACK_LOOP_TYPE == NSTIMER_BASED_LOOP
                _timer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / (UnityGetTargetFPS() * kThrottleFPS)) target:self selector:@selector(Repaint) userInfo:nil repeats:YES];
#endif
        }

        [self registerAccelerometer];

        KeyboardOnScreen::Init();

        if (_displayLink == nil)
        {
#if FALLBACK_LOOP_TYPE == THREAD_BASED_LOOP
                [NSThread detachNewThreadSelector:@selector(startRendering) toTarget:self withObject:nil];
#elif FALLBACK_LOOP_TYPE == EVENT_PUMP_BASED_LOOP
                [self performSelectorOnMainThread:@selector(startRendering) withObject:nil waitUntilDone:NO];
#endif
        }

        if( _activityIndicator )
                [_activityIndicator stopAnimating];
        RemoveSplashScreen();

        // immediately render 1st frame in order to avoid occasional black screen
        // we do it twice to fill both buffers with meaningful contents.
        // set proper orientation right away?
        [self Repaint];
        [self Repaint];

}


- (void) startUnity:(UIApplication*)application
{
        if( [ [[UIDevice currentDevice] systemVersion] compare: @"3.0" options: NSNumericSearch ] != NSOrderedAscending )
                _ios30orNewer = true;

        if( [ [[UIDevice currentDevice] systemVersion] compare: @"3.1" options: NSNumericSearch ] != NSOrderedAscending )
                _ios31orNewer = true;

        if( [ [[UIDevice currentDevice] systemVersion] compare: @"4.3" options: NSNumericSearch ] != NSOrderedAscending )
                _ios43orNewer = true;

        char const* appPath = [[[NSBundle mainBundle] bundlePath]UTF8String];
        UnityInitApplication(appPath);

        if( _activityIndicator )
                [_activityIndicator startAnimating];

        [self performSelector:@selector(prepareRunLoop) withObject:nil afterDelay:0.1];
}

- (void)application:(UIApplication*)application didReceiveLocalNotification:(UILocalNotification*)notification
{
        UnitySendLocalNotification(notification);
}

- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
        UnitySendRemoteNotification(userInfo);
}

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
        UnitySendDeviceToken(deviceToken);
}

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
        UnitySendRemoteNotificationError(error);
}

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
        printf_console("-> applicationDidFinishLaunching()\n");
        // get local notification
        if (&UIApplicationLaunchOptionsLocalNotificationKey != nil)
        {
                UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
                if (notification)
                {
                        UnitySendLocalNotification(notification);
                }
        }

        // get remote notification
        if (&UIApplicationLaunchOptionsRemoteNotificationKey != nil)
        {
                NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
                if (notification)
                {
                        UnitySendRemoteNotification(notification);
                }
        }

        if ([UIDevice currentDevice].generatesDeviceOrientationNotifications == NO)
                [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

        [self startUnity:application];

        return NO;
}

// For iOS 4
// Callback order:
//   applicationDidResignActive()
//   applicationDidEnterBackground()
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    printf_console("-> applicationDidEnterBackground()\n");
}

// For iOS 4
// Callback order:
//   applicationWillEnterForeground()
//   applicationDidBecomeActive()
- (void)applicationWillEnterForeground:(UIApplication *)application
{
        printf_console("-> applicationWillEnterForeground()\n");
}

- (void) applicationDidBecomeActive:(UIApplication*)application
{
        printf_console("-> applicationDidBecomeActive()\n");
        if (_didResignActive)
        {
                UnityPause(false);
        }

        _didResignActive = NO;
}

- (void) applicationWillResignActive:(UIApplication*)application
{
        printf_console("-> applicationDidResignActive()\n");
        UnityPause(true);

        _didResignActive = YES;
}

- (void) applicationDidReceiveMemoryWarning:(UIApplication*)application
{
        printf_console("WARNING -> applicationDidReceiveMemoryWarning()\n");
}

- (void) applicationWillTerminate:(UIApplication*)application
{
        printf_console("-> applicationWillTerminate()\n");

        Profiler_UninitProfiler();

        UnityCleanup();
}

- (void) dealloc
{
        DestroySurface(&_surface);
        [_context release];
        _context = nil;

        [_window release];
        [super dealloc];
}

- (void) accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
{
        UnityDidAccelerate(acceleration.x, acceleration.y, acceleration.z, acceleration.timestamp);
        _accelerometerIsActive = YES;
}

@end

@implementation UnityViewController
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
        EnabledOrientation targetAutorot   = kAutorotateToPortrait;
        ScreenOrientation  targetOrient    = ConvertToUnityScreenOrientation(interfaceOrientation, &targetAutorot);
        ScreenOrientation  requestedOrientation = UnityRequestedScreenOrientation();

        if (requestedOrientation != autorotation)
                return (requestedOrientation == targetOrient);

        if (UnityIsOrientationEnabled(targetAutorot))
        {
                _autorotOrientation = targetOrient;

                if (_allowOrientationDetection)
                {
                        return true;
                }

                if (UnityUseOSAutorotation() || !_autorotEnableHandling)
                {
                        return true;
                }
        }

        return false;
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
        _curOrientation = ConvertToUnityScreenOrientation(toInterfaceOrientation, 0);
        [[NSNotificationCenter defaultCenter] postNotificationName:kUnityViewWillRotate object:self];
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
        UnitySetScreenOrientation(_curOrientation);
        ScreenOrientation prevOrientation = ConvertToUnityScreenOrientation(fromInterfaceOrientation, 0);

        if( OrientationWillChangeSurfaceExtents(prevOrientation, _curOrientation) || _allowOrientationDetection )
        {
                if( _glesContextCreated )
                        DestroySurface(&_surface);
        }

        UnitySetAllowOrientationDetection(false);

        [[NSNotificationCenter defaultCenter] postNotificationName:kUnityViewDidRotate object:self];
}

@end

@implementation EAGLView

+ (Class) layerClass
{
        return [CAEAGLLayer class];
}

- (id) initWithFrame:(CGRect)frame
{
        if((self = [super initWithFrame:frame])) {
                [self setMultipleTouchEnabled:YES];
                [self setExclusiveTouch:YES];
        }
        return self;
}

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
        UnitySendTouchesBegin(touches, event);
}
- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
        UnitySendTouchesEnded(touches, event);
}
- (void) touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event
{
        UnitySendTouchesCancelled(touches, event);
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
        UnitySendTouchesMoved(touches, event);
}

@end
 
Изображение
Аватара пользователя
xcube
UNITрон
 
Сообщения: 304
Зарегистрирован: 23 сен 2011, 12:20
Откуда: Spb

Re: Профайлинг и управление памятью в Unity iOS

Сообщение mp3 16 июл 2012, 23:09

Да, єто старьій метод. Нужно добавить:

Синтаксис:
Используется csharp
void Awake(){
   Application.targetFrameRate = 0;
}


В один из стартовьіх скриптов.
Be straight, or go forward.
Аватара пользователя
mp3
Адепт
 
Сообщения: 1071
Зарегистрирован: 21 окт 2009, 23:50

Re: Профайлинг и управление памятью в Unity iOS

Сообщение xcube 18 июл 2012, 21:22

mp3 писал(а):Да, єто старьій метод. Нужно добавить:

Синтаксис:
Используется csharp
void Awake(){
   Application.targetFrameRate = 0;
}


В один из стартовьіх скриптов.


Спасибо, наконец-то заработало!! Изображение
Изображение
Аватара пользователя
xcube
UNITрон
 
Сообщения: 304
Зарегистрирован: 23 сен 2011, 12:20
Откуда: Spb


Вернуться в Уроки

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5