728x90

CUDA와 DirectX의 상호운용 방법에 대해서 살펴보기 전에, 몇가지 구조체들과 함수에 대해 알아보자.



이 함수는 디바이스 장치의 개수를 획득하는 함수이다.

parameter로 count의 포인터를 넘겨 받기 때문에 당연히 count에는 Device의 개수가 리턴되어서 나오게 된다.



이 구조체는 CUDA Device의 정보들을 저장할 수 있는 구조체이다. 

이 구조체의 변수는 매우 많기 때문에 다음 링크를 참조하도록 하자.

http://horacio9573.no-ip.org/cuda/structcudaDeviceProp.html



이 함수는 CUDA Device에서 정보들을 가져오는 함수이다. 이 함수를 이용하여 각 Device들의 정보를 가져와서 알맞게 사용할 수 있다.



위의 함수들을 이용하여 Device를 읽어오는 코드를 보자.



Device를 찾을 때 또 다른 유용한 함수도 있다.


cudaDeviceProp 구조체의 값을 채운 후 이 함수를 호출하면 이 정보에 맞는 Device를 찾아서 Device 번호를 첫 번째 매개변수에 넣어준다.



728x90
728x90

자원의 개요 

자원은 앞에서 말햇듯이 크게 두 가지의 종류로 나뉘는데, 버퍼(Buffer)텍스처(Texture)이다.




위의 그림은 자원 클래스들이 모두 ID3DResource라는 단일 공통 기반 클래스로부터 파생된 것임을 보여준다.


이러한 구조는 자원이라는 것이 결국은 파이프라인에 부착(연결)할 수 있고, 입력 또는 출력에 쓰이는 메모리 블록이라는 점을 생각하면 당연한 것이다. 다른 말로 하면 자원은 GPU가 사용하고 조작하도록 마련된 메모리 블록일 뿐이라는 것이다.


자원의 생성

모든 메모리 자원의 생성은 ID3D11Device 인터페이스가 책임진다. 생성된 자원을 파이프라인에 직접 연결할 수도 있고 자원 뷰를 통해서 부착할 수도 있다. 일단 연결이되면 이후 파이프라인 실행 과정 안에서 자원이 실제로 사용된다. 


자원의 생성에 쓰이는 ID3D11Device의 메서드는 자원의 종류마다 다르지만, 모두 동일한 일반 패턴을 따른다.


모든 자원 생성 메서드는 세 개의 매개변수를 받는다. 

첫 매개변수는 자원 생성에 관한 모든 옵션을 지정하는 구조체이다. 이를 자원 서술(Resource Description)이라고 부른다. 자원 종류마다 자원 서술 구조체가 다르다. 그러나 이 구조체들은 모두 동일한 목적(생성된 자원의 원하는 특성들을 정의)으로 사용된다.


둘째 매개변수는 D3D11_SUBRESOURCE_DATA 구조체를 가리키는 포인터인데, 이 구조체는 자원에 적재할 초기 자료를 제공하는 데 쓰인다. 예를 들어 정적 정점 자료를 담을 버퍼 자원을 만드는 경우 이 구조체를 이용해서 모형의 정점 자료를 버퍼 자원에 채워 넣을 수 있다. 


세번째 매개변수는 자원 종류에 맞는 자원 인터페이스를 가리키는 포인터의 포인터로, 자원 생성이 성공하면 해당 자원을 가리키는 포인터가 이 매개변수에 설정된다.




자원 용도 플래그

자원이 존재하는 '메모리'는 비디오 카드일 수도 있고, 시스템의 주 메모리일 수도 있다. 또한 Direct3D 실행 모듈이 자원을 비디오 카드 메모리에서 시스템 메모리로 또는 그 반대 방향으로 이동할 수도 있다. 때문에 응용 프로그램은 반드시 자원의 사용 방식에 대한 자신의 '의도'를 용도 명세 필드를 통해서 명시적으로 밝혀야 한다. 


enum D3D11_USAGE

{

D3D11_USAGE_DEFAULT,

D3D11_USAGE_IMMUTABLE,

D3D11_USAGE_DYNAMIC,

D3D11_USAGE_STAGING

}


 자원 용도

DEFAULT 

DYNAMIC 

 IMMUTABLE

 STAGING

 GPU 읽기 

 YES 

YES 

YES 

YES

GPU 쓰기

YES

 

 

 YES 

 CPU 쓰기 

 

 

 

YES

CPU 읽기

 

YES 

 

YSE


D3D11_USAGE_DEFAULT(기본 용도) : 표에서 보듯이 기본 용도 자원은 GPU의 읽기 쓰기만 가능하고 CPU의 접근은 모두 거부한다. 이 용도는 렌더 타겟 텍스처나 스트림 출력 정점 버퍼가 있다.


D3D11_USAGE_IMMUTABLE(불변 용도) : 가장 간단한 사용 패턴으로 오직 GPU가 읽을 수만 있다. GPU와 CPU의 쓰기를 모두 거부한다. 이 용도는 정적인 상수나, 정점, 색인 버퍼를 들 수 있다.


D3D11_USAGE_DYNAMIC(동적 용도) : CPU의 쓰기가 가능한 두 가지 용도 중 하나이다. GPU는 읽기만 가능하다. 이 사용 용도는 CPU가 자원의 내용을 생산하고 GPU가 자원을 소비한다. 

이 용도는 상수 버퍼에서 사용하면 좋다.


D3D11_USAGE_STAGING(예비 용도) : 이 예비 용도는 특별한 종류의 사용 패턴을 제공한다. 앞에서 말한 세 가지 용도는 렌더링 수행을 위한 전형적인 자원 사용 시나리오들에 해당하는 것이다. 그러나 GPU에서 자료를 계산, 조작하고 그것을 저장이나 추가 조사를 위해 CPU로 읽어 들어야 하는 경우도 있다. 그런 목적의 응용 프로그램에서는 다른 사용 패턴들에 CPU의 읽기 접근을 강제로 허용하는 대신 이 예비 용도의 자원을 중간 계산을 위한 장소로 활용하면 된다.


CPU 접근 플래그

자원의 용도를 지정했다면, 다음으로는 자원에 대한 CPU의 접근 방식을 지정해야 한다. 이 플래그는 CPU에만 국한 된다. 이 열거형의 두 값을 비트 단위 OR로 결합해서 사용하면 읽기와 쓰기를 모두 허용 할 수도 있다. 하지만 자원 용도 플래그에 맞추어서 설정해야만 한다.


enum D3D11_CPU_ACCESS_FLAG

{

D3D11_CPU_ACCESS_WRITE,

D3D11_CPU_ACCESS_READ

}


연결 플래그

자원 서술 구조체의 또 다른 공통 필드로 연결 플래그(Bind Flag)가 있다. 이 필드는 자원을 파이프라인의 어디에 연결할 것인지를 나타낸다. 이 값들을 비트 단위 OR로 결합함으로써 연결 가능 장소를 여러개 지정하는 것도 가능하다. 이 플래그를 제대로 지정하지 않고 자원을 생성하면 나중에 응용 프로그램이 자원을 파이프라인에 연결하려 할 때 오류가 발생한다.


enum D3D11_BIND_FLAG 

{

D3D11_BIND_VERTEX_BUFFER,

D3D11_BIND_INDEX_BUFFER,

D3D11_BIND_CONSTANT_BUFFER,

D3D11_BIND_SHADER_RESOURCE,

D3D11_BIND_STREAM_OUTPUT,

D3D11_BIND_RENDER_TARGET,

D3D11_BIND_DEPTH_STENCIL,

D3D11_BIND_UNORDERED_ACCESS,

}


자원을 파이프라인에 연결할 수 있는 지점은 총 여덟 가지이다. 처음 둘은 정점 버퍼와 색인 버퍼에 해당하는 것으로, 파이프라인의 기하구조 자료를 공급하기 위한 입력 조립기 단계에 부착할 자원에 쓰인다. 반면 여섯 번째와 일곱번째의 렌더 타겟 플래그와 깊이/스탠실 버퍼 플래그는 파이프라인의 렌더링 결과를 받는 출력 병합기 단계에 연결할 자원을 위한 것이다. 다섯 번째의 스트림 출력 플래그 역시 파이프라인으로부터의 출력을 위한 것이나, 래스터화된 이미지 자료가 아니라 기하구조 자료를 받는다는 점이 다르다. 반면 D3D11_BIND_CONSTANT_BUFFER, D3D11_BIND_SHADER_RESOURCE, 

D3D11_BIND_UNORDERED_ACCESS는 셰이더 프로그램 안에서 사용한다.


위의 그림에서 연결 플래그가 연결되는 부분을 확인 할 수 있다.


자원 해제

자원들은 모두 COM 인터페이스를 구현하는 객체의 형태이며, 따라서 해당객체의 계통 구조 안에는 IUnknown 인터페이스가 존재한다. 이는 자원들이 참조 계수 방식으로 관리된다는 뜻이며, 따라서 응용 프로그램이 자원을 다 사용하고 난 후에는 반드시 참조를 해제해 주어야 한다.


728x90
728x90




728x90
728x90

CUDA에서는 많은 스레드를 사용하게 된다. 앞에서 메모리의 계층구조를 보면, 공유 메모리라는 것도 있다. 

많은 스레드들이 공유 메모리에서 서로 데이터를 '쓰기, 읽기' 를 하기 위해서는 당연히 동기화를 해야만 한다.

이 동기화를 위해 C언어에서는 굉장히 머리 아픈 상황이 많이 발생하지만, CUDA C에서는 다행히 동기화 함수를 제공하고 있다. 

__syncthreads() 이 함수는 블록 내의 다른 모든 스레드가 __syncthreads()를 호출해야만 다음 명령어로 넘어가게 되어 있다.


그림 - __syncthreads() 사용 예


스레드 동기화에서 주의 할 점은 일단 동기화 자체가 작업이 먼저 끝난 스레드가 아직 작업이 끝나지 않은 스레드를 기다리는 것이기 때문에 성능에 영향이 갈 것이다. 꼭 사용해야 되는 부분에서만 사용하도록 하자.


728x90
728x90

예전에 다른 팀과 연동하는 과정에서 매개 변수로 넘긴 값이 함수 내부로 넘어가면서 값이 혼자 변하는 버그를 경험했다.


그림 - test.cpp


그림 - main.cpp


위와 같은 상황에서 abc()를 통해 값을 넘겼을 때, 매개변수 a[3]은 모두 제대로 값이 넘어갔지만, 매개변수 b의 경우 계속해서 0의 값이 들어가는 것을 확인했었다.


이런저런 테스트 결과 "test.h"에서 abc()의 선언을 추가함으로 써 문제가 해결되었다.


이런 일이 발생한 정확한 이유는 모르겠지만, C 형태로 코딩을 할 때에는 함수의 선언이 빠졌을 때 이런 일이 발생할 수 있으므로 주의하도록 하자.

728x90
728x90

Visual Studio 2010으로 작업하는 도중에 아래 그림과 같이 Stack Overflow가 발생했었다.



그림 - 0xC00000FD: Stack oveflow


이것은 기본 배열이 0x7fffffff 크기를 초과해서 이다.

이 문제를 해결하기 위해서는 배열 대신 동적 할당을 이용해서 Heap에 저장하는 방법이 있다. (나는 이렇게 고쳤다...)


도저히 코드 수정이 불가능한 상태라면 프로젝트의 옵션을 수정하는 방법이 있다.

그것은 원래 default로 제공되는 stack의 공간을 수정하는 방법인데 원래 값은 1MB로 되어 있다. 이것을 임의의 값으로 강제로 늘려버리면 된다.


그림 - 프로젝트 설정 값 변경


링커 -> 시스템 -> 스택 예약 크기에서 0으로 되어 있는 설정 값을 1024 * 1024 * 1 = 1MB이므로 1024 * 1024 * 10 = 10485760(10MB)로 입력한다.


이렇게 코드를 변경하지 않고 수정하는 방법도 있다. 하지만, 프로젝트 옵션을 수정하는 것은 최후의 최후의 방법으로 쓰도록 하자...


* Visaul Studio 2013을 사용하기 시작했는데, 2013은 처음부터 배열의 크기가 넘어가면 빌드 에러를 띄워준다. (고맙...)


참고 : http://ocllos.tistory.com/39

728x90
728x90

우선 파사드의 의미를 사전에서 살펴보면 다음과 같다.

1. <건축> (건물의) 정면, 전면, 파사드

2. <<비유적>> (사물의) 표면, 외관, 겉보기, 허울 (또는 facade)


위의 사전적 의미에서도 알 수 있듯이 파사드 패턴이라 함은 인터페이스를 단훈화시키기 위해서 인터페이스를 변경하는데, 하나 이상의 클래스의 복잡한 인터페이스를 깔끔하면서도, 말쑥한 파사드(겉모양, 외관등)으로 덮어주는 것이다.


파사드 패턴을 다시 한번 정의하자면, 어떤 서브 시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공함으로써 서브시스템에서 더 쉽게 사용할 수 있도록 하는 패턴이다.

그림 - 파사드 패턴


홈씨어터를 예로 들어서 설명하자면 다음과 같은 몇가지 작업을 실행해야 된다.

1. 팝콘 기계를 켠다.

2. 팝콘을 튀기기 시작한다.

3. 전등을 어둡게 조절한다.

4. 스크린을 내린다.

5. 프로젝터를 켠다.

6. 프로젝터로 DVD 신호가 입력되도록 한다.

7 프로젝터를 와이드 스크린 모드로 전환한다.

8. 앰프를 켠다.

9. 앰프의 입력을 DVD로 전환한다.

10. 앰프를 서라운드 음향 모드로 전환한다.

11. 앰프 볼륨을 중간으로 설정한다.

12. DVD 플레이를 켠다.

13. DVD 재생한다.


위와 같은 작업을 하기 위해서 사용자가 코드를 한 줄씩 모두 작업을하게 될 것이다.

만약, 이렇게 된다면 문제가 몇가지 존재하게 된다.

1. 홈씨어터의 사용법이 너무 복잡해진다.

2. 영화를 꺼야할 때는 어떻게 처리해야 할지 고민하게 된다.

3. 시스템이 업그레이드 되면 작동 방법을 배워야 한다.


이럴 때 파사드 패턴을 사용해서 복잡한 일을 간단하게 사용할 수 있다.


그림 - CD Player 구현 코드


그림 - Tuner 구현 코드


몇가지 클래스가 더 만들어져야 하지만 글이 너무 길어지기 때문에 생략한 클래스는 (Amplifier, Projecter, TheaterLight, Screen, PopcornPopper) 등이 있을 것이다.


이제 파사드 패턴을 구현한 클래스를 보도록 하자.


그림 - 파사드 패턴 클래스


위와 같이 파사드 패턴은 단순화된 인터페이스를 통해서 서브 시스템을 더 쉽게 사용할 수 있도록 하기 위한 용도로 사용된다.

덕분에 클라이언트에서는 단순한 메소드 하나만을 호출함으로 일하기도 편리하고 수원해질 수 있는 것이다.


728x90
728x90

싱글턴(Singleton)이라는 것은 디자인 패턴의 가장 기초적인 패턴이다.

하지만 이 패턴이라는 것은 사실상 딱 부러지는 코드를 제공하는 것은 아니고 코드라는게 항상 그렇지만 100% 정답은 없다.


그 중에서 싱글턴은 아래의 조건만 맞춰 진다면 개인적으로 "어떠한" 방법을 쓰든 싱글턴이라고 부르는게 맞다고 생각한다.

1. Process내에서 단 한 개만 생성되는 것을 보장하며, 그것을 표현할 수 있을 것.

2. 사용하는 시점이 생성되는 시점일 것.


싱글턴과 전역 변수가 비슷하지만 차이 점을 하나씩 비교해보자. 

싱글턴은 Process내에서 단 한개만 생성이 된다는 것을 보장함과 동시에 표현이 가능하다는 점에 있어서 전역 변수로는 표현하기 힘든 부분이라는 것에 싱글턴의 존재성을 깨닫게 된다.


아래 예제를 보자.


그림 - 싱글턴인듯 아닌듯 한 기본 예제


위의 코드는 처음 싱글턴을 공부할 때 항상 만들어보는 예제 일 것이다. 하지만 이것만으로는 이것이 단 한개 만을 가지는지는 보장이 되지 않는다. 왜냐하면 생성자와 소멸자가 private이나 protected로 보호되지 않고 public으로 선언되어 있기 때문이다.

한마디로 굳이 CreateInstance()를 사용하지 않고 직접 new나 delete로 생성 및 삭제가 외부에서 가능해지기 때문이다. 



그림 - 싱글턴 기본 예제 1


이렇게 생성자와 소멸자를 private으로 외부에서 접근하지 못하도록 보호를 한다면, 


CSingleton* pTest = new CSingleton();

delete pTest;


위의 코드는 컴파일 단계에서 에러가 날 것이다. private이기 때문에 생성도 할 수 없고, 삭제도 할 수 없기 때문이다.

하지만, 위 처럼 싱글턴을 생성하면 static 객체는 생성의 시점이 명확하게 정의되지 않기 때문에, 다른 전역 객체에서 이를 참조하고자 할 때 생성 순서 때문에 문제가 발생할 수 있다. 그래서 new를 이용하여 생성하는 것이 더 안전해 보인다.


자 이번엔 new를 이용해서 싱글턴을 만들어보자.



위의 방법은 처음에 말했던 조건에 모두 부합한다. 사용하기 위해 CreateInstance()를 하는 순간 생성되고, 원하는 시점에 삭제가 가능하다. 


만약 CreateInstance()가 동시에 여러 곳에서 호출될까봐 무서운 사람은 Singleton 전용 Mutex를 하나 만들어서 사용하는 것도 괜찮은 방법일 것이다.


여기서, 조금 생각 해볼 것은 new로 생성한 인스턴스를 굳이 삭제해야 하는 것이다. 프로그램이 종료되는 시점에는 어차피 new로 생성한 메모리까지 전부 해제가 된다. 따라서, 어차피 생성한 목적이 프로그램 종료시까지 단 하나의 객체가 동작하는 것이라면 그 크기가 어마어마한 것이 아니라면 명시적으로 메모리 해제를 수행할 필요는 없다는 것이다. 하지만, 만약의 상황을 대비해 해제 함수를 하나 만들어 두는게 더 나아 보이긴 하다.... (어려운 작업이 아니니....)



이 싱글턴은 멀티 쓰레드에서는 안전하지 않다... 

728x90

+ Recent posts