2. SVN 저장소의 hooks디렉토리에 다음에 나오는 배치 명령이 들어있는 post commit hook 파일 생성(C:\Repository\hooks\post-commit.bat). SVN이 commit되는 동안에 Mantis에 이슈노트로 추가될 내용들을 넣습니다. REM Post-commit hook for MantisBT integration SET REPOS=%1 SET REV=%2 SET DETAILS_FILE=C:\Repository\GNIS4M\svnfile_%REV% SET LOG_FILE=C:\Repository\GNIS4M\svnfile_%REV%_Log
스피드 트리의 dll과 OpenAL및 ogg관련 dll들이 보인다. 98계열의 유니코드를 위한 uncows.dll도 보이고 vc관련 dll들을 봤을때 vc2003으로 개발되었다는 걸 알 수 있다. freetype은 찾을 수 없는걸 봐서는 일반 텍스트는 dx출력을 사용하고 캐릭터 이름의 경우 별도의 이미지 프로세싱을 거치는것 같다.
- 폰트구성
꽤 많은 양의 폰트가 보인다. 돈이 많은 회사이니 구매를 했다고 해도 이상하지 않긴 하지만.. 폰트가 한 회사의 것이 아니라 여러회사의 폰트들로 구성되있는건 의문이 간다.
- 패치 시스템
패치시스템으로 RTPatch를 사용하고 있다. 메틴2이후로는 오랜만에 보는것 같다.
- 스크립트 시스템
자세히 보면 <USERNAME>과 같은 형태로 키워드 대치가 가능하다. 그리고 텍스트의 중간에 칼라등을 지정하는 기능도 보인다.
Q라고 되어있는건 퀘스트 관련으로 보인다. 처음엔 질문형 스크립트라고 생각했는데.. 퀘스트외의 형태는 보이지 않는걸 봐선느 퀘스트용으로만 사용하는것 같다. 실제로 처음에 위치안내를 해주는 부분이 스크립트 구성이 안보이는걸 봐서는 일반 질문지는 따로 처리하는것 같다. <Q index="1368" value="받아다 준다." quest="2"/> 같은 형태로 되어있는데 value는 출력되는 내용이고 index는 선택했을때 나올 다음 스크립트 번호이다. quest는 퀘스트 번호와 연결되는것 같다.
위에서 내용을 선택하면 다음과 같이 다음 스크립트로 연결되는것 같다.
- 쉐이더
쉐이더는 cg와 hlsl이 보인다. cgc.exe로 된 컴파일러가 같이 있다. 실제 파일을 열어보면 컴파일 되어 있지 않는 소스형태로 구성되어 있다. cg와 hlsl 두개가 있는건 각각 다른 개발자가 개발했거나.. 언리얼엔진에서 cg형태로 제공된걸 사용하고 hlsl만 따로 개발한것일지도 모르겠다.
- 스크린샷
스크린샷은 bmp형태로 제공된다. 처음에 스크린샷 폴더를 한참 찾았는데 안보이길래 안쪽을 뒤져보니 시스템 파일이 있는 폴더에 들어가 있었다..;; 다..당황스러운 내용이다..; 참 성의 없다..;;;
- ui
ui이미지 파일들이 그냥 있어서 쉽게 볼 수 있다. tga에 bmp를 사용하고 있고 아이콘들은 dds를 사용하고 있다.
ui구성은 xml파일로 되어 있다.
대략 이런 형태이다. 창하나가 하나의 파일로 구성되는 듯 하다. 파일에 주석들이 있는걸로 봐서는 별도의 에디터같은 형태는 없고 수작업을 하는 모양이다..; 별도의 이벤트 관련 내용이 보이지 않는다. 이벤트 설치는 소스에서 하던가 클릭에 대한 이벤트만 처리가 되는걸지도 모르겠다.
- 그래픽 분석
- 물표현
물은 일반 애니텍스쳐와 파도가 밀려오는 이펙트로 구성되어 있다.
보이는 것처럼 물가쪽은 투명한 걸 알 수 있다. 카메라 시점 깊이값 체크는 아니고 지형과의 높이차로 투명도를 계산하고 있다.
그 결과로 위 스샷같은 현상이 생긴다. 지형이 안보이면 물이 보이는게 아니라 그냥 비어있게 된다. 물의 시야거리와 지형의 시야거리가 달라서 생기는 현상이다.
- 물속환경
물속에 들어갔을때 fog의 색을 조절해주는 기능이 있다. 하지만 카메라가 물안에 있을때가 아닌 캐릭터가 일정 깊이에 있을때로 구현되어 있어서 버그처럼 보인다.
- 지형체크
이정도의 경사도 가뿐하게 올라간다.
- 그림자
그림자의 경우 high로 놔도 퀄리티가 높은편이 아니며 다른 크리쳐의 경우 상당히 거리가 짧다. 그림자 텍스쳐를 너무 아끼는 것 같다.
- 그래픽 옵션
대략 이런 내용들로 구성되어 있다.
- 배경사물 표현
두 스샷의 차이로 봤을때는 풀외에는 변화가 없다. 풀의 경우 별도의 풀엔진이 있는것 같지 않고 오브젝트 속성에 옵션처리여부가 들어있는것 같다.
- 지형오브젝트 처리
보이는것처럼 오브젝트위에 올라갈 수 있는데. 테스트 결과 밟을수 있는 속성이 따로 있지 않고 폴리곤이 있으면 아무데나 올라가진다.
- IK
보이는것처럼 IK는 구현되어 있지 않다..;
- 캐릭터 폴리곤
옷 안쪽의 피부가 보인다. 보통은 옷 안의 피부는 만들지 않는데.. 분절방식이 몸과 옷이 분리되어 있거나 아니면? 흐음..
- 오브젝트 출현 연출
위의 스샷과 같이 포그색으로 변하면서 사라지거나 나타난다. 하지만 지형과 오브젝트의 시야거리가 따로 처리되서 좀 이상해 보이기도 한다.
- 오브젝트 시야처리
카메라를 돌릴때 가운데의 나무가 사라졌다 보였다 한다. 하지만 다음 스샷들을 살펴보면 이상한걸 알 수 있다.
자세히 보면 눈치챘겠지만 카메라거리를 조절해도 오브젝트에는 영향이 없다. 이걸로 봤을때 카메라의 위치가 아닌 캐릭터의 위치를 기준으로 판단함을 알 수 있다. 하지만 위에서는 카메라를 회전했을때 오브젝트가 보였다 안보였다 한걸 생각해서는 캐릭터위치를 기준으로 반경이 아닌 평면거리값으로 거리 계산을 한다..라는 이상한 결론이 나온다.
- 지형표현
기본적인 스플래팅형태로 보이고 텍스쳐의 퀄리티는 보통수준이다. 지형에 스페큘러 효과는 보이지 않았다.
- 라이트맵
보이는것처럼 라이트맵의 퀄리티는 꽤 높은 편이다. 하지만 마을 안쪽에만이고 필드쪽에는 라이트맵이 보이지 않는다.
- 카메라 충돌
카메라충돌은 와우형태의 일반오브젝트도 모두 충돌한다. 저위에 레벨오브젝트에서도 말했지만 일반 오브젝트와 레벨오브젝트의 구분이 없기 때문일 수도 있다.
- 플레어 아쉽게도 스샷이 없다. 밤에 달이 보일때 빛이 번지는 형태의 플레어 이펙트를 출력해주는데. 오브젝트에 가리면 출력되지 않는 기능이 구현되있다. 다만 보간이 되지 않아서 깜빡거리는것처럼 보이기도 한다.
머 전체적으로는 특별히 눈에 띄는 내용은 수영과 점프로 아무데나 올라갈 수 있다와 다양한 페이셜 연출... 말고는 특별한건 보이지 않았다. 다만 생각보다 메모리 사용량이 많지 않았다.
파일이 패킹되어 있지 않아서 분석하기는 좋았지만... 혹시 오베까지 저렇게 내용이 오픈되어있는 상태로 가면 좀 문제가 있겠다..;
평가는 첫 클베치고는 괜찮았다..라고도 생각되지만 개발기간과 언리얼2.x를 생각할때는 생각보다 별로.. 라고도 생각된다.
우선 Win32 API 의 경우 CloseHandle() 을 이용해서 파일 핸들을 닫았다고 해서 실제로 disk 에 write 되는것은 아니다. CloseHandle() 이 flush 를 해줄것이라고 생각할지도 모르겠지만 CloseHandle 한다고 해서 file 이 flush 된다는 얘기는 MSDN 어디에서도 찾아볼 수 없다. 실제로도 CloseHandle() 만으로는 물리적으로 disk 에 write 되지 않고 단지 캐쉬에 write 저장될 뿐이다. 다시 open 해보면 변경된 내역을 확인이 가능한것처럼 보이겠지만 그것은 write/close/open/read 가 모두 OS 의 디스크 캐쉬상에서 이루어 졌기 때문이다. CloseHandle() 후에 PC 코드를 뽑았다 다시 부팅해서 읽게 되면.. 운이 나쁘면 뒤의 일부분은 write 되지 않는것을 발견할 수 있을 것이다.
그렇다면 Win32 에서 데이터가 원하는 시점에 disk 에 기록되게 하려면 어떻게 해야하느냐? 방법은 FlushFileBuffers() 를 명시적으로 호출 해 주는 것이다. 여전히 CloseHandle() 과는 별개라는것을 주의 할것. CloseHandle() 은 내부적으로 FlushFileBuffers() 를 호출하지 않는다.
이제 CRT 의 경우를 살펴보자. CRT 의 fflush() 가 disk 에 write 해주는것 아니었냐고? 안타깝게도 대답은 'No' 이다. CRT 의 fopen()/fwrite()/fclose() 들은 내부적으로 FILE 단위의 버퍼링을 가지고 있으며 fflush() 는 그 버퍼링을 flush 해주는 것일 뿐이다. 그러니까 CRT 에서 fflush() 를 호출하게 되면 FlushFileBuffers() 가 호출되는게 아니라 그동안 쌓여있던 데이터를 그냥 WriteFile() - UNIX 계열에서는 write() - 해 줄 뿐이다. 결국 여전히 데이터가 OS 의 디스크 캐쉬에만 기록되고 물리적으로는 기록되지 않을 가능성이 남아있게 된다. system-call 로 구현될 수 밖에 없는 CRT 의 특성상 이는 모든 OS 에서도 일어날 수 있는 증상이다.
그래서 M$ 의 경우 fopen()/fflush() 의 extension 을 제공한다. 물론 이것은 표준이 아니다. 사용법은 간단한데 fopen() 시에 'c' 플래그를 추가하게 되면 fflush() 시에 FlushFileBuffers() 가 추가적으로 호출된다.물론 여기서도 fclose() 만으로는 물리적인 기록을 기대할 수 없다.
정리해보면, Win32 의 경우 disk 에 저장될 것이라 기대할 수 있는 코드는 다음 두가지다.
위의 코드를 수행해 보고 HDD 램프를 지켜보라. 간헐적으로 깜빡일 것이다. fclose() 만으로는 실제 disk 에 기록이 되지 않는다는 얘기다. #2 의 주석을 제거해도 마찬가지다. "wb" 옵션을 "wbc" 로 바꾸고 #2 의 주석을 제거해야 비로소 HDD 램프가 미친듯이 깜빡이고 시스템이 엄청나게 느려지는것을 확인할 수 있을 것이다. Win32 API 도 마찬가지.
어찌보면 사소한 문제로 보일수도 있지만 어플리케이션의 업데이트 루틴을 작성하는 사람이라면 꼭 알아두어야 한다. 유저가 수만명 단위로 늘어나게 되면, 분명히 발생하기 때문이다. 나역시 직접 당해보기 전까지는 fflush() 를 하고 파일 핸들을 닫으면 당연히 disk 에 저장 될거라고 알고 있었기 때문에 이것을 알아내는데에 고생을 좀 했다. 부디 이 포스팅을 읽는 분들은 같은 삽질을 하지 마시길...
Managed textures (also known as "automatic texture management") have been available in DirectX since version 6, with several revisions and enhancements made in subsequent releases. As of the Direct3D 9 API, the automatic resource management includes support for textures, vertex buffers, and index buffers all with a consistent shared interface. By using the Direct3D resource manager, applications can greatly simplify the handling of lost-device situations and can rely on the system to handle a reasonable amount of over-commitment of video memory resources.
Managed texture("자동 texture 관리"라고 알려진)는 DirectX 버젼 6이후로 사용 가능했으며, 여러 번의 리비젼과 개선을 거쳤다. Direct3D 9 API에 이르러서 자동 리소스 관리(Automatic resource management)는 texture, 공유된 interface(consistent shared interface)로 구성된 vertex buffer, index buffer 지원을 포함하고 있다. Direct3D의 리소스 관리자를 사용함으로써, 응용프로그램은 lost-device 상황을 매우 간단히 다룰 수 있고, 비디오 메모리 리소스의 over-commitment의 적당한 양을 다루는 것을 시스템에 의존할 수 있다.
Developers sometimes have difficulties using managed resources, in part due to the abstract nature of the system. While many common scenarios for resources are a good fit for managed resources, some cases are more performant using unmanaged resources. This article will discuss best practices for dealing with resources generally, how managed and unmanaged resources behave, and provide some detail on how resources are typically handled by the runtime and drivers.
개발자는 때때로 시스템의 숨겨진 특징 때문에 managed 리소스를 사용하는데 어려움을 가진다. 일반적인 많은 경우가 managed 리소스를 사용하는 것이 더 좋을 테지만, 어떤 경우는 unmanaged 리소스를 사용하는 것이 더 성능에 좋을 수 있다. 이글은 일반적으로 어떻게 managed와 unmanaged 리소스가 행동하는지에 대한 최고 Practice를 제공하고 실행시간에 드라이버에 의해 리소스가 어떻게 다루어지는 지에 대한 자세한 내용을 제공할 것이다.
In order for the video system to make use of a resource, it must be located in memory accessible to the GPU. Local video memory is the most performant for the GPU, and certain resources (such as render targets and depth/stencil buffers) must be located in local video memory. With the advent of AGP, the GPU can also access a portion of the system memory directly. This memory area, known as the AGP aperture, is referred to as 'non-local video memory' and is not available for other purposes. Non-local video memory can be read from and written to by the CPU, which typically has no high-performance access to local video memory, and is thus ideal for use as a shared memory resource. A key thing to remember about AGP memory is that it, like local video memory, is invalidated in lost-device situations and persistent assets located there must be restored.
비디오 시스템이 리소스를 사용하기 위해서, 그 리소스는 GPU가 접근 가능한 데 위치해야만 한다. Local video memory는 GPU가 가장 빨리 접근할 수 있고, 어떤 리소스(Render target, depth/stencil buffer)는 local video memory에 위치해야 하는 것도 있다. AGP의 출현과 함께 GPU는 시스템 메모리의 일부를 직접 접근할 수 있게 되었다. 이 메모리 영역은 AGP aperture라고 알려져 있으며 'non-local video memory'로 참조되어 진다. 이것은 다른 용도로 사용되어 질 수 없다. Non-local video memory는 local video memory에 빠른 속도로 접근할 수 없는 CPU에 의해 읽혀지고, 쓰여질 수 있으며 공유 메모리 리소스로써 이상적으로 사용되어 질 수 있다. AGP 메모리에 대해 기억해 두어야할 중요한 것은 local video memory와 같이 lost-device 상황에서는 무효화되어진다는 것과 유지되어져야 할 자원 있는 위치에 되돌려져야 한다는 것이다.
Some integrated video solutions make use of a Unified Memory Architecture where main memory is addressable by all components of the systems. Direct3D supports UMA without requiring any change to the application, utilizing the same hints as for local video memory configurations. For such systems, resources are always located in system memory and the driver is responsible for ensuring resources work much like they do in a more traditional architecture while taking advantage of UMA's properties and any specific behavior of the hardware implementation.
일부 Unifed Memory Architecture를 사용하는 통합 비디오 솔루션은 메인 메모리가 시스템의 모든 부분에 의해 접근할 수 있다. Direct3D는 응용프로그램의 어떤 변화없이, local video memory 구성에 대한 그런 정보없이 UMA를 사용할 수 있다. 그러한 시스템에서 리소스는 항상 시스템 메모리에 위치하고 있고, 드라이버는 리소스가 UMA의 특성과 하드웨어 구현 방식의 잇점을 활용하는 동안 기존의 전통적인 Architecture(통합되어 있지 않은 구조)와 상당히 유사하게 동작하도록 보장해주는 책임을 가지고 있다.
Managed Resources
The majority of your resources should be created as managed resources in POOL_MANAGED. All your resources will be created in system memory, and then copied as needed into video memory. Lost-device situations will be handled automatically from the system memory copy. Since not all managed resources are required to fit into video memory all at once, you can over commit memory where a smaller video memory working set of resources is all that is required to render in any given frame. Note that it is likely that the majority of this backing-store system memory will be paged out to disk over time, which is why the Reset operation can be slow due to the need to page this data in to restore the lost video memory.
당신의 리소스 대부분을 managed 리소스인 POOL_MANAGED로 생성해야 한다. 당신의 모든 리소스들은 시스템 메모리에서 생성되고 필요한 순간에 비디오 메모리로 복사되어 질 것이다. Lost-device 상황에서는 자동으로 시스템 메모리로부터 복사함으로써 처리될 것이다. 모든 managed 리소스가 한번에 비디오 메모리에 넣는 것이 요구되어지지 않기 때문에, 당신은 주어진 어떤 프레임을 render하기 위해 요구되어지는 모든 리소스를 사용하기에는 다소 작은 메모리에 과도하게 보낼 수도 있다. 대부분의 backing-store 시스템 메모리는 오랫 동안 디스크로 복사되어지기(page out, 가상메모리로 이동) 쉬울 것이다. 이것이 재설정 명령(Reset operation)이 느린 이유는 잃어버린 비디오 메모리를 다시 담는데 이러한 data를 가상메모리에 담을(page할) 필요성 때문이다.
The runtime keeps a timestamp for the last time a resource is used, and when a video memory allocation fails for loading a needed managed resource, it will release resources based on this timestamp in a LRU fashion. Usage of the SetPriority API takes precedence over the timestamp, so more commonly used resources should be set to a higher priority value. Direct3D 9.0 has limited information about the video memory managed by the driver, so the runtime may have to evict several resources in order create a large enough region for the allocation to succeed. Proper priorities can help eliminate situations where something gets evicted and then is required again shortly there-after. The application can also use the EvictManagedResources API call to force all the managed resources to be removed. Again, this can be a time-consuming operation to reload all the resources required for the next frame, but is very useful for level transitions where the working set changes significantly and removing video memory fragmentation.
리소스가 사용된 가장 마지막 시간은 timestamp로 runtime이 가지고 있다가 필요한 managed 리소스를 불러오는 동안 비디오 메모리 할당이(Local video memory) 실패가 발생 때, timestamp를 근거로 하여 가장 최근에 사용된 리소스를 나중에(LRU(Least Recently Used) fashion) 해체할 것이다. SetPriority API를 사용한 것은 timestamp보다 우선한다. 그래서 상당히 자주 사용되어지는 리소스는 더 큰 우선 순위값을 설정해야 한다. Direct3D 9.0은 드라이버에 의해 관리되어지는 비디오 메모리에 대한 정보가 제한적이다. 그래서 runtime은 다음 할당할 충분한 영역을 확보하기 위해 연속된 몇개의 리소스를 제거해야 할 지도 모른다. 적절한 우선순위값은 어떤 것이 제거되고 난 직후 다시 필요한 상황을 없애는 데, 도움을 줄 수 있다. 응용 프로그램은 EvictManagedResources API를 호출하여 모든 managed 리소스를 강제로 제거할 수도 있다. 이것은 다음 프레임에 필요한 리소스를 모두 다시 읽어들여야 하기 때문에 시간을 허비하는 명령이 될 수도 있다. 그러나 작업 데이터(working set)의 변화가 큰, 레벨 전환과 비디오 메모리의 단편화를 제거하는 데는 유용할 수 있다.
A frame count is also kept to allow the runtime to detect if the resource it just choose to evict was used early the current frame, which implies a 'thrashing' situation where more resources are in use in a single frame than will fit into video memory. This triggers the replacement policy to switch to a MRU fashion rather than LRU for the remainder of the frame as this tends to perform slightly better under such conditions. Such 'thrashing' behavior will significantly impact the rendering performance. Note that the notion of current frame is tied to EndScene, so any application making use of managed resources needs to make regular calls to this method.
제거할려고 선택한 리소스가 현재 프레임의 초기에 사용된 것인지를 runtime이 알아내기 위해 Frame count를 가지고 있다. 이것은 비디오 메모리에 넣을 수 있는 양보다 더 많은 리소스가 한 프레임내에서 사용되어지는 "thrashing" 상황(실제 메모리보다 사용하는 data가 더 많아서, paging이 과도하게 일어나는 상황)을 의미한다. 이것은 그러한 상황에서 좀 더 성능이 향상되는 경향이 있기 때문에 프레임의 남은 시간동안 LRU(Least Recently Used)보다는 MRU(Most Recently Used) fashion으로 전환하는 메모리 교체 정책을 바꾸도록 한다. 그러한 "thrashing" 상황은 rendering 성능에 상당한 영향을 준다. 여기서의 현재 프레임의 개념은 EndScene을 기준으로 한다. 그래서 managed 리소스를 사용하는 모든 응용프로그램은 일정하게 이 method를 호출할 필요가 있다. (BeginScene 호출 이후, EndScene 호출될 때, 이때 사용하는 managed 리소스의 양이 비디오 메모리 보다 많으면, thrashing 상황이 발생한다.)
Developers looking to find more information about how managed resources are behaving in their application can make use of the RESOURCEMANAGER event query via the IDirect3DQuery9 interface. This only works when using the debug runtimes so this information cannot be depended upon by the application, but it provides deep detail on the resources managed by the runtime.
개발자는 그들의 응용프로그램에서 managed 리소스가 어떻게 행동하는지에 대한 더 많은 정보를 찾는 방법은 IDirect3DQuery9 Interface를 통해 RESOURCEMANAGER event query를 사용하는 것이다. 이것은 debug runtime을 사용할 때만 동작한다. 그래서 응용프로그램에 의해 의존되어질 수 없는 정보이지만, runtime에 의해 관리되어지는 리소스에 대한 더 많은 정보를 제공할 것이다.
While understanding how the resource manager works can help when tuning and debugging your applications, it is important to not tie your application too tightly to the implementation details of the current runtime or drivers. Revisions of the driver or changes in hardware can significantly change the behavior, and future versions of Direct3D will have significantly improved and sophisticated resource management.
리소스 관리자가 어떻게 동작하는지를 이해하는 것은 당신의 응용프로그램을 디버깅하고 튜닝하는 데, 도움을 줄 수 있는 반면, 당신의 응용프로그램이 드라이버나 현재 runtime의 세세한 구현에 너무 얽매이지 않도록하기 위해서 중요하다. 드라이버의 리버젼이나 하드웨어의 변화에 따라 이러한 동작은 상당히 변할 수도 있다. 그리고 다음 버젼의 Direct3D는 상당히 향상되고, 대중화된 리소스 관리를 가질 것이다.
Driver Managed Resources
Direct3D drivers are free to implement the 'driver managed textures' capability, indicated by D3DCAPS2_CANMANAGERESOURCE, which allows the driver to handle the resource management instead of the runtime. For the (rare) driver that implements this feature, the exact behavior of the driver's resource manager can vary widely and you should contact the driver vendor for details on how this works for their implementation. Alternatively, you can ensure that the runtime manager is always used instead by specifying D3DCREATE_DISABLE_DRIVER_MANAGEMENT when creating the device.
Direct3D 드라이버는 runtime 대신 드라이버가 리소스 관리를 처리할 수 있도록 하는 D3DCAP2_CANMANAGERSOURCE 를 가지고 '드라이버 관리 texture(driver managed textures)'를 구현할 수 있다. 매우 드물지만, 이런한 기능을 구현한 드라이버의 리소스 매니져의 정확한 동작 방식은 매우 다양할 수 있고, 어떻게 구현되었는지에 대한 자세한 내용은 드라이버 벤더에 문의해야 한다. runtime 매니저가 항상 사용되기를 보장받기를 원할 때는 디바이스를 생성할 때, D3DCREATE_DISABLE_DRIVER_MANAGEMENT를 사용하면 된다.
Default Resources
While managed resources are simple, efficient, and easy-to-use there are times when using video memory directly is preferred or even required. Such resources are created in the POOL_DEFAULT category. Making use of such resources does cause additional complications for your application. Code is required to cope with the lost-device situation for all the POOL_DEFAULT resources, and performance considerations must be taken into account when copying data into them. Failure to specify USAGE_WRITEONLY or making a render target lockable can also impose serious performance penalties.
managed 리소스가 간단하고, 효율적이고, 쉽게 사용할 수 있는 반면, 비디오 메모리를 직접 사용해야하는 게 더 낫거나 필요할 때가 있다. 그러한 리소스는 POOL_DEFAULT로 생성되어 진다. 그러한 리소스의 사용은 응용 프로그램이 조금 복잡해지게 된다. lost-device 상황에서 모든 POOL_DEFAULT 리소스에 대해 대응되는 코드를 작성해 주어야 한다. 그리고 그것을 복사할 때도 성능상 여러가지 상황을 고려해 주어야 한다. USAGE_WRITEONLY로 지정하는 것이 실패하거나 lock을 걸수 있는 render target을 만드는 것을 실패하는 것은 성능상의 심각한 부담을 지어준다.
Calling Lock on a POOL_DEFAULT resource is more likely to cause the GPU to stall than working with a POOL_MANAGED resource unless using certain hint flags. Depending on the location of the resource the pointer returned could be to a temporary system memory buffer or it can be a pointer directly into AGP memory. If it is a temporary system memory buffer, data will need to be transferred to the video memory after the Unlock call. If the video resource is not write-only, data will have to be transferred into the temporary buffer during the Lock. If it is an AGP memory area, temporary copies are avoided but the cache behavior required can result in slow performance.
만약 어떤 hint flag를 사용하지 않고, Lock을 POOL_DEFAULT 리소스에 호출하는 것은 GPU가 POOL_MANAGED 리소스를 가지고 동작할 때보다 stall(아무 동작도 하지 못하는 상태)에 빠지기 쉽다. 리소스의 위치에 의존해서 받은 포인터는 임시 시스템 메모리 버퍼(temporary system memorly buffer)이거나 AGP 메모리 바로 지칭하는 포인터일 수 있다. 만약 임시 시스템 메모리 버퍼라면, data는 Unlock이 호출된 뒤 비디오 메모리로 전송되어져야 한다. 만약 AGP 메모리 영역이라면, 임시 복사는 피할 수 있으나, 요구되는 캐쉬 동작은 성능에 나쁜 영향을 끼칠 수 있다.
Care should be taken to write a full cache line of data into any pointer to AGP aperture memory to avoid the penalty of write-combing which induces a read/write cycle, and sequential access of the memory area is preferred. If your application needs to make random access to data during creation and you do not wish to make use of a managed resource for the buffer, you should work with a system memory copy instead. Once the data has been created, you can then stream the result into the locked resource memory to avoid paying a high penalty for the cache write-combing operation.
read/write cycle을 하게 만드는 write-combing penalty를 피하기 위해 AGP aperture 메모리를 가리키는 어떤 포인터로 full cache line의 data를 쓰는데 주의를 기울여야 한다. 그리고, 메모리 영역의 순차적인 접근이 선호되어진다. 만약 당신의 응용프로그램이 생성되는 동안 data로의 임의 접근을 할 필요가 있고, buffer에 managed 리소스를 사용하기를 원하지 않는다면, 대신해서 system 메모리 복사를 통해 작업해야 한다. 일단 data가 생성되면, cache write-combing operation을 하기 위한 높은 penalty 지불하는 것을 피하기 위해서 당신은 그 결과를 locked 리소스 메모리에 보낼 수 있다.
The LOCK_NOOVERWRITE flag can be used to append data in an efficient manner for some resources, but ideally multiple Lock and Unlock calls to the same resource can be avoided. Making proper use of the various Lock flags is important to optimal performance, as is using a cache-friendly data access pattern when filling locked memory.
LOCK_NOOVERWRITE flag는 어떤 리소스에는 효과적인 방법으로 data를 추가하는데, 사용되어질 수 있으나, 이론적으로 같은 리소스를 두번 Lock, Unlock 호출하는 것을 피할 수 있다. 다양한 Lock flag를 적절히 사용하는 것은 lock을 건 메모리를 채울 때, 캐쉬에 유리한 data 접근 방법을 선택할 수 있으므로 성능최적화에 중요하다.
Using Both Managed and Default Resources
Mixing allocations of managed and POOL_DEFAULT resources can cause video memory fragmentation and confuse the runtime's view of the video memory available for managed resources. Ideally, you should create all POOL_DEFAULT resources before making use of POOL_MANAGED resources or make use of the EvictManagedResources call before allocating unmanaged resources. Remember that all allocations made from POOL_DEFAULT that reside in video memory tie up memory for the life that resource that is unavailable for use by the resource manager or for any other purpose.
managed와 POOL_DEFAULT 리소스를 혼합해서 사용하는 것은 비디오 메모리 단편화와 runtime에 입장에서 managed 리소스를 위한 메모리 확보를 혼란스럽게 할 수 있다. 이론적으로는 POOL_MANAGED 리소를 호출하기전에 모든 POOL_DEFAULT 리소스를 생성하거나, unmanaged 리소스를 할당하기 전에 EvictManagerdResource 호출을 사용해야 한다. 비디오 메모리에 있는 POOL_DEFAULT로 만든 모든 할당은 일생동안 메모리를 리소스 관리자나 다른 목적에 의해 사용되어 질 수 없도록 묶어 버린다는 사실을 기억해라.
Note that unlike previous versions of Direct3D, the version 9 runtime will automatically evict some managed resources before giving up on a failed unmanaged resource allocation for a lack of video memory, but this can potentially create additional fragmentation and even force a resource into a sub-optimal location (a static texture in non local video memory for example). Again, it is best to allocate all required unmanaged resources up-front and before using any managed ones.
이전의 다른 Direct3D 버전과는 달리 9버전 runtime은 비디오 메모리가 부족으로 unmanaged 리소스로 할당이 실패하기 전에 자동으로 managed 리소스를 폐기할 것이다. 그러나 이것은 잠재적으로 추가적인 단편화를 생성시키고, 리소스가 덜 최적화된 위치에 할당되도록 할 것이다. (예를 들면, static texture를 Local video memory에 두지 못하는 것) 다시 말해, 필요한 모든 unmanaged 리소스는 managed 리소스를 사용하기전에 먼저 할당하는 것이 최선의 방법이다.
Dynamic Default Resources
Data that is generated and updated at a high frequency has no need for the backing-store since all the information will be re-created when restoring the device. Such data is typically best created in POOL_DEFAULT specifying the USAGE_DYNAMIC hint so the driver can make optimization decisions when placing the resource knowing it will be updated often. This typically means putting the resource into non-local video memory, and thus is usually much slower for the GPU to access than local video memory. For UMA architectures, the driver might choose a particular placement for dynamic resources to optimize for CPU write access.
아주 빈번히 생성되고, 업데이트되는 data는 backing-store에 둘 필요가 없다. 왜냐하면 모든 정보는 디바이스에 저장될 때, 재생성되기 때문이다. 그러한 data는 USAGE_DYNAMIC hint를 지정하고, POOL_DEFAULT에 생성하는 것이 최선이다. 그렇게 함으로 드라이버가 그것이 자주 업데이트되어지는 것을 알고 있는 리소스를 배치할 때 최적의 결정을 할 수 있다. 이것은 리소스를 non-local video memory에 둔다는 것을 의미하고, non-local video memory는 일반적으로 local video memory에 비해 접근 속도가 훨씬 느리다. UMA architecture는 드라이버가 CPU의 쓰기 접근을 최적화하기 위해 dynamic 리소스를 특정한 위치에 둘 수 있다.
This usage is typical for software skinning solutions and CPU-based particle systems filling out vertex/index buffers, and the LOCK_DISCARD flag will ensure that stalls are not created in cases where the resource is still in use from the previous frame. Using a managed resource in this case would update a system memory buffer, which would then be copied to video memory, and then used for only a frame or two before being replaced. For systems with non-local video memory, the extra copy is eliminated by proper use of this dynamic pattern.
이 usage(USAGE_DYNAMIC)는 소프트웨어 skinning 방법과 Vertex/index buffer를 채우는 CPU기반 particle 시스템 에 전형적으로 사용된다. 그리고, LOCK_DISCARD flag가 앞 전 프레임에서 여전히 사용되어진 리소스의 경우에 stall이 생기지 않도록 해 준다. managed 리소스를 이러한 경우에 사용하는 것은 비디오 메모리에 복사되어져야하는 system 메모리 buffer를 한 두 프레임 밖에 사용하지 못하고 업데이트 시킨다. non-local video memory를 가진 시스템은 이러한 dynamic 유형을 적절히 사용하면 추가적인 복사 과정을 제거할 수 있다.
Standard textures cannot be locked, and can only be updated via UpdateSurface or UpdateTexture. Some systems support dynamic textures, which can be locked and use the LOCK_DISCARD pattern, but a capabilities bit (D3DCAPS2_DYNAMICTEXTURES) must be checked before making use of such resources. For highly dynamic (video or procedural) textures, your application could create matching POOL_DEFAULT and POOL_SYSTEMMEM resources and handle video-memory update via the UpdateTexture API. For high frequency partial updates, the UpdateTexture paradigm is likely the better choice.
표준 texture는 lock되어지고, UpdateSurface나 UpdateTexture를 통해서만 갱신되어 질 수 있다. 어떤 시스템은 LOCK_DISCARD 유형을 사용하고, Lock을 걸 수 있는 dynamic texture를 지원하다. 하지만, 그러한 리소스를 사용하기전에 능력 비트(capabilities bit)(D3DCAP2_DYNAMICTEXTURES)를 확인해 보아야 한다. 자주 바뀌는 texture(video나 순차)는 응용프로그램에서 POOL_DEFAULT와 POOL_SYSTEMMEM 리소스의 짝을 두어 생성할 수 있고, UpdateTexture API를 통해 비디오 메모리 update를 처리해 할 수 있다. 일부만 자주 바뀌는 경우는 UpdateTexture 유형을 더 좋은 선택이다.
As useful as dynamic resources can be, be careful when designing systems that rely heavily on dynamic submission. Static resources should be placed into POOL_MANAGED to ensure both good utilization of local video memory, and to make more efficient use of limited bus and main memory bandwidth. For resources that are 'semi-static', you may find that the cost of an occasional upload to local video memory is much less than the constant bus traffic generated by making them dynamic.
dynamic submission에 크게 의존하는 시스템을 만들 때는 dynamic 리소스가 유용하도록 주의를 기울여라. Static 리소스는 POOL_MANAGED에 두어서 local video memory를 잘 활용할 수 있도록 해야하고, 제한된 bus와 메인 메모리의 bandwidth를 효과적으로 만들어야 한다. semi-static한 리소스는 local video memory로 자주 올리는 부담이 그것을 dynamic으로 함으로 생기는 끊임없는 bus traffic 보다 작다는 것을 알 수 발견할 것이다.
System Memory Resources
Resources can also be created in POOL_SYSTEMMEM. While they cannot be used by the graphics pipeline, they can be used as sources for updating POOL_DEFAULT resources via UpdateSurface and UpdateTexture. Their locking behavior is simple, although stalls might occur if they are in use by one of the previously mentioned methods.
리소스는 POOL_SYSTEMMEM로 생성할 수 있다. 그것은 그래픽 파이프라인을 통해 사용할 수 없는 반면, 그것은 UpdateTexture와 UpdateSurface를 통한 POOL_DEFAULT 리소스를 업데이트함으로 그것을 소스로써 사용할 수 있다. 만약 앞전에 언급된 방법중 하나로 사용되어진다면, stall을 발생할 수 있다하더라도 그것의 locking 방식은 간단하다.
Though they reside in system memory, POOL_SYSTEMMEM resources are limited to the same formats and capabilities (such as maximum size) supported by the device driver. The POOL_SCRATCH resource type is another form of system memory resource that can utilize all formats and capabilities supported by the runtime, but cannot be accessed by the device. Scratch resources are intended primarily for use by content tools.
비록 그들은 시스템 메모리에 있지만, POOL_SYSTEMMEM 리소스는 디바이스 드라이버에 의해 지원되어지는 같은 용량과 형식에 제한 받는다. POOL_SCRATCH 리소스형은 runtime에 의해서 지원되는 모든 형식과 용량을 사용할 수 있는 또 다른 시스템 메모리의 한 유형이지만, 디바이스는 접근할 수 없다. Scratch 리소스는 content 툴에 의해 주로 사용되어지는 경향이 있다.
General Recommendations
Getting the technical implementation details of resource management correct will go a long way to achieving your performance goals in your application. Planning how the resources are presented to Direct3D and the architectural design around getting the data loaded in a timely fashion is a more complicated task. We recommend a number of best practices when making these decisions for your application:
올바른 리소스 관리에 대한 상세한 기술적인 구현을 가지고 당신의 응용프로그램의 성능을 목표치까지 올리는 데는 걸릴 것이다.
Pre-process all your resources. Relying on expensive load-time conversion and optimization for your resources is convenient during development, but puts a high performance burden on your users. Pre-processed resources are faster to load, faster to use, and gives you the option of doing sophisticated off-line work.
Avoid creating many resources per frame. The driver interactions required can serialize the CPU and GPU, and the operations involved are heavy-weight as they often require kernel transitions. Spread out creation over several frames or reuse resources without creating/releasing them. Ideally, you should wait several frames before locking or releasing resources recently used to render.
Be sure to unbind all resource channels (i.e. stream sources, texture stages, and current indices) at the end of the frame. This will ensure that dangling references to resources are removed before they cause the resource manager to keep resources resident that are actually no longer in use.
For textures, use compressed formats (e.g. DXTn) with mip-maps and consider making use of a texture atlas. These greatly reduce bandwidth requirements and can reduce the overall size of the resources making them more efficient.
For geometry, make use of indexed geometry as this helps compress vertex buffer resources and modern video hardware is heavily optimized around reuse of vertices. By making use of programmable vertex shaders, you can compress the vertex information and expand it during the vertex processing. Again, this helps reduce bandwidth requirements and makes vertex buffer resources more efficient.
Be careful about over-optimizing your resource management. Future revisions of drivers, hardware, and the operating system can potentially cause compatibility problems if the application is tuned too heavily to a particularly combination. Since most applications are CPU bound, expensive CPU-based management generally causes more performance issues than they solve.
당신의 모든 리소스에 대해 전처리를 해라. 리소스를 읽어들일 때, 변환하고, 최적화하는 것이 개발 중에는 편리하나, 높은 성능에 대한 부담은 당신에게 지어진다. 전처리된 리소스는 전처리된 리소스는 읽어들이고, 사용하는 데 더 빠르고, 대중화된 off-line 작업이 선택으로 주어진다.
프레임 중에 많은 리소스를 생성하는 것을 피하라. 요구되는 드라이버의 상호작용은 CPU와 GPU를 serialize할 수 있고, 따르는 연산은 자주 Kernel transition이 요구 되어지는 무거운 작업이다. 리소스 생성을 여러 프레임에 걸쳐 나누어서 하거나, 생성, 소멸을 하지 않고 재 사용하라. 이론적으로 당신은 최근에 렌더링되는 데 사용한 리소스를 release하거나 locking하기 전에 여러 프레이을 기다려야 한다.
프레임의 끝에는 모든 리소스 channel(stream sources, texure sources, current indices)을 풀어라. 이것은 그 리소스들이 리소스 manager에 의해 실제로는 더 이상 사용되지도 않는 리소스를 메모리에 유지시키도록 하기전에 애매모호한 reference가 제거되어지도록 해 준다. (역자 - bind를 풀어라. 다음 프레임의 처음에는 마지막에 설정한 값이 바로 재사용될 가능성이 없다.)
texture는 map-maps을 가진 압축 형식(DXTn)을 사용하고 texture atlas(여러 texture를 하나에 집어 넣어 사용) 사용을 고려해라. 이것은 필요한 bandwidth를 상당히 줄여주고, 전체 리소스 크기를 줄여서 더 효율적으로 만들어 준다.
geometry는 indexed geometry를 사용해라. 왜냐하면, 이것은 vertex buffer 리소스를 압축하는 데, 도움을 추고, 최근 비디오 하드웨어는 vertex의 재사용에 상당히 최적화되어 있다. Programmable Vertex Shader를 사용함으로써, 당신은 vertex 정보를 압축할 수 있고, vertex processing 중에 vertex 정보를 확장할 수 있다. 다시말해 이것은 필요한 bandwidth를 줄이고, vertex buffer 리소스를 좀 더 효율적으로 사용할 수 있도록 도와 준다.
당신의 리소스 관리에 과도한 최적화에 대해 주의해라. 다음 버젼의 드라이버, 하드웨어, 운영체제는 응용 프로그램에서 특정한 조합에 대해 너무 많은 조정을 가하면 잠재적으로 호환성에 문재를 일으킬 수도 있을 것이다. 대부분의 응용프로그램이 CPU Bound(CPU 속도가 가장 많은 부하를 차지한다는 뜻)이기 때문에 너무 과도한 CPU기반 관리는 일반적으로 그 성능 문제를 해결하기 보다는 성능 상 문제를 읽으킨다.
Returns the reflection vector v, given the entering ray direction i, and the surface normal n. Such that v = i - 2 * dot(i, n) * n
sin(x)
cos(x)
tan(x)
Returns the sine/cosine/tangent of x.
refract(i, n, eta)
Returns the refraction vector v, given the entering ray direction i, the surface normal n, and the relative index of refraction eta. If the angle between i and n is too great given eta, refract returns (0,0,0).
위와 같이 처리하면 화면에 "테스트 문자열 - 유니코드" 라고 찍히는 것을 볼 수 있습니다.핵심은 볼드체 처리한 부분의 코드입니다.
std::wcin.imbue( std::locale( "korean" ) );
std::wcout.imbue( std::locale( "korean" ) );
다음과 같이 지정하면 현재 쓰고 있는 wcin과 wcout 에만 영향을 미치게 됩니다. 따라서 위와 같이 골치 아픈 문제는 일단 피할 수 있겠죠?
그리고 이에 대한 자료가 더 필요하시면 http://www.cantrip.org/locale.html 여기 가서 더 읽어보시거나 Standard C++ IOStreams and Locales: Advanced Programmer's Guide and Reference 또는 C++ Standard Library 라는 책을 참고하시길 바랍니다.