Map [duplicate]을 사용하여 백 버퍼 D3D11에서 데이터 가져 오기
ID3D11DeviceContext :: Map ()을 올바르게 사용하는 데 문제가 있습니다.
지금까지의 전체 기능은 다음과 같습니다.
Color Graphics::GetPixel(int x, int y) const
{
//Temp frame buffer descriptor;
CD3D11_TEXTURE2D_DESC pFrameDesc;
pFrameDesc.Width = WindowWidth;
pFrameDesc.Height = WindowHeight;
pFrameDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
pFrameDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
pFrameDesc.MipLevels = 1u;
pFrameDesc.ArraySize = 1u;
pFrameDesc.SampleDesc.Count = 1u;
pFrameDesc.SampleDesc.Quality = 0u;
pFrameDesc.Usage = D3D11_USAGE_DEFAULT;
pFrameDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
pFrameDesc.MiscFlags = 0u;
// Create temp frame buffer(2d texture)
wrl::ComPtr<ID3D11Texture2D>pFrame = nullptr;
HRESULT hr = pDevice->CreateTexture2D(&pFrameDesc, nullptr, &pFrame);
GFX_THROW_INFO(hr);
hr = pSwapChain->GetBuffer(0, __uuidof(pFrame), &pFrame);
GFX_THROW_INFO(hr);
D3D11_MAPPED_SUBRESOURCE map;
map.RowPitch = WindowWidth * 4;
map.DepthPitch = WindowHeight * 4;
//Throwing here, CPU access flags problem.
hr = pContext->Map(pFrame.Get(), 0u, D3D11_MAP_READ, 0u, &map);
GFX_THROW_INFO(hr);
pContext->Unmap(pFrame.Get(), 0u);
return { 0.0f, 0.4f, 0.0f, 0.0f };
}
pContext-> Map ()에서 예외가 발생했습니다.
"리소스가 D3D11_CPU_ACCESS_READ 플래그로 생성되지 않았기 때문에 MAP_READ 액세스로 맵을 호출 할 수 없습니다."
새로 생성 된 리소스에 D3D11_CPU_ACCESS_READ 플래그가 활성화되어 있기 때문에 혼란 스럽습니다. MAP_WRITE를 시도하고 액세스 플래그를 일치하도록 변경하는 경우에도 마찬가지입니다. 나는 또한 운없이 플래그를 ORing 시도했습니다.
이 함수의 궁극적 인 사용은 Color 객체의 CPU 측 배열을 생성 할 수 있도록하는 것입니다 (현재 색상은 4 개의 float의 구조체입니다). 그런 다음 NewTek NDI sdk로 전송할 수 있습니다. 하지만 스크린 샷을 저장하고 색상 선택기를 만드는데도 유용 할 것 같습니다.
어떤 아이디어라도 환영합니다!
답변
코드는 D3D11_CPU_ACCESS_READ
.
텍스처를 만듭니다.
// Create temp frame buffer(2d texture)
wrl::ComPtr<ID3D11Texture2D>pFrame = nullptr;
HRESULT hr = pDevice->CreateTexture2D(&pFrameDesc, nullptr, &pFrame);
GFX_THROW_INFO(hr);
그런 다음 해당 텍스처를 해제하고 스왑 체인에서 하나에 대한 참조를 가져옵니다 ( CPU READ에 대해 설정 되지 않음 ).
hr = pSwapChain->GetBuffer(0, __uuidof(pFrame), &pFrame);
GFX_THROW_INFO(hr);
그런 다음 swapchain 버퍼를 매핑합니다.
hr = pContext->Map(pFrame.Get(), 0u, D3D11_MAP_READ, 0u, &map);
GFX_THROW_INFO(hr);
Chuck Walbourn의 대답은 맞지만 좀 더 컨텍스트를 제공하기 위해 생성하는 텍스처 pDevice->CreateTexture2D
는에서 얻는 것과 동일하지 않습니다 pSwapChain->GetBuffer
.
와 pDevice->CreateTexture2D
, 당신이 만드는 새로운 (실제로 CPU에서 읽을 수 있도록 설정되어 있습니다)에 메모리 질감을. 새 텍스처는에 저장됩니다 pFrame
.
그런 다음을 사용 하여 스왑 체인 (CPU 읽기 액세스로 생성되지 않음)에서 기존 백 버퍼를 pSwapChain->GetBuffer
가져옵니다 . 이것은에 저장되어 이전 값을 효과적으로 버립니다.pFrame
여기에 두 가지 선택이 있습니다. (나는 몇 년 동안 D3D11을 건드리지 않았습니다. 이것은 제 D3D12, Vulkan 및 현재 세대 콘솔 지식을 기반으로합니다)
옵션 A 는 새로운 온 메모리 텍스처를 버리고 대신 CPU 액세스를 위해 스왑 체인에 백 버퍼를 설정하는 것입니다. CPU 리드 백을위한 텍스처가 CPU 액세스없이 생성 된 텍스처만큼 반드시 수행되는 것은 아니기 때문에 권장하지 않습니다.
또한 메모리를 매핑하는 동안 GPU는 텍스처의 내용을 비우고 메모리 매핑을 해제 할 때까지 모든 GPU 작업을 중지해야합니다. 드로잉 프로세스에서이 작업을 수행하는 위치에 따라이 작업은 큰 병목 현상이 발생합니다.
그건 그렇고, Direct3D가 CPU 읽기 액세스로 스왑 체인을 만들 수 있는지 여부는 확실하지 않으므로 사용해 볼 수도 없을 것입니다.
옵션 B 는 전체 화면 텍스처 쿼드로 그리기 작업을 만드는 것입니다. 여기서 텍스처는 백 버퍼이고 렌더링 대상은 CPU에서 읽을 수있는 텍스처입니다. 이것은 하나의 전체 화면 그리기 작업을 희생하면서 옵션 A의 모든 문제를 해결하기 때문에 일반적으로 선호되는 방법입니다.
백 버퍼를 드로잉 용 텍스처로 설정하지 못할 수도 있다는 점을 기억하십시오 (D3D11에서는 기억하지 못함). 이 경우 게임의 드로 콜을 백 버퍼로 직접 만드는 대신 또 다른 렌더 타겟을 만들고 여기에 모든 것을 그린 다음 두 개의 복사본을 만들어야 할 수 있습니다. 하나는 스왑 체인 백 버퍼에, 다른 하나는 CPU 판독 가능 텍스처.
이 방법은 좀 더 복잡하지만 D3D12 및 다른 모든 최신 플랫폼에서 작동하는 것이 보장됩니다.