문제

나는 방법을 알아낼 필요가에서 데이터를 얻을 수 있 D3D 질감을 표시하는 시스템 메모리입니다.What's 하는 가장 빠른 방법은 다음 사항을 어떻게?

또한다면 내가 하나만 필요 subrect,할 수 있습니다 어떻게 해야 하나 다시 읽는 부분을 읽어들이지 않고 다시 모든 것을 시스템 메모리가 있습니까?

에서 짧은 내가 찾는 간결한 설명으로 복사하는 방법을 다음 시스템 메모리:

  1. a
  2. a 하위 집합
  3. a 표면
  4. a 하위 집합표면
  5. a D3DUSAGE_RENDERTARGET 질감
  6. a 하위 집합D3DUSAGE_RENDERTARGET 질감

이 Direct3D9 지만,응답에 대한 새로운 버전의 D3D 너무 감사하겠습니다.

도움이 되었습니까?

해결책

가장 관련 부분은 독서에서는 표면에서 비디오 메모리("기본 수영장").이는 대부분의 렌더 대상입니다.

하기 쉬운 부분이 먼저:

  1. 에서 읽고 텍스처와 동일에서 읽 0-수평면의 것 텍스처입니다.아래를 참조하십시오.
  2. 에 대해 동일한 하위 집합의 질감입니다.
  3. 에서 읽고 표면에 있는 기본이 아닌 메모리 풀("시스템"또는"처리")는 단지 잠금 그것을 읽기를 바이트 단위이다.
  4. 에 대해 동일한 하위 집합의 표면입니다.그냥 잠금 관련 부분을 읽습니다.

그래서 지금 우리가 왼쪽 표면에 있는 비디오 메모리("기본 수영장").이 것이 어떤 표면 질감으로 표시되는 렌더링 대상,또는 일정한 표면 질감/을 만들어서 기본 수영장,또는 backbuffer 자체입니다.복잡한 부분은 여기할 수 없는 잠급니다.

짧은 대답입니다: GetRenderTargetData 는 방법에 D3D 장치입니다.

더 이상 정답(대략적 코드는 아래에있을 것입니다):

  1. rt =얻을 렌더 타겟 표면(이 수 있는 표면의 질감,또는 backbuffer,etc.)
  2. 는 경우 rt 은 전체(GetDesc 확인 D3DSURFACE_DESC.MultiSampleType 음):a)다른 렌더 타겟 표면의 동일한 크기,동일한 형식으로만 멀티샘플링;b)StretchRect 서 rt 이 새로운 표면;c) rt =이 새로운 표면(즉에 진행이 새로운 표면).
  3. =create 화면 일반 표면(CreateOffscreenPlainSurface,D3DPOOL_SYSTEMMEM 수영장)
  4. 장치->GetRenderTargetData( rt, )
  5. 지금 담 렌더링 대상이다.LockRect(),읽기 데이터,UnlockRect()니다.
  6. 정리

더 이상 정답(에서 붙여넣기 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++.

위의 코드를 읽고 다시 표면 전체.를 읽어들이는 경우 단지 그것의 일부를 효율적으로 다음을 믿는 가장 빠른 방법은 대략 다음과 같습니다:

  1. 만들기 기본 수 있는 표면에 필요한 크기입니다.
  2. StretchRect 부분에서의 표면의 작은 하나입니다.
  3. 진행을 정상적으로 작은 하나입니다.

사실 이것은 매우 비슷하는 코드는 위의지를 처리하는 멀티 샘플링 표면이 있습니다.을 얻고 싶은 경우 단지의 일부는 멀티 샘플링 표면,당신이 할 수 있는 multisample 해결하고 얻을 수있는 그것의 일부에 한 StretchRect,나는 생각한다.

편집:제거하는 코드 부분은 실제로 읽의 픽셀 형식으로 변환.되지 않았 직접 관련된 질문,그리고 코드는 오래되었다.

편집:맞게 업데이트 편집 질문입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top