directx12 11

[Dx12] cpu-gpu 병렬처리

dx12는 fence를 통해 gpu작업이 끝나면 cpu가 실행되도록한다.그런데 gpu실행하는 동안 cpu가 놀고있으면 비효율적이니 context를 2~3개로 써서 cpu와 gpu가 동시에 실행 될 수 있도록 하는 기법이 있다.그림으로 보면 다음과 같다 커맨드리스트, 디스크립터풀 등을 2개로 만든다.첫번째 프레임에는 첫번째 커맨드리스트, 첫번째 디스크립터 풀 작업을 cpu에서한다. 그리고 gpu에 올린다. 그러면 gpu작업을 하는동안 두번째 커맨드리스트, 두번째 디스크립터 풀작업을 cpu에서 한다. 이렇게 돌아가는 식이다. 여기서 포인트는 반드시 해당 프레임에선 해당 번째의 커맨드리스트와 디스크립터 풀을 이용해야한다는 점이다. 그렇지않으면 gpu작업중에 그 gpu에 해당하는 데이터(디스크립터 및 리소스)..

[3dsmax-plugin]애니메이션 time0일땐 되고 나머지는 다 망가질 때 해결법

스키닝이 꼬이는 문제는 정말 많지만. 아무리 생각해도 값 완벽하게 들어갔는데 뭔가 스키닝이 꼬이는 경우가 있을 수 있다. max에서는 애니메이션이 잘 작동하는데 내 엔진에서는 이렇게 꼬일 수도 있다. 근데 이걸 time을 0으로 맞춰놓고 찍어보면 그냥 가만히 서있는 model로서 잘 나온다. 즉 값은 잘 들어갔다는 것이다. 그런데 time을 0으로 찍지말고 800으로 찍어보니까 이렇게 엄청 뒤틀린다. 분명 0과 800샘플링 된 값을 비교해 봤을때 아주 미세한 움직임인데 왜 저렇게 많이 뒤틀릴까? 그리고 내 엔진에서 행렬값을 잘 찍어봐도 다 명확하게 잘 들어갔다. 특히 time이 0일때는 잘 그려지는데 나머지는 망가질때 첫번째로 의심해야할 부분은 이것이다."bone과 bind-pose가 정확히 매칭이 ..

외부 애니메이션 씬 파일 뽑아서 엔진에 넣을 때 case 구분

max에서 데이터를 뽑아서 자체 엔진에 넣을 때, 다양한 케이스를 나눠서 읽도록 해야한다. 이미 유니티나 언리얼은 그걸 다 구현해놓았다. 예를들어 어떤 사이트에서 스키닝된 캐릭터와 그에 딸린 몇몇 오브젝트들(스키닝 되지 않음)이 한꺼번에 애니메이션이 구현되는 경우가 있다. 그럴 땐, 그냥 스키닝 된 캐릭터와 그에 딸린 지오메트리만 선택해서 따로빼는게 좋겠다. 나머지 스키닝 되지 않은 오브젝트들은 스키닝 되어있지 않지만, bone에 딸려있을 수도 있다. 그걸 다 한꺼번에 빼버리면 너무 작업량이 많아지고, 완전히 익스포트해서 임포트가 잘 진행되었다 하더라도 비효율적인 것 같다. 가령 스키닝된 캐릭터와 캐릭터의 손목의 자식으로 무기가 하나 딸려있고 그 무기의 나사부분이 계속 돌아가는 씬을 다운받았다고 가정하자..

max sdk에서 offsetMatrix를 어떻게 보내야할까

assimp의 offsetMatrix의 주석을 살펴보면,Matrix that transforms from mesh space to bone space in bind pose..뭐 이렇다고한다. 이게 정확히 무슨 의미이고 왜 필요할까? 애니메이션의 bone을 gpu에보낼때 마지막에m_FinalBoneMatrices[index] = offset * globalTransformation 이렇게 처리한다.globalTransformation은 현재 nodeTransform * parentTransform이다. 여기서 nodeTransform은 localSpace이고, parentTransform은 worldTransform(=globalTransform)이다. parentTransform은 localTransf..

[매크로 충돌 제거] 디버깅누수 new 매크로와, Assimp new매크로

메모리 leak이 났을 때 출력창에Detected memory leaks!Dumping objects ->C:\Users\Lenovo\source\repos\Dx12Engine\Dx12Engine\Renderer.cpp(398) : {257} normal block at 0x000001CFFEC93A20, 592 bytes long. Data: 02 00 00 00 00 00 00 00 CD CD CD CD CD CD CD CD Object dump complete.The program '[10252] Dx12Engine.exe' has exited with code 0 (0x0). 이렇게 코드 몇번째 줄 어디서 에러가 떴는지 출력해주기 위해선#ifdef _DEBUG#define new new(_NOR..

[Dx12] suballocate로 메모리 관리해야 하는 이유

VRAM에 데이터 올릴 때 vertex리소스는 Upload힙을 통해 Default힙으로 메모리를 올린다. Constant리소스는 매 프레임당 Cpu에서 접근해야하기 때문에 그냥 Upload힙으로 올린다(CPU메모리에 존재). 그런데, vertexBuffer는 프로그램 끝날 때까지 메모리에 상주해야하는데, 하나 생성할 때마다 하나씩 메모리를 생성해서 뒤죽박죽 메모리가 자리를 잡으면 외부 단편화가 생길 수 있다. 따라서 그냥 한번만 CreateCommittedResource를 호출하여 전체 vertex크기만큼의 리소스를 생성하고, vertex생성할 때마다 나눠서 가져가서 연속적으로 메모리에 배치한다. upload힙과 default힙 둘다 그렇게 해서 offset으로 잘 allocate하면 된다. consta..

[DirectX12] 디스크립터 힙의 메모리 - Write Combine Memory

Dx12에서 디스크립터 힙은 cpu메모리에 저장된 것일까? gpu메모리에 저장된 것일까? 정해지지 않았다. 매번 다르다. 하지만 flag를 구분하면 나눠볼수 있다.D3D12_DESCRIPTOR_HEAP_FLAGS 는 2가지로 나뉜다. 1) D3D12_DESCRIPTOR_HEAP_FLAG_NONE 이건 cpu메모리이다. 일반적인 시스템 메모리에 속한다. 그래서 읽기와 쓰기가 둘다 빠르다. 하지만 gpu에서 접근할 수 없다. 따라서 이 flag속성으로 만든 디스크립터 힙은 SetDescriptorHeaps에 절대 할당할 수 없다. 쉐이더에서 이용 할 수 없으니까. 하지만, 복사를 할 때 읽어야 하므로 반드시 이 flag를 써야한다.2) D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE..

[DirectX12] 디스크립터 힙을 배열처럼 사용하기 (pre-filled strategy)

매 오브젝트당 디스크립터 힙을 사용해서 렌더링하면 힙을 교체할때마다 큰 오버헤드가 발생해서 성능에 큰 문제가 생길 수 있다. 다음 마이크로소프트 디스크립터 힙 문서 내용이다https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptor-heaps-overview Switching heapsIt is acceptable for an application to switch heaps within the same command list or in different ones using the SetDescriptorHeaps and Reset APIs. On some hardware, this can be an expensive operation, r..

[DirectX12] 디스크립터와 gpu리소스의 관계

디스크립터 힙과 리소스는 완전히 다른 개념이다. (어쨌든 둘다 메모리에 할당되니 같지 않나? 라고 잘못 이해할 수도 있다. 하지만 디스크립터 복사와는 다르게 resource를 복사하려면(D3D12_HEAP_TYPE_DEFAULT인 경우) resource Barrier를 치고 commandList를 이용해야 하고, execute후에 fence를 쳐야한다는 점을 보면 완전히 다른 개념이다) 디스크립터 힙에 디스크립터들이 있고, 그 디스크립터는 리소스와 연결을 해주는 매개체이다. 리소스도 메모리 할당이 따로있고, 디스크립터 또한 메모리 할당이 따로있다. 디스크립터를 한방에 다뤄주는것이 디스크립터 힙이다.pD3DDeivce->CopyDescriptorsSimple(1, destHandle,srcHandle, ..

[DirectX12] vertex와 constant buffer 메모리 관리 차이

vertex buffer는 메모리잡아먹는 량이 크다. 그리고 한번 올리면 변경되는게 아니라 쭉 사용된다. 반면 constant buffer는 매 프레임마다 변한다. 그리고 vertex buffer만큼 메모리를 많이 잡아먹지도 않는다. 따라서 vertex buffer는 첫 초기화 시 gpu에 한번에 올리고 매 프레임마다 gpu가 접근하기 쉽게 짜야한다. constant buffer는 매 프레임마다 cpu가 접근해서 변경해야 하기에, cpu가 접근하기 쉽게 짜야한다. vertex buffer는 그래서 첫 초기화시 upload heap에 cpu가 데이터를 쓰고, 그 리소스를 gpu에 올린다. 즉 D3D12_HEAP_TYPE_UPLOAD => D3D12_HEAP_TYPE_DEFAULT 방식이다. consta..