[미리보는 C++ AMP-3] array와 array_view

DirectX 11 2011.12.21 08:00 Posted by 조진현

들어가기 앞서 지금까지 AMP가 GPU를 활용하는 프로그래밍 기법이라고,
제가 지속적으로 언급해 왔었습니다.
사실 이 말은 적절하지 않는 표현이였습니다.

얼마 전까지만 해도, 개발자에게 주어지는 프로세싱 유닛은 CPU와 GPU 뿐이였습니다.
CPU는 개발자의 활용 영역에 있었지만, GPU는 제한적으로 사용할 수 있었습니다.
왜냐하면 GPU를 사용하기 위해서는 DirectX API 사용이 필수였기 때문입니다.
그 DirectX 의 영역을 일반적인 개발자 영역으로 확장하는 것이 C++ AMP 입니다.
그런데 최근에 CPU와 GPU를 통합한 APU 라는 것이 등장했습니다.
앞으로 또 다른 프로세싱 유닛이 등장할지도 모르는 일입니다.
그래서 이런 프로세싱 유닛들을 통합한 용어가 필요하게 되었고,
C++ AMP에서는 이를 accelerator 라고 합니다.
즉, CPU와 GPU 그리고 APU 가 이 accelerator 에 속한다고 할 수 있습니다.
accelerator 는 C++ AMP 코드가 실행될 수 있는 이런 타겟을 표현합니다.
그래서 C++ AMP는 이 accelerator를 활용하는 프로그래밍 기법이라고
해석하는 것이
더 적절한 표현입니다.
앞으로 이 accelerator 라는 표현을 많이 사용할 것이니 확실히 알아두시기 바랍니다.


앞서 간단하게 작성했던 샘플을 다시 한번 보겠습니다.
 

void AddArrays(int n, int * pA, int * pB, int * pC)

{

    array_view<int,1> a(n, pA);

    array_view<int,1> b(n, pB);

    array_view<int,1> sum(n, pC);

 

    parallel_for_each(

        sum.grid,

        [=](index<1> i) restrict(direct3d)

        {

            sum[i] = a[i] + b[i];

        }

     );

}



array_view 라는 것이 먼저 눈에 보입니다.
C++ AMP 에서는 대규모 메모리를 의미하는 클래스로
array 와 array_view 라는 것이 있습니다.
기본적으로 이 두 클래스의 목적은
accelerator 상으로 데이터를 옮기기 위함 입니다.


array 의 경우에는 실제 데이터 배열입니다.
STL 의 컨테이너와 유사합니다.
반면 array_view 는 데이터 배열의 일종의 래퍼( wrapper ) 입니다.
그래서 array_view 는 STL의 이터레이터( iterator ) 와 유사한 동작을 합니다.
array_view는 한 번에 여러 데이터의 동시에 접근할 수 있으며,
랜덤 액세스( random-access ) 가 가능합니다.

array 에 의해서 정의되는 배열 데이터는 accelerator 상에 메모리를 가지게 됩니다.
이것은 개발자가 직접 정의해서 할당할 수도 있고,
런타임( runtime ) 에 의해서 자동적으로 생성될 수도 있습니다.
그렇기 때문에 실제 데이터가 생성되어질 때 깊은 복사( deep-copy )를 하게 됩니다.
우리가 일반적으로 오브젝트를 메모리에 생성했을 때와 같다고 생각하시면 됩니다.
array 는 다음과 같이 사용할 수 있습니다.( 샘플은 msdn 에서 가져왔습니다 )

vector<int> data(5);
for (int count = 0; count < 5; count++)
{
    data[count] = count;
}

array<int, 1> a(5, data);

parallel_for_each(
    a.grid,
    [=, &a](index<1> idx) restrict(direct3d)
    {
        a[idx] = a[idx] * 10;
    }
);

data = a;
for (int i = 0; i < 5; i++)
{
    cout << data[i] << "\n";
}



반면에 array_view는 이름에서 유추할 수 있듯이,
실제 데이터들은 다른 accelerator 상에 있고,
이를 연산을 위해서 복사를 하는 개념
입니다.

즉, 커널 함수가 실행될 때, 데이터가 복사됩니다.
( 커널 함수는 AMP 내의 람다 함수 부분을 의미합니다. )

이 array_view 개념은 DirectX11 에서 보셨던 분들은 쉽게 이해할 수 있는 개념입니다.
바로 ComputeShader 를 위해서 데이터들을 연결하는 바로 그 개념이기 때문입니다.
아래의 그림은 ComputeShader 의 동작 방식을 보여주는데,
SRV( shader resource view )와 UAV( unordered access view ) 라는 것이
결국 view 의 역할을 하는 것입니다.




DirectX11 과 연계해서 생각한다면,
array 라는 메모리 배열도 결국 텍스쳐 메모리라는 것을
눈치챌 수 있을 것입니다.
DirectX10 부터 텍스쳐 인터페이스는 꼭 이미지 데이터를 의미하지 않습니다.
대용량의 메모리 블럭의 의미에 더 가깝다는 것을 알아두시기 바랍니다.
텍스쳐의 개념을 사용하기 때문에 동시에 여러 데이터에 접근이 가능하고,
랜덤 액세스도 가능한 것입니다.^^

신고

[미리보는 C++ AMP-2] C++ AMP 맛 보기

DirectX 11 2011.12.01 08:00 Posted by 조진현


백문이 불여일견이라고들 하죠?
글로써 언급하는 것보다,
프로그래머들은 코드로 볼 때 더 직관적인 이해를 할 수 있는 경우가 많습니다.

간단하게 두 배열의 합을 구하는 코드를 통해서,
이를 AMP 적으로 어떻게 작성하는지를 보겠습니다.

아래는 우리가 일반적으로 생각할 수 있는 CPU를 활용해서
합을 구하는 코드입니다.

void AddArrays(int n, int * pA, int * pB, int * pC)

{

   for (int i=0; i<n; i++)

   {

      pC[i] = pA[i] + pB[i];

   }

}


자세한 설명은 생략해도 될 것이라 생각합니다.^^
아래는 C++ AMP로 작성된 합을 구하는 코드입니다.

#include <amp.h>

using namespace concurrency;

void AddArrays(int n, int * pA, int * pB, int * pC)

{

   array_view<int,1> a(n, pA);

   array_view<int,1> b(n, pB);

   array_view<int,1> sum(n, pC);

   parallel_for_each( sum.grid,

                                          [=](index<1> i) restrict(direct3d)

   {

      sum[i] = a[i] + b[i];

   }   );

}


 

위의 AMP 구현 부분에서 색상이 들어간 부분이 CPU를 활용한 부분과 다른 부분입니다.
코드량이 증가해버린 단순한 사실을 우리는 확인할 수 있습니다.
코드가 증가한 가장 기본적인 이유는 메모리 문제입니다.
우리가 지금까지 C++ 에서 사용하는 메모리는 CPU 가 접근할 수 있는 시스템 메모리입니다.
이 메모리를 GPU 로 처리하기 위해서는 GPU가 직접적으로 접근 가능해야 합니다.
그런데 C++ 에서 할당한 메모리는 GPU가 접근할 수가 없습니다.
그래서 비디오-메모리에 시스템-메모리의 데이터를 복사하는 과정이 필요합니다.
그 과정이 바로 코드의 증가를 불러오는 것입니다.
( 복사라고 보기는 조금 모호합니다만, 지금은 그냥 넘어가겠습니다. )

이 증가한 코드들에 대해서 지금부터 살펴보겠습니다.


#include <
amp.h>

using namespace concurrency;


AMP를 사용하기 위한 헤더의 선언입니다.
기본적으로 AMP를 사용하기 위해서는 람다식과 concurrency  에 대한 이해가 있어야 합니다.


array_view
<int,1> a(n, pA);

array_view<int,1> b(n, pB);

array_view<int,1> sum(n, pC);

이 부분은 앞서 언급했던 GPU가 접근할 수 있는 메모리 영역으로
데이터를 만드는 부분입니다.
이 데이터를 만들 수 있는 메모리 영역이
array 와 array_view 라는 것으로
구분됩니다.
이 둘의 차이는 이후에 다루어 드릴테니,
지금은 GPU가 접근할 수 있는 메모리 영역으로 생각해 주셨으면 합니다.^^


parallel_for_each(
 ... ) restrict( direct3d )

c++ 에 main(...) 이 있다면, AMP 에는 parallel_for_each( ... ) restrict( direct3d ) 가 있습니다.
이 부분은 GPU가 연산을 시작하는 진입점( EntryPoint ) 입니다.

parallel_for_each를 잘 모르시는 분들은 아래의 링크를 참고하시 바랍니다.
http://vsts2010.net/123
더 자세한 사항은 이 블로그의 VC++ 10 Concurrency Runtime 카테고리를 참고하시기 바랍니다.

 

제가 단순하게 정리해 드리면,
기존에 VC++ 10 에서 사용되는 parallel_for_each 는 CPU를 활용해서 병렬적으로 처리하는 것이지만,
뒤에 restrict( direct3d )를 명시함으로써 이를 GPU에서 병렬적으로 처리
하도록 합니다.
 

이 진입 함수는 parallel_for_each(  람다식 ) 형태를 가지게 됩니다.
이는 GPU의 많은 스레드들에게 '이 람다식을 각각 실행해 주세요' 라고 명령을 내리는 것입니다.
역시 람다( Lambda ) 에 대해서 잘 모르시는 분은 옆의 카테고리에서
c++0x 를 보시기 바랍니다.
람다의 첫번째 설명 링크는 아래와 같습니다.
http://vsts2010.net/73

 

그러면 얼마나 많은 스레드들이 람다식을 실행해야 하는지에 대한 명시가 있어야 합니다.
그것이 바로 paralle_for_each( ... ) 의 첫번째 인자인 sum.grid 입니다.

grid 에 대한 설명은 뒷부분에서 자세히 다루겠으니,
지금은 스레드 갯수에 대한 정의로 보시면 충분합니다.

람다식의 인자로 index<1> idx 가 보이실 것입니다.
이 인자는 람다식에 전달되는 스레드들의 ID들입니다.
이 ID들을 통해서 스레들을 식별할 수 있습니다.
스레드들의 ID를 통해서 배열 형태의 데이터를 캡쳐해서 값을 저장하는 것입니다.

간단한 프로그램이지만, 사실 이런 형태가 C++ AMP의 전부입니다.^^

물론 이렇게 간단히 끝나면 무척 행복하겠지만,
난이도는 역시 알면 알수록 높아집니다.^^


본 글에서 사용된 예제들은 MS에서 사용된 예제들입니다.
제가 구현한 것들이 아님을 알려드립니다.^^

신고

앞서 작성했던 예제 샘플들은 사실 완전한 상태의 코드가 아닙니다. ( 죄송...^^ )
바로 이 디바이스-로스트와 관련한 상황이 있어야, 안정성을 향상시킬 수 있습니다.

디바이스-로스트의 처리는 다음과 같은 절차를 진행해야 합니다.

1. 디바이스-로스트가 발생함을 체크
2. 디바이스 의존적 리소스를 모두 제거
3. 디바이스 의존적 리소스를 재할당


이 세가지를 처리하는 것이 디바이스-로스트 상황에 대처하는 것입니다.
Direct2D 의 리소스와 관련한 내용은
http://vsts2010.net/593 글에서 제가 언급했었습니다.^^

그러면 하나씩 살펴보겠습니다.
우리가 진행했던 일반적인 렌더링 작업은 아래와 같습니다.


여기서 우리의 첫번째 단계를 처리합니다.
바로 hr = ::g_ipRT->EndDraw(); 부분입니다.
EndDraw()는 렌더링 작업의 결과를 리턴합니다.
리턴 값이 D2DERR_RECREATE_TARGET 이면, 바로 디바이스-로스트 상황입니다.
이름에서 유추할 수 있듯이 "에러가 났으니, 다시 생성하라" 입니다.

이번에 제가 사용할 샘플은 바로 이전 시간에 했던 알파이미지를 렌더링하는 샘플입니다.
이 샘플에서 디바이스 의존적인 리소스는 렌더 타겟과 비트맵입니다.
이 샘플에서 디바이스-로스트 상황이 발생한다면,
렌더타겟과 비트맵 리소스는 메모리에서 제거했다가 다시 생성해 주어야 합니다.

그래서 이번 샘플에서는 이들 리소스를 한번에 생성/삭제 하는 함수를 만들었습니다.


그리고 또 하나 고려해야 하는 부분이 있습니다.
바로 윈도우 사이즈의 변경입니다.
이 경우는 디바이스-로스트가 발생하지는 않습니다만,
순간적으로 화면이 깜빡이는 현상을 보이게 됩니다.
이 곳에도 역시 적절한(?) 처리를 해야 합니다.


렌더타겟의 리사이즈 작업이 실패하면,
역시 디바이스 의존적 리소스들을 모두 제거해 버립니다.

이제 WM_PAINT 이벤트를 위와 관련된 작업들과 연계해서 수정해야 합니다.


렌더타겟이 없는 경우는 디바이스-로스트 상황이거나 초기화 상태로 인식하고,
관련된 리소스를 생성합니다.
그리고 렌더타겟의 CheckWindowState()를 통해서 해당 윈도우가 가려져 있는지를 체크하고,
가려져 있지 않다면 렌더링 작업을 수행합니다.

렌더링 작업의 마지막에는 디바이시 로스트 상황을 체크해서
디바이스 의존적 리소스를 제거하고 있습니다. ( 앞서 언급했었죠..^^ )

이제 샘플이 약간은 안정성이 향상되었습니다.^^
이상으로 디바이스-로스트와 관련한 작업을 마치겠습니다.^^


신고

GPU를 활용하는 일은 모든 개발자에게 열려있는 길이여야 합니다.
하지만 DirectX를 직접적으로 활용해야만 하는
MS의 GPGPU 플랫폼인 DirectCompute는 그렇지가 않습니다.

그래픽카드라는게 원래 특수한 목적성을 가지고 등장한 장치이기 때문에,
이를 활용하는 사람들 또한 특정 영역에 국한되어 있는게 현실입니다.
'이제부터 GPGPU 를 적극 활용합시다!' 라고 생각을 하더라도, 
실제로 그것을 활용하기 위한 진입 장벽은 굉장히 높을 수 밖에 없습니다.

그러면 어떻게 해야만 이 장벽을 조금이라도 낮출 수 있을까요?
엔비디아의 CUDA 를 보면, 힌트가 있습니다.
하지만 몰라도 상관없습니다.^^
C++ 파일 내에서 컴파일러에 의해서 자동적으로 처리가 될 수 있으면 가장 좋지 않을까요?
순수 C++ 의 기능만 사용해서 컴파일러가 자동적으로 처리해 준다면,
개발자는 DirectX와 ComputeShader 에서 해방될 수 있을 것입니다.
그것이 바로 C++ AMP 가 등장하는 배경
입니다.
C++ AMP는 다음 버전의 VisualStudio 에 탑재 되어져서 등장할 예정이라고 합니다.


어떤 함수가 아래와 같이 있습니다.
void Func( ... )
{
    코드
}

위의 함수는 결국 컴파일러에 의해서 CPU 와 관련한 명령어를 생성하게 됩니다.
이를 AMP 적으로 확장하면 정확히 아래와 같이 구성됩니다.
void Func( ... ) restrict( cpu )
{
   코드
}

restrict 이라는 키워드를 함수에 적용함으로써 간단히 이를 구현합니다.
눈치가 좀 빠르신 분들이라면
'저 cpu를 gpu 로만 변경하면, gpu 로 컴파일 되어지는 것인가?' 라고 생각이 드실 겁니다.
네. 맞습니다.
그것이 바로 C++ AMP 가 DirectCompute 를 구현하는 방법입니다.
정확히는 아래와 같습니다.
void Func( ... ) restrict( direct3d )
{
   코드
}
'direct3d' 가 바로 'gpu' 를 의미합니다.
현재 이 옵션용 예약어는 확정적인 것은 아닙니다.
'direct3d' 가 확정될 수도 있고, 그렇지 않을 수도 있습니다.
아직 C++ AMP가 출시되지 않아서 유동적인 부분이 있습니다.
그 점 주의해서 읽어주시기 바랍니다.^^

다음 버전의 Visual C++ 부터는 
함수마다 저렇게 restrict 한정자에 컴파일 옵션을 지정해주어야 합니다.

물론 지정을 하지 않았을 때는, 디폴트로 restrict( cpu ) 로 자동 처리할 것입니다.

그러면 한 함수 내에서 CPU와 GPU를 활용해야 하는 경우는 어떻게 해야할까요?
void Func( ... ) restrict( direct3d, cpu )
{
   GPU를 사용하는 코드
   CPU를 사용하는 코드
}

위와 같이 혼합해서 사용하는 것도 가능합니다.
또한 오버로드와 관련한 이슈도 문제 없이 처리될 것입니다.
void Func( ... );
void Func( ... ) restrict( direct3d );

간단히 위와 같이 restrict 만으로 GPU를 사용하는 것이 완전히 된다면 얼마나 좋겠습니까만,
restrict( direct3d ) 로 정의되어지는 함수들은 그에 상응하는 규칙으로 코딩 작업을
해야만 합니다.
이것이 사실 그렇게 쉬운 개념만으로 이해할 수 있는 것은 아닙니다.
하지만 DirectCompute를 직접 제어하는 것보다는 쉽습니다.

다음 시간부터 C++ AMP 로 프로그래밍 하는 개념에 대해서 살펴보겠습니다.^^
신고

[KGC 2011] 발표 자료

DirectX 11 2011.11.14 08:00 Posted by 조진현


안녕하세요~ 조진현입니다.
얼마 전 대구에서 KGC 2011 행사가 있었습니다.
저는 그 곳에서 DirectX11 과 관련한 발표를 진행하고 왔습니다.
그래서 발표 슬라이드를 공개해 드립니다.

특히나 이번 발표 때, C++ AMP 에 대한 언급이 있었습니다.
AMP는 아래 링크에 흥배님이 자세히 설명해 주셨습니다.
http://vsts2010.net/591

빠른 시간 내에 발표 때 언급했던 C++ AMP 와 관련한 내용을
팀 블로그에 게재하도록 하겠습니다..^^

[조진현] [Kgc2011]direct x11 이야기
View more presentations from 진현 조.
신고

디바이스 로스트( Device Lost ) 라는 용어에 대해서 친숙한 분도 계실 것이고,
그렇지 않은 분도 계실 것입니다.
아마 Direct3D 를 다루어 보신 분들은 이 용어에 무척이나 친숙할 것입니다.

디바이스 로스트라는 것은 특정 상황을 얘기하는 것입니다.
이 상황은 지금까지 확보하고 있던 메모리 같은 리소스들이 모두 사라져서,
아무 작업도 할 수 없는 상황을 얘기합니다.
즉, 시스템 리소스가 모두 무효화 되어버린 상황이라 할 수 있습니다.

GDI 를 사용해서 렌더링 한다면, 갑자기 HDC 가 비활성화 되어버린 것이라 생각할 수 있습니다.
게임 개발에서 주로 사용하는 Direct3D를 사용하는 경우에는 Alt + Tab 문제라던지,
실시간으로 화면 사이즈를 조절하게 되었을 때 주로 나타납니다.
Direct3D로 개발하는 경우에는 예전부터 이 문제에 친숙했기 때문에,
이 상황에 대해서 리소스들을 복구하는 코드를 개발자들이 직접 작성해 주었습니다.

Direct2D도 DirectX의 하나이기 때문에 바로 이 디바이스 로스트 상황이 발생을 합니다.
그래서 개발자들이 이 상황에 대해서 직접 적절한 처리를 해주어야 합니다.

그런데 중요한 것은 현재의 디바이스 로스트 상황이 예전과는 다르다는 것입니다.
이 차이를 설명하려면 디스플레이 드라이버 모델까지 언급을 해야 합니다.

Windows XP 시대와 현재의 Windows 7 시대는 디스플레이 드라이버 모델이 다릅니다.
XP 시대는 XPDM 이라는 드라이버 모델을 사용하고 있으며,
윈도우 7 시대에는 WDDM( Windows Display Driver Model ) 라는 모델을 사용하고 있습니다.
( 모니터에 그리기까지의 과정이 다르다고 생각하시면 좋을 것 같습니다.^^ )
이 모델의 차이가 디바이스 로스트에서도 차이를 만들어 냅니다.

XPDM 은 XP때까지 Windows OS가 발전시켜온 드라이버 모델입니다.
즉, 옛 것을 꾸준히 업데이트 한 결과라 할 수 있습니다.
아무래도 너무 오래되다보니 복잡하고 난해한 구조가 되었고,
그 복잡성 때문에 버그들이 드라이버 내부에 있었다고 합니다.

또한 하드웨어의 발전에도 빠르게 대응하는 것에 굉장한 한계가 있었다고 합니다.

그래서 Windows Vista 때 이 문제를 극복하기 위해서 도입된
새로운 디스플레이 드라이버 모델이 바로 WDDM 입니다.
WDDM 은 기존의 복잡성을 최대한 버려서 심플한 구성을 가지도록 설계되었습니다.
기존의 XPDM 이 커널모드에서 대부분의 처리를 수행했던 것을
커널모드와 사용자 모드로 분리를 시켜서 이 디바이스 로스트에 대한 상황에 대한
대응을 용이하게 했습니다.

XPDM의 경우에는 커널에서 문제가 발생하면,
이 때문에 시스템 전체를 다시 시작해야 하는 불상사(?)가 꽤 있었습니다.
MS 통계에 따르면 우리가 흔히 보던 블루스크린 상황의 20% 정도가
바로 이 디스플레이 드라이버가 원인이였다고 합니다.
그렇기 때문에 간략화 된 커널 모드의 드라이버를 제공하고,
계산이 복잡한 대부분의 기능은 사용자 모드 드라이버로 이동시킴으로써
문제를 해당 애플리케이션 하나로 국한 시킬 수 있습니다.
이는 블루스크린 상황을 감소시킬 수 있는 하나의 방법이기도 합니다.

XP OS의 디스플레이 드라이버 모델 교체가 어렵기 때문에
WDDM 은 Vista 이상의 OS에서만 지원합니다.
결국 이는 최신의 DirectX 들이 XP OS 에서 정상적으로 작동하지 못하는
가장 근본적인 이유입니다.

WDDM과 XPDM 의 차이는 바로 GPU 활용에 있습니다.
XPDM 의 경우에는 GPU 관련 처리를 할 수 없었습니다.
왜냐하면 옛것을 꾸준히 계승시켜 발전시킨 모델이였기 때문에,
GPU 처리와 같은 큰 패러다임의 전환은 이 모델 자체를 변경하는 일이기 때문입니다.
현재 Vista 이후의 Windows OS에서는 대부분의 그래픽 작업과 윈도우 관리에
바로 이 GPU가 활용되고 있습니다.

XP 시대에서 DirectX를 사용하는 것은 GPU를 독점적으로 사용하는 작업이였습니다.
만약에 GPU 작업을 실행하는 중에 다른 애플리케이션에서 GPU를 사용하려 한다면,
GPU의 제어 권한을 빼앗기게 됩니다.
XP 시대에서는 GPU를 여러 애플리케이션에서 동시에 공유할 수가 없었습니다.

하지만 현 세대의 Windows OS에서는 GPU 메모리 관리자가 비디오 메모리를 관리하고 있으며,
GPU 스케줄러에 의해서 스케줄을 조정합니다.
우리가 '빠르다' 라고 하는 작업의 뒤에 바로 이런 작업들이 이루어지고 있습니다.

이러한 GPU 활용의 적극적인 도입은 결국 퀄리티의 향상까지 연결됩니다.
XP 시대의 XPDM 의 경우에는 GDI로 렌더링 작업을 할 때,
화면에 직접 그리는 개념으로 작업을 했습니다.
그렇기 때문에 윈도우를 이동하거나 사이즈를 조절하게 되면,
화면이 깜빡이는 것을 확인 할 수 있었습니다.
( 티어링과 같은 현상도 확인할 수 있었습니다.^^ )

또한 이 때 대량의 WM_PAINT 메시지가 발생해서 시스템에 상당한 부하를 주기도 했었습니다.
이는 XPDM 의 경우 모니터 화면에 직접 렌더링 작업을 했었기 때문입니다.

비디오 메모리가 풍족해진 현 세대에서는 오프-스크린 버퍼를 두어서,
화면이 아닌, 다른 버퍼에 렌더링 작업을 수행합니다.
( 흔히들 얘기하시는 더블-버퍼링 기법입니다.^^ )

이러한 것을 담당하는 것이 DWM( Desktop Window Manager ) 입니다.
이는 OS 에서 자동적으로 실행하기 때문에 쉽게 확인할 수 있습니다.


DWM 은 간단히 말해서 DirectX 애플리케이션입니다.
DWM 은 비디오 메모리를 만들어서 각 애플리케이션 화면을 모아서
우리에게 화면을 보여주는 역할을 합니다.
그렇기 때문에 DWM 은 오프-스크린 버퍼를 관리하는 기능을 가지고 있습니다.

WDDM 에 대해서 논할 내용도 상당히 많이 있습니다.
Vista 시절에는 WDDM 1.0 이였고,
Windows 7 에서는 WDDM 1.1 이 사용되고 있습니다.
역시 버전이 업데이트 되면서, 더 좋아진 부분이 있습니다.
1.1 에 관한 개선 사항은 아래의 링크로 대신합니다.^^
http://jacking.tistory.com/442


GPU를 활용한 많은 기능들이 현세대의 Windows OS에 기본적으로 탑재가 되어 있습니다.
그렇기 때문에 디바이스-로스트 같은 GPU 관련한 예외 상황들에 대한 처리를
개발자들이 해주어야 합니다.
XPDM의 경우와 개념도 다르고, 발생되는 상황도 다릅니다.
Direct2D의 경우 디바이스-로스트란,

그래픽카드가 일정시간 동안 응답을 하지 않을 때를 의미합니다
.
여기서 일정 시간이란 기본적으로 2초로 설정되어 있다고 합니다.
Direct2D 에서 디바이스-로스트는 잘 발생되지는 않습니다.^^

이와 관련한 실제 처리는 다음 시간에 계속하겠습니다.^^

신고

[StartD2D-8] 투명 이미지 다루기

DirectX 11 2011.09.28 08:00 Posted by 조진현


이번 시간에 다룰 것은 투명 이미지 입니다.
얼마 전 댓글로 문의하신 내용인데 답변을 달기가 조금 부족한 듯 싶어서,
이렇게 별도로 아티클(?)로 남깁니다.

예전에 Win32 API 로 알파가 있는 이미지를 표현하는 작업은 무척 번거로운 작업이였습니다.
이미지 색상에 알파가 고려되어지면, 각 색상 성분마다 알파 연산을 해주어야 합니다.
또한 RGB 각 성분이 8비트씩 사용하는데 A성분이 추가되어지면서,
다시 8비트의 추가 데이터들이 각 색상값들에 필요하게 됩니다.
용량이 커지면 성능에 문제가 생기게 되는 것은 당연한 일입니다.

그래서 이를 흉내내기 위한 대안으로 마련된 것이 ColorKey 라고 불리는 기법입니다.
이 기법은 이미지 내의 특정 색상을 표현하지 않음으로써 구현됩니다.
아래의 그림을 예로 들어보겠습니다.



이미지 내에서 배경이 모두 붉은 색으로 되어있습니다.
이런 경우에 붉은 색을 ColorKey로 지정해서 데이터를 읽지 않는 것입니다.
그러면, 캐릭터 관련 색상만 메모리에 기록되게 됩니다.
이 방법을 사용하면 24비트 비트맵만으로 캐릭터를 표현할 수 있습니다.
주의해야 할 점은,
ColorKey 에 해당하는 색상 값을 아티스트들에게 사용하지 말 것에 대한
사전 협의가 있어야 겠지요.

아쉽게도(?) Direct2D에서 이 ColorKey 사용에 대한 API를 찾지 못했습니다.
( Direct3D 에는 있습니다.^^ )

사실 ColorKey 방식이 널리 이용되긴 하지만,
근본적으로 알파 처리를 이용하며 관련 효과를 모두 구현할 수 있습니다.
그렇기 때문에, 굳이 ColorKey 를 염두할 필요성은 없습니다.

이번에 샘플에 사용한 이미지는 알파가 있습니다.

 


우측의 흑백 이미지가 알파 성분만 표현한 이미지 입니다.
당연히 검은 부분은 알파 성분이 0 이기 때문에
해당 영역은 화면에 표현되지 않을 것입니다.

이번에 살펴볼 샘플은 아래와 같습니다.



똑같은 이미지 파일에서 데이터를 읽었지만,
위의 그림은 알파 처리가 되어서 동물 부분만 출력이 되었습니다.
하지만 아래 부분은 알파처리가 이루어지지 않아서 이미지 영역이 모두 출력되었습니다.

이번 결과의 차이는 WIC를 이용한 것입니다.
우리가 지금껏 무심코(?) 지나쳤던 WIC의 컨버터를 기억하십니까?


제가 이번 샘플을 위해서 약간 개량을 했습니다.
두 사용법에 별 차이는 없지만, GUID_WICPixelFormat... 부분이 보일 것입니다.
이 인자가 바로 두 이미지의 차이를 만들어낸 부분입니다.
즉, 컨버터에서 데이터를 어떤 포맷으로 읽어들일지를 설정하는 부분입니다.

첫번째는 알파처리를 수행하는 방법으로 데이터를 읽어들입니다.
GUID_WICPixelFormat32bppPBGRA는
4개의 색상 채널을 가지고 채널당 8개의 비트를 가지고 있으며,
픽셀 당 32비트를 표현하며 UINT로 각 색상이 저장되어 있는 포맷을 의미합니다.

두번째 알파처리를 하지 않는 GUID_WICPixelFormat32bppBGR은
3개의 색상 채널과 8비트로 각 채널을 표현하는 32비트 픽셀 포맷을 의미합니다.
이 포맷도 UINT로 각 색상 성분을 표현합니다.
이 경우에는 알파 채널이 존재하지만, 실제로 읽어들이지 않습니다.
즉, 알파 채널을 무시하는 것입니다.

관련 포맷이 매우 방대하기 때문에, 여기서 더 이상 자세히 다루지 않습니다.
중요한 것은 이 컨버터 덕분에 별다른 수고 없이 알파 처리를 쉽게 수행할 수 있습니다.

Direct2D 가 사실 많은 부분을 우리가 모르게 자동적으로 처리하는 부분이 많이 있습니다.
Direct2D에서는 프로퍼티를 생성하는 부분들이 많이 있습니다.
예를 들면 다음과 같은 것들입니다.



사실 이 프로퍼티 정보들을 별도로 설정하지 않으면,
자동적으로 Direct2D에서 처리를 해버립니다.
혹은 디폴트 생성자들이 모두 들어있습니다.
자동적으로 처리되는 부분들 이외의 기능이 필요하다면,
이들을 잘 제어해야만 하겠지요..^^

부족하지만 샘플을 참조해 드립니다..^^

신고


< 변환의 중심 점은 어디인가? >

Direct2D의 변환과 관련된 API는 모두 변환을 수행할 중심점을 함수 인자로 요구를 합니다.
그렇다면, 이 중심점은 스크린 기준에서 정의되어지는 것일까요?

다음과 같은 다람쥐 그림이 있다고 가정해 보겠습니다.


이 그림은 ( 100, 100 ) 의 크기로 그려지기를 원한다고 가정해 보겠습니다.

 


그리고 우리의 모니터에 ( 300, 200 ) 위치에 그려지기 원하도록 설정하겠습니다.
그러면, 우리에게 변환을 위한 중점을 설정하기 위한 기준 좌표는 어떻게 설정되어야 할까요?
그림의 좌측 상단을 변환의 중점으로 원한다면 ( 300, 200 )으로 설정하면 될까요?
그림의 좌측 상단이 변환의 중점이 된다는 말의 의미를 잘 되새겨 보시기 바랍니다.

그림의 중심을 기준으로 중점을 설정해 두는 것이 훨씬 쉬운 개념으로 변환할 수 있습니다.
즉, 위의 그림에서 변환의 중심이 되는 좌측 상단은 좌표는 ( 0, 0 ) 이 되는 것입니다.
만약, 우측 하단이 변환이 중심이 되길 원한다면 ( 100, 100 )을 설정하면 됩니다.

앞서 살펴 보았던 샘플에는 이 의미를 그냥 넘겼지만
이번에 제공되는 샘플에서는 이를 고려해서 모두 작성했으니,
유심히 살펴보시기 바랍니다.^^

우리는 이 개념을 다음과 같이 지금까지 사용하고 있었습니다.


D2D1_RECT_F 정의의 변수가 보이시나요?
바로 이 dxArea 를 기준으로 변환이 되는 중점을 설정하는 것이 이해하기가 편리합니다.^^

이번 샘플은 지난 번 샘플의 연장에 있습니다.
지난 번 샘플에서 이번 내용과 관련된 부분을 추가 했습니다.

 




< Scale( 확대/축소 ) >

확대/축소 작업은 1.0을 기준으로 이루어집니다.
1.0 보다 작으면 축소가, 1.0보다 크다면 확대가 이루어 집니다.
이 작업은 D2D1::Matrix3x2F::Scale() API를 통해서 이루어 지는데,
역시나 변환의 중점을 요구합니다.^^



만약 좌측 상단을 기준으로 확대를 하면 다음과 같은 개념입니다.






< Skew( 찌그러뜨리기 ) >

마지막 변환은 찌그러뜨리기 작업입니다.
이는 Matrix3x2F::Skew() API를 통해서 설정할 수 있습니다.
함수 인자로 받는 것은 X축과 Y축의 찌그러질 각도와 역시나 기준이 되는 중점입니다.



역시나 변환이 되는 중점에 따라 결과가 변합니다.
아래의 그림은 30도씩 찌끄러뜨린 결과입니다.
첫번째는 X축만 적용한 것이고, 두번째는 Y축을,
세번째는 X와 Y축 모두를 30도씩 찌그러뜨린 결과입니다.



부족하지만, 제가 작성한 샘플을 첨부해 드립니다.^^


 

신고

[StartD2D-6] 이동/회전 변환 이해하기

DirectX 11 2011.09.21 08:00 Posted by 조진현


 

행렬의 등장

기존의 윈도우 애플리케이션 개발자가 Direct2D를 접할 때,
가장 생소한 개념은 행렬( Matrix ) 일 것입니다.

즉, 아래의 API 이겠죠?

<코드>

::g_ipRT->SetTransform( ::D2D1::Matrix3x2F::Identity() );

</코드>

우리는 항상 렌더링 작업을 하기 전에, 이 작업을 해주었습니다.
이것은 과연 무슨 의미를 가지고 있는 것일까요?  

불행하게도(?) Direct2D에서 각종 변환 작업을 위해서는 행렬( Matrix )을 사용합니다.
저는 고등학교 2학년 학기 초에 배웠던 기억이 있습니다.
그 때는 주로 연립 방정식의 해를 구하기 위해서 풀이 방법을 익혔습니다.
아마 대부분 저와 비슷하실 것이라 생각이 듭니다.

왜 뜬금없이 행렬이 등장했는지를 언급하고자 하면, 상당히 고통스럽습니다.^^
저는 이 행렬에 대한 깊은 이해를 원하지 않습니다.
제가 원하는 것은 이 행렬 관련 API를 이용해서 화면 상에 나오는 오브젝트들의
이동이나 회전 등과 같은 변환을 표현 할 수 있다는 것만 아셨으면 좋겠습니다.^^


Direct2D 에서는 3ⅹ2 행렬을 사용합니다.
행렬의 각 성분들은 아래와 같습니다.  

M11

Default : 1.0

M12

Default : 0.0

M21

Default : 0.0

M22

Default : 1.0

M31

OffsetX : 0.0

M32

OffsetY : 0.0

 

이 행렬은 D2D1_MATRIX_3X2 라는 구조체로 표현됩니다.
Direct2D에서는 이 행렬을 손쉽게 다루기 위해서 Matrix3x2F 라는 유틸리티 기능을 지원합니다.
우리는 주로 이 Matrix3x2F 의 기능을 이용해서 변환 정보를 설정할 것입니다.
행렬의 M11, M12, M21, M22 성분은 회전과 확대/축소와 관련된 수치가 입력됩니다.
M31과 M32에는 이동과 관련된 수치가 입력됩니다.
행렬의 수치를 통해서 우리가 원하는 변형을 하고자 할 때,
이들 수치를 직접 입력해서 행렬을 제어하기는 무척 어렵습니다.

그래서 Direct2D 에서 제공하는 개발자 편의를 위한 여러 클래스들을 사용해서 이들 수치를 제어합니다.

 

스크린 좌표계  

변환의 이해를 위해서는 좌표계에 대한 이해가 필수적입니다.
우리가 가장 많이 사용하는 좌표계는 당연히 2차원 좌표계입니다.
바로 모니터가 2차원이기 때문입니다.
하지만 이전에도 언급드린 적이 있지만,
컴퓨터 모니터의 좌표계는 우리가 일반적으로 알고 있는
2차원 좌표계가 아닙니다.

 

좌측이 우리가 흔히 학창시절에 배우는 2차원 데카르트 좌표계( 2D Cartesian coordinate system ) 입니다.
우측이
컴퓨터 모니터가 사용하는 스크린 좌표계입니다.
이점 숙지 하시고, 다음 내용을 보시기 바랍니다.^^

 

이번에 제공되는 샘플의 결과는 다음과 같습니다.

 

이동( Translate )

먼저 살펴 볼 것은 이동( Translate ) 입니다.
가장 위에 있는 이미지가 바로 이동만 적용된 형태입니다.
샘플에서는 단순히 ( X,Y ) 축으로 +20씩만 움직였습니다

<코드>
D2D1::Matrix3x2F matTranslation; 
matTranslation = ::D2D1::Matrix3x2F::Translation( 20.0f, 20.0f );
::g_ipRT->SetTransform( matTranslation );                    
::g_ipRT->DrawBitmap( ::g_ipD2DBitmap, dxArea );    
</코드 

D2D1::Matrix3x2F::Translation() 를 통해서 우리가 원하는 이동을 수행하고 있습니다.
쉽죠? 이런 식으로 하면 행렬에 대한 깊은 이해도 필요하지 않을 것이라 생각합니다.^^  


회전( Rotate ) 

두 번째는 회전입니다.
샘플에서는 두 번째 그림과 세 번째 그림이 바로 회전 변환에 대한 결과물입니다.
사실 회전은 행렬의 성분들을 굉장히 복잡한 수치로 변경시킵니다.
왜냐하면 이들 회전 수치들은 삼각함수 값들이기 때문입니다.

하지만, 두려워하지 마시기 바랍니다.
Direct2D 에서는 이를 편리하게 수행하기 위해
::D2D1::Matrix3x2F::Rotation() 를 제공하고 있습니다.
회전 시킬 때, API 에 입력되는 값이 회전량과 회전 중점입니다.
회전량의 경우에는 라디안 값이 아닌, 각도 값이 입력됨을 주의하시기 바랍니다. 
즉, Degree 값입니다.
그리고 이 회전량의 경우 음의 값과 양의 값을 모두 입력이 가능합니다.
음의 값이 입력이 되면 시계 반대 방향으로 회전을 수행하게 됩니다.
( 양수면 시계방향으로 회전 합니다. )

 

또한 회전 중점의 경우도 유의해야 하는데, 아래의 그림을 보시기 바랍니다.

 

좌측 그림의 경우에는 물체의 중점 위치를 기준으로 회전을 수행한 것입니다.
반면에, 우측 그림의 경우에는 물체의 좌측 상단을 기준으로 회전을 수행한 것입니다.
결과물이 다르죠?
이처럼 회전 변환을 할 때는 이 두 가지를 잘 고려해서 수행해야 합니다.  

<코드>
matRot = ::D2D1::Matrix3x2F::Rotation( -30.0f,
                                       D2D1::Point2F( 120.0f, 320.0f ) );
 

::g_ipRT->SetTransform( matRot );                           
::g_ipRT->DrawBitmap( ::g_ipD2DBitmap, dxArea );    
</코드>


이동과 회전의 결합 

지금까지 이동과 회전을 각각 수행해 보았습니다.
만약에 이동 작업과 회전 작업이 모두 한 오브젝트에 필요하다면 어떻게 해야 할까요?
그런 경우가 필요하다면 바로 행렬의 곱셈 작업을 적용합니다.
그러면 이 두 가지 작업을 모두 표현 할 수 있습니다.
그런데 이 때 주의 할 부분이 있습니다.
행렬은 교환 법칙이 성립하지 않습니다.
즉 행렬 A, B 가 있을 때, A * B != B * A 라는 것입니다.

<코드>
matTranslation = ::D2D1::Matrix3x2F::Translation( 20.0f, 220.0f );         matRot = ::D2D1::Matrix3x2F::Rotation( -30.0f,
                                       D2D1::Point2F( 120.0f, 320.0f ) );
matTM = matTranslation * matRot;            
::g_ipRT->SetTransform( matTM );
                          
::g_ipRT->DrawBitmap( ::g_ipD2DBitmap, dxArea );     

 
matTranslation = ::D2D1::Matrix3x2F::Translation( 300.0f, 220.0f );         matRot = ::D2D1::Matrix3x2F::Rotation( -30.0f, 
                                       D2D1::Point2F( 400.0f, 320.0f ) );

matTM = matRot * matTranslation;                        
::g_ipRT->SetTransform( matTM );
::g_ipRT->DrawBitmap( ::g_ipD2DBitmap, dxArea ); 
</코드>

 

이 코드가 우리의 샘플에서 두 번째와 세 번째 그림의 차이를 보여주는 것입니다.
두 번째 그림은 이동을 한 후에 회전 작업을 수행한 것이고,
세 번째 그림은 회전 작업을 수행한 후에 이동 작업을 수행한 것입니다.  

실제로 우리가 수행하는 모든 변환은 좌표계 변환입니다.
위에서 우리가 했던 변환은 모두 실제로 오브젝트들의 좌표계를 변환시켜서 얻은 결과물들입니다.
이 개념들은 분명히 이해하기 어려운 부분들입니다.
굳이 이렇게 어려운 부분까지 이해하실 필요는 없습니다.
샘플을 올려드리니, 수치를 바꿔보면서 여러 결과들을 눈으로 확인해 보시기 바랍니다.^^


 

 

 

신고


안녕하세요..^^

잠잠하던 DirectX 게시판에 이번 달에 작은 소식이 몇 가지 발표되었습니다.
먼저 Direct3D 11.1 이 릴리즈가 되었습니다.
아래 링크를 보시면 특징들을 확인하실 수 있습니다.
큰 기능의 추가는 다행이(?) 없으니 안심하시기 바랍니다.^^

http://msdn.microsoft.com/en-us/library/hh404562%28v=VS.85%29.aspx


다른 소식은 Visual Studio 11 소식입니다.
이번 Visual Studio 11 에서는 게임 개발 관련한 편의를 위해서
몇 가지 비쥬얼 적인 에디팅을 지원하는 듯 합니다.

아래는 관련 링크입니다.
http://blogs.msdn.com/b/jasonz/archive/2011/09/14/announcing-visual-studio-11-developer-preview.aspx


특히나 이번에 주목한 부분은 쉐이더 에디터가 Visual Studio 11로 통합되어진 것입니다.
( 설마 나중에 빠지는 것은 아니겠지요? ^^ )
앞으로 더 정보를 지켜봐야 하겠지만, 상당히 기대되는 부분인 것은 분명한 것 같습니다.^^





신고

[StartD2D-5] Direct2D의 리소스 기본 개념.

DirectX 11 2011.07.11 08:30 Posted by 조진현

 

 

Direct2D 리소스( Resource ) 기본 개념

 

Direct2D 에서 리소스라는 것은 단지 메모리를 의미합니다.

그 메모리는 지오메트리(Geometry)나 비트맵 이미지가 될 수도 있습니다.

즉, 이들 리소스는 메모리들이 추상화 된 일종의 개념적인 분류들입니다.

 

이들 리소스를 처리해서 모니터에 최종적으로 보여주는 것이 Direct2D의 역할입니다.

이전 까지 사용되던 GDI 도 바로 이런 역할을 하는 것입니다.

 

하지만, GDI와 Direct2D 는 리소스 처리 방식이 완전히 다릅니다.

앞선 시간을 통해서, GDI는 CPU만을 활용한다고 꾸준히 언급했습니다.

 

반면에, Direct2D는 CPU와 GPU를 동시에 활용합니다.

CPU와 GPU를 동시에 활용하기 때문에,

리소스들도 이들에 맞게 추상적으로 재분류 되어야 합니다.

 

Direct2D는 이 리소스들을 크게 두 가지 형태로 분류합니다.

바로 디바이스 독립적인 리소스( device-independent resource )와

디바이스 의존적인 리소스( device-dependent resource )로 분류하고 있습니다.

이들 두 리소스들은 모두 ID2D1Resource 인터페이스를 상속받습니다.

 

 

디바이스 독립적인 리소스

 

디바이스 독립적인 리소스라고 하는 것은 CPU에 의해서 처리되는 리소스를 의미합니다.

단어 자체에서 볼 수 있듯이,

이들 리소스는 사용자의 그래픽 하드웨어와 상관없는 처리 결과를 보장합니다.

 

뒤에서 살펴보겠지만, 지오메트리를 표현하는 인터페이스들이 여기에 속합니다.

( 조금 더 정확히 나열하면, ID2D1DrawingStateBlock, ID2D1Factory, ID2D1Geometry,

ID2D1GeometrySink, ID2D1SimplifiedGeometrySink, ID2D1StrokeStyle 등이 여기에 속합니다. )

아래는 이런 디바이스 독립적인 리소스들의 계층구조를 보여주는 그림입니다.

 

 

 

 

 

디바이스 의존적인 리소스

 

반면에 디바이스 의존적인 리소스는 GPU에 의해서 처리되는 리소스를 의미합니다.

사용자들이 가지고 있는 그래픽 하드웨어들은 매우 다양하기 때문에, 그 기능들을 모두 동일한 방식으로 처리하는 것이 쉽지 않습니다.

( 각각의 하드웨어마다 성능이나 명령어들이 모두 차이가 나기 때문이겠죠..^^ )

즉, 이들은 사용자의 하드웨어들에 따라서 결과가 차이가 날 수 있습니다.

이 차이라는 것은 눈으로 확인 가능한 차이를 얘기하는 것이 아니라,

그래픽 하드웨어들이 생성하는 명령어들과 성능 등과 같은 차이를 얘기하는 것입니다.

 

우리가 보는 모니터는 그래픽 하드웨어들이 생성한 명령어들의 최종적인 결과입니다.

리소스들도 바로 이 그래픽 하드웨어의 영향을 받아서 결과가 생성되는 것입니다.

 

앞서 우리가 화면에 렌더링 하기 위해서 만들었던 렌더타겟이나 브러시, 이미지 같은 리소스들은 모두 여기에 속합니다.

아래의 그림은 디바이스에 의존적인 리소스들의 계층구조를 표현하는 그림입니다.

 

 

 

 

Direct2D는 리소스 처리 방식은 되도록이면 GPU를 활용합니다.

GPU 처리가 불가능하다면, 자동적으로 CPU로 처리하게 됩니다.

GPU를 활용하는 리소스라면, 더욱 높은 품질로 빠르게 처리할 수 있습니다.

 

이들 리소스에 대한 설명은 다음 시간부터 차근히 살펴보겠습니다.^^

 

신고

 

  

이번 시간에는 직접 이미지를 화면에 표현하는 방법에 대해서 언급합니다.

Win32 API를 이용할 때, 우리는 '비트맵(Bitmap)' 이라는

그래픽 데이터 포맷을 읽어서 화면에 그려주었습니다.

사람마다 차이는 있겠지만, 일반적으로 다음과 같은 순서를 따라서 구성했을 것입니다.

 

  1. 비트맵을 읽기 위해서 파일을 오픈한다.

  2. 파일에서 헤더를 읽어 들인다.


  3. 비트맵 헤더의 정보를 통해서 관련 메모리를 생성하고,

    파일에서 색상 데이터에 대한 정보를 읽는다.


  4. DIBSection 을 생성하고, 실제 데이터를 읽는다.
  5. 그리고 마무리 한다.

 

이 순서는 수 많은 방법 중에 하나일 뿐이지만,

기본적으로 파일을 열어서 헤더를 먼저 읽고, 관련 메모리를 생성하고,

이후에 실제 데이터를 채우게 되는 순서는 공통된 작업입니다.

Direct2D 에서도 이와 같이 작업을 해도 되지만,

이미 편의를 위해 만들어진 라이브러리를 사용해서 조금 더 확장성 있는 작업을 할 필요가 있습니다.

지금부터는 WIC를 이용한 간단한 이미지 뷰어 작업을 해보겠습니다.

  

WIC( Windows Imaging Component )

 

DirectX 가 윈도우 운영체제 전반으로 광범위하게 활용되면서,

이들과 관련한 내용들을 분리할 필요가 있었습니다.

과거까지는 DirectX 는 게임 개발자들의 전유물에 가까웠기 때문에,

다른 개발자들도 손쉬운 개념으로 접근할 수 있는 그런 분류가 필요했습니다.


결과적으로 아래와 같이 분류가 되었습니다.  

 

WIC는 모든 이미지를 쉽게 처리할 수 있도록 만들어낸 COM 기반의 프레임워크입니다.

그림에서 보듯이 WIC도 하나의 큰 영역으로서 자리 잡고 있습니다.

( 참고로 DXVA는 영상 처리를 위한 프레임워크입니다. )

 

WIC를 이용한 이미지 처리는 앞서 GDI 기반에서 작성했던 것과는 완전히 다릅니다.

WIC는 PNG, JPG, GIF 등과 같은 거의 모든 주요한 이미지 형식을 포함하고,

기본 코덱들을 지원하고 있습니다.

 

말이 참 어렵죠?

쉽게 말해서, Direct2D 기반에서 이미지 처리를 하려면 WIC를 사용하면 쉽게 할 수 있다는 것입니다.

우리는 이것을 사용하는 순서와 방법에 대해서 배우기 위해서,

윈도우 화면에 이미지를 그려주는 간단한 애플리케이션을 만들어 볼 것입니다.

 

 

기본 WIC 프로그래밍

 

애플리케이션 마법사로 새로운 프로젝트를 만들고, stdax.h 에 다음을 추가를 합니다.

 

'WindowsCodecs.lib'와 'wincodec.h' 가 바로 WIC를 사용하기 위해 추가시킨 것입니다.

눈치 빠른 분들이라면, 이름에서 약간 앞으로의 작업 방향을 예측할 수 있을 것입니다.

 

이번 프로젝트에서 사용할 전역 변수들은 아래와 같습니다.

 

 

익숙한 개념이 눈에 보이지 않으십니까?

바로 IWICImagingFactory 입니다. 네 그렇습니다~

WIC 도 바로 팩토리 형태로 생성이 됩니다.

 

추가된 변수들은 아래와 같은 절차에 의해 값이 채워집니다.

즉, 아래는 WIC의 처리 과정입니다.

 

  1. WIC 팩토리를 만든다.

  2. 파일 경로를 기반으로 해서 디코더를 만든다.

  3. 디코딩된 프레임을 가져온다.

  4. 변환기에 넣어서 Direct2D 형식으로 변환한다.

  5. Direct2D 비트맵을 생성하고, 이를 렌더링한다.

 

이제 위의 절차를 실제로 어떻게 처리하는지를 차근차근 살펴보겠습니다.

 

가장 먼저하는 초기화 작업입니다.

앞서 언급했듯이, WIC 도 팩토리 개념으로 생성됩니다.

COM 기반이기 때문에 API 인자들이 굉장히 어려워 보일 수도 있지만, 관심을 둘 부분은 아닙니다.

위와 같은 방법으로만 하면, WIC가 생성 되어진다는 개념으로만 인식하고 다음 단계로 넘어갑니다.

 

 

 

다음 단계는 디코더를 만들고, 이를 기반으로 해서 Direct2D 형식으로 데이터를 변환하는 것입니다.

이를 위해서 가장 먼저 해야 하는 일은

이미지를 읽어들이기 위한 디코더( Decoder )를 만드는 일입니다.


갑자기 등장한 생소한 용어에 조금 혼란스러울 것 같습니다.

우리가 사용하는 모든 멀티미디어 파일( 이미지, 영상, 사운드 등 )들은

굉장히 어려운 방법으로 압축이 되어있습니다.


이들에 대한 원리나 형식을 이해하는 것도 중요한 일일 수도 있지만,

이는 간단하게 본 페이지에서 설명할 수 있는 내용이 아닙니다.

물론 저도 이와 관련한 전문가는 더더욱 아닙니다.

우리는 단지 API만으로 이들에 대한 고민을 해결할 수 있습니다.

바로 그것이 WIC의 존재 이유 중 하나 일 것입니다.^^

 

즉, 우리는 이미 만들어진 API를 이용해서 손쉽게 이미지 파일을 읽어올 수 있습니다.

그런 역할을 하는 것이 바로 디코더입니다.

아래는 디코더를 가지고 실제 작업을 하는 부분입니다.

 

 

디코더는 WIC 팩토리 멤버함수로써 생성이 되어집니다.

우리가 사용했던 이 API의 원형은 다음과 같습니다.

<코드>

HRESULT CreateDecoderFromFilename(

[in] LPCWSTR wzFilename,

[in] const GUID *pguidVendor,

[in] DWORD dwDesiredAccess,

[in] WICDecodeOptions metadataOptions,

[out, retval] IWICBitmapDecoder **ppIDecoder

);

</코드>

 

이 API는 주어진 이미지 파일을 기반으로 해서 디코더를 생성해 줍니다.

첫 번째 인자로 파일명이 들어갑니다.

이 파일을 기반으로 해서 적합한 디코더를 생성해 주게 되는 것입니다.

예를 들어, PNG 파일이면 PNG에 대한 디코더가 필요하다고 인식하고,

그에 맞는 디코더를 자동적으로 생성해 주는 것입니다.

 

두 번째 인자는 선호하는 디코더 벤더(vendor)의 GUID를 입력해야 하는데, 지금은 NULL을 사용합니다.

 

세 번째 인자로는 디코더에 대한 접근 방법을 명시합니다.

읽기(read), 쓰기(write), 혹은 둘 다 가능한지를 넣어주면,

가장 최적화된 방법과 메모리 위치를 가지는 디코드를 생성해 줍니다.

위의 예제에서는 읽기용으로만 디코더를 만들었습니다.

 

네 번째 인자는 디코더의 캐시 관련 옵션입니다.

우리가 인자로 넘긴 WICDecodeMetadataCacheOnDemand는

필요한 이미지 정보만 캐시 하도록 옵션을 준 것입니다.

다음 번에 언급할 지도 모르지만, 하나의 이미지 파일에는 여러 이미지들을 포함하고 있을 수 있습니다.

예를 들면 GIF 애니메이션 이미지 같은 것들이다.

이런 경우에 유용하게 캐시하려면, 다른 옵션을 주어야 할 것입니다.

 

마지막 인자는 생성된 디코더를 저장할 디코더의 포인터입니다.

여기까지 작업하면, 우린 이제 파일을 읽은 디코더를 소유하게 되는 것입니다.

뭔가 절차 상으로 굉장히 복잡한 것처럼 느껴지죠?

 

 

다음으로 할 작업은 프레임(frame) 작업입니다.

프레임이라는 것은 실제 픽셀 데이터를 가지고 있는 비트맵입니다.

앞서 잠깐 언급했듯이, 하나의 이미지 파일은 여러 장의 이미지가 존재할 수 있습니다.

그런 경우를 대비해서 체크를 해야겠지만,

우린 여기서 단 하나의 프레임만이 존재한다고 가정할 것입니다.

디코더의 멤버 함수인 GetFrame()를 통해서 우린 가장 첫 번째 프레임을 얻을 수 있습니다.

이 프레임을 얻는다는 것은 우리가 화면에 표현할 수 있는 이미지를 얻었다는 것입니다.

 

이제 우리는 디코더를 통해서 이미지를 Direct2D에서 표현할 수 있도록

적절하게 변환을 해주어야
합니다.

CreateFormatConverter() API는 이를 위해서 컨버터를 만들어줍니다.

그리고 이 컨버터를 우리가 원하는 형태로 초기화를 시켜 줍니다.

컨버터의 멤버함수 Initialize() 는 이미지를 컨버팅 하면서

픽셀 정보를 보정해 줄 수 있는 많은 옵션을 가지고 있습니다.

이들 옵션에 대한 세부 설정을 하지 않았습니다.

그래서 위에 인자들 형태로 주면, 별다른 이미지의 수정 없이 32비트 포맷으로 남게 됩니다.

 

이제 마지막으로 실제 렌더링 가능한 형태의 메모리를 생성해야 합니다.

렌더타겟의 멤버함수인 CreateBitmapFromWicBitmap() API를 통해서 이 작업을 하게 됩니다.

여기까지 하면, 이미지를 렌더링 하기 위한 준비작업이 모두 끝난 것입니다.

 

저는 여기에 모든 옵션들을 나열하지 않습니다.

( 기본 목적인 이미지를 띄우는데 충실하고자 합니다.^^ )

 

 

생소한 API들이 눈에 많이 띄지만, 이들은 일련의 절차에 지나지 않습니다.

중요한 개념은 이미지를 읽어 들일 디코더를 만들고,

이 이미지 데이터를 Direct2D가 표현할 수 있는 픽셀 데이터로 변환하는 것입니다.

그리고 이 데이터를 렌더타겟에서 표현할 수 있는 비트맵으로 만들어서

렌더링 가능한 상태로 만듭니다.

위의 코드는 바로 이 개념들을 표현하고 있는 것입니다.

 

그러면 실제 WM_PAINT 메시지를 통해서 이들이 어떻게 화면에 그려야 하는지 살펴보겠습니다.

 

WM_PAINT 메시지에서는 렌더타겟이 존재하지 않는 경우, 렌더타겟을 생성합니다.

렌더 타겟이 존재한다면, 비트맵을 그리고 있습니다.

렌더타겟의 렌더링 작업도 BeginDraw() / EndDraw() 의 매커니즘 내부에서

특정 상태를 기반으로 작업을 수행하게 됩니다.

우리는 Clear() 라는 API를 통해서 렌더타겟의 메모리를 흰색으로 채우고 있습니다.

그리고 현재 우리가 이미지를 (0,0) 위치에 (300,300) 크기로 렌더링 합니다.

 

마법의 함수 DrawBitmap()

 

앞선 작업을 통해서 우린 Direct2D를 이용해서 이미지를 화면에 그릴 수 있었습니다.

만약 우리가 읽어 들인 이미지의 일부분만을 화면에 그리고 싶다면 어떻게 해야 할까요?

혹은 흐릿한 효과를 주고 싶다면 어떻게 해야 할까요?

굉장히 어려운 일들 같지만, 이들 기능은 DrawBitmap() 에 모두 옵션 인자로서 존재하고 있습니다.

( 무척 고마운 일이지요..^^ )

그렇기 때문에, 우리는 이 함수를 잘 사용할 수 있어야 합니다.

API의 원형은 다음과 같습니다.

 

<코드>

virtual void DrawBitmap(

[in] ID2D1Bitmap *bitmap,

[in, optional] const D2D1_RECT_F *destinationRectangle = NULL,

         FLOAT opacity = 1.0f,

D2D1_BITMAP_INTERPOLATION_MODE interpolationMode =

D2D1_BITMAP_INTERPOLATION_MODE_LINEAR

,

[in, optional] const D2D1_RECT_F *sourceRectangle = NULL

) = 0;

</코드>

 

첫 번째 인자는 우리가 렌더링 작업을 수행할 이미지입니다.

 

두 번째 인자부터는 옵션적으로 설정할 수 있다.

두 번째 인자는 렌더링 작업을 수행할 화면의 영역을 설정합니다.

NULL 로 설정한다면, 렌더타겟의 원점에 그리게 됩니다.

만약 이미지 크기보다 크게 설정된다면, 자동적으로 이미지를 확대해서 보여주게 됩니다.

 

세 번째 인자는 투명도를 설정합니다.

범위는 0.0~1.0 사이의 값으로 0.0은 투명한 상태를 나타내고 1.0은 불투명한 상태를 나타냅니다.

 

네 번째 인자는 우리가 렌더링하는 이미지가 회전을 하거나 크기가 조정되었을 때,

어떻게 부드럽게 보일 것인가에 대한 옵션을 설정하는 부분입니다.

즉, 보간( interpolation ) 옵션입니다.

 

마지막 인자는 원본 이미지에서 일정 영역을 보여주고 싶을 때 영역을 입력하는 옵션입니다.

이 때 단위는 해당 이미지 파일의 사이즈를 기준으로 영역을 설정해 주면 됩니다.

 

그러면, 간단하게 실제로 이미지의 일부 영역을 약간 투명하게 보여지는 것을 프로그램으로 구현해자면,

앞서 작성했던, 이미지 뷰어의 기능에서 DrawBitmap()만 변경해주면 됩니다.

 

<코드>

HRESULT hr = E_FAIL;

::g_ipRT->BeginDraw();

::g_ipRT->SetTransform( ::D2D1::Matrix3x2F::Identity() );

::g_ipRT->Clear( ::D2D1::ColorF( ::D2D1::ColorF::White ) );

                            

if( ::g_ipD2DBitmap != nullptr )

{

    ::D2D1_RECT_F dxArea = ::D2D1::RectF( 0.0f, 0.0f, 500.0f, 500.0f );

    ::D2D1_RECT_F dxSrc = D2D1::RectF( 0.0f, 0.0f, 250.0f, 250.0f );

    ::g_ipRT->DrawBitmap( ::g_ipD2DBitmap, dxArea, 0.3f,

D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, &dxSrc );

                

}

hr = ::g_ipRT->EndDraw();                

</코드>

 

우리는 간단하게 DrawBitmap() 의 인자들만 변경해주는 것만으로 이미지의 일부 영역만을 보여주고,

투명도를 조절할 수 있음을 확인해 보았습니다.

각각의 값을 변경시키면서, 여러가지 아이디어를 구상해 보기 바랍니다. ^^


아래 소스코드를 첨부합니다..


신고

처음 Visual Studio 2010 릴리즈 되었을 때는 HTML5 기능이 추가가 되지 않았습니다. 그래서 XML Schema 를 이용하는 방법으로 HTML 텍스트 에디터에서 HTML5 구문을 사용하기도 하였습니다. 하지만 이번 Visual Studio 2010 SP1에는 정식으로 HTML5 인텔리센스와 유효성을 검사할 수 있는 기능이 추가가 되었습니다.

이 기능을 활성화하기 위해서 도구->옵션의 텍스트 에디터->HTML->유효성에서 HTML5 유효성 검사를 지정할 수 있습니다.

HTML5가 지원하는 여러 구문을 인텔리센스에서 자연스럽게 보여줍니다.

더불어 CSS3 를 완벽하게 지원하지는 않지만, 일부분 CSS3를 지원해 줍니다. CSS3 기능은 앞으로 그 기능을 보강할 수 있는 확장 기능으로 Visual Studio Gallery 에서 배포가 되길 기대해봅니다.


저작자 표시 비영리 동일 조건 변경 허락
신고

배포 가능한 종속성(Deployable Dependencies) 는 이번 Visual Studio 2010 SP1 에서 새롭게 추가된 기능입니다. 웹 응용 프로그램을 서버로 배포하기 위해서는 필수 구성 요소들이 설치가 되어 있어야 하는데, 배포 가능한 종속성 기능을 이용하면 웹 응용 프로그램이 동작에 필요한 일부 컴포넌트를 바로 배포할 수 있도록 도와줍니다.

웹 응용 프로그램에서 마우스 오른쪽 버튼을 클릭하여 컨텍스트 메뉴를 활성화하면 다음과 같은 메뉴 항목이 추가가 되어 있습니다.

메뉴 항목을 선택하면 아래와 같은 창이 나타납니다. 이 창에서는 ASP.NET MVC3 에서 사용하는 Razor 컴포넌트와 SQL Server Compact 를 선택할 수 있습니다.

위와 같이 배포 시 포함할 종속된 어셈블리/컴포넌트를 선택하여 확인 버튼을 클릭하면, 다음과 같이 웹 응용 프로그램 프로젝트에 _bin_deployableAssemblies 폴더가 생성이 되고, 이 하위에 관련된 어셈블리가 추가가 됩니다.

웹 응용 프로그램을 게시를 하게 되면, 위의 _bin_deployableAssemblies 폴더의 어셈블리는 웹 응용 프로그램의 bin 폴더로 배포가 됩니다.

물론, 웹 배포 패키지로 .ZIP 파일로 생성을 하여도 종속성을 추가한 어셈블리는 BIN 폴더에 추가가 되며, 이 패키지를 이용하여 배포할 서버에 컴포넌트의 설치 없이 바로 배포할 수 있습니다.

다만 현재는 여러 가지 배포 어셈블리/컴포넌트를 지원하지 않고 아래의 3개지의 컴포넌트만 배포를 지원해 줍니다.

  • ASP.NET Web Pages / Razor
  • SQL Server Compact 4.0
  • ASP.NET MVC 3

저작자 표시 비영리 동일 조건 변경 허락
신고

Razor 지원

ASP.NET MVC3 가 릴리즈 되면서 이에 발맞추어 Visual Studio 2010 SP1이 개발 도구에서 ASP.NET MVC3를 지원합니다. 특히 ASP.NET MVC3 Beta 버전에서는 지원하지 않았던, ASP.NET MVC3의 중요한 기능 중의 하나인 Razor View Engine인데, Razor View Engine의 Syntax 및 Intellisence 도 함께 지원합니다.

새로운 프로젝트를 만들 때 ASP.NET MVC3 프로젝트 템플릿에서 Razor 뷰를 선택하면 Razor View Engine을 사용할 수 있습니다.

더불어 일반 ASP.NET MVC3의 ASPX 페이지 또한 새로운 뷰를 추가할 때 Razor 뷰로 추가하면, 기존 ASP.NET MVC3의 Razor Engine을 그대로 사용할 수 있습니다.

Web Platform Installer 통합

Visual Studio 2010과 Web Platform Installer(WPI) 가 통합이 되었습니다. Visual Studio 2010에서 WPI를 바로 실행할 수 있는 툴바가 추가 되었습니다.

WPI를 통해 아래의 최신 제품을 다운로드 받을 수 있습니다.

  • SQL Server Compact 4.0
  • IIS 7.5 express
  • ASP.NET MVC3
  • WebMatrix
  • 기타…


저작자 표시 비영리 동일 조건 변경 허락
신고

기본적으로 웹 응용 프로그램을 개발할 경우 로컬에서 동작하는 ASP.NET Development Server 가 활성화가 됩니다.

그림 1 로컬 ASP.NET Development Server 가 동작하는 화면

웹을 개발할 때 Visual Studio가 제공하는 로컬에서 동작하는 ASP.NET Development Server 로 충분히 어려움 없이 개발을 할 수 있으나 웹 개발의 여러 가지 상황을 고려해 보면 기능이 충분하지는 않았습니다.

예를 들면, 기존의 로컬에서 동작하는 ASP.NET Development Server는 특정 웹 페이지나 XML 웹 서비스, WCF 서비스가 SSL(Secure Sockets Layer)로 동작한다거나 WCF의 NET.TCP, NET.PIPE 등의 바인딩을 사용할 수 없었습니다.

이런 여러 가지 기능적으로 IIS Express 를 사용할 경우 얻을 수 있는 이점이 많고, 기존 웹 응용 프로그램을 IIS Express에서 동작하도록 변경하기 위한 절차 또한 매우 간단합니다.

IIS Express가 설치되어 있다면, 웹 응용 프로그램에서 마우스 오른쪽 버튼을 클릭하여 IIS Express 사용을 선택하면 즉시 IIS Express 에서 웹 응용 프로그램이 동작하도록 할 수 있습니다.

그리고 다음의 확인 메시지에서 '예'를 클릭하면 바로 IIS Express로 웹 응용 프로그램을 개발할 수 있습니다.

IIS Express는 윈도우의 알림 영역에서 찾을 수 있으며 이 아이콘을 이용하여 여러 개의 호스팅 되고 있는 웹 응용 프로그램을 관리할 수 있습니다.

IIS Express를 사용하여 Visual Studio 2010에서 여러 가지 설정을 즉시 변경해 줄 수 있습니다.

그림 2 IIS Express 설치시 웹 응용 프로그램 속성

그림 3 기존 ASP.NET Development Server 속성

IIS 7과 IIS Express 버전의 비교표:

Area

IIS 7

IIS Express

Shipping mechanism

Ships with the OS.

Ships out-of-band. It is automatically included with WebMatrix but can also be installed separately.

Supported Windows editions

Limited number of Windows Vista and Windows 7 editions

Most editions of Windows Server 2003, 2008 and 2008 R2

All editions of Windows XP, Vista, Windows 7

All editions of Windows Server 2008 and 2008 R2

Supported .NET Framework versions

v2.0 SP1 and above

v2.0 SP1 and above (.NET 4.0 is required).

Supported programming languages

Classic ASP, ASP.NET, and PHP

Classic ASP, ASP.NET, and PHP

Process model

Windows Process Activation Service (WAS) automatically manages configured sites.

User launches and terminates sites.

Hosted WebCore (aka Hostable Web Core) support

Yes

Yes. IIS Express is implemented as a layer over HWC.

Supported protocols

HTTP, FTP, WebDAV, HTTPS, and WCF (including over TCP, Named Pipes, and MSMQ)

HTTP, HTTPS, and WCF over HTTP

Non-admin support

WAS must run with administrator user rights.

A standard user is allowed to complete most tasks.

Multi-developer support

None

Yes. Configuration files, settings, and Web content are maintained on a per-user basis.

Visual Studio support

Yes

VS 2010 SP1 Beta allows IIS Express to be used instead of Cassini. VS 2008 can also be manually configured to use IIS Express.

Runtime extensions

See http://www.iis.net/download/All for a complete list.

URL Rewrite and FastCGI. These extensions are built into IIS Express.

Management tools

IIS Manager, appcmd.exe

Appcmd.exe. Common IIS Express management tasks are also built into WebMatrix and Visual Studio 2010 SP1 Beta.

System tray support

None

Yes

Includes built-in IIS 7x modules for authentication, authorization, compression, etc.

Yes

Yes

IIS Express를 설치하기 위해 WPI(Web Platform Installer) 다운로드 페이지

http://www.microsoft.com/web/gallery/install.aspx?appid=iisexpress

그림 4 Web Platform Installer 초기 설치 화면

그림 5 기본적인 구성 요소인 IIS Express 설치 화면


저작자 표시 비영리 동일 조건 변경 허락
신고

실버라이트 4 이전의 버전에서 Visual Studio에서 성능 프로파일을 지원하지 않은 것은 아닙니다. 다만, 개발 도구에서 지원하지 않았을 뿐이고, Command Line을 이용하여 브라우저를 Attached 하여 성능 프로파일을 할 수 있었습니다.

물론, 예전에도 실버라이트에서 성능 프로파일링을 위해 커맨드 라인으로 프로파일링을 할 수 있었습니다. 아래와 같은 순서대로 커맨드를 실행하면 되었습니다.

  1. VSPerfClrEnv /sampleon
  2. "c:\Program Files (x86)\Internet Explorer\iexplore.exe" C:\Breakout\Breakout\Bin\Release\TestPage.html
  3. VSPerfCmd /start:sample /output:MyFile /attach:<PID of iexplore.exe process>
  4. Run your scenario
  5. VSPerfCmd /detach
  6. VSPerfCmd /shutdown
  7. VSPerfClrEnv /off

이번 Visual Studio 2010 SP1에서는 개발 도구에서 직접 성능 프로파일을 지원합니다. 번거로이 Command Line을 사용할 필요 없이, 기존의 성능 프로파일의 사용 경험을 그대로 실버라이트 4에 적용할 수 있습니다.

Visual Studio 2010의 분석->성능 마법사 시작 메뉴를 클릭하여 실버라이트 응용 프로그램을 프로파일링 할 준비를 합니다.

아래와 같이 성능 프로파일을 시작하면 성능 마법사 페이지가 실행됩니다.

  • CPU 샘플링
    예를 들어, 많은 데이터 작업이나 UI요소 핸들링에서 CPU에 얼만큼의 부담을 주는지 측정할 수 있는 방법입니다.

  • 계측
    관리되는 응용 프로그램이 런타임에 얼마만큼의 리소스와 실행 시간을 갖는지 측정할 수 있습니다. 모듈/클래스/메서드 수준에서 성능을 측정할 수 있는 방법입니다.

  • .NET 메모리 할당
    관리되는 응용 프로그램이 얼만큼의 메모리를 소비하고, 가비지 컬렉션(Garbage Collection) 되는지 등의 수준 높은 메모리 정보를 제공합니다.

  • 동시성
    운영체제 차원에서 메모리의 교착 및 컨텍스트 스위칭(Context Switching)을 관찰하고 다른 프로세스에 어떤 영향을 받는지 Low Level의 정보를 제공합니다.


필자는 CPU 샘플링을 선택하였고, 2단계 페이지에서는 어떤 응용 프로그램을 프로파일링 할 지 선택합니다. 만약 솔루션 탐색기에 로드 되지 않은 프로젝트는 실행 파일(.EXE) 형태의 파일을 선택하면 소스 코드 없이 다음 단계로 이동할 수 있습니다.

3단계 마법사 페이지는 즉시 프로파일링을 시작할지 여부를 선택합니다. 기본 설정으로 마침을 선택하면 선택한 프로젝트 또는 실행 파일을 실행하고 프로파일링을 시작하게 됩니다.

응용 프로그램이 실행되면 다양한 테스트 시나리오로 테스트를 진행하고, 응용 프로그램을 마치면 수집된 프로파일링 정보로 프로파일링 결과 페이지를 볼 수 있습니다.

화면의 좌측 상단의 뷰를 변경하면서 성능 구간을 다양한 측면에서 분석을 할 수 있습니다.


저작자 표시 비영리 동일 조건 변경 허락
신고

Visual Studio 2010에서 단위 테스트 프로젝트를 생성하면 .NET Framework 4.0 의 단위 테스트 프로젝트를 지원했습니다. 단위 테스트 프로젝트를 .NET Framework 3.5 로 변경을 하게 되면 올바로 단위 테스트가 수행되지 않았던 문제가 있었습니다. 바로 아래와 같이 .NET Framework 버전을 변경하게 되면 발생하는 오류 메시지입니다.

그림 1 Visual Studio 2010에서 .NET Framework 3.5 로 변경할 경우

때문에 MSBuild 4.0으로 .NET Framework 3.5 빌드 및 테스트를 하게 되면 올바르게 빌드가 되지 않는 문제가 있었습니다.

필자 또한 이러한 문제로 인하여 다음과 같은 불편한 과정을 겪어야 했습니다.

참고

VS2008 을 VS2010 에서 동시에 개발하기

http://blog.powerumc.kr/314

VS2008 과 VS2010 동시에 개발하기 : 테스트 프로젝트가 포함 될 경우

http://blog.powerumc.kr/315

Visual Studio 2010 SP1은 이제 .NET Framework 3.5 버전의 단위 테스트도 지원이 가능하게 되었습니다.

그림 2 Visual Studio 2010에서 .NET Framework 3.5, 4.0 모두 단위 테스트 지원

다만, Visual Studio 2010 SP1은 .NET Framework 3.5까지 단위 테스트 프로젝트를 지원하며, 그 이하(.NET Framework 2.0, 3.0) 단위 테스트는 지원하지 않습니다.

저작자 표시 비영리 동일 조건 변경 허락
신고

Visual Studio 2010 SP1 의 실버라이트 4 개발 환경

Visual Studio 2010 SP1은 실버라이트 4 개발자 툴 킷이 포함이 되어 바로 실버라이트 4 개발을 할 수 있습니다.

그림 4 실버라이트 프로젝트 템플릿 선택

기존의 실버라이트 프로젝트 템플릿을 선택하여 프로젝트를 생성하면, 실버라이트 버전을 선택하여 원하는 실버라이트 버전으로 개발을 할 수 있습니다.

그림 5 실버라이트 버전 선택

실버라이트 4는 많은 사용자의 요구 사항과 코어의 변화가 있습니다. 자세한 내용은 아래의 링크를 ㅋ통해 MSDN 을 참고하십시오

참고

Silverlight 4의 새로운 기능 http://msdn.microsoft.com/ko-kr/library/dd772166(v=vs.95).aspx

실버라이트 4 의 새로운 기능

  • 컨트롤
  • 브라우저 외부에서 실행
  • 미디어
  • 네트워킹
  • 인쇄
  • 사용자 인터페이스
  • XAML
  • 데이터
  • 응용 프로그램 모델
  • 코어
  • Silverlight 디자이너
  • Windows Forms 플랫폼 지원
  • 관련 항목
저작자 표시 비영리 동일 조건 변경 허락
신고

[Visual Studio 2010 SP1] Help Viewer 1.1

Visual Studio 2010 2011.06.08 08:30 Posted by POWERUMC

웹 브라우저 도움말이 데스크탑 응용 프로그램으로 변경

Visual Studio 2010 이전의 도움말 설명서(Help Documentation) 은 별도의 클라이언트 응용 프로그램으로 구동되었습니다. 하지만 Visual Studio 2010버전에서는 웹 브라우저를 통해 MSDN Online과 같은 화면으로 도움말 설명서가 로컬 웹 서버를 통해 구동이 되었습니다.

그림 1 Visual Studio 2008 도움말 설명서

그림 2 Visual Studio 2010 로컬 웹 도움말 설명서

두 가지 방식의 장단점은 다르겠지만, Visual Studio 2010 로컬 웹 도움말 설명서는 입력한 내용의 인덱스를 보여주지 않아 매우 불편했었습니다. 클래스 이름이나 네임스페이스 이름으로 검색할 때 AJAX 기술로 키워드의 인덱스를 보여주었더라면 그나마 좋았을 텐데 하고 불편함을 감수하기도 하였습니다.

Visual Studio 2010 SP1 에서는 로컬 웹이 구동되고 키워드가 인덱스 되지 않는 부분을 개선하여 기존의 로컬 도움말 설명서로 개선이 되었습니다.

그림 3 Visual Studio 2010 SP1 의 로컬 도움말 설명서

기존의 Visual Studio 2008 과 유사한 로컬 도움말 설명서 응용 프로그램으로 구동이 됩니다. 다만, 필자는 색인 창을 오른쪽에 도킹하여 쓰는데, 현재 Visual Studio 2010 SP1 에서는 도킹 기능은 제공하지 않습니다.

개선해야 할 점

기존의 웹 브라우저 방식보다 Help Viewer 1.1 이 낫긴 하지만, 여전히 사용자의 측면에서 불편하기는 마찬가지 입니다.

첫 번째, 여전히 로컬 웹 서버가 동작하여 도움말이 구동됩니다. 닫아버리고 싶은 왠지 모를 강박감…!

두 번째, 도움말의 폰트 크기가 제각각 입니다. 폰트도 작은데, 크게 키우면 너무 크고...
좌측은 Help Viewer 1.1, 우측은 MSDN 온라인 도움말.


세 번째, 샘플 코드 구조가 사정없이 깨집니다.
좌측, Help Viewer 1.1, 우측은 MSDN 온라인 도움말

네 번째, 개인적으로 인덱스 창을 오른쪽에 도킹하는데, 도킹 기능이 없네요^^;

다섯 번째, MSDN Documentation 2008 에서는 고유 URL 이 있는데, 지금은 도움말 에이전트의 URL 도 보여주지 않네요.
좌측은 MSDN Documentation 2008, 우측은 Help Viewer 1.1

그 밖에, 사용자 경험은 여러분께 맡기겠습니다.

저작자 표시 비영리 동일 조건 변경 허락
신고