을 리드백에서는 Direct3D 표면 질감과
-
02-07-2019 - |
문제
나는 방법을 알아낼 필요가에서 데이터를 얻을 수 있 D3D 질감을 표시하는 시스템 메모리입니다.What's 하는 가장 빠른 방법은 다음 사항을 어떻게?
또한다면 내가 하나만 필요 subrect,할 수 있습니다 어떻게 해야 하나 다시 읽는 부분을 읽어들이지 않고 다시 모든 것을 시스템 메모리가 있습니까?
에서 짧은 내가 찾는 간결한 설명으로 복사하는 방법을 다음 시스템 메모리:
- a 감
- a 하위 집합 의 감
- a 표면
- a 하위 집합 의 표면
- a D3DUSAGE_RENDERTARGET 질감
- a 하위 집합 의 D3DUSAGE_RENDERTARGET 질감
이 Direct3D9 지만,응답에 대한 새로운 버전의 D3D 너무 감사하겠습니다.
해결책
가장 관련 부분은 독서에서는 표면에서 비디오 메모리("기본 수영장").이는 대부분의 렌더 대상입니다.
하기 쉬운 부분이 먼저:
- 에서 읽고 텍스처와 동일에서 읽 0-수평면의 것 텍스처입니다.아래를 참조하십시오.
- 에 대해 동일한 하위 집합의 질감입니다.
- 에서 읽고 표면에 있는 기본이 아닌 메모리 풀("시스템"또는"처리")는 단지 잠금 그것을 읽기를 바이트 단위이다.
- 에 대해 동일한 하위 집합의 표면입니다.그냥 잠금 관련 부분을 읽습니다.
그래서 지금 우리가 왼쪽 표면에 있는 비디오 메모리("기본 수영장").이 것이 어떤 표면 질감으로 표시되는 렌더링 대상,또는 일정한 표면 질감/을 만들어서 기본 수영장,또는 backbuffer 자체입니다.복잡한 부분은 여기할 수 없는 잠급니다.
짧은 대답입니다: GetRenderTargetData 는 방법에 D3D 장치입니다.
더 이상 정답(대략적 코드는 아래에있을 것입니다):
- rt =얻을 렌더 타겟 표면(이 수 있는 표면의 질감,또는 backbuffer,etc.)
- 는 경우 rt 은 전체(GetDesc 확인 D3DSURFACE_DESC.MultiSampleType 음):a)다른 렌더 타겟 표면의 동일한 크기,동일한 형식으로만 없 멀티샘플링;b)StretchRect 서 rt 이 새로운 표면;c) rt =이 새로운 표면(즉에 진행이 새로운 표면).
- 륙 =create 화면 일반 표면(CreateOffscreenPlainSurface,D3DPOOL_SYSTEMMEM 수영장)
- 장치->GetRenderTargetData( rt, 륙 )
- 지금 륙 담 렌더링 대상이다.LockRect(),읽기 데이터,UnlockRect()니다.
- 정리
더 이상 정답(에서 붙여넣기 codebase 에서 일하고 있어요)다음과 같습니다.이 지 않을 것이다 컴파일한 상자,사용하기 때문에 일부 교실,기능,매크로,유틸리티의 나머지 부분에서 codebase;그러나 그것은 당신을 얻을 시작했다.또한 ommitted 대부분의 오류를 검사(예:주어진 여부를 width/height 은 경계에서).나는 또한 생략되는 부분을 읽고 실제 픽셀,가로 변환 적절한 대상 형식으로(즉,매우 쉽지만 오랫동안 얻을 수 있는,사무소 방문민원의 수에 따라 다 형식으로 변환을 지원할).
bool GfxDeviceD3D9::ReadbackImage( /* params */ )
{
HRESULT hr;
IDirect3DDevice9* dev = GetD3DDevice();
SurfacePointer renderTarget;
hr = dev->GetRenderTarget( 0, &renderTarget );
if( !renderTarget || FAILED(hr) )
return false;
D3DSURFACE_DESC rtDesc;
renderTarget->GetDesc( &rtDesc );
SurfacePointer resolvedSurface;
if( rtDesc.MultiSampleType != D3DMULTISAMPLE_NONE )
{
hr = dev->CreateRenderTarget( rtDesc.Width, rtDesc.Height, rtDesc.Format, D3DMULTISAMPLE_NONE, 0, FALSE, &resolvedSurface, NULL );
if( FAILED(hr) )
return false;
hr = dev->StretchRect( renderTarget, NULL, resolvedSurface, NULL, D3DTEXF_NONE );
if( FAILED(hr) )
return false;
renderTarget = resolvedSurface;
}
SurfacePointer offscreenSurface;
hr = dev->CreateOffscreenPlainSurface( rtDesc.Width, rtDesc.Height, rtDesc.Format, D3DPOOL_SYSTEMMEM, &offscreenSurface, NULL );
if( FAILED(hr) )
return false;
hr = dev->GetRenderTargetData( renderTarget, offscreenSurface );
bool ok = SUCCEEDED(hr);
if( ok )
{
// Here we have data in offscreenSurface.
D3DLOCKED_RECT lr;
RECT rect;
rect.left = 0;
rect.right = rtDesc.Width;
rect.top = 0;
rect.bottom = rtDesc.Height;
// Lock the surface to read pixels
hr = offscreenSurface->LockRect( &lr, &rect, D3DLOCK_READONLY );
if( SUCCEEDED(hr) )
{
// Pointer to data is lt.pBits, each row is
// lr.Pitch bytes apart (often it is the same as width*bpp, but
// can be larger if driver uses padding)
// Read the data here!
offscreenSurface->UnlockRect();
}
else
{
ok = false;
}
}
return ok;
}
SurfacePointer
위 코드에서는 스마트 포인터를 COM 체(이것은 자료에 객체를 할당하거나 소멸).간단한 오류 처리을 많이합니다.이것은 매우 비슷하기 _comptr_t
일 Visual C++.
위의 코드를 읽고 다시 표면 전체.를 읽어들이는 경우 단지 그것의 일부를 효율적으로 다음을 믿는 가장 빠른 방법은 대략 다음과 같습니다:
- 만들기 기본 수 있는 표면에 필요한 크기입니다.
- StretchRect 부분에서의 표면의 작은 하나입니다.
- 진행을 정상적으로 작은 하나입니다.
사실 이것은 매우 비슷하는 코드는 위의지를 처리하는 멀티 샘플링 표면이 있습니다.을 얻고 싶은 경우 단지의 일부는 멀티 샘플링 표면,당신이 할 수 있는 multisample 해결하고 얻을 수있는 그것의 일부에 한 StretchRect,나는 생각한다.
편집:제거하는 코드 부분은 실제로 읽의 픽셀 형식으로 변환.되지 않았 직접 관련된 질문,그리고 코드는 오래되었다.
편집:맞게 업데이트 편집 질문입니다.