블로그 이미지
Every unexpected event is a path to learning for you.

카테고리

분류 전체보기 (2738)
Unity3D (817)
Programming (475)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (58)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (53)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday
05-03 00:02

IME

Programming/Win32API / 2010. 9. 2. 17:07

먼저 IME를 사용하려면 프로젝트에 Imm32.lib를 추가하고, imm.h를 인클루드 해야한다.



IME 메시지

WM_IME_STARTCOMPOSITION 
    IME가 조립 문자열을 만들기 직전에 보냄. WPARAM, LPARAM의 값은 없음. 이 메시지를 DefWindowProc으로
    보내지 않으면 조립윈도우가 나타나지 않는다.

WM_IME_ENDCOMPOSITION
    조립이 끝났다는 통지 메시지. 인수와 리턴값 없음. 커스텀 IME 윈도우를 작성하지 않는다면 무시해도 무방함.

WM_IME_COMPOSITION
    조립 상태가 변경될때마다 보내진다. 
    WPARAM - 조립중의 문자의 코드가 전달, 이 코드는 2byte의 DBCS문자로 조립중인 중간 문자코드이다.
    LPARAM - 조립상태가 어떻게 변경되었는지, 이 문자를 어떻게 처리해야 하는지를 나타내는 플래그의 집합.
                    한글의 경우 다음 두 플래그가 특히 중요함.
                        GCS_COMPSTR : 아직 문자를 조립중이라는 뜻, 즉 아직 한 음절이 완성되지는 않았음.
                        GCS_RESULTSTR : 한 음절을 완전히 조립했다는 뜻.
                    이 플래그들이 있는지 살펴보면 문자가 완성된 것인지, 조립중인지 알 수 있음.

WM_IME_CHAR
    문자 하나가 완성되었을때 보내짐.
    WPARAM - 완성된 문자의 코드가 전달. 1byte만 전달되는 WM_CHAR과는 달리 DBCS일 수 있음.
                     (단, 유니코드 윈도우에서는 WM_CHAR, WM_IME_CHAR 모두 2byte이다.)
    이 메시지를 무시하면 한글 한 문자에 대해 WM_CHAR 메시지를 두번 받게 된다.

WM_IME_SETCONTEXT
    응용프로그램이 활성/비활성화될 때 보내진다. WPARAM이 TRUE이면 활성, FALSE이면 비활성화 되었다는 뜻이다.

WM_IME_NOTIFY
    IME 윈도우가 변경되었다는 통지 메시지이다. WPARAM으로 어떤 변경인지 통보됨.한글 입력, 영문 입력모드를
    변경할 때도 이 메시지가 전달된다.



Input Context 생성, 해제

Input Context(입력 컨텍스트) : IME가 내부적으로 사용하는 구조체이며 조립 문자열, 변환모드, IME 윈도우의 위치 등 IME의 현재 상태에 대한 정보들이 저장됨.


Input Context의 핸들을 얻는 함수

HIMC ImmGetContext(void); 
BOOL ImmReleaseContext(HWND hWnd, HIMC hIMC); 

Input Context를 조작하는 함수

BOOL ImmGetConversionStatus(HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence); 
BOOL ImmSetConversionStatus(HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence); 

    입력모드를 한글로 변환하고 싶으면
ImmSetConversionStatus(hImc, IME_CMODE_NATIVE, IME_SMODE_NONE); 

    입력모드를 영어로 변환하고 싶으면
ImmSetConversionStatus(hImc, 0, IME_SMODE_NONE); 
를 호출하면 된다.

    하지만 시스템이 만드는 Default Input Context는 스레드 내의 모든 윈도우가 공유하기 때문에 한글이나 영문으로 변경시
    모든 입력모드가 통일되게 변경된다. 만약 각각의 컨트롤에서 다른 입력모드를 주고 싶다면 윈도우별로 InputContext를
    생성, 해제하여 연결시키면 된다.


Input Context를 생성, 해제하는 함수

// InputContext를 위한 메모리를 할당하고, 그 핸들을 리턴 HIMC ImmCreateContext(void); 
// 특정 윈도우와 연결 HIMC ImmAssociateContext(HWND hWnd, HIMC hIMC); 
// InputContext를 메모리에서 해제 BOOL ImmDestroyContext(HIMC hIMC); 

    InputContext를 생성, 해제할 경우에는 Pen, Brush를 생성, 해제할때와 같은 방법으로 한다.
 
 
 
 
 
 
 
 
 
---
 
 
IME 활성, 비활성 제어 ( 출처 : http://smilewjp.springnote.com/pages/3182684 )
 

IME 관련 작업을 하다보면 IME의 활성/비활성 상태를 강제로 조정해야할 필요가 생깁니다.

관련 자료를 찾기 위해 인터넷을 검색하다보니 비밀번호나 아이디로 영문만 입력받고자 할때 많이 사용하더군요.

 

저같은 경우에는 중국어 관련해서 사설 IME를 사용하는데 문제가 생겨서 사용했습니다.

사설IME에서 입력을 받으면 안되는 상황에서 입력을 받고있어서 문제가 발생했습니다.

그래서 IME를 비활성 시키는 구문을 찾아서 넣었습니다.

  1. HIMC ImmAssociateContext( HWND hWnd, HIMC hImc );

MSDN의 ImmAssociateContext()를 살펴보면 이 API는 윈도우 별로 입력 컨텍스트를 만들었을때 컨텍스트를

지정하는데 사용할 수 있지만 hImc의 값에 NULL을 줄 경우, 해당 윈도우 창의 IME 포커스를 죽이게 됩니다.

따라서 관련된 IME는 동작하지 않게 되고, 사설 IME역시 동작을 하지 않습니다.

 

하지만 중요하게 알고 있어야 하는것은 ImmAssociateContext()를 할 경우 리턴값으로 기존의 HIMC값이 반환되기 때문에

나중에 사용을 위해서는 저장해 두어야합니다.

  1. void SetActive( BOOL isActive )
    {
       if( isActive )
       {
          // 기존의 값으로 IME를 다시 설정합니다.
          ImmAsscociateContext( hWnd, _oldhImc );
       }
       else
       {
          _oldhImc = ImmAssociateContext( hWnd, NULL );
          // IME를 비활성 시킵니다.
          // _oldhImc는 값을 저장하고 있어야 합니다.
       }
    }

출처 : Tong - race0203님의 C++통

반응형

'Programming > Win32API' 카테고리의 다른 글

Keyboard 입력 받기  (0) 2010.09.03
IME 영문만 입력가능하게 하기  (0) 2010.09.03
getClienteRect 와 getWindowRect  (0) 2010.08.31
mfc, api 의 HINSTANCE 구하기 GetModuleHandle(NULL)  (0) 2010.06.03
Virtual Keys, Standard Set  (0) 2010.04.21
Posted by blueasa
, |

남 몰래 이상한 동영상?을 보고 있거나, 회사에서 상사 몰래 채팅 하다 걸린적이 있는가? 이제는 더이상 걱정 할 필요없다. 단축키 한 방에 자신이 실행하고 있는 프로그램, 윈도우 창을 단 번에 숨겨준다. 
그럼도 참 --; 눈치코치다. 윈도우 창 숨기기 프로그램.


다운받고, 설치 할 필요없이 바로 실행 할 수 있다. 

실행 파일을 실행 하면 알림 창이 뜬다. 기본 단축키는 f8 이다. 마법의 F8.


단축키 변경, 아니면 감추기 대상에 자신이 자주 사용하는 프로그램을 추가 하고 싶을 때, 바탕화면 오른쪽 하단에 눈치코치 아이콘을 더블 클릭한다. 


그러면 감추기 대상, 단축키 변경 하기 싶다. 목록외 다른 프로그램을 추가 하고 싶다면, 지정 프로그램 감추기를 사용하면 된다. 

처음에 F8를 눌러서 안 될 경우, 컨트롤을 체크 하거나, 변경 해 본다. 


그리고 환경설정, 윈도우 시작하면서 자동으로 실행 할지, 그리고 눈치코치 아이콘 마져도 감출 것인지 설정하는 곳이다. 이제는 음지에서 초조한 마음으로 살지말자, 깨끗하고, 밝고, 자신있게 ㅡㅡ^
반응형

'Etc' 카테고리의 다른 글

치킨 명소  (0) 2010.09.09
아이폰4 받고 나서 제일 먼저 할 것들  (0) 2010.09.08
How To Be A Programmer  (0) 2010.08.23
프로세스 선호도 관련 API 함수  (0) 2010.07.20
Metacognition  (0) 2010.07.13
Posted by blueasa
, |

환경 변수

Programming/C# / 2010. 9. 1. 14:04

using System;

public class 환경변수
{
    public static void Main()
    {
         /// 교재 389p
        Console.WriteLine( Environment.SystemDirectory ); //시스템폴더
        Console.WriteLine( Environment.Version ); // 닷넷기준버전:2.0.50727
        Console.WriteLine( Environment.OSVersion ); //운영체제 버전
        Console.WriteLine( Environment.MachineName ); //컴퓨터명
        Console.WriteLine( Environment.UserName ); //사용자명
        Console.WriteLine( Environment.CurrentDirectory ); //현재 폴더
        Console.WriteLine( Environment.GetFolderPath
            (Environment.SpecialFolder.MyDocuments)); //내문서 폴더
    }
}

 

[출처] 환경변수|작성자 앙기

반응형
Posted by blueasa
, |

getWindowRect 은 윈도우 전체 화면에 대한 좌표를 말하며

getClientRect 는 각 핸들에 대한 좌표를 말한다.

 

getWindowRect 사용시

 

cRect.left  화면 좌측에서 핸들 좌측까지의 거리

cRect.right 화면 좌측에서 핸들 우측까지의 거리

cRect.top  화면 위쪽에서 핸들 위쪽까지의 거리

cRect.bottom 화면 위쪽에서 핸들 아래쪽까지의 거리

 

즉. 기준은 화면의 좌측과 위쪽이며, 그 기준에서 핸들의 각 위치까지의 거리를 말한다.

따라서 핸들의 가로 길이는 right - left, 세로 길이는 bottom - top 하면 구할 수 있다.

 

getClientRect 사용시

 

cRect.left  핸들 좌측에서 핸들 좌측까지의 거리

cRect.right 핸들 좌측에서 핸들 우측까지의 거리

cRect.top  핸들 위쪽에서 핸들 위쪽까지의 거리

cRect.bottom 핸들 위쪽에서 핸들 아래쪽까지의 거리

 

기본 개념은 getWindowRect와 같다. 다만 기준 위치가 다를 뿐이다.

기준위치가 핸들의 좌측과 위쪽이므로

cRect.left 와 cRect.top은 항상 0이 된다.

cRect.right 는 핸들의 가로 길이 cRect.bottom은 핸들의 세로 길이가 된다.


출처 : http://maximaro.blog.me/50047243920

반응형

'Programming > Win32API' 카테고리의 다른 글

IME 영문만 입력가능하게 하기  (0) 2010.09.03
IME  (0) 2010.09.02
mfc, api 의 HINSTANCE 구하기 GetModuleHandle(NULL)  (0) 2010.06.03
Virtual Keys, Standard Set  (0) 2010.04.21
Drag & Drop 예제 소스  (0) 2010.04.20
Posted by blueasa
, |
출처 : http://www.gamecode.org/tt/entry/1851

1. 도입

게임을 만드는 데 있어서 높은 프레임 레이트는 모든 프로그래머들의 공통적인 관심사가 아닐까 싶다. 이러한 관심사에 대한 아이디어와 이미 많이 적용되고 있는 것들을 정리하고자 한다.
(사실 제 관심사는 이런 거보단 '어떻게 해야 빨리 개발할 수 있나'입니다만, 항상 실패만 해서... T_T;;)

2. 하드웨어 가속

하드웨어의 발전과 함께 최적화에 대한 접근도 시시각각 변하고 있는 데, 최근 가장 큰 화제는 3차원 가속기를 얼마나 활용하느냐 하는 문제이다.

비디오카드가 최적화된 아키텍처로 렌더링의 많은 부분을 처리해 주면서 얻은 이점 중에 두 가지에 주목할 필요가 있다.

첫 번째로 기존의 CPU에서 해주어야 했던 일거리를 더욱 빠르고 효율적으로 처리해준다는 점이다. 즉 프로젝션, 클리핑등의 일을 CPU보다 GPU에서 더욱 빠르게 수행한다는 얘기다. (GPU가 CPU보다 코어 스피드는 느릴 수도 있지만, 최적화된 메모리 억세스, 다수의 계산 유닛을 통한 병렬적인 계산등을 통해 더 많은, 즉 더 빠른 계산을 하도록 설계되기 때문이다.) 얼마나 많은 일을 CPU가 아닌 GPU가 하느냐가 최적화의 포인트라고 할 수 있다.

두 번째로 병렬성에 있다. 즉, 비디오카드의 GPU와 메인CPU와는 완전히 별개로 수행된다는 점이다. 즉, 비디오카드가 열심히 렌더링하는 시점에도 CPU는 다른 일을 할 수 있다는 점이다. 즉, 비디오카드가 렌더링 할 동안 CPU가 더욱 많은 일을 하는 것이 최적화의 포인트겠고, 비디오카드가 한순간도 쉬지 않고 렌더링 작업을 하는 것이 가장 이상적이라고 할 수 있다. (여담으로 XBOX 개발킷 중에 카르마란 프로파일링 도구를 본 적이 있는 데, 그 툴의 기능은 원하는 타이밍의 프레임에 비디오카드가 idle 이 되는 구간을 - 즉 CPU가 일을 못 주고 혼자 뭔가 연산하는 타이밍 구간- 측정해서 리포트해주는 것이다. 이러한 관점에서 프로그래밍 허점을 찾도록 도와주는 도구인데 하드웨어 성능을 살리는 데 상당히 도움이 될 꺼란 생각이 든다.)

어떻게 해야 더욱 빠르게 렌더링 되느냐 같은 문제는 다음 글에서 다루기로 하고, 더 이상 렌더링 속도를 개선할 수 없는 상황이라고 가정하면, 위의 두 가지가 그것을 극복할 수 있는 방법이 될 것이다.

첫 번째의 경우에는 사실상 최적화할 수 있는 부분이 정해져 있기 때문에 [1], 하드웨어의 T&L과정을 완전히 GPU에 넘긴 후라면, 연산을 GPU로 넘긴다는 관점에서는 더 이상 해줄 수 있는 것이 없다.

하지만, 두 번째의 경우에는 특별한 무언가만 해준다면 쉽게 큰 효과를 얻을 수도 있는 데, 차근 차근 생각해보도록 하자.

3. 일반적인 CPU 와 GPU 의 작업 타이밍

메인 루핑은 렌더링과 전혀 상관없는 _process() 와 렌더링만 하는 _display() 함수로 구분해보자. (만약 인공지능 루틴 등에 렌더링 루틴이 삽입되어 있다면 원하는 대로 렌더링 배치를 하기가 힘드므로, 여기서 얘기하는 것을 적용하기는 쉽지 않다.)

만약 이와 같은 구성이라면 일반적인 프로세스의 처리 그래프는 [그림3.1]과 같을 것이다.


(그림 3.1)

간단히 그림을 살펴보면 먼저 process 가 수행되는 동안에는 GPU가 놀고 있다. 그러다. DISPLAY 가 시작되면 본격적으로 GPU 가 활동하게 된다. DISPLAY 루틴 상 부하가 있다면 위처럼 비디오 카드가 놀고 있는 타이밍이 있을 수 있다. 그리고 DISPLAY 루틴이 끝나는 지점 -일반적으로 flip 을 하거나 present 를 하는 순간- 부터 CPU는 비디오카드의 내부 큐(리스트)에 있는 작업들이 끝날 때까지 대기를 한다. (파란색 선 사이가 한 프레임을 나타낸다.)

[그림3.1]의 모양은 나타내는 프로그램은 비효율적으로 프로그래밍을 한 것이다. 하나씩 체크해보면서 이 구성을 최적화해서 비디오카드가 전혀 쉬지 않고 작동할 수 있도록 구성해본다.

4. 렌더링 루틴과 타이밍의 관계

먼저, GPU의 타이밍에 대해서 확인하고 넘어가자.


(그림 4.1)

[그림4.1]과 같은 경우를 생각해본다. CPU에서 매트릭스 트랜스폼하는 시간을 1 이라고 표시했다. A라는 오브젝트를 DrawPrimitive 하게 되면 거의 딜레이 없이 CPU에게 프로세스가 넘어오며, 그와  동시에 CPU와는 별개로 GPU는 렌더링을 한다. 여기서 CPU는 다시 매트릭스 트랜스폼 등의 과정을 거친후에 B 오프젝트를 렌더링하게 되며 GPU는 B를 렌더링 하게 된다.
여기서 관심있게 볼 것은 A보다 B의 오브젝트가 폴리곤이나 렌더링 부하가 더 많다고 가정했지만 DrawPrimitive 호출후 CPU에 프로세스 권한이 넘어오는 타이밍은 A나 B나 비슷하다는 것이다. GPU에게 명령을 주는 것은 폴리곤 수에 따라 하는 일에 큰 차이가 없다는 얘기다.

여기서 눈에 띄는 부분은 GPU가 A의 렌더링을 끝내고 대기하는 타이밍이다.
만약 B를 먼저 렌더링 한다면 어떻게 될까 ?


(그림4.2)

[그림4.2]처럼 된다. 즉 A의 작업은 비디오카드의 큐에 추가되고 비디오카드는 B의 렌더링이 끝나는 시점에 A를 렌더링하게 된다.

단순히 렌더링 타이밍에 맞춰서 배치만 조절해도 GPU가 대기하는 시간을 제거할 수 있다는 얘기다. 물론 위의 예처럼 GPU 타임을 예측해서 배치하는 것은 불가능하지만, [그림 4.3]처럼 단지 GPU가 부담을 느끼는 일을 먼저 던져준다면 별다른 처리 없이도 어느 정도의 효과를 얻을 수 있다.


(그림 4.3)

특히 CPU의 부담이 생길 수밖에 없는 배경 렌더링의 경우에는 배경 렌더링하기 전에 적절히 GPU에게 (좀 부담스러운 녀석으로) 할 일을 준다면 효과를 볼 수 있을 것이다. 항상 위의 그래프처럼 향상될 수도 있다는 얘기는 아니지만, 그렇지 않더라도 완충 효과를 줄 수 있어 대기 상태가 나타날 확률을 훨씬 줄일 수 있다. (배경보다 먼저 렌더링해도 전체적인 필레이트에 변화가 적다면 절대 손해 안보는 장사가 될 것이다. - 저라면 작게 렌더링 되면서, 폴리곤이 많은 녀석을 제물로 삼겠습니다.)

다만, 고려해야 할 것은 비디오의 큐 메모리도 한계가 있다는 것이다.
렌더링 타임이 긴 것들을 연속으로 넘기면 뒤의 처리들이 계속 큐게 쌓여서, 큐의 한계까지 차버리게 되는 데, 이 경우 큐에 넣기 위해 대기하는 시간이 생길 수 있다. (큐를 빨리 비우는 방법은 렌더링 타임이 작은 오브젝트를 찍는 것이므로 대기 시간이 안 생기고 큐에 무리를 주지 않는 범위에서 매니징을 해야 한다.)

한가지 주의할 것은 여기서 얘기하는 것은 순수하게 하드웨어의 힘으로 렌더링을 하는 경우여야 효과를 발휘할 수 있다는 점이다. 아닐 경우에는 GPU가 렌더링하는 시간이나 CPU가 처리하는 시간이나 비슷해져서 어떻게 해도 큰 차이가 없게 된다.

5. 최종 렌더링 타이밍

렌더링시 부하가 될만한 부분을 분리하여 구현하고 배치가 적절히 되었다면 [그림 5.1]처럼 나타낼 수 있다.


(그림 5.1)

한가지 짚고 넘어가면 보통 DISPLAY의 마지막에 호출되는 present나 flip 관련함수는 GPU 가 끝나기 전에 프로세스 권한을 넘겨주지 않는다. 즉 해당 함수에서는 큐가 빌 때까지 딜레이가 생기는 것이다. 실제로 DrawPrimitive 는 대부분 내부 큐에 렌더링할 꺼리를 쌓는 역할을 할 뿐이고 최종적으로 렌더링이 끝나는 것은 present 를 수행한 뒤가 된다.
(흔히 비 경험자들은 "프로파일링을 했더니 present함수가 가장 느리다." 라고 오해하기도 하는 데, 이는 직접적으로 present 함수의 부하가 아니므로 present 함수가 느리다고 생각하는 것은 적절한 판단은 아니다.)

인공지능, 물리학 등의 처리가 늘어날수록 process의 비중이 커져서 위의 구성으로는 GPU가 대기하는 시간이 비례해서 늘어나게 된다. 물론 위와 같이 배치하지 않고 렌더링 루틴 사이에 인공지능루틴들을 잘 넣으면, GPU가 대기하는 타이밍을 줄일 수도 있겠지만, 일정하게 효율을 얻기는 힘들기 때문에 추천하기는 어렵다.

결론부터 말하면 present 호출 후에 렌더링이 끝날 때까지 대기하는 시간에 CPU가 놀지 않고 다음 프레임의 process 를 실행하는 방법으로 이 문제를 해결할 수 있다.

#include <stdio.h>
#include <windows.h>

void _process()
{
   static int cnt=0;
   printf("process(%d)n", cnt++);
   Sleep(500); // process 부하
}

void _flip()
{
   Sleep(500); // flip 후 대기
}

void _display()
{
   static int cnt=0;
   static int time = timeGetTime();

   int delta = timeGetTime() - time;
   time += delta;

   printf("tdisplay (%d) %dn", cnt++, delta);
   Sleep(500); // 렌더링 명령

   _flip();
}

void main()
{
   int i;
   for(i=0; i<10; i++) {
       _process();
       _display();
   }
}

이해를 돕기 위해 가상적으로 위와 같은 파일을 구성해 봤다. 일반적인 구성을 만들어 본 것으로 process 가 500 ms, display 가 1000ms 의 부하를 가진다고 가정했다. (display는 500ms는 렌더링 명령하는 데 소비하는 시간, 500ms는 대기하는 시간이라고 가정했다.) 이를 실행해보면 다음과 같은 결과가 나온다.

process(0)
       display (0) 0
process(1)
       display (1) 1501
process(2)
       display (2) 1501
process(3)
       display (3) 1500
process(4)
       display (4) 1501

즉, _process와 _display에서 각 500ms, 1000ms 를 잡아먹기 때문에 한 프레임은 1500ms가 소요된다. 일반적인 경우라면 이 타이밍을 줄일 수는 없지만 [그림5.1]과 같다고 가정해보면 방법이 생긴다. 즉, _display의 렌더링 시간 중에 대기하는 시간에 다음 프레임의 _process 작업을 하는 것이다. 이 처리를 아래처럼 동기화 객체[2][3]를 이용하여 아래처럼 구현했다.

#include <stdio.h>
#include <windows.h>

HANDLE    g_hFlip, g_hRenderScene;

void _process()
{
   static int cnt=0;
   printf("process(%d)n", cnt++);
   Sleep(500);
}

void _flip()
{
   Sleep(500);
}

int g_done = 1;

DWORD WINAPI _flipper(void * ptr)
{
   WaitForSingleObjectEx(g_hFlip, INFINITE, FALSE);
   while(g_done) {
       _flip();
       SetEvent(g_hRenderScene);
       WaitForSingleObjectEx(g_hFlip, INFINITE, FALSE);
   }
   return 0;
}

void _display()
{
   static int cnt=0;
   static int time = timeGetTime();

   WaitForSingleObjectEx(g_hRenderScene, INFINITE, FALSE);

   int delta = timeGetTime() - time;
   time += delta;

   printf("tdisplay (%d) %dn", cnt++, delta);

   Sleep(500);

   SetEvent(g_hFlip);
}

void main()
{
   DWORD threadid;
   int i;

   g_hFlip = CreateEvent(NULL, FALSE, FALSE, NULL);
   g_hRenderScene = CreateEvent(NULL, FALSE, TRUE, NULL);

   CreateThread(NULL, 0, _flipper, 0, 0, &threadid);

   for(i=0; i<5; i++) {
       _process();
       _display();
   }

   CloseHandle(g_hFlip);
   CloseHandle(g_hRenderScene);
}

플리핑 함수만 처리하는 쓰레드를 두어서 이벤트 객체 g_hFlip로 _flip 을 컨트롤한다. 즉 처음엔 대기하다가 시그널을 주면 flip 함수를 실행하고 flip을 마친후엔 다음 시그널이 들어올때까지 블럭되어 대기하게 된다. 즉 _flip 함수 호출은 시그널을 주는 것으로 대체된다.
렌더링이 다되기도 전에 다음 프레임 렌더링하는 것을 방지하기 위해 g_hRenderScene 이벤트 객체를 두어서 흐름을 조정했다.

결과는 아래와 같다.

process(0)
       display (0) 0
process(1)
       display (1) 1001
process(2)
       display (2) 1001
process(3)
       display (3) 1002
process(4)
       display (4) 1001

즉 같은 내용을 실행하지만 전체적인 실행 간격을 줄일 수 있다는 얘기다.

보통 GPU 렌더링으로 대기하는 시간보다 process 시간이 작다면 이상적으로 GPU는 쉬지 않고 렌더링을 하게 되고, 최적의 프레임으로 렌더링이 가능해진다.

6. 결론

단순히 프레임을 극대화하는 방법은 아니지만, 물리학처리의 과부하, 네트워크 처리, 스크립트 호출 등으로 인한 불규칙한 프레임 저하에 좀 더 유연하도록 처리할 수 있고, 세세한 루틴 최적화에 대한 부담도 줄일 수 있다. (렌더링에 CPU가 관여하는 시간을 최소화했다면 최적화의 의미가 없을 수도 있겠다. - 물론 PC 플렛폼에서는 모든 하드웨어를 고려해야하기 때문에 생각하기 힘들지만...)

아주 기본적인 관계만을 고려한 것이지만 GPU를 최대한 활용하는 상황이라며 효율을 크게 높일 수 있는 방법이다.
점차 게임에서 처리하는 그래픽처리 규모나, 처리할 인공지능이나 물리학의 비중이 커지는 상황에서는 반드시 고려해야할 처리라고 생각된다.

(동기화 객체를 잘 이용한다면 프레임의 저하 없이 비동기적으로 리소스 로딩하는 루틴에도 활용할 수 있을 거 같네요. - 대기시간의 다음 프레임의 process 처리하고 남는 시간까지 활용해서...)

7. REFERENCE

[1] DirectX 9 Performance
   http://mirror.ati.com/developer/gdc/D3DTutorial3_Pipeline_Performance.pdf

[2] Win32 Multithreading and Synchronization
   http://blacksun.box.sk/tutorials.php/id/150

[3] Siberschatz. Operating System Concepts 6nd edition, chapter 7, WILREY, 2003


출처 : http://www.gamecode.org/tt/entry/1851
반응형
Posted by blueasa
, |

TLS - Thread Local Storage [ 펌 http://purewell.egloos.com/3398289]
쓰레드를 돌리다보면 해당 쓰레드에서만 유효한 변수를 만들고 싶을 때가 있다. 그럴 때 어떻게 해야할까? 쓰레드 개수만큼 벡터를 잡고, 해당 쓰레드마다 벡터 인덱스를 넘겨주는 것도 나름 방법이지만, 이러한 경우를 위해 TLS라는 것이 존재한다. 축약처럼 쓰레드 안에서만 따로 스토리지를 할당한 것인데, 일반 프로세스의 스텍과 비슷하나 그 크기는 프로세스 것보다 당연히 작고 제약이 심한 편이다. 뭐 암튼 그런게 있다고 치자.

* GCC 메뉴얼 보면 TLS가 아니라 TSD(Thread Storage Duration)이라고 표현하였는데 대충 같은 말이다.

이것을 위해 POSIX는 pthread_key_create, pthread_get/setspecific 등 함수를 마련해놨지만 눈만 팽글팽글 돌고, 소스만 지저분해져 보일 것 같다. 귀찮으면 C99, C++98 표준 __thread 키워드를 사용하자. MSDN에 보니 __thread가 없어 보인다. 이가 없으면 잇몸으로라도...
#define __thread __declspec( thread )
대충 이 정도면 될 듯하다. 자자 각설하고, __thread란 키워드는 TLS에 변수를 선언해주는 일을 한다. 위에 나열한 pthread_* 함수를 호출하는 것으로 컴파일러가 대신 해석해주는 것일 수도 있으나 이건 가정이므로 넘어가고. 사용에 주의해야할 점은 아래와 같다. (대충대충 표준하고 MSDN 보면서 정리한 것임)
  1. 글로벌 변수나 static 변수에만 사용 가능하다.
    - function 안에 local 변수가 static이 아니라면 뭐더게 TLS에 저장할까? 당연히 그럴 필요가 없기 때문에 저런 제약이 있는 것이다. 이는 class에서 멤버 변수에도 적용한 법칙이다. static으로 선언한 멤버 변수에만 저 키워드를 사용할 수 있다.
  2. SO(DLL)과 로컬 영역을 넘나들면 뻑난다.
    - ... 그러니까 쓰지마라. 왜?
  3. 타입에 대한 한정자로 사용이 불가능하다.
    - const처럼 쓰지 말라는 것이고, 무조건 타입 앞에 붙이란 말이다. (VC에만 해당)
  4. 객체 이름과 이름 없는 객체에만 쓸 수 있다.
  5. 앞에 붙을 수 있는 건 static과 extern 뿐이다.
  6. 클래스 자체를 TLS에 넣을 때는 생성자와 소멸자가 없어야 한다.
역시나 예가 없으면 아무 것도 할 수 없는 나를 위하여~*
#include <iostream>
using namespace std;

__thread int gTest1;      // 성공

__thread void func(void); // 실패

void
func(__thread int lTest2) // 실패
{
}

class A
{
    static __thread int mTest3;   // 성공
    __thread int mTest4;          // 실패
};

int
func(void)
{
    static __thread int lTest5; // 성공
    __thread int lTest6;   // 실패
}

__thread union
{
    int i;
    char p[sizeof(int)];
} gTest7;   // 성공

__thread struct
{
    int i;
    char p[sizeof(int)];
} gTest8;   // 성공

class MyClass
{
public:
    int i;
    MyClass() i(0) {}
};

__thread MyClass cTest9; // 실패

int __thread * gTest9; // gcc 성공

int
main(int,char**)
{
    return 0;
}
나머진 시간 나는대로 정리하도록 해야겠다.


출처 : http://blog.naver.com/kkan22?Redirect=Log&logNo=80057856857
반응형

'Programming > C/C++' 카테고리의 다른 글

GameLoop (번역)  (0) 2010.09.16
IME 관련  (0) 2010.09.10
TCHAR을쓰면 바뀌는 함수들  (0) 2010.07.27
TCHAR printf  (0) 2010.07.12
A * pA = new B 과 B * pB = new B의 차이점.  (0) 2010.06.21
Posted by blueasa
, |
반응형
Posted by blueasa
, |

/FIXED[:NO]

설명

/FIXED 옵션을 사용하면 운영 체제에서는 기본 설정 기준 주소에서만 프로그램을 로드하게 됩니다. 기본 설정 기준 주소를 사용할 수 없으면 파일이 로드되지 않습니다. 자세한 내용은 /BASE(기준 주소)를 참조하십시오.

기본적으로 DLL을 빌드할 때는 /FIXED:NO가 기본값이 되고 다른 모든 프로젝트 형식에 대해서는 /FIXED가 기본값이 됩니다.

/FIXED를 지정하면 LINK에서는 프로그램에 재배치 섹션을 생성하지 않습니다. 런타임에 운영 체제가 해당 주소에서 프로그램을 로드할 수 없으면 오류 메시지가 표시되며 프로그램은 로드되지 않습니다.

프로그램에 재배치 섹션을 생성하려면 /FIXED:NO를 지정합니다.

Windows NT용 장치 드라이버를 빌드할 때는 /FIXED를 사용하지 마십시오.

Visual Studio 개발 환경에서 이 링커 옵션을 설정하려면

  1. 프로젝트의 속성 페이지 대화 상자를 엽니다. 자세한 내용은 Visual C++ 프로젝트 속성 설정을 참조하십시오.

  2. 링커 폴더를 클릭합니다.

  3. 명령줄 속성 페이지를 클릭합니다.

  4. 추가 옵션 상자에 옵션을 입력합니다.

프로그래밍 방식으로 이 링커 옵션을 설정하려면

반응형
Posted by blueasa
, |

/FORCE:[MULTIPLE|UNRESOLVED]

설명

/FORCE 옵션을 사용하면 링커에서는 기호가 참조되어 있지만 정의되어 있지 않은 경우나 여러 번 정의되어 있는 경우에도 올바른 .exe 파일 또는 DLL을 만듭니다.

/FORCE 옵션에는 다음과 같이 선택적 인수를 사용할 수 있습니다.

  • /FORCE:MULTIPLE을 사용하면 LINK에서 기호에 대한 정의를 하나 이상 찾더라도 출력 파일을 만들 수 있습니다.

  • /FORCE:UNRESOLVED를 사용하면 LINK에서 정의되지 않은 기호를 찾더라도 출력 파일을 만들 수 있습니다. 진입점 기호가 확인되지 않으면 /FORCE:UNRESOLVED는 무시됩니다.

/FORCE에 인수를 사용하지 않으면 MULTIPLE과 UNRESOLVED를 모두 의미합니다.

이 옵션을 사용하여 만든 파일이 예상대로 실행되지 않을 수도 있습니다. 링커에서는 /FORCE 옵션이 지정된 경우 증분 링크를 수행하지 않기 때문입니다.

/clr를 사용하여 모듈을 컴파일하는 경우 /FORCE를 지정해도 이미지가 생성되지 않습니다.

Visual Studio 개발 환경에서 이 링커 옵션을 설정하려면

  1. 프로젝트의 속성 페이지 대화 상자를 엽니다. 자세한 내용은 Visual C++ 프로젝트 속성 설정을 참조하십시오.

  2. 링커 폴더를 클릭합니다.

  3. 명령줄 속성 페이지를 클릭합니다.

  4. 추가 옵션 상자에 옵션을 입력합니다.

프로그래밍 방식으로 이 링커 옵션을 설정하려면

반응형
Posted by blueasa
, |

How To Be A Programmer

Etc / 2010. 8. 23. 19:31
반응형
Posted by blueasa
, |