本文章是由機器翻譯。

Windows 中的 C++

Direct2D 中的分層視窗

Kenny Kerr

在上 Direct2D 我第三個一篇,我要進行交互操作性時,顯示關閉某些不符合的電源。而不徹底詳細描述的所有各種交互操作性選項 Direct2D 提供,我打算帶您逐步完成實際的應用:分層的視窗。分層的視窗是那些已周圍建立一段很長的時間但 haven’t 發展大部分,因此需要特別注意,若要有效地使用與現代的圖形技術的 Windows 功能的一種。

本文中我將假設您有 Direct2D 程式設計基本的熟悉。如果沒有,我建議您讀取我先前的發行項六月 ( msdn.microsoft.com/magazine/dd861344 ) 和九月 ( msdn.microsoft.com/magazine/ee413543 ) 會發出所引入的程式設計和繪製 Direct2D 基礎。

原先,分層的視窗服務幾個不同的用途。在特別它們可能被用來輕鬆且有效地產生視覺效果和閃爍的轉譯。在 GDI 何時 predominant 產生圖形的方法天,這是真正的加分。在現今 ’s 硬體加速世界不過,它不再吸引人,因為分層的視窗仍屬於 User32/GDI 的世界,且尚未更新以任何明顯的方式支援 DirectX Microsoft 平台提供高效能和高品質的圖形。

分層的視窗提供唯一能夠撰寫使用每像素 Alpha 混色,而無法達成任何其他方式,Windows SDK 桌面上一個視窗。

我應該提到有真正兩種類型的分層的視窗。區別向下談到是否需要每個像素不透明度控制項,或者您只需要控制整個視窗的不透明度。本文是關於前者但如果您其實只需要控制的一個視窗不透明度您可以只需要呼叫之後建立設定 Alpha 值視窗的 [SetLayeredWindowAttributes 函式來進行。

Verify(SetLayeredWindowAttributes(
  windowHandle,
  0, // no color key
  180, // alpha value
  LWA_ALPHA));

這是假設您 WS_EX_LAYERED 延伸樣式建立視窗,或使用 SetWindowLong 函式的事實之後套用。圖 1 提供這類視窗的範例。應該明顯好處:您 don’t 需要變更任何項目如桌面視窗管理員 (DWM) 會自動融合視窗適當地在您的應用程式會繪製視窗的方式有關。水平翻轉一邊您需要自行繪製絕對的所有項目。當然如果使用一個全新的呈現技術,例如 Direct2D,’s 不問題!

圖 1 視窗具有 Alpha 值

因此什麼涉及?嗯,在基本層級它很簡單。首先,您必須填滿 UPDATELAYEREDWINDOWINFO 結構中。這個結構提供位置和大小的分層的視窗,以及 GDI 裝置內容 (DC) 定義視窗的表面 — 和暗示是出問題。DC 屬於 GDI 的舊的世界,遠離 DirectX] 和 [硬體加速的世界。更多的稍後。

除了完整的您需要配置您自己的結構的指標,UPDATELAYEREDWINDOWINFO 結構 isn’t 完全記錄在 Windows SDK 使其小於明顯使用。在所有,您需要配置五個結構。有 ’s 識別將從 DC 複製點陣圖位置的來源位置。有 ’s 識別視窗將會被上放置一次更新的桌面視窗的位置。有 ’s 它也定義視窗的大小來複製,點陣圖的大小:

POINT sourcePosition = {};
POINT windowPosition = {};
SIZE size = { 600, 400 };

然後 ’s BLENDFUNCTION 結構定義分層的視窗與桌面的混合方式。 這是一種是令人意外多功能的結構,經常忽略,但可能會很有幫助。 通常您可能會填入它,如下所示:

BLENDFUNCTION blend = {};
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;

AC_SRC_ALPHA 常數只是表示來源點陣圖是最常見的案例的 Alpha 通道。

SourceConstantAlpha 不過,是有趣,您可以使用它在很多相同的方式,您可能會使用 SetLayeredWindowAttributes 函式來控制整個視窗的不透明度。 當設定為 255 時,分層的視窗只會使用每像素 alpha 值,但是您可以調整它到零,] 或 [完全透明,產生效果,例如淡出的重繪成本沒有視窗放大或縮小。 現在很明顯原因 BLENDFUNCTION 結構命名方式是:產生 Alpha 混合視窗是這個結構 ’s 值的函式。

上次,’s 一起繫結 UPDATELAYEREDWINDOWINFO 結構:

UPDATELAYEREDWINDOWINFO info = {};
info.cbSize = sizeof(UPDATELAYEREDWINDOWINFO);
info.pptSrc = &sourcePosition;
info.pptDst = &windowPosition;
info.psize = &size;
info.pblend = &blend;
info.dwFlags = ULW_ALPHA;

這應該是相當自我闡明這個時候有唯一的未記載成員被 dwFlags 變數。 值為應該看起來很熟悉如果使用前,較舊的 UpdateLayeredWindow 函式的 ULW_ALPHA 只是表示應使用混合函式。

最後,您必須提供控點以來源 DC,並呼叫 UpdateLayeredWindowIndirect 函式來更新該視窗:

info.hdcSrc = sourceDC;

Verify(UpdateLayeredWindowIndirect(
  windowHandle, &info));

這樣就大功告成了。 視窗 won’t 接收任何 WM_PAINT 訊息。 您需要顯示或更新該視窗任何時候只要呼叫 UpdateLayeredWindowIndirect 函式。 若要保持此現成的程式碼的所有開,我將使用 LayeredWindowInfo 包裝函式類別 圖 2 本文的其餘部分中所示。

圖 2 的 LayeredWindowInfo 包裝函式類別

class LayeredWindowInfo {
  const POINT m_sourcePosition;
  POINT m_windowPosition;
  CSize m_size;
  BLENDFUNCTION m_blend;
  UPDATELAYEREDWINDOWINFO m_info;

public:

  LayeredWindowInfo(
    __in UINT width,
    __in UINT height) :
    m_sourcePosition(),
    m_windowPosition(),
    m_size(width, height),
    m_blend(),
    m_info() {

      m_info.cbSize = sizeof(UPDATELAYEREDWINDOWINFO);
      m_info.pptSrc = &m_sourcePosition;
      m_info.pptDst = &m_windowPosition;
      m_info.psize = &m_size;
      m_info.pblend = &m_blend;
      m_info.dwFlags = ULW_ALPHA;

      m_blend.SourceConstantAlpha = 255;
      m_blend.AlphaFormat = AC_SRC_ALPHA;
    }

  void Update(
    __in HWND window,
    __in HDC source) {

    m_info.hdcSrc = source;

    Verify(UpdateLayeredWindowIndirect(window, &m_info));
  }

  UINT GetWidth() const { return m_size.cx; }

  UINT GetHeight() const { return m_size.cy; }
};

圖 3 分層視窗,使用 ATL/WTL 和 LayeredWindowInfo 包裝函式類別,從 的 圖 2 提供基本的基本架構。 注意到此第一件事就是 ’s 不需要呼叫 UpdateWindow,因為這段程式碼 doesn’t 使用 WM_PAINT。 相反地它立即呼叫 Render 方法,這又是 [需要執行某些繪圖,並提供 LayeredWindowInfo ’s Update 方法的 DC。 該繪圖,就會發生的方式,以及在何處 DC 是來自是有趣取得。

圖 3 分層視窗骷髏

class LayeredWindow :
  public CWindowImpl<LayeredWindow, 
  CWindow, CWinTraits<WS_POPUP, WS_EX_LAYERED>> {

  LayeredWindowInfo m_info;

public:

  BEGIN_MSG_MAP(LayeredWindow)
    MSG_WM_DESTROY(OnDestroy)
  END_MSG_MAP()

  LayeredWindow() :
    m_info(600, 400) {

    Verify(0 != __super::Create(0)); // parent
    ShowWindow(SW_SHOW);
    Render();
  }

  void Render() {
    // Do some drawing here

    m_info.Update(m_hWnd,
      /* source DC goes here */);
  }

  void OnDestroy() {
    PostQuitMessage(1);
  }
};

在 GDI / GDI + 的方式

我先告訴您如何將它完成 GDI 中 / GDI +。 首先您必須建立 pre-multiplied 的 32-位元-每像素 (bpp) 點陣圖,使用以藍色-綠-紅色-Alpha (BGRA) 色彩通道的位元組順序。 該色彩通道值有已經被乘以 Alpha 值 pre-multiplied 的只是表示。 這傾向於提供較佳的效能的 Alpha 混合影像,但它表示您需要反轉程序相除 
alpha 值若要取得其全彩值所色彩值。 GDI 術語中這稱為 32 bpp 與裝置無關點陣圖 (DIB),而且透過填寫 BITMAPINFO 結構並傳遞它以 [CreateDIBSection 運作 (請參閱 的 圖 4) 所建立的。

圖 4 建立一個 DIB

BITMAPINFO bitmapInfo = {};
bitmapInfo.bmiHeader.biSize = 
  sizeof(bitmapInfo.bmiHeader);
bitmapInfo.bmiHeader.biWidth = 
  m_info.GetWidth();
bitmapInfo.bmiHeader.biHeight = 
  0 – m_info.GetHeight();
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biCompression = 
  BI_RGB;

void* bits = 0;

CBitmap bitmap(CreateDIBSection(
  0, // no DC palette
  &bitmapInfo,
  DIB_RGB_COLORS,
  &bits,
  0, // no file mapping object
  0)); // no file offset

有很多的詳細資料這裡,但 aren’t 相關討論。 這個 API 函式回到一個長的方法。 什麼您應該注意的是我指定負數的高度為點陣圖。 BITMAPINFOHEADER 結構定義由下而上的] 或 [由上而下點陣圖。 如果高度是正數您得到由下而上的點陣圖並如果 ’s 負取得由上而下點陣圖。 由上而下點陣圖左上角有其原點,而底部向下點陣圖有其原點在左下角。

雖然並非嚴格必要在這種情況下,我傾向於使用由上而下點陣圖,就使用的大部分現代的影像處理元件在 Windows 中的格式並且因此可以改善互通性。 這也會通往可依下列方式計算一個正數分散寬度:

UINT stride = (width * 32 + 31) / 32 * 4;

現在您有足夠的資訊可以開始繪製透過位元指標點陣圖中。 當然除非 ’re 完全 insane 想要使用某些繪圖的函式,但不幸的是大部分的 GDI 提供那些 don’t 支援 Alpha 通道]。 ’s 其中 GDI + 進來。

雖然您可以直接以 GDI + 傳遞點陣圖資料,let’s 改 DC 為其建立後您需要它仍要傳遞至 UpdateLayeredWindowIndirect 函式。 若要建立 [DC,呼叫適時具名的 CreateCompatibleDC 函式,可建立記憶體與桌面相容的 DC。 您可以再呼叫 SelectObject 巨集函式,以點陣圖選取到 DC。 GdiBitmap 包裝函式類別 的 圖 5 中包裝這一切,並提供一些額外的內部。

圖 5 的 DIB 包裝函式類別

class GdiBitmap {
  const UINT m_width;
  const UINT m_height;
  const UINT m_stride;
  void* m_bits;
  HBITMAP m_oldBitmap;

  CDC m_dc;
  CBitmap m_bitmap;

public:

  GdiBitmap(__in UINT width,
            __in UINT height) :
    m_width(width),
    m_height(height),
    m_stride((width * 32 + 31) / 32 * 4),
    m_bits(0),
    m_oldBitmap(0) {

    BITMAPINFO bitmapInfo = { };
    bitmapInfo.bmiHeader.biSize = 
      sizeof(bitmapInfo.bmiHeader);
    bitmapInfo.bmiHeader.biWidth = 
      width;
    bitmapInfo.bmiHeader.biHeight = 
      0 - height;
    bitmapInfo.bmiHeader.biPlanes = 1;
    bitmapInfo.bmiHeader.biBitCount = 32;
    bitmapInfo.bmiHeader.biCompression = 
      BI_RGB;

    m_bitmap.Attach(CreateDIBSection(
      0, // device context
      &bitmapInfo,
      DIB_RGB_COLORS,
      &m_bits,
      0, // file mapping object
      0)); // file offset
    if (0 == m_bits) {
      throw bad_alloc();
    }

    if (0 == m_dc.CreateCompatibleDC()) {
      throw bad_alloc();
    }

    m_oldBitmap = m_dc.SelectBitmap(m_bitmap);
  }

  ~GdiBitmap() {
    m_dc.SelectBitmap(m_oldBitmap);
  }

  UINT GetWidth() const {
    return m_width;
  }

  UINT GetHeight() const {
    return m_height;
  }

  UINT GetStride() const {
    return m_stride;
  }

  void* GetBits() const {
    return m_bits;
  }

  HDC GetDC() const {
    return m_dc;
  }
};

GDI + 圖形類別提供繪圖到某些裝置的方法可建構與點陣圖 ’s DC。 圖 6 顯示如何 LayeredWindow 類別從 的 圖 3 以支援使用 GDI + 的呈現時可以被更新。 一旦您有所有未定案 GDI 代碼開,’s 作業很單純。 視窗 ’s 大小傳遞至 GdiBitmap 建構函式,而點陣圖 ’s DC 會傳遞至圖形建構函式和 Update 方法。 雖然明確,GDI 和 GDI + 都不是硬體加速的 (大多數的情況),也執行它們會提供特別強大的呈現功能。

圖 6 GDI 分層視窗

class LayeredWindow :
  public CWindowImpl< ... {

  LayeredWindowInfo m_info;
  GdiBitmap m_bitmap;
  Graphics m_graphics;

public:
  LayeredWindow() :
    m_info(600, 400),
    m_bitmap(m_info.GetWidth(), m_info.GetHeight()),
    m_graphics(m_bitmap.GetDC()) {
    ...
  }

  void Render() {
    // Do some drawing with m_graphics object

    m_info.Update(m_hWnd,
      m_bitmap.GetDC());
  }
...

架構問題

相反的這是所有所需建立分層的視窗與 Windows 簡報基礎 (WPF):

class LayeredWindow : Window {
  public LayeredWindow() {
    WindowStyle = WindowStyle.None;
    AllowsTransparency = true;

    // Do some drawing here
  }
}

雖然相當簡單 belies 所涉及的複雜性,而且使用的架構的限制分層視窗。 不管如何您 sugarcoat 它,分層的視窗必須遵循本文所述到目前為止的架構原則。 儘管 WPF,或許能夠對其呈現方式使用硬體加速功能,結果仍需要複製到 pre-multiplied BGRA 點陣圖選取到相容的 DC,透過 UpdateLayeredWindowIndirect 函式呼叫更新顯示之前。 由於 WPF 無法公開超過 bool 變數的任何項目,它具有您得到沒有控制權替您做某些選擇。 為什麼該事務? 就是向下硬體時。

一個圖形處理器 (GPU) 慣用專用的記憶體,以達到最佳效能。 這表示如果需要管理現有的點陣圖它需要從系統記憶體 (RAM) 複製到傾向於會比在系統記憶體中的兩個位置之間複製慢很多的 GPU 記憶體。 converse 也是如此:如果您建立,並呈現點陣圖,使用 [GPU 接著決定要將它複製到 ’s 昂貴的複製作業的系統記憶體。

通常這應該不會由 [GPU 所呈現的點陣圖通常送直接到顯示裝置。 在分層視窗的情況下點陣圖必須旅行回到系統記憶體,因為 User32/GDI 資源牽涉到核心模式] 和 [使用者模式需要點陣圖存取的資源。 比方說考慮 User32 需要點擊測試事實分層的視窗。 點擊測試分層視窗根據允許透過滑鼠訊息,如果在特定時點像素是透明點陣圖的 Alpha 值。 如此一來的點陣圖複本,才能在系統記憶體中允許此狀況發生。 一旦已由 UpdateLayeredWindowIndirect 複製點陣圖,傳送直線後到 [GPU 讓 [DWM 可以撰寫在桌面上。

除了複製記憶體來回的費用,強迫 CPU 與同步 GPU 也昂貴時。 不像一般的 CPU 繫結作業 GPU 作業傾向於所有執行非同步時批次處理的呈現指令資料流,,其中會提供很好的效能。 每當我們需要跨以 CPU 路徑,它會強制清除的批次的命令和所要等待直到 [GPU 已經完成小於最佳效能而導致 CPU。

這個所有表示您需要小心這些往返次數以及頻率和相關的成本。 如果不夠複雜而正在呈現的場景,然後硬體加速效能可以輕易地彌補成本的複製點陣圖。 在另一方面,如果呈現不是非常昂貴且可由 CPU 執行,您可能會發現沒有硬體加速的選擇將最後提供較佳的效能。 這些選擇 aren’t 容易進行。 某些 GPU don’t 甚至有專用的記憶體,並改用降低的副本的系統記憶體的一部份。

比較麻煩的是 GDI 和 WPF 都不提供您的選擇。 在 GDI 的情況下,您停與 CPU。 在 WPF 的情況下您強制到使用任何呈現方法 WPF 使用,這通常是透過 Direct3D 硬體加速。

然後 Direct2D 附。

Direct2D GDI/DC

Direct2D 設計用來呈現到任何目標您選擇。 如果它 ’s 視窗或 Direct3D 紋理,Direct2D 會直接在 [GPU 上但不涉及任何複製。 如果它 ’s Windows 影像元件 (WIC) 點陣圖,Direct2D 同樣地呈現直接改為使用 CPU。 而 WPF 致力於大部分其呈現方式放在 [GPU 上,並使用軟體光柵掃描處理器當做後援,Direct2D 最好上的硬體加速 GPU unparalleled 即時模式呈現和高度最佳化的呈現兩全其美的 CPU 上時,提供一個 GPU 是無法使用或不想要。

如您可以想像有很多方式呈現具有 Direct2D 的分層的視窗。 let’s 看看幾個,而我點出建議的方法視您要使用硬體加速。

第一次,您可以只擷取出 GDI + 圖形類別從 圖 3 和它與 Direct2D DC 呈現目標的取代。 如果您有舊版的應用程式與投資 GDI,在很多,但它 ’s 絕對不最有效率的方案,這可能會使有意義。 而非直接到 DC 呈現,Direct2D 呈現第一個內部的 WIC 點陣圖,然後將結果複製到 [DC。 雖然比 GDI + 快這不過涉及額外複製,如果您 didn’t 需要用於呈現的 DC 可以加以避免。

若要請使用這個方法先初始化 D2D1_RENDER_TARGET_PROPERTIES 結構。 這會告訴 Direct2D 用於其呈現目標點陣圖格式。 您應該還記得它必須是 pre-multiplied 的 BGRA 像素格式。 這會以 D2D1_PIXEL_FORMAT 結構表示,而且可以被定義,如下所示:

const D2D1_PIXEL_FORMAT format = 
  D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,
  D2D1_ALPHA_MODE_PREMULTIPLIED);

const D2D1_RENDER_TARGET_PROPERTIES properties = 
  D2D1::RenderTargetProperties(
  D2D1_RENDER_TARGET_TYPE_DEFAULT,
  format);

您現在可以建立使用 Direct2D 工廠物件 DC 呈現目標:

CComPtr<ID2D1DCRenderTarget> target;

Verify(factory->CreateDCRenderTarget(
  &properties,
  &target));

最後,您必須告訴呈現目標到哪一個 DC 傳送繪圖的命令:

const RECT rect = {0, 0, bitmap.GetWidth(), bitmap.GetHeight()};

Verify(target->BindDC(bitmap.GetDC(), &rect));

此時您可以按照一般方式繪製以 Direct2D BeginDraw 和 EndDraw 方法呼叫之間,然後呼叫 Update 方法做之前,先與點陣圖 ’s DC。 EndDraw 方法可確保所有的繪圖已被清除至繫結的 DC。

Direct2D WIC

現在如果您可以完全避免 GDI DC,並且只要直接使用 WIC 點陣圖,您就可以達到最佳的可能效能沒有硬體加速。 若要使用此方法開始透過直接與 WIC 建立 pre-multiplied 的 BGRA 點陣圖:

CComPtr<IWICImagingFactory> factory;
Verify(factory.CoCreateInstance(
  CLSID_WICImagingFactory));

CComPtr<IWICBitmap> bitmap;

Verify(factory->CreateBitmap(
  m_info.GetWidth(),
  m_info.GetHeight(),
  GUID_WICPixelFormat32bppPBGRA,
  WICBitmapCacheOnLoad,
  &bitmap));

接下來您必須再一次在很多相同的方式之前中, 初始化 D2D1_RENDER_TARGET_PROPERTIES 結構不同之處在於您必須也告訴 Direct2D 呈現目標必須是 GDI 相容:

const D2D1_PIXEL_FORMAT format = 
  D2D1::PixelFormat(
  DXGI_FORMAT_B8G8R8A8_UNORM,
  D2D1_ALPHA_MODE_PREMULTIPLIED);

const D2D1_RENDER_TARGET_PROPERTIES properties = 
  D2D1::RenderTargetProperties(
  D2D1_RENDER_TARGET_TYPE_DEFAULT,
  format,
  0.0f, // default dpi
  0.0f, // default dpi
  D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE);

您現在可以建立使用 Direct2D 工廠物件 WIC 呈現目標:

CComPtr<ID2D1RenderTarget> target;

Verify(factory->CreateWicBitmapRenderTarget(
  bitmap,
  properties,
  &target));

但是完全 D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE 何在吗? 它 ’s 提示,以 Direct2D 您將查詢 ID2D1GdiInteropRenderTarget 介面呈現目標:

CComPtr<ID2D1GdiInteropRenderTarget> interopTarget;
Verify(target.QueryInterface(&interopTarget));

為簡單起見和效率實作,查詢這個介面會永遠成功。 當您嘗試使用它,然而是,則會失敗如果 didn’t 指定您渴望事先。

ID2D1GdiInteropRenderTarget 介面有只是兩種方法:GetDC 並 ReleaseDC。 若要最佳化用硬體加速的情況下,這些方法限於正呈現目標 ’s BeginDraw 及 EndDraw 方法呼叫之間。 GetDC 會傳回該 DC 之前清除呈現目標。 因為 Interop 介面 ’s 方法需要配對,很合理來包裝它們 C + + 類別中,如 的 圖 7 所示。

圖 7 Render 目標 DC 包裝函式類別

class RenderTargetDC {
  ID2D1GdiInteropRenderTarget* m_renderTarget;
  HDC m_dc;

public:
  RenderTargetDC(ID2D1GdiInteropRenderTarget* renderTarget) :
    m_renderTarget(renderTarget),
    m_dc(0) {

    Verify(m_renderTarget->GetDC(
      D2D1_DC_INITIALIZE_MODE_COPY,
      &m_dc));

  }

  ~RenderTargetDC() {
    RECT rect = {};
    m_renderTarget->ReleaseDC(&rect);
  }

  operator HDC() const {
    return m_dc;
  }
};

現在可以使用 [RenderTargetDC 更新視窗 ’s Render 方法,如 的 [圖 8] 所示。 有關此方法很好的事情是所有的程式碼的特定建立 WIC 呈現目標 tucked 離開 CreateDeviceResources 方法中。 接下來我告訴您如何建立以取得硬體加速的 Direct3D 呈現目標,但不論是哪一種情況 的 [圖 8] 所示的 Render 方法保持不變。 這樣可以讓您的應用程式相當輕鬆地切換呈現目標實作,而變更所有繪圖程式碼。

圖 8 GDI 相容 Render 方法

void Render() {
  CreateDeviceResources();
  m_target->BeginDraw();
  // Do some drawing here
  {
    RenderTargetDC dc(m_interopTarget);
    m_info.Update(m_hWnd, dc);
  }

  const HRESULT hr = m_target->EndDraw();

  if (D2DERR_RECREATE_TARGET == hr) {
    DiscardDeviceResources();
  }
  else {
    Verify(hr);
  }
}

Direct2D Direct3D/DXGI

若要取得硬體加速呈現,您需要使用 Direct3D。 因為您不呈現直接到透過會自動,取得硬體加速的 ID2D1HwndRenderTarget HWND 您要自行建立 Direct3D 裝置及連接點中基礎 DirectX 圖形基礎結構 (DXGI),讓您可以得到 GDI 相容的結果。

DXGI 是相當新的子系統,居住下方抽象 Direct3D 從基礎的硬體,並提供高效能閘道 Interop 案例的 Direct3D 圖層上。 Direct2D 也會利用這個新的 API,以簡化移動到未來版本的 Direct3D。 若要將這種方法開始建立 Direct3D 硬體裝置。 這是表示將會執行轉譯的 GPU 的裝置。 此處我使用 Direct3D 10.1 API,因為這目前所需的 Direct2D:

CComPtr<ID3D10Device1> device;

Verify(D3D10CreateDevice1(
  0, // adapter
  D3D10_DRIVER_TYPE_HARDWARE,
  0, // reserved
  D3D10_CREATE_DEVICE_BGRA_SUPPORT,
  D3D10_FEATURE_LEVEL_10_0,
  D3D10_1_SDK_VERSION,
  &device));

D3D10_CREATE_DEVICE_BGRA_SUPPORT 旗標是重要 Direct2D 交互操作性並 BGRA 像素格式應該現在查看熟悉。 在傳統的 Direct3D 應用程式中,您可能會建立交換鏈結,並擷取其回復緩衝區為到呈現之前呈現呈現的視窗紋理。 因為只呈現的不能用於簡報,使用 Direct3D,可以只是直接建立紋理資源。 紋理是用於儲存 Texel 也就是像素的 Direct3D 相同對應項的 Direct3D 資源。 您只需要雖然 Direct3D 提供 1-,2 和 3 維紋理是最接近對應到一個 2D 的 2D 紋理浮現 (請參閱 的 圖 9)。

圖 9 A 2D 紋理

D3D10_TEXTURE2D_DESC description = {};
description.ArraySize = 1;
description.BindFlags = 
  D3D10_BIND_RENDER_TARGET;
description.Format = 
  DXGI_FORMAT_B8G8R8A8_UNORM;
description.Width = GetWidth();
description.Height = GetHeight();
description.MipLevels = 1;
description.SampleDesc.Count = 1;
description.MiscFlags = 
  D3D10_RESOURCE_MISC_GDI_COMPATIBLE;

CComPtr<ID3D10Texture2D> texture;

Verify(device->CreateTexture2D(
  &description,
  0, // no initial data
  &texture));

D3D10_TEXTURE2D_DESC 結構描述來建立材質。 D3D10_BIND_RENDER_TARGET 常數會指示紋理繫結為輸出緩衝區或的 Direct3D 管線的呈現目標。 DXGI_FORMAT_B8G8R8A8_UNORM 常數可確保 Direct3D 會產生正確的像素格式為 GDI。 最後,D3D10_RESOURCE_MISC_GDI_COMPATIBLE 常數會指示基礎 DXGI 介面,以便提供 GDI DC,可透過它取得呈現結果。 這個 Direct2D 公開透過 ID2D1GdiInteropRenderTarget 介面我在前一節中討論。

我有提到 Direct2D 都可以經由 DXGI API,以避免中斷至任何特定版本的 Direct3D API 的 Direct3D 表面的呈現。 這表示您需要取得 Direct3D 紋理 ’s 基礎 DXGI 表面介面来傳遞給 Direct2D:

CComPtr<IDXGISurface> surface;
Verify(texture.QueryInterface(&surface));

此時您可以使用 Direct2D 工廠物件來建立 DXGI 表面的呈現目標:

CComPtr<ID2D1RenderTarget> target;

Verify(factory->CreateDxgiSurfaceRenderTarget(
  surface,
  &properties,
  &target));

呈現目標屬性就會為那些我前一節所述相同。只要記住使用正確的像素格式,並要求 GDI 相容性。您可以接著查詢 ID2D1GdiInteropRenderTarget 介面,並使用相同 Render 方法從 的 圖 8

和,’s 所有沒有給它。如果您想要呈現與硬體加速您分層的視窗,使用 Direct3D 紋理。否則使用 WIC 點陣圖。這兩種方法將會提供最佳的可能效能與最少量的複製。

請務必檢查出 DirectX 部落格,然後在特定的、 上 componentization 和交互操作性在 blogs.msdn.com/directx Ben Constable ’s 八月 2009年文件。

Kenny Kerr是一個軟體工匠激情有關 Windows。他同時也是視窗剪輯 (windowclippings.com) 的建立者。 weblogs.asp.net/kennykerr 在到達他。

將針對 Kerr 提出問題或意見傳送給 mmwincpp@microsoft.com

多虧來檢閱本文的下列的技術專家:Ben Constable 和 Mark Lawrence