다이렉트컴퓨트(DirectCompute)는 프로그래머들이 컴퓨터의 그래픽 처리 장치(GPU)에서 범용 컴퓨팅을 수행할 수 있도록 하는 다이렉트X 11의 기능이다. 

 

목차

     

     


     

     

     

    Direct Compute

     

    DirectCompute는 프로그래머들이 컴퓨터의 그래픽 처리 장치(GPU)에서 범용 컴퓨팅을 수행할 수 있도록 하는 다이렉트X 11의 기능이다.

    전통적인 그래픽스 프로그래밍에서 GPU는 화면에 이미지를 렌더링하고 표시하는 데 사용된다. 그러나 DirectCompute는 개발자들이 GPU의 병렬 처리 능력을 사용하여 물리 시뮬레이션, 데이터 처리 또는 인공 지능과 같은 그래픽과 반드시 관련이 없는 계산을 수행할 수 있도록 한다.

    DirectCompute는 DirectX 11의 프로그래밍 가능한 파이프라인 단계인 컴퓨팅 셰이더 기술을 기반으로 한다. GPU 상에서 실행되는 컴퓨팅 셰이더(Compute Shaders)라는 프로그램을 작성할 수 있으며, 대규모 병렬 아키텍처를 활용하여 계산을 가속화할 수 있다.

    컴퓨팅 셰이더는 그래픽 셰이더에 사용되는 HLSL(High-Level Shading Language)의 변형으로 작성되지만 입력 및 출력 요구 사항이 다르다. 컴퓨팅 셰이더는 구조화되거나 구조화되지 않은 데이터를 가져와 정의된 알고리즘을 사용하여 처리한 다음 결과를 메모리로 출력하거나 CPU로 다시 출력한다.

    DirectCompute는 과학 컴퓨팅, 엔지니어링 시뮬레이션, 재무 모델링 및 기계 학습을 포함한 다양한 분야에서 점점 더 인기를 얻고 있다. 개발자들은 최신 GPU의 힘을 이용하여 CPU를 단독으로 사용하는 것보다 더 빠른 성능을 달성할 수 있다.

     


     

     

    Timer

     

    Timer.h

    더보기
    #pragma once
    
    class Time
    {
    public:
    	static Time* Get();
    
    	static void Create();
    	static void Delete();
    
    	static bool Stopped() { return isTimerStopped; }
    	static float Delta() { return isTimerStopped ? 0.0f : timeElapsed; }
    
    	void Update();
    	void Print();
    
    	void Start();
    	void Stop();
    
    	float FPS() const { return framePerSecond; }
    	float Running() const { return runningTime; }
    
    private:
    	Time(void);
    	~Time(void);
    
    	static Time* instance;// 싱글톤 객체
    
    	static bool isTimerStopped;// 타이머 중지
    	static float timeElapsed;// 이전 프레임으로부터 경과시간
    
    
    	INT64 ticksPerSecond;// 초당 틱카운트
    	INT64 currentTime;// 현재 시간
    	INT64 lastTime;// 이전시간
    	INT64 lastFPSUpdate;// 마지막 FPS 업데이트 시간
    	INT64 fpsUpdateInterval;// fps 업데이트 간격
    
    	UINT frameCount;// 프레임 수
    	float runningTime;// 진행 시간
    	float framePerSecond;// FPS
    };
    
    
    class Timer
    {
    public:
    	Timer();
    	~Timer();
    
    	void Start(function<void()> func, int milliSec, UINT repeat = 0);
    	void Stop();
    
    private:
    	mutex m;
    
    	bool bComplete;
    	UINT count;
    };
    
    
    class Performance
    {
    public:
    	Performance();
    
    	void Start();
    	float End();
    
    private:
    	__int64 tick;
    	__int64 start, end;
    };

     

     

    Timer.cpp

    더보기
    #include "framework.h"
    #include "Time.h"
    
    Time* Time::instance = NULL;
    
    bool Time::isTimerStopped = true;
    float Time::timeElapsed = 0.0f;
    
    Time::Time(void) :
    	ticksPerSecond(0), currentTime(0), lastTime(0), lastFPSUpdate(0), fpsUpdateInterval(0),
    	frameCount(0), runningTime(0), framePerSecond(0)
    {
    	QueryPerformanceFrequency((LARGE_INTEGER *)&ticksPerSecond);
    	fpsUpdateInterval = ticksPerSecond >> 1;
    
    	/*TwBar* bar = TweakBar::Get()->GetBar();
    	TwAddVarRO(bar, "Time", TW_TYPE_FLOAT, &framePerSecond, "");*/
    }
    
    Time::~Time(void)
    {
    
    }
    
    Time* Time::Get()
    {
    	assert(instance != NULL);
    
    	return instance;
    }
    
    void Time::Create()
    {
    	assert(instance == NULL);
    
    	instance = new Time();
    }
    
    void Time::Delete()
    {
    	SafeDelete(instance);
    }
    
    void Time::Update()
    {
    	if (isTimerStopped) return;
    
    	//1. 현재시간을 가져와 시간 간격 및 진행 시간을 계산한다.
    	QueryPerformanceCounter((LARGE_INTEGER *)&currentTime);
    	timeElapsed = (float)(currentTime - lastTime) / (float)ticksPerSecond;
    	runningTime += timeElapsed;
    
    
    	//2. FPS Update
    	frameCount++;
    	if (currentTime - lastFPSUpdate >= fpsUpdateInterval)
    	{
    		float tempCurrentTime = (float)currentTime / (float)ticksPerSecond;
    		float tempLastTime = (float)lastFPSUpdate / (float)ticksPerSecond;
    		framePerSecond = (float)frameCount / (tempCurrentTime - tempLastTime);
    
    		lastFPSUpdate = (INT64)currentTime;
    		frameCount = 0;
    	}
    
    	lastTime = currentTime;
    }
    
    void Time::Print()
    {
    
    }
    
    void Time::Start()
    {
    	if (!isTimerStopped)
    		assert(false);
    
    	QueryPerformanceCounter((LARGE_INTEGER *)&lastTime);
    	isTimerStopped = false;
    }
    
    void Time::Stop()
    {
    	if (isTimerStopped)
    		assert(false);
    
    	INT64 stopTime = 0;
    	QueryPerformanceCounter((LARGE_INTEGER *)&stopTime);
    	runningTime += (float)(stopTime - lastTime) / (float)ticksPerSecond;
    	isTimerStopped = true;
    }
    
    
    Timer::Timer()
    {
    	bComplete = false;
    
    	count = 0;
    }
    
    Timer::~Timer()
    {
    
    }
    
    void Timer::Start(function<void()> func, int milliSec, UINT repeat)
    {
    	assert(bComplete == false);
    
    	bComplete = false;
    	thread t([=]()
    	{
    		while (true)
    		{
    			if (repeat > 0 && count == repeat)
    				break;
    
    			if (bComplete == true)
    				break;
    
    			count++;
    			Sleep(milliSec);
    
    			if (bComplete == true)
    				break;
    
    			func();
    		}
    
    		Stop();
    	});
    	t.detach();
    }
    
    void Timer::Stop()
    {
    	count = 0;
    
    	bComplete = true;
    }
    
    
    Performance::Performance()
    {
    	QueryPerformanceFrequency((LARGE_INTEGER *)&tick);
    }
    
    void Performance::Start()
    {
    	QueryPerformanceCounter((LARGE_INTEGER *)&start);
    }
    
    float Performance::End()
    {
    	QueryPerformanceCounter((LARGE_INTEGER *)&end);
    
    	//start~end 사이의 소요시간
    	return (float)((double)(end - start) / tick * 1000.0f);
    }

     


     

    Thread Demo

     

    ThreadDemo.h

    더보기
    #pragma once
    #include "Systems/IExecute.h"
    
    class ThreadDemo : public IExecute
    {
    public:
    	virtual void Initialize() override;
    	virtual void Ready() override {}
    	virtual void Destroy() override {}
    	virtual void Update() override;
    	virtual void PreRender() override {}
    	virtual void Render() override;
    	virtual void PostRender() override {}
    	virtual void ResizeScreen() override {}
    
    private:
    	void ExecuteTimer();
    	void ExecutePerfomence();
    
    private:
    	mutex m;
    	float progress = 0.0f;
    
    	Timer timer;
    	Timer timer2;
    };

     

     

    ThreadDemo.cpp

    더보기
    #include "stdafx.h"
    #include "ThreadDemo.h"
    
    void ThreadDemo::Initialize()
    {
    	//ExecuteTimer();
    	ExecutePerfomence();
    }
    
    void ThreadDemo::Update()
    {
    }
    
    void ThreadDemo::Render()
    {
    }
    
    
    void ThreadDemo::ExecuteTimer()
    {
    	timer.Start([]() //람다식
    	{
    		printf("Timer\n");
    	}, 2000, 2); //2000ms(=2초)마다 2번 수행
    
    	timer2.Start([]()
    	{
    		printf("Timer2\n");
    	}, 3000);//뒤에 값이 없으니 default값인 0. 따라서 3000ms마다 무한번 실행.
    }
    
    void ThreadDemo::ExecutePerfomence()
    {
    	int arr[10000];
    	for (int i = 0; i < 10000; i++)
    		arr[i] = Math::Random(0, 100000);
    
    	
    	Performance p;
    	p.Start();
    	{
    		sort(arr, arr + 10000);
    	}
    	float last = p.End();
    
    	printf("총 수행시간 : %f\n", last);
    }

     


     

    실행화면