我需要找出如何获得数据从D3D纹理和面回到系统的记忆。什么是最快的方式做这样的事情又如何?

此外,如果我只需要一部分区域,如何可以一读后只部分,而不必回读了整个事情到系统的记忆?

在短我找了简要的描述如何复制下来 系统存储器:

  1. 一个 纹理
  2. 一个 纹理
  3. 一个 表面
  4. 一个 表面
  5. 一个 D3DUSAGE_RENDERTARGET纹理
  6. 一个 D3DUSAGE_RENDERTARGET纹理

这是Direct3D9,但答案有关的新版本D3D将不胜感激。

有帮助吗?

解决方案

最所涉及的部分是从阅读一些表面是在视频存储器("默认池").这是最经常呈现的目标。

让我们简单的第一部分:

  1. 阅读,从纹理是一样的读数,从0-水平面上的纹理。见下文。
  2. 同样子的纹理。
  3. 阅读,从表面上是在非默认存池("系统"或"管理")是仅仅锁它并阅读字节。
  4. 同样子的表面。只是锁定的相关部分,并阅读。

所以现在我们左侧面是在视频存储器("默认池").这将是任何表面质地标记为呈现目标,或任何正面/纹,你已经创造了默认池,或者backbuffer本身。复杂的是,你不能锁定它。

短的回答是: GetRenderTargetData 方法上的D3D设备。

再回答(一个粗略的轮廓的代码这还将以下):

  1. rt =get呈现的目标表面(这可以表面质地、或backbuffer,等等。)
  2. 如果 rt 是multisampled(GetDesc,检查D3DSURFACE_DESC.MultiSampleType),则:a)创建的另一个呈现的目标表面的尺寸相同,但相同的格式 没有 多重采样;b)从StretchRect rt 进入这个新的表面;c) rt =这种新的表面(即继续在这个新的表面)。
  3. 关闭 =创造屏幕外面(CreateOffscreenPlainSurface,D3DPOOL_SYSTEMMEM池)
  4. 设备>GetRenderTargetData( rt, 关闭 )
  5. 现在 关闭 包含呈现目标的数据。LockRect()、读取的数据,UnlockRect()。
  6. 清理

甚至更长的时间回答(贴从codebase我的工作)下。此 将不会 编译出的框框,因为它使用了一些类、职能、宏和公用事业的其他代码;但是应该让你开始。我也省略了这些最大的错误检查(例如是否给予的宽度是超出界限).我也省略的一部分,读取实际素和可能将它们转换成适宜的目的格式(这是相当容易,但是可以得到长期的,取决于数量的格式转换你想要的支持)。

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 东西在视觉C++。

代码以上读取回的整个表面。如果你想读只是它的一部分有效,那么我相信最快的方式大致为:

  1. 创建一个默认的游泳池面的需要的大小。
  2. StretchRect从部分原来的表面,较小的一个。
  3. 继续进行正常与较小的一个。

事实上,这是相当类似于上述代码并处理多样的表面。如果你想得到的只是一部分的多样面,你可以做一个多级采样的决心和获得它的一部分在一个StretchRect,我想。

编辑:删除段代码,不会实际阅读素和格式转换。是没有直接关系的问题,代码很长。

编辑:更新编辑的问题。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top