Friday, August 11, 2017

Node.js WebSocket 서버 클라이언트 예제

서버: index.js
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws, request) {
    console.log('connection');
    ws.on('message', function incoming(message) {
        console.log('received: %s', message);
    });
    ws.on('close', function close(code, reason) {
        console.log('close ' + code + ':'+reason);
    });
    ws.send('something');
});

클라이언트: index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Native WebSocket Example</title>
</head>
<body>
<script>
  // 웹소켓 전역 객체 생성
  var ws = new WebSocket("ws://localhost:8080", "echo-protocol");

  // 연결이 수립되면 서버에 메시지를 전송한다
  ws.onopen = function(event) {
    ws.send("Client message: Hi!");
  }

  // 서버로 부터 메시지를 수신한다
  ws.onmessage = function(event) {
    console.log("Server message: ", event.data);
    document.write("Server message: ", event.data);
  }

  // error event handler
  ws.onerror = function(event) {
    console.log("Server error message: ", event.data);
  }
</script>
</body>
</html>

Thursday, August 10, 2017

Node.js nvm 기본 버전 설정하기

맥에서 node.js를 설치한 후에 항상 nvm use ${version}을 해야 되는 불편함이 있었다.
나같은 경우는 기본적으로 터미널을 연 후에 nvm use stable을 입력하고 node를 실행했었다.
이 상황에서 매번 nvm을 실행하지 않게 하기위해서는 다음과 같이 터미널에 입력하게 되면, 다음번 터미널 열때부터는 nvm use를 입력하지 않아도 된다.

nvm alias default node

Friday, July 21, 2017

Android RecyclerView Ripple 이펙트

리스트 아이템의 layout에다가 다음을 추가한다.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="70dp"
    android:background="?android:attr/selectableItemBackground">


Android 볼륨키 이벤트

@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)){
            //Do something
        }
        return true;
    }

Thursday, July 20, 2017

Android 7.0 APK 파일 설치

프로그램 코드로 APK 파일을 설치해 보자. 안드로이드 7.0에서는 직접 외부 폴더(External Storage)의 APK를 설치할수 없다.
따라서 다음과 같이 FileProvider를 만들어야 한다.

xml/provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

AndroidManifest.xml
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.duongame.XXX.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>

JAVA
                final Intent intent = new Intent(Intent.ACTION_VIEW);
                final Uri apkURI = FileProvider.getUriForFile(getActivity(), getActivity().getApplicationContext().getPackageName() + ".provider", new File(item.path));
                intent.setDataAndType(apkURI, "application/vnd.android.package-archive");
                intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);

Tuesday, July 11, 2017

Android FragmentPagerAdapter vs FragmentStatePagerAdapter

FragmentPagerAdapter - 페이지 갯수가 고정적일때
About FragmentPagerAdapter Google's guide says:
This version of the pager is more useful when there are a large number of pages, working more like a list view. When pages are not visible to the user, their entire fragment may be destroyed, only keeping the saved state of that fragment. This allows the pager to hold on to much less memory associated with each visited page as compared to FragmentPagerAdapter at the cost of potentially more overhead when switching between pages.

FragmentStatePagerAdapter - 페이지 갯수가 가변적일때
And about FragmentStatePagerAdapter:
This version of the pager is best for use when there are a handful of typically more static fragments to be paged through, such as a set of tabs. The fragment of each page the user visits will be kept in memory, though its view hierarchy may be destroyed when not visible. This can result in using a significant amount of memory since fragment instances can hold on to an arbitrary amount of state. For larger sets of pages, consider FragmentStatePagerAdapter.

Thursday, June 15, 2017

Android ListView divider 없애기

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="@null"
        android:dividerHeight="0dp"></ListView> 

Android RoundedImageView 예제

public class RoundedImageView extends ImageView {
    public RoundedImageView(Context context) {
        super(context);
    }

    public RoundedImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public RoundedImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        final Path clipPath = new Path();

        final float radius = UnitConverter.dpToPx(5);
        final float padding = 0;
        final int w = this.getWidth();
        final int h = this.getHeight();

        clipPath.addRoundRect(new RectF(padding, padding, w - padding, h - padding), radius, radius, Path.Direction.CW);
        canvas.clipPath(clipPath);

        super.onDraw(canvas);
    }

Saturday, April 29, 2017

iOS ARC 코딩 규칙

다음은 ARC를 적용하기 위한 코딩 상의 규칙이다.

1. 명시적으로 dealloc을 호출해서는 안된다.
2. retain, release, retainCount, autorelease를 명시적으로 호출하거나 오버라이드 할 수 없다.
3. dealloc 메소드에 대해 ARC의 적용을 받지 않는 인스턴스 변수를 해제하기 위해 오버라이드를 할 수는 있다. 단 이 때에도 [super dealloc]을 명시적으로 호출해서는 안된다.
4. CFRetain, CFRelease는 앞서 설명했듯이 사용할 수 있다. 코어 파운데이션 타입은 ARC에서 제외되므로 수동으로 관리해야 한다.
5. C구조체 내에 Objective-C 객체 포인터를 저장할 수 없다. 구조체보다는 Objective-C 객체를 쓸 것을 추천한다.
6. id 와 void *간의 캐주얼 캐스팅을 쓸 수 없다. 이들 간의 캐스팅에서는 컴파일러가 객체의 라이프사이클을 파악할 수 있도록 추가적인 지시어 (__reatin 등)를 써서 관계를 명시해야 한다.
7. NSAutoreleasePool 객체는 더 이상 쓸 수 없다. @autoreleasepool{ } 블럭을 사용한다.
8. NSZone을 쓸 수 없다. 어차피 ARC가 아니어도 최신 런타임은 이를 무시해버린다.
9. 접근자명에 new를 붙일 수 없다. @property NSString *newTitle;은 컴파일 오류를 일으킨다.
10. 단, getter 명을 바꾸면 쓸 수는 있다. @property (getter=theNewTitle) NSString *newTitle;은 동작한다.

변수 지정자
프로퍼티 지정자처럼 변수 지정자가 추가되었다.
__strong__weak
__unsafe_unretained__autoreleasing
__strong은 디폴트 값이다. 이 변수에 할당한 객체는 강한 참조를 하게 된다.
weak는 약한 참조만을 갖도록 한다. 변수가 가리키는 객체가 파괴되면 (객체는 강한참조의 수가 0일 때 자동으로 파괴된다) nil로 변경된다.

unsafe_unretained 는 강한 참조처럼 객체를 유지하지 않지만 약참조처럼 nil로 변경되지 않는다. CF객체나 C포인터등을 가리킬 때 사용한다.
__autoreleasing은 자동 해제될 객체를 담는 변수이다. 함수의 인자로 넘겨지는 변수는 모두 이 타입을 사용한다.

strong = retain
weak = objective c
assign = c

iOS Swift 요약 정리

init? 실패할수도 있는(nil을 리턴할수 있는) 생성자
A ?? B 3항 연산자로 unwrapping이 가능하면 unwrapping 실패하면 B를 리턴

Optional - nil을 가질수 있음. 그리고 할당하지 않으면 nil임
? - 언래핑 해야함
!  - 암묵적 언래핑이 되어 있어서 !를 붙여서 언래핑 할필요 없음

Casting
as NSString  - 다운캐스팅
as! NSString - 업캐스팅. 실패시 에러
as? NSString - 옵셔널캐스팅. 실패시 false 리턴. if절에서 체크

if let, var 언래핑 where

Guard
일반적으로 에러처리해서 함수에서 리턴하는 명령들이다
guard let number = value where value < 10 else {
    // false시 처리할 문장
    return
}

do while => repeat while

Switch
0..49가능 where 가능
fallthrough break없이 다음 case까지 진행가능

String formatting
print(“\(userName)”)

Function
func funcName(var1:int, var2: int) -> Float
{
}

Class static method
class ClassName
{
    class func funcName
}

함수에 변수 포인터 전달
inout

생성자/소멸자
init()
deinit()

계산된 속성
var balance: Float {
    get {
        return _balance
    }
    set(newBalance) {
        _balance = newBalance
    }
}


접근자
open, public
internal (default)
fileprivate
private


do catch
try func() - exception을 throw하는 경우에는 이렇게 호출해야함
try! func() - throw하는 함수에 대해서 에러처리를 받지 않고 호출함

enum ZZZException : ErrorType {
case XXX
case YYY
}

defer - 함수 종료시에 무조건 호출되는 함수를 지정

이 예제에서 class타입은 override할 수 있지만, static타입은 컴파일 에러를 발생시키네요.
static타입 선언은 class final선언과 같다고 볼 수 있습니다.

클로저
let multiply = {(val1: Int, val2: Int) -> Int in
    return val1*val2;
}

Friday, April 28, 2017

윈도우10 가상화 안될경우 해결 방법

윈도우10을 설치후 CMOS BIOS에서 인텔 가상화를 활성화 하였음에도 불구하고 가상화가 안되는 경우가 있다.

인텔의 가상화 여부는 다음의 프로그램으로 확인이 가능하다.
http://www.intel.com/content/www/us/en/support/processors/000005651.html



만약에 위의 부분이 No로 되어 있다면 실제 윈도우10 상에서 가상화가 불가능한 상황이다. 그렇게 되면 VirtualBox 등 가상화 프로그램에서 CPU가속을 받을수 없다.

그래서 CMOS에서 셋팅을 하였더라도 가상화 확인이 실패하면 다음과 같이 하여서 가상화를 활성화 시켜야 한다.
[제어판] - [프로그램 및 기능] - [Windows 기능 켜기/끄기]에서 Hyper V를 제거한다.





윈도우10 크롬 '연결이 비공개로 설정되어 있지 않습니다'

다음과 같이 크롬을 새로 설치한 후에도 에러메세지가 발생한다면 이렇게 수정하면 된다.


1. Internet Explorer (인터넷 익스플로러)를 마우스 오른쪽 버튼을 클릭하여 관리자 모드로 실행
2. [도구] - [인터넷 옵션] - [연결] - [LAN 설정] 클릭
3. 다음과 같이 [프록시 서버]를 체크 해제


윈도우10 SSD 최적화

1. Superfetch 비활성화
제어판 -> 시스템 및 보안 -> 관리도구 -> 서비스 -> Superfetch -> 시작 유형 -> 사용안함

2. Windows Error Reporting Service 비활성화
제어판 -> 시스템 및 보안 -> 관리도구 -> 서비스 -> Windows Error Reporting Service -> 시작 유형 -> 사용안함

3. Windows Search 비활성화
제어판 -> 시스템 및 보안 -> 관리도구 -> 서비스 -> Windows Search -> 시작 유형 -> 사용안함

4. 디스크에 쓰기 캐시 사용
제어판 -> 시스템 및 보안 -> 시스템-> 장치 관리자 -> 디스크 드라이브 -> 해당 SSD -> 속성 -> 정책 -> 장치에 쓰기 캐싱 사용 -> 체크

5. 시스템 로그에 이벤트 기록 비활성화
제어판 -> 시스템 및 보안 -> 시스템 -> 고급 시스템 설정 -> 시작 및 복구 -> 설정 -> 시스템 오류 -> 시스템 로그에 이벤트 기록 -> 체크 해제
/ 디버깅 정보 쓰기 -> 없음

6. 시스템 복원 기능 비활성화
제어판 -> 시스템 및 보안 -> 시스템-> 시스템 보호 -> 해당 SSD -> 구성 > 디스크 공간 사용 -> 삭제 / 복원 설정 -> 시스템 보호 해제 -> 체크

7. 가상 메모리 수동 설정
제어판 -> 시스템 및 보안 -> 시스템 -> 고급 시스템 설정 -> 성능 -> 설정 -> 고급 -> 가상 메모리 -> 변경 -> 사용자 지정 크기       -> 처음 크기 512입력 -> 최대 크기 1024입력 -> 설정

8. 고성능 모드 활성화
제어판 -> 시스템 및 보안 -> 전원옵션 -> 고성능 선택

9. 디스크 색인 비활성화
모든프로그램 -> 보조프로그램 ->  Windows 탐색기(관리자 권한으로 실행)  -> 해당 SSD 로컬 디스크 -> 속성 -> 이 드라이브의 파일 속성 및 내용 색인 허용 -> 체크 해제

10. 디스크 조각모음 비활성화
시작 -> 실행 -> dfrgui 입력 후 엔터 -> 일정 구성 -> 예약 실행(권장) -> 체크 해제

<*참고*명령창의 모든 명령어는 복사 후 붙여넣기가 가능합니다.>

11. 최대절전모드 비활성화
모든프로그램 -> 보조프로그램 -> 명령프롬프트 (마우스 우측 누른 후 관리자 권한으로 실행) -> powercfg -h off 로 입력 후 엔터
 
12. 자동 Trim 작동 여부 확인 & 활성화
모든프로그램 -> 보조프로그램 -> 명령프롬프트 (마우스 우측 누른 후 관리자 권한으로 실행)  -> fsutil behavior query DisableDeleteNotify 입력 후 엔터 -> "DisableDeleteNotify =  0" 이면 Trim 작동중이며 미작동시에는  fsutil behavior set DisableDeleteNotify 0 입력 후 엔터를 누르면 작동 합니다.

13. winsxs폴더 용량 줄이기 (윈7 sp1 이상)
모든프로그램 -> 보조프로그램 -> 명령프롬프트 (마우스 우측 누른 후 관리자 권한으로 실행) -> DISM /online /Cleanup-Image /SpSuperseded    입력 후 엔터 -> "작업을 완료 했습니다."가 나올때 까지 기다림 (다소 시간이 걸릴 수 있음 -> 완료




Tessellation Shader vs Geometry Shader

Tessellation shader는 재귀 세분할이다.
반면 geometry shader는 primitive 단위로 적용된다.

The tessellation shader is for recursive subdivision. An important features is adjacency information so you can do smoothing correctly and not wind up with gaps. You could do some limited subdivision with a geometry shader, but that's not really what its for.

Geometry shaders operate per-primitive. For example, if you need to do stuff for each triangle (such as this), do it in a geometry shader. I've heard of shadow volume extrusion being done. There's also "conservative rasterization" where you might extend triangle borders so every intersected pixel gets a fragment. Examples are pretty application specific.

Wednesday, April 26, 2017

서버 프로그래밍 공부에 대한 생각

바쁘신분들을 위한 요약
1. 먼저 무료/상용 엔진을 학습해 보세요 (상용엔진 추천! 가장 표준적이고 쉬우며 편의성을 제공)
2. 자신이 컨텐츠를 만들고 싶은지, 서버 엔진 프로그래머로 취업을 원하는지 고민해 보세요.
3. 그래도 욕심이 나시면 이 글에서 소개하는 내용들을 참고해보세요.

어떤 분께서 클라이언트신데 서버를 어떻게 배워야 할지 모르겠다고 쓰신 글을 보고 작성해 봅니다.
C++ 윈도우 서버를 처음부터 만든다면 다음과 같은 내용을 공부해야 할것으로 생각됩니다.
지극히 주관적인 생각이니까 참고만 부탁드려요. 의견은 환영하지만 부드럽게 부탁드립니다 ^_^;;
1. 준비학습
1-1. win socket (tcp/udp)
1-2. iocp
1-3. overlapped io
1-4. 멀티스레드
1-5. 메모리/오브젝트 풀
1-6. 3,5를 활용한 브로드캐스팅
1-0. 별도로 간단히 SQL의 사용법
이 밖에도 TCP의 전송 및 혼잡제어 부분은 udp를 만들때 응용되기도 하고, 전송 중 예외처리를 위해 중요하다고 생각합니다.
보통 이쯤 될때까지 혼자 만들다보면 어쩐지 udp를 슬슬 버리게 됩니다. 이핑계 저핑계 대면서요 ㅎ
중국에서 udp를 쓰면 다 털린다던가...
암호화 알고리즘에 대해 나와야 할것같은데? 라고 생각하시는 분도 계시겠지만 공부하며 혼자 하다보면 저것도 벅차요 ㅋ
디비는 살짝 논외로 쳤는데 결국은 필요해집니다. 레디스라거나 하는걸 추가로 학습하면 좋을듯!

공부가 끝난 뒤 개발해야 할 내용은
2. 모듈 개발
2-1. 로깅시스템
2-2. 메모리/오브젝트 풀
2-3. 스레드 풀 (TLS랑 전역적인거 둘 다 되는걸로)
2-4. iocp 모듈 (프로엑터 패턴. tcp, udp)
2-5. 패킷 프로세싱 (전송 및 혼잡제어)
2-6. 테스트로 사용할 서버/클라
2-7. 우아한 접속/종료 및 예외처리
2-8. 스트레스 테스트 툴
이렇게 만들어보면 조금 감이 올 것이고 그 다음에 해야 할 일은 모듈화 해서 라이브러리로 만드는 것이겠죠.
그런데 라이브러리화가 끝나면 '자 이제 시작이야~(내꿈을) 내꿈을 위한여행~(피카츄)' 가 시작됩니다.
바로 서버 구조란 무엇인가... 에 대해 고민해야 할 차례거든요.

3. 서버 구조 설계
3-1. 한대의 서버가 클라이언트들을 받아들이는 가장 단순한 구조 (유저가 많아지면 서버를 나눔)
3-2. 서버가 많아짐에 따라 접속/인증만 처리하는 로비서버 + 여러대의 게임서버 구조
3-3. 인증을 만들다보면 필요한 페킷 암호화 및 인증키 처리 (여기서 이걸 우겨넣다가 라이브러리를 재설계 하는 일도;;)
3-4. 그런데 요즘 유저들은 서버 자체가 나뉘면 싫어하지 않을까요? 체널링에 대한 고민
3-5. 체널링에 따른 인증 이동기능
3-6. 서버간 통신 및 브로드캐스팅 (ex 메이플의 메가폰. 운영자공지 등)
뭐 이정도 공부하고 이정도 만들면 되지 않을까... 그렇게 생각하고 있습니다.
그런데 과연... 자신이 서버 프로그래머로 취직할게 아니거나, 컨텐츠 서버 프로그래머로 취직하려고 해도 이런 내용들이 전부 필요할까요? 저는 그것에 대해서는 상당히 회의적입니다. 간단히 클라이언트만 봐도 요즘 DirectX12 배우시는 학생분들 있으신가요? 여기서 만약 부스트 asio가 등장한다고 해도 대분류 1번 준비학습 정도만 생략되는 수준입니다.
뿐만 아니라 아무리 asio나 부스트가 좋다고 해도 사실 1번에서 누군가 이끌어주지 않으면 많은 시행착오를 겪게됩니다.
어떻게 만들어야 쓰기 편하고 표준적인지 알기 어렵기 때문이죠.
DirectX 처음 배울때 3D MAX 파싱해서 물체 띄우는 수준으로 게임엔진을 만들 수 없는것과 같습니다.

4. 권장 사항
이때 제가 권할 수 있는 방법은 일단 오픈소스나 상용엔진을 학습해보는 것입니다.
여기서 서버엔진이란 무엇이며, 어떻게 쓰는것이 표준적이고 효율적인 설계인지를 엿볼 수 있습니다.
그 뒤에 자신이 무엇을 하고싶은지 고민해보세요.
컨텐츠를 만드시고 싶다면 서버엔진을 배우시고 잘 활용하는 쪽으로 학습하시는걸 추천합니다.
그러나 나는 '서버 엔진 프로그래머가 되겠어!'라고 결심하셨다면 위의 것들을 하나씩 정복해 나가시면 될 것 같습니다 ㅎ

5. 핵심?
프로그래머로 일하는데 있어서 서버를 지향하시는 분들께서는 이정도면 되지 않을까.. 그렇게 생각합니다.
라우터라던가 L4스위치 등 하드웨어에 대한 지식이 풍부하면 도움은 되겠지만 프로그래밍 이외의 범위임으로 일단 생략...
우리 마음대로 만들겠다! 라며 상용 엔진을 사용하지 않는 회사들도 재야의 고수들이 기본기 있고 범용적인 라이브러리
드ㄹ을 자체적으로 개발해서 사용하고 있기 때문에 무료/상용 엔진으로 기본기와 구조를 익혀도 좋습니다.
넷트워크에서 중요한 신뢰성등은 사실 지식도 필요하지만 많은 노하우가 중요한 만큼 상용엔진을
쓰는것이 안정적이고 편안하고 안락한 퇴근을 보장하죠... ㅇ<-<
세롭게 공부하면서 개발해 보는것도 중요하지만 상용 엔진을 권하는 이유는 이밖에도 많습니다.
요즘 트렌드는 엔진을 처음부터 개발하기 보다는 그간 만들어진 바퀴들도 얼마나 멋진것을 만들어내느냐에 있으니까요
!

두서없고 주관적인 글 읽어주셔서 감사합니다. 위에 살짝 요약해뒀고요. 질문이나 부드러운 의견은 언제나 환영합니다!
http://www.gamecodi.com/board/zboard.php?id=GAMECODI_Talkdev&page=2&sn1=&divpage=1&sn=off&ss=on&sc=on&select_arrange=headnum&desc=asc&no=4473

Java enum 사용하기

자바는 C++이나 C#과는 다르게 enum을 int로 형변환 하는 등 제대로 사용하려면 많이 구현해 주어야 한다.
아래와 같은 enum이 있다고 하였을 경우, Carrier.SKT enum을 int로 변환하려고 할때 다음을 호출하면 0이 리턴 된다.
Carrier.SKT.getValue();

그리고 1을 Carrier.KT로 변환하려 할때는 다음과 같이 한다.
Carrier.values()[1];

public enum Carrier {
    SKT(0),
    KT(1),
    LGT(2),
    NA(3);

    int value = 0;

    Carrier(int value) {
        this.value = value;
    }
    public int getValue() {
        return value;
    }

    @Override
    public String toString() {
        switch (value) {
            case 0:
                return "SKT";
            case 1:
                return "KT";
            case 2:
                return "U+";
            default:
                return "N/A";
        }
    }
}

Java Singleton 문제 정답(DCL)

public class Singleton {
    //쓰레드에서 변수의 변화를 바로 감지하게 하기 위함
    private volatile static Singleton instance;

    private Singleton() {

    }

    public static Singleton getInstance() {
        // 생성할때만 초기화 한다.
        if (instance == null) {
            // 클래스 단위로 락을 건다. static 이므로
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

Visual Studio 2015 Boost 1.62.0 빌드

call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" x86

set cores=%NUMBER_OF_PROCESSORS%
echo Building boost with %cores% cores

rem cd boost_1_62_0
call bootstrap.bat

rem Most libraries can be static libs
b2 -j%cores% toolset=msvc-14.0 address-model=64 architecture=x86 link=static threading=multi runtime-link=shared --build-type=minimal stage --stagedir=stage/x64
b2 -j%cores% toolset=msvc-14.0 address-model=32 architecture=x86 link=static threading=multi runtime-link=shared --build-type=minimal stage --stagedir=stage/win32

pause

Tuesday, April 25, 2017

Linux BSP(Board Support Package)의 정의

BSP(Board Support Package)란 이름의 의미 그대로 Board를 사용할 수 있도록 하기 위한 Software 묶음이라고 보면 될 것이다. 자세히 설명하자면 운영체제를 로드하기 위한 최소한의 장치를 지원하고, 하드웨어 보드의 모든 장치를 위한 드라이버를 말한다. 몇몇의 공급자들은 루트 파일 시스템, 임베디드 시스템에서 실행하는 프로그램을 만들기 위한 툴체인 그리고 장치들을 위한 configurator를 제공한다.

BSP의 구성은 일반적으로 아래와 같다.

1. Bootloader
시스템의 하드웨어를 초기화하고 운영체제의 이미지를 RAM에 올려주는 역할을 하는 시스템 프로그램으로 하드웨어 의존성이 강하다.

2. OAL(OEM Adaption Layer)
HAL(Hardware Abstraction Layer) 아래에 위치하며, 하드웨어 초기화 및 관리를 지원한다.
HAL란 컴퓨터의 하드웨어와 소프트웨어 사이의 추상화 계층이다.

3. Device Driver
특정 하드웨어나 장치를 제어하기 위한 커널의 일부분으로 동작하는 프로그램으로, 각각 장치 드라이버가 프로그램 되어 커널에 통합되어 실행된다.

iOS 오픈소스 라이브러리 모음

SDWebImage - 이미지 다운로더 및 캐쉬 라이브러리
https://github.com/rs/SDWebImage

Toast - 안드로이드 Toast 기능 라이브러리
https://github.com/scalessec/Toast

JSONKit - 써보니 그냥 편하고 빠른 JSON Parser
https://github.com/johnezang/JSONKit

AFNetworking - Network Framework
https://github.com/AFNetworking/AFNetworking

OpenCL 예제

OpenCL 예제이다. 이 예제에서는 GPU와 CPU를 동시에 사용하고 있다.

인텔 CPU에서 테스트를 했는데 인텔 OpenCL 드라이버를 설치하지 않으면, GPU만 가지고 수행을 하기 때문에 ret_num_platforms=1이 된다.

인텔 i5-2500과 지포스 GTX970에서 테스트 하였을때 ret_num_platforms=3이 되었다.

#include <stdio.h>
#include <stdlib.h>

#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif

#define MEM_SIZE (128)
#define MAX_SOURCE_SIZE (0x100000)

int main()
{
cl_device_id device_cpu = NULL;
cl_device_id device_gpu = NULL;
cl_context context_cpu = NULL;
cl_context context_gpu = NULL;
cl_command_queue command_queue_cpu = NULL;
cl_command_queue command_queue_gpu = NULL;
cl_mem memobj_cpu = NULL;
cl_mem memobj_gpu = NULL;
cl_program program_cpu = NULL;
cl_program program_gpu = NULL;
cl_kernel kernel_cpu = NULL;
cl_kernel kernel_gpu = NULL;
cl_platform_id platform[2];
cl_uint ret_num_devices;
cl_uint ret_num_platforms;
cl_int ret;

char string_cpu[MEM_SIZE];
char string_gpu[MEM_SIZE];

FILE *fp;
char fileName[] = "./hello.cl";
char *source_str;
size_t source_size;

/* 커널을 포함한 소스 코드를 로드 */
fp = fopen(fileName, "r");
if (!fp) {
fprintf(stderr, "Failed to load kernel.\n");
exit(1);
}
source_str = (char*)malloc(MAX_SOURCE_SIZE);
source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp);
fclose(fp);

/* 플랫폼, 디바이스 정보를 얻음 */
ret = clGetPlatformIDs(2, platform, &ret_num_platforms);
ret = clGetDeviceIDs(platform[0], CL_DEVICE_TYPE_ALL, 1, &device_gpu, &ret_num_devices);
ret = clGetDeviceIDs(platform[1], CL_DEVICE_TYPE_ALL, 1, &device_cpu, &ret_num_devices);

/* OpenCL 컨텍스트 생성 */
context_gpu = clCreateContext(NULL, 1, &device_gpu, NULL, NULL, &ret);
context_cpu = clCreateContext(NULL, 1, &device_cpu, NULL, NULL, &ret);

/* 커맨드 큐 생성 */
command_queue_cpu = clCreateCommandQueue(context_cpu, device_cpu, 0, &ret);
command_queue_gpu = clCreateCommandQueue(context_gpu, device_gpu, 0, &ret);

/* 메모리 버퍼 생성 */
memobj_cpu = clCreateBuffer(context_cpu, CL_MEM_READ_WRITE, MEM_SIZE * sizeof(char), NULL, &ret);
memobj_gpu = clCreateBuffer(context_gpu, CL_MEM_READ_WRITE, MEM_SIZE * sizeof(char), NULL, &ret);

/* 미리 로드한 소스 코드로 커널 프로그램을 생성 */
program_cpu = clCreateProgramWithSource(context_cpu, 1, (const char **)&source_str, (const size_t *)&source_size, &ret);
program_gpu = clCreateProgramWithSource(context_gpu, 1, (const char **)&source_str, (const size_t *)&source_size, &ret);

/* 커널 프로그램 빌드 */
ret = clBuildProgram(program_cpu, 1, &device_cpu, NULL, NULL, NULL);
ret = clBuildProgram(program_gpu, 1, &device_gpu, NULL, NULL, NULL);

/* OpenCL 커널 생성*/
kernel_cpu = clCreateKernel(program_cpu, "hello", &ret);
kernel_gpu = clCreateKernel(program_gpu, "hello", &ret);

/* OpenCL 커널 파라미터 설정 */
ret = clSetKernelArg(kernel_cpu, 0, sizeof(cl_mem), (void *)&memobj_cpu);
ret = clSetKernelArg(kernel_gpu, 0, sizeof(cl_mem), (void *)&memobj_gpu);

/* OpenCL 커널 실행 */
ret = clEnqueueTask(command_queue_cpu, kernel_cpu, 0, NULL, NULL);
ret = clEnqueueTask(command_queue_gpu, kernel_gpu, 0, NULL, NULL);

/* 실행 결과를 메모리 버퍼에서 얻음 */
ret = clEnqueueReadBuffer(command_queue_cpu, memobj_cpu, CL_TRUE, 0, MEM_SIZE * sizeof(char), string_cpu, 0, NULL, NULL);
ret = clEnqueueReadBuffer(command_queue_gpu, memobj_gpu, CL_TRUE, 0, MEM_SIZE * sizeof(char), string_gpu, 0, NULL, NULL);

/* 결과 출력 */
puts(string_cpu);
puts(string_gpu);

/* 종료 처리 */
ret = clFlush(command_queue_cpu);
ret = clFlush(command_queue_gpu);
ret = clFinish(command_queue_cpu);
ret = clFinish(command_queue_gpu);
ret = clReleaseKernel(kernel_cpu);
ret = clReleaseKernel(kernel_gpu);
ret = clReleaseProgram(program_cpu);
ret = clReleaseProgram(program_gpu);
ret = clReleaseMemObject(memobj_cpu);
ret = clReleaseMemObject(memobj_gpu);
ret = clReleaseCommandQueue(command_queue_cpu);
ret = clReleaseCommandQueue(command_queue_gpu);
ret = clReleaseContext(context_cpu);
ret = clReleaseContext(context_gpu);

free(source_str);

// while (1);
return 0;
}

CUDA 예제

#include "device_launch_parameters.h"
#include <cuda_runtime.h>
#include <stdlib.h>
#include <stdio.h>

#define SIZE 1024

// __global__을 통해서 커널임을 표시한다. host에서 호출된다.
__global__ void VectorAdd(int *a, int *b, int *c, int n)
{
    // 수많은 스레드가 동시에 처리한다.
    // 따라서 threadIdx(스레드 인덱스)를 통해서 스레드들을 구별한다.
    int i = threadIdx.x;
    printf("threadIdx.x : %d, n : %d\n", i, n);
    for (i = 0; i < n; i++)
    {
        c[i] = a[i] + b[i];
        printf("%d = %d + %d\n", c[i], a[i], b[i]);
    }
}

int main()
{
    int *a, *b, *c;
    int *d_a, *d_b, *d_c;

    // 호스트의 메모리에 할당한다.
    a = (int *)malloc(SIZE * sizeof(int));
    b = (int *)malloc(SIZE * sizeof(int));
    c = (int *)malloc(SIZE * sizeof(int));

    // cudaMalloc(destination, number of byte)로 device의 메모리를 할당한다.
    cudaMalloc(&d_a, SIZE * sizeof(int));
    cudaMalloc(&d_b, SIZE * sizeof(int));
    cudaMalloc(&d_c, SIZE * sizeof(int));

    // 초기화
    for (int i = 0; i < SIZE; ++i)
    {
        a[i] = i;
        b[i] = i;
        c[i] = 0;
    }

    // cudaMemcpy(destination, source, number of byte, cudaMemcpyHostToDevice)로 호스트에서 디바이스로 메모리를 카피한다.
    cudaMemcpy(d_a, a, SIZE * sizeof(int), cudaMemcpyHostToDevice);
    cudaMemcpy(d_b, b, SIZE * sizeof(int), cudaMemcpyHostToDevice);
    cudaMemcpy(d_c, c, SIZE * sizeof(int), cudaMemcpyHostToDevice);

    // 함수 호출을 위해서 새로운 신텍스 요소를 추가할 필요가 있다.
    // 첫번째 parameter는 블럭의 수이다. 예제에서는 스레드 블럭이 하나이다.
    // SIZE는 1024개의 스레드를 의미한다.
    VectorAdd<<<1, SIZE>>>(d_a, d_b, d_c, SIZE);

    //cudaMemcpy(source, destination, number of byte, cudaMemDeviceToHost)로 디바이스의 메모리(연산 결과 데이터)를 호스트에 카피한다.
    cudaMemcpy(a, d_a, SIZE * sizeof(int), cudaMemcpyDeviceToHost);
    cudaMemcpy(b, d_b, SIZE * sizeof(int), cudaMemcpyDeviceToHost);
    cudaMemcpy(c, d_c, SIZE * sizeof(int), cudaMemcpyDeviceToHost);
    for (int i = 0; i < SIZE; ++i)
        printf("c[%d] = %d\n", i, c[i]);

    // 호스트의 메모리 할당 해제
    free(a);
    free(b);
    free(c);

    // cudaFree(d_a)를 통해 디바이스의 메모리를 할당 해제
    cudaFree(d_a);
    cudaFree(d_b);
    cudaFree(d_c);
    return 0;
}

iOS ARC와 GC의 차이

가비지 컬렉션 방식은, 메모리 관리를 가비지 컬렉터라는 것이 프로그램 실행중에 동적으로 감시하고 있다가, 더이상 사용할 필요가 없다고 여겨지는 것을 메모리에서 삭제해 주는 것입니다. 즉, 실행타임에서 메모리 관리를 하는 것입니다.


그와는 달리, ARC는 프로그램이 실행되고 있는 상태에서 감시하는 것이 아니라, 코드를 빌드할 때에(컴파일할 때) 컴파일러가 프로그래머 대신에 release 코드를 적절한 위치에 넣어주는 것입니다.


이건 아주 중요한 장점인데, 가비지 컬렉션이라는 것이(대표적으로 Java나 .NET에서 사용됩니다.) 항상 메모리를 차지하고 감시해야기 때문에 프로그램 자체 외에 메모리 사용량이 더 늘어날 수 밖에 없으며, 지속적인 감시를 위해 CPU를 일부 사용할 수 밖에 없는데 비해, ARC는 어차피 수동으로 개발자가 넣을 코드를 컴파일러가 넣어주는 것이기 때문에, 전혀 그런 오버헤드가 필요 없다는 것입니다.

iOS GCD와 NSOperationQueue의 차이

GCD는 동시에 실행하려는 작업 단위를 대표 할 수있는 경량의 방법이다. 해당 작업 단위는 개발자가 직접 스케줄하지 않고 시스템이 스케줄 관리를 해준다. 블럭들 사이에서 의존성을 부여하는 것은 쉽지 않은 일이며, 작업 취소 혹은 일시정시 같은 일을 하기 위해서는 각 개발자가 개인별로 추가해야한다.

NSOperation과 NSOperationQueue는 GCD에 비해 추가적인 기능을 제공하며 여러 operation에 의존성을 부여할 수도 있다. 뿐만 아니라 재사용도 가능하며 취소 혹은 일시정지와 같은 기능도 가능하다. NSOperation은 KVO 기술을 완벽하게 사용할 수 있다. 그래서 NSOperation이 실행되기 시작하면 NSNotificationCenter를 통해 상태 변화에 대한 노티를 받을 수 있다. 

iOS 백그라운드 비동기 작업 방법 (3 가지)

1. PerformSelectorInXXX
self performSelectorInBackground:@selector(myMethod:) withObject:
self performSelectorInMainThread:@selector(updateUI:) withObject:

-(void)updateUI:(NSDictionary *)param{
}

2. NSOperationQueue
_queue = [[NSOperationQueue alloc] init];

//시간이 오래 걸리는 작업을 만들어 백그라운드 큐에 돌려줍시다.
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        [self heavyOperation];
        //오래 걸리는 작업의 결과로 UI업데이트를 진행시켜줍니다.
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [self updateUI:nil];
        }];
    }];
    [_queue addOperation:operation];

3. GCD
// 여기서부터 비동기 코드 시작.
    // dispatch_async 함수는 내부블럭의 코드 실행에 영향을 받지 않고 바로 실행이 끝난다.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
        // 작업이 오래 걸리는 API를 백그라운드 스레드에서 실행한다.
        BOOL res = [self heavyOperation];
        dispatch_async(dispatch_get_main_queue(), ^{
            // 이 블럭은 메인스레드(UI)에서 실행된다.
            if (res) {
                [self updateUI:nil];
            }else {
                [self alertFail];
            }
        });
    });

dispatch_one : 한번만
dispatch_after : 일정 시간 후에

EGL PBuffers vs Pixmaps differences

EGL에서 생성할수 있는 EGLSurface는 다음과 같이 3가지 종류이다.

1) Window Surface
    - On-Screen Rendering Surfaces를 위해 사용
    - 리눅스의 framebuffer에 해당 할 것이다
    - eglCreateWindowSurface() 사용
2) Pbuffers Surface
    - Off-Screen Rendering Surfaces를 위해 사용
    - Graphic 메모리나 GPU 메모리에 생성
    - eglCreatePbufferSurface() 사용
    - Client(OpenGL ES)에서 생성한 Pbuffer를 EGL의 Pbuffer와 binding 할 때 사용은 eglCreatePbufferFromClientBuffer() 를 사용
3) Pixmaps Surface
    - Off-Screen Rendering Surfaces 를 위해 사용하고
      Graphic 메모리나 GPU 메모리에 생성한다는 점에서
      Windows Surface와 다름
    - OpenGLES 및 OpenVG와 같은 Client APIs 외의
       APIs를 지원한다는 점에서 Pbuffer Surface와 다름
    - Android의 TextureSurface에서 사용 (SurfaceTextureClient, SurafceTexureLayer 클래스)

Pixmaps는 PBuffers와 다르게 다른 Client APIs를 사용가능하다고 하는데 이는 buffer의 포인터가 노출이 되어 있어서 다른 클라이언트도 접근이 가능하다는 뜻이다. 예를 들어 C언어에서 포인터로 접근하여 직접 픽셀을 수정이 가능.

Android OpenGL GLSurfaceView 예제

안드로이드에서 OpenGL ES를 사용하려면 가장 간단하게 GLSurfaceView를 사용하면 된다.
GLSurfaceView를 생성하고 GLSurfaceView.Renderer를 구현하면 기본적인 뼈대가 완성 된다.
아래의 예제는 화면을 빨간색으로 지우는 단순한 예제이다.

package com.duongame.opengl;

import android.opengl.GLSurfaceView;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    GLSurfaceView glSurfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        glSurfaceView = new GLSurfaceView(this);
        glSurfaceView.setRenderer(new MainRenderer());
        setContentView(glSurfaceView);

        //setContentView(R.layout.activity_main);
    }
}

package com.duongame.opengl;

import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class MainRenderer implements GLSurfaceView.Renderer {
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        gl.glClearColor(1,0,0,1);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {

    }

    @Override
    public void onDrawFrame(GL10 gl) {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    }
}

OpenGL ES Desktop Windows 버전에 관하여

NVIDIA와 INTEL 그래픽카드는 데스크탑에서 EGL을 사용할수 없다. 그러므로 OPENGL ES를 사용할수 없다.

AMD는 EGL을 통해서 데스크탑 OPENGL ES를 구현하고 있다.

Using OpenGL ES on desktops differs from IHV to IHV. While NVIDIA and Intel expose OpenGL ES on desktop via WGL/GLX extensions (e.g. http://opengl.delphigl.de/gl_listreports.php?listreportsbyextension=WGL_EXT_create_context_es_profile), AMD exposes it through EGL.