블로그 정리중 발견한 글 옮김(2008년 8월 26일 글)

두개의 32비트 Register에서 상하위 의 16비트 값씩을 조합해서 새로운 값을 만들어 낼때 유용하게 사용할수 있는 명령어가 바로 PKHBT,TB 명령어 이다.

이 명령어는 ARM v6 ARCH에 추가된 명령어로  v6 아키텍쳐를 지원하는 모든 ARM cpu에서 사용할수 있다.

아래의 예제를 보면, 실제 사용예를 이해할수 있다.

참고: H : 상위 16비트
        L  : 하위 16비트

r9 == C(H)A(L)  : r9 레지스터의 상위 16비트에 C가, 하위 16비트에 A가 저장되어 있다.
r1 == D(H)B(L)  : r1 레지스터의 상위 16비트에 D가, 하위 16비트에 B가 저장되어 있다.
 
PKHTB  r12,r1,r9, ASR #16 ; 
PKHBT  r9,r9,r1, LSL #16 ; r9 = B ,A

결과 >
r12 = D(H)C(L) , 즉, r1의 TOP(상위16비트)와 r9를 16비트 ASR한 BOTTOM(하위 16비트)를 packaging!
r9 == B(H)A(L) , 즉, r9의 BOTTOM(하위 16비트)과 r1를 16비트 LSL한 TOP(상위16비트)을 packaging!

이런 방법을 사용하지 않고 다르게 할수 있는 방법은 Register를 하나 더 사용해서, AND연산과 ORR연산을 사용하는 방법이 있다. 그러나, 위의 두방법처럼 하나의 명령어로 처리되지는 못하므로, LOOP사용시 훨씬더 많은 비용을 소모하게 된다.

이런 방법을 그래픽 렌더링 엔진쪽에서 ASM 코딩으로 최적화 해주면, 지금 나오는 Embedded 단말보다 훨씬 빠른 UI를 경험할수 있을것이다. 

블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,

아주 오래전에 적어두었던 글을 블로그 정리중 발견하여 옮겨적습니다.(2008년 8월 27일 글)

 

그래픽 처리하는 루틴이나 라이브러리의 경우 C언어나 CPP로 아무리 컴팩트하게 프로그래밍을 했다고 해도, 컴파일러가 사람만큼 스마트 하지 못하기 때문에 비효율적이게 되는 부분이 발생하게 된다. 

컴파일러의 첫 목적은 사용자가 의도한 대로 안전하게 어셈블링 해주는 것이기 때문에 이런 비효율은 피할 수 없는 것이다.

만약 사용자가 어셈블리에 관한 지식과 해당 H/W에 대한 지식이 조금이라도 있다면, 어셈블리 레벨에서 최적화를 시도해 볼 수 있는데, 그 실제적인 예를들어 설명하겠다.

<C CODE>

typedef _DWORD DWORD
struct _DWORD
{
    unsigned short  a ;  
    unsigned short  b ;  
    unsigned short  c ;  
    unsigned short  d ;  
};

typedef _DWORD2 DWORD2
struct _DWORD2
{
    unsigned int   A;  
    unsigned int   C ;  
};

void Loop(DWORD2 *dst,DWORD *src,int loopsize)
{
    while(loopsize--)
    {
         int d = 256 - src->d;
         dst->A=(DWORD2*)src->A+((dst->A*d)>>8)&0x1F001F00;
         dst->C=(DWORD2*)src->C+((dst->C*d)>>8)&0x1F001F00;
         dst++;
         src++;
   }       
}

위의 코드를 C언어 레벨에서 분석하였을때, 구조체가 사용이 덜 최적화 되었다는 것을 알수 있다.
즉, (DWORD2*)src->C값은 src->d 값을 포함하고 있기 때문에, C코드상에서도 메모리 Access를 1회 제거하는데 큰 공헌을 할수는 있다. 

CPU상에서 연산되는 것보다, 메모리 IO에 의한 성능저하가 상당하기 때문에 위와 같이 메모리 IO를 1회 줄이는것만으로도 성능향상을 확인할 수 있다.

앞으로, 우리가 튜닝을 할때에는 C언어로 무결한 코드를 완전히 컴팩트하게 구성한다음에 어셈블리 언어로 최적화 하면 된다.

위 C코드의 컴파일 결과 : ASM 코드(armcc 사용,LE, arm1136j-S)

Loop
     SUBS    R3,R2,#1
     BXCC   R14
     PUSH   {R14}
     LDRH    R2,[R1,#6]
     LDR      R4,[R0,#0]
     LDR      R12,[R1,#0]
     RSB      R2,R2,#0X100
     SUBS    R3,R3,#1
     MUL     R4,R2,R4
     ADD      R12,R12,R4,LSR #8
     BIC       R12,R12,#0x1F000000
     BIC       R12,R12,#0x1F00
     STR      R12,[R0,#0]
     LDR      R4,[R0,#4]
     LDR      R12,[R1,#4]
     ADD      R1,R1,#8
     MUL     R2,R4,R2
     ADD      R2,R12,R2,LSR #8
     BIC       R2,R2,#0x1F000000
     BIC       R2,R2,#0x1F00
     STR      R2,[R0,#4]!
     ADD      R0,R0,#4
     BCS      {PC} -0x4C
     POP      {R14}
     BX         R14

위의 ASM 코드를 보면 상당히 많은 부분이 개선가능하다는 것을 발견할 수 있다. 

두 말 할 것 업이 바로 최적화 작업에 돌입한다.!!!

개선된 코드

Loop_opt
    SUBS     R3,R2,#1
    BXCC     R14
    PUSH     {R4-R9}   ; 레지스터를 더 많이 쓰기 위해, 스택에 저장
    MOV      R8,#0x1F00
    ORR       R8,R8,R8, LSL #16
    MOV      R9,#0xFF
    ORR       R9,R9,R9 LSL #8
INLOOP
    LDM       R1!,{R6,R7}  ; 한번에 두개씩 읽어오자!!
    LDM       R0, {R4,R5}  ; 역시 한번에 두개 씩  읽어올것!!
    AND       R2,R9,R7, ASR #16   ;위에서 말했던, 메모리 Access 1회 줄이는 방법.!!!!
    RSB       R2,R2,#0x100 
    MUL      R4,R2,R4 ; STALL제거를 위해 위로 올라옴
    MUL      R5,R2,R5 ; STALL제거를 위해 위로 올라옴
    SUBS     R3,R3,#1
    ADD       R6,R6,R4, LSR #8 ;이놈은 줄이고 싶지만... 더 연구해봐야 됨.
    BIC        R6,R6,R8  ; 이런거 말고 방법이 있을거야~~
    ADD       R7,R7,R5, LSR #8 ;이놈도...
    BIC        R7,R7,R8 ; 이런거 말고 방법이 있을거야~~
    STM      R0!, {R6,R7} ; 두개 저장.
    BCS      INLOOP
    POP      {R4-R9}
    BX         R14

적용 테스트 결과 :루틴 자체의 성능이 약 3배 개선되었다. (시스템 점유율 12 % --> 4%로 개선)
최적화 방법 :
1. 메모리 접근 횟수를 줄임
2. LOOP내 인스트럭션의 수를 줄임
3. STALL 발생 횟수를 없앰.
4. BIT 연산을 한번에 가능하도록 함.

그러나, "나는 더 개선하고 싶다." 하는 사람은 아직 한가지 더 방법이 있다.
바로 Cache의 최대한 활용하는 방법을 연구하는 것과 SIMD(Single Instruction Multiple Data)를 사용하는 것이다.  ARM의 경우 Cache Line 사이즈가 32byte이므로 한 라인에 딱 맞는 Loop Code를 작성하면 캐시 Hit Ratio가 증가할것이고 이에 따라 성능향상도 기대할 수 있다.
그러기 위해서는 Thumb code는 16개, ARM code는 8개의 instruction으로 코드를 작성해야 한다. 

그리고 SIMD를 적용한다면, 아래 코드를 개선할수 있다.

MUL      R4,R2,R4 ; 
MUL      R5,R2,R5 ; 
ADD       R6,R6,R4, LSR #8 ;
BIC        R6,R6,R8  ;
ADD       R7,R7,R5, LSR #8 ;
BIC        R7,R7,R8 ;

구조체 구조가 32bit SIMD에서는 못써먹을 구조라서, 64bit SIMD가 되면 바로 적용해 볼 수 있을것 같다.

한줄요약 : RISC에서는 생각 보다 최적화는 어렵지 않다.

블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,
스카이프, 네이트온, 유클라우드, 드랍 박스 등등등을 깔고 나니...
건방지게도 이 어플들이 시작하자 마자 자동으로 실행된다.

너무 건방진거 아닌가? 주인님이 사용하고자 원할때 실행되어야 겸손하고 올바른 어플이지...

그래서 오늘 다 지워버렸다.

윈도우즈 환경과는 관리하는 방식이 다른데, 그 방법은?

OSX 의 독에 보면, 시스템 환경 설정이라는것이 있다.
요런게 생긴거.


이넘을 클릭하게 되면. 설정 메뉴가 나오는데 그중에서 계정이라는걸 선택하자.



그러면 다음처럼  계정 설정 메뉴가 나오는데, 로그인 항목이라는 메뉴를 선택하면, 시작할때 자동으로 실행되는 응용프로그램들이 쭈욱 나온다.


+ 는 추가하는것이고, -는 제거하는 것이다, 필요한 작업을 해주면 된다. 




 


블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,
이번에는 cocos2d Touch Event  처리 방법이다.

터치 이벤트는 두가지 방법이 있는데, 하나는 싱글 터치 처리 방식이고, 나머지 하나는 멀티 터치 처리 방식이다.

게임을 할때, 좌우 방향 버튼도 있고, 발사 버튼, 점프 버튼 등이들어가는 아케이드 같은 게임들은 멀티 터치 처리를 해줘야 한다.
즉, 터치 이벤트들을 모두 받아서 차례로 다 처리 해줘야 하는 것이다.

하지만, 앵그리버드 같은 게임은 그냥 손가락 하나만 슥슥 움직이고, 눌러주고 하는 컨트롤이 대부분이기 때문에, 굳이 멀티 터치를 사용할 필요가 없다.
오직 한번에 터치 이벤트 하나만 처리하도록 만들면 되는 것이다.

그러면 다음 소스를 보면서, 첫번째는, 싱글터치 처리 방법에 대해서 알아보고, 두번째는 멀티 터치 처리 방법에 대해서 알아보자.
구현할 예제는 지난 예제에서 사용한 우리 거북군을 아무런 효과도 없이 그냥 터치가 들어오는 이벤트에 맞게 이리 저리 움직여 보는것으로 하자.

멀티 터치는 예제로 표현하기 좀 애매해서, 예제 동영상은 싱글 터치에 대해서만 촬영해서 올리도록 하겠다.

1. 싱글 터치만 사용할 경우.(지난 예제들과 똑같다,)

 

//

//  HelloWorldLayer.m

// 



// Import the interfaces

#import "HelloWorldLayer.h"



//static int transitionIndex=0;

static int effectIndex=0;


// HelloWorldLayer implementation

@implementation HelloWorldLayer

+(CCScene *) scene

{

// 'scene' is an autorelease object.

CCScene *scene = [CCScene node];

// 'layer' is an autorelease object.

HelloWorldLayer *layer = [HelloWorldLayer node];

// add layer as a child to scene

[scene addChild: layer];

// return the scene

return scene;

}


-(id) init

{

// always call "super" init

// Apple recommends to re-assign "self" with the "super" return value

if( (self=[super init])) {       

        self.isTouchEnabled = YES;     // Layer를 초기화 할때, 나는 터치를 받겠습니다. 라고 해줘야 한다.     


}

return self;

}

 

- (void) registerWithTouchDispatcher {

    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];

}


- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {// 터치 시작했다.

    CGPoint location = [touch locationInView: [touch view]];

    

CGPoint convertedLocation = [[CCDirector sharedDirector] convertToGL:location];

NSLog(@"ccTouchBegan : %f , %f",convertedLocation.x ,convertedLocation.y);

    

    return YES;

   

}


- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event { // 엇? 움직이네?

    CGPoint location = [touch locationInView: [touch view]];

    

CGPoint convertedLocation = [[CCDirector sharedDirector] convertToGL:location];

NSLog(@"ccTouchMoved  %f , %f",convertedLocation.x ,convertedLocation.y);

    

    


}


- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event { // 손뗐어.

    CGPoint location = [touch locationInView: [touch view]];

    

CGPoint convertedLocation = [[CCDirector sharedDirector] convertToGL:location];

NSLog(@"ccTouchEnded : %f , y : %f",convertedLocation.x ,convertedLocation.y);


    

}


- (void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event { // 터치한거 취소야.

    

} 
그런데 레이어마다 각가가 터치 이벤트를 처리할수 있게 되면 어떻게 되는거지? 하고 잠시 고민하고 생각했다면.!!! 굉장히 바람직하다.
처음에 나는매번 레이어가 바뀔때마다, "이 놈들은 터치를 받지 말아야 해" 하며 NO로 설정하는 작업을 넣어줬으나, cocos2d는 그렇게 호락 호락한 프레임워크가 아니었다. 

여러개의 레이어들이 중첩되어 있는 상태라면, 터치 이벤트를 처리할수 있돌고 한 레이어중 TOP에 올라오는 레이어가 해당 터치 이벤트를 받아먹게 된다. 위에서 언급한 각 레이어들을 직접 터치 enable/disable 해주는 작업이 필요한 경우도 있으나, 그렇게 많이 고민 할필요는 없다.
 
그리고 어떤 터치 방법을 사용할것이냐에 대해서 설정하는 것이, registerWithTouchDispatcher 메소드 인데, CCTouchDispatcher를 들여다보면 아래와 같이 되어 있습니다.

즉, 이 레이어에서 터치를 전달 받겠다고 하는 것이고, 그 이벤트들을 처리해주는 메소드들이 바로 위에 나오는 메소드들이다.
 

-(void) addStandardDelegate:(id<CCStandardTouchDelegate>) delegate priority:(int)priority

{

CCTouchHandler *handler = [CCStandardTouchHandler handlerWithDelegate:delegate priority:priority];

if( ! locked ) {

[self forceAddHandler:handler array:standardHandlers];

} else {

[handlersToAdd addObject:handler];

toAdd = YES;

}

}


각 터치 이벤트를 처리하는 메소드 아래 아래와 같은 내용이 있는데, 이건 좌표계를 변환해주는것이다. 우리가 사용하는 코코스2d좌표계와 openGL의 좌쵸가 다르기 때문에(y좌표) 아래 처럼 사용하는 것이다.

CGPoint location = [touch locationInView: [touch view]];  // 싱글 터치라서 touch를 바로 가져다가 쓴다.

    

GPoint convertedLocation = [[CCDirector sharedDirectorconvertToGL:location];



2. 멀티 터치를 사용할 경우.  (메소드의 인자가 다르다)

 

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

NSSet *allTouches = [event allTouches];

int count = [allTouches count];

if(count > 1){


NSArray *current_touches = [allTouches allObjects];

for(int i=0; i<count;i++){

UITouch *touch = [current_touches objectAtIndex:i];

CGPoint location = [touch locationInView:[touch view]];

location = [[CCDirector sharedDirector] convertToGL:location];


}

}else {

UITouch *touch = [touches anyObject];

CGPoint location = [touch locationInView:[touch view]];

location = [[CCDirector sharedDirector] convertToGL:location];


}

}


-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{

UITouch *touch = [touches anyObject];

CGPoint location = [touch locationInView:[touch view]];

location = [[CCDirector sharedDirector] convertToGL:location];


}


- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{

UITouch *touch = [touches anyObject];

CGPoint location = [touch locationInView:[touch view]];

location = [[CCDirector sharedDirector] convertToGL:location];


}


 
 
멀티 터치는 싱글 터치보다 역시 복잡하다. register하는 메소드는 사용하면 안되고, 위에서 보는 것처럼 함수를 구현해주면, 멀티 터치를 처리 해줄수 있다. 눈여겨 봐야 할부분은 began시에 터치 이벤트의 수를 세이라는 부분이다. 이놈이 지금 멀티 터치일경우,아닐경우를 잘 구분해서처리해줘야 한다.


오늘도 어김 없이. 예제를 하나 만들어보자.

거북군을 움직여 보자. 움직이는 방법은 손가락으로 화면의 임의의 곳을 터치 하면 거북군이 스멀 스멀 그쪽으로 이동하게 한다.

 

- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {

    CGPoint location = [touch locationInView: [touch view]];

    

CGPoint convertedLocation = [[CCDirector sharedDirector] convertToGL:location];

NSLog(@"ccTouchEnded : %f , y : %f",convertedLocation.x ,convertedLocation.y);


    [turtleSprite stopAllActions];

    [turtleSprite runAction: [CCMoveTo actionWithDuration:MOVE_DURATION position:convertedLocation]];

    

}

 

 이전까지 했던 소스에서, 터치가 업되는 순간에 위와 같이 해주면 터치된 좌표로 움직이게 된다. 너무 쉽다. 맞다!! 이렇게 시작하는거다 원래.

위 코드에서 CMoveTo 효과가 나오는데, 지난번에 이야기 한 것들과 마찬가지로 이것도 하나의 action이다, 이전것들은 effect 를 위한 action 들이고, 이넘은 아주 기초적인 action이다. 이 내용도 굉장히 많은데, 다음 포스트에서 basic action들을 비롯해서, 한번 또 다 확인해보도록 하자.

그리고 MOVE_DURATION 값을 3.0으로 줬는데, 의미하는 바는, 정해진 좌표까지 moveto하는데 걸리는 시간은 항상 일정하게 3초가 걸리도록 하라 이다.
즉, 멀리 찍으면 빨리 움직이고, 가까이 찍으면 천천히 움직이게 하는 것이다.


마지막으로 동영상 올라간다.
 

'코딩하고 > iOS' 카테고리의 다른 글

iOS용 게임 개발기 -7-  (0) 2011.08.19
iOS용 게임 개발기 -6-  (0) 2011.08.17
VoodooHDA 64비트 빌드 그리고, nVidia HDMI 제거.  (2) 2011.08.15
iOS용 게임 개발기 -5-  (0) 2011.08.10
iOS용 게임 개발기 -4.1-  (0) 2011.08.02
블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,
세상 정말 편해졌다. 아니, 세상을 편하게 해주는 사람들이 많아졌다.

얼마전까지만 해도 OSX를 일반 PC에 설치하려면 정말 피똥 싸면서, 일주일은 기본 삽질에, 적게는 한달, 많게는 몇개월씩 삽질하곤했었는데...
이 당시 내 PC의 cpu가 AMD 제품이었다..... ㅠ.ㅠ.

한 50만원 정도 투자해서, 맥 제품에 들어가는 시퓨와 비슷한거 사고, 메인보드도 기가바이트류 보드 싼걸로 하나 사서 조립하고 나니...

OSX 설치는 윈도우보다 더 더 쉬워졌네.

아무것도 하지 않아도, 설치가 완료되고 , 심지어는 업데이트도 그냥 된다.!!! 10.6.8까지 업데이트가 그냥 되다니!!!
예전에는 kext 정리해주고,...또 버전에 따른 드라이버 설치해주고... 삽질을 준비하고 단단히 마음먹고 했는데. 지금은 아무것도 안해도 된다.
OSX DVD를 하나 사서 가지고만 있다면, DVD를 넣고 iBoot로 부팅해서 그냥 설치하면 된다.

그 방법은???

 http://tonymacx86.blogspot.com/2010/04/iboot-multibeast-install-mac-os-x-on.html

i
Boot라는 부트로더를 부트 시디로 만들어서 부팅을 하고, 난후 OS X DVD를 반드시 정품으로구매한(얼마 안한다). 것을 넣고, 부팅을 하면.설치가 된다. 일단 iBoot로 부팅이 되고나면, cd를 빼고, OSX DVD를 넣으면 되는것이다.

물론 여러가지 다른 방법도 많다. 가장 속편한 방법이 이 방법인것 같다. 2008년에 처음 해킨 할때 절망과 고통의 나나들을 AMD와 함겨 견뎌내며, 겨우 잘 깔아서 썻으나, 10.6 설범이 나오고 나서는 그냥 인텔 CPU하나 사고 타협했다. 그런데 인텔은 신세계이다. "이건 해킨이 아니야. 그냥 프로그램 설치나 마찬가지야" 를 왜치며 사용하기 시작했다.

아무런 것도 해줄 필요가 없다.

다만 설치후 사운드라던지, VGA라던지 이런거는 잘 셋팅해줘야 한다.

위 사이트 DSDT database가 있는데,  거기가서 메인보드별로 다 나오니까, 검색해서 가장 싼놈으로 메인보드를 선택하고, 저기서 다운받아둔 DSDT를 준비해두면 왠만한건 다 해결된다.

그리고 그래픽 카드는 nVidia 제품으로 해서 게임이런거 안할거라면 8400gs정도만 되도 무난하게 설치되고 정상적으로 사용할수 있다. 중고로 1만원이면 사니까. 이런것도 부담없이....

사운드가 문제인데, 그 문제를 해결해주는 녀석은 ?

 http://code.google.com/p/voodoohda/

바로 VoodooHDA라는 드라이버이다. 어지간한 오디오는 다 잡아준다. 안되면, 소스가 공개되어 있으니, 약간만 수정해도 되고....

애플이 해킨 유저들에게 미끼를 조금 씩 던져주는거 아닌가 싶다. 왜냐면?
해킨을 사용하면서 OSX를 접하고 나면, 그 끝은 결국 리얼맥을 사게 되는것으로 끝난다.

애플 제품을 하나씩 , 둘씩 접하게 되면, 점점 맥이든, 아이패드든, 아이팟이든. 아이폰이든 계속 사게 된다.
내가 벌써 두개를 샀다.곧 하나 더 사게 될거고....

 누구든 이글을 보는 사람은 한번 정도는 설치해보길 추천한다. 매장가서 OSX DVD하나 사는 것부터 시작해라.
블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,