【问题标题】:Direct2D fails when drawing a single-channel bitmap绘制单通道位图时 Direct2D 失败
【发布时间】:2017-05-30 19:15:39
【问题描述】:

我是一名经验丰富的计算机图形专业程序员,主要使用 Direct3D 9.0c、OpenGL 和通用算法。目前,我正在评估 Direct2D 作为处理医学图像数据的专业应用程序的渲染技术。至于渲染,它是一个窗口模式(不是全屏)的 x64 桌面应用程序。

在我最初的步骤中,我已经在努力完成一项我认为不费吹灰之力的任务:在屏幕上渲染单通道位图。

在 Windows 8.1 机器上运行时,我创建了一个 ID2D1DeviceContext,并使用 Direct3D 交换链缓冲区表面作为渲染目标。交换链是从 HWND 和缓冲区格式 DXGI_FORMAT_B8G8R8A8_UNORM 创建的。注意:另见最后的代码sn-ps

之后,我创建了一个像素格式DXGI_FORMAT_R8_UNORM 和alpha 模式D2d1_ALPHA_MODE_IGNORE 的位图。在设备上下文中调用DrawBitmap(...) 时,会触发调试断点,并显示调试消息“D2d DEBUG ERROR - This operation is not compatible with the pixel format of the bitmap”。

我知道这个输出很清楚。此外,当使用DXGI_ALPHA_MODE_IGNORE 将像素格式更改为DXGI_FORMAT_R8G8B8A8_UNORM 时,一切正常,我看到了渲染的位图。然而,我简直不敢相信!从那时起,显卡就支持单通道纹理——每个 3D 图形应用程序都可以毫不犹豫地使用它们。这个不用说了。

我试图在这里和谷歌找到任何东西,但没有成功。我能找到的唯一提示是带有 (supported pixel formats) 的 MSDN Direct2D 页面。该文档暗示 - 通过不提及它 - DXGI_FORMAT_R8_UNORM 确实不支持位图格式。我还发现有关 alpha 掩码的帖子(使用 DXGI_FORMAT_A8_UNORM),但这不是我想要的。

我无法说服 Direct2D 创建和绘制灰度位图,我错过了什么?还是说 Direct2D 不支持绘制 R8 或 R16 位图是真的吗??

非常感谢任何帮助,因为我不知道如何解决这个问题。如果我不能让这些琐碎的基础知识发挥作用,我想我必须停止深入研究 Direct2D :-(。

这里是相关的代码sn-ps。请注意,它们可能无法编译,因为我将它从我的 C++/CLI 代码动态移植到纯 C++。另外,我扔掉了所有的错误检查和其他噪音:

设备、设备上下文和交换链创建(D3D 和 Direct2D):

// Direct2D factory creation
D2D1_FACTORY_OPTIONS options = {};
options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
ID2D1Factory1* d2dFactory;
D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, options, &d2dFactory);

// Direct3D device creation
const auto type = D3D_DRIVER_TYPE_HARDWARE;
const auto flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
ID3D11Device* d3dDevice;
D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0, D3D11_SDK_VERSION, &d3dDevice, nullptr, nullptr);

// Direct2D device creation
IDXGIDevice* dxgiDevice;
d3dDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice));
ID2D1Device* d2dDevice;
d2dFactory->CreateDevice(dxgiDevice, &d2dDevice);

// Swap chain creation
DXGI_SWAP_CHAIN_DESC1 desc = {};
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 2;

IDXGIAdapter* dxgiAdapter;
dxgiDevice->GetAdapter(&dxgiAdapter);
IDXGIFactory2* dxgiFactory;
dxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&dxgiFactory));

IDXGISwapChain1* swapChain;
dxgiFactory->CreateSwapChainForHwnd(d3dDevice, hwnd, &swapChainDesc, nullptr, nullptr, &swapChain);

// Direct2D device context creation
const auto options = D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
ID2D1DeviceContext* deviceContext;
d2dDevice->CreateDeviceContext(options, &deviceContext);

// create render target bitmap from swap chain
IDXGISurface* swapChainSurface;
swapChain->GetBuffer(0, __uuidof(swapChainSurface), reinterpret_cast<void **>(&swapChainSurface));
D2D1_BITMAP_PROPERTIES1 bitmapProperties;
bitmapProperties.dpiX = 0.0f;
bitmapProperties.dpiY = 0.0f;
bitmapProperties.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
bitmapProperties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
bitmapProperties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE;
bitmapProperties.colorContext = nullptr;
ID2D1Bitmap1* swapChainBitmap = nullptr;
deviceContext->CreateBitmapFromDxgiSurface(swapChainSurface, &bitmapProperties, &swapChainBitmap);


// set swap chain bitmap as render target of D2D device context
deviceContext->SetTarget(swapChainBitmap);

D2D 单通道位图创建:

const D2D1_SIZE_U size = { 512, 512 };
const UINT32 pitch = 512;
D2D1_BITMAP_PROPERTIES1 d2dProperties;
ZeroMemory(&d2dProperties, sizeof(D2D1_BITMAP_PROPERTIES1));
d2dProperties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE;
d2dProperties.pixelFormat.format = DXGI_FORMAT_R8_UNORM;
char* sourceData = new char[512*512];

ID2D1Bitmap1* d2dBitmap;
deviceContext->DeviceContextPointer->CreateBitmap(size, sourceData, pitch, d2dProperties, &d2dBitmap);

位图绘制(失败):

deviceContext->BeginDraw();
D2D1_COLOR_F d2dColor = {};
deviceContext->Clear(d2dColor);

// THIS LINE FAILS WITH THE DEBUG BREAKPOINT IF SINGLE CHANNELED
deviceContext->DrawBitmap(bitmap, nullptr, 1.0f, D2D1_INTERPOLATION_MODE_LINEAR, nullptr);  

swapChain->Present(1, 0);
deviceContext->EndDraw();

【问题讨论】:

  • 真的没有人需要绘制灰度位图吗?我真的不知道如何处理这个问题,非常感谢任何提示:)!

标签: direct2d


【解决方案1】:

根据我的小经验,Direct2D 似乎确实非常有限。

您是否尝试过 Direct2D effects (ID2D1Effect)?你可以自己写[看起来比较复杂],或者使用built-in effects之一[相当简单]。

有一个叫Color matrix effect (CLSID_D2D1ColorMatrix)可能将你的DXGI_FORMAT_R8_UNORM(或DXGI_FORMAT_A8_UNORM,任何单通道都可以)作为输入(效果的输入是ID2D1ImageID2D1Bitmap 继承自ID2D1Image) .然后设置D2D1_COLORMATRIX_PROP_COLOR_MATRIX 将输入通道复制到所有输出通道。不过没试过。

【讨论】:

  • 您好,谢谢您的回答。我需要非常节省内存,因此我不想花费额外的通道,也不想将单通道图像转换为跨颜色通道具有相同值的 RGB(A) 图像。我真的需要能够创建单通道位图,否则 Direct2D 就出局了……或者我需要混合 D3D 和 D2D 并使用前者作为位图?!
  • @MisterX 您指向supported pixel formats 的链接似乎表明DXGI_FORMAT_A8_UNORM 是您唯一的选择。我对效果的经验太少,所以无法确认,但也许效果的输出没有具体化(即直接渲染到渲染目标),或者只是暂时如此。我并不是说要保留输出,我只是建议在渲染时链接效果。我希望您的渲染目标已经是 RGB(A)。您需要检查这种方法是否适合您...
  • @MisterX 另一方面,一旦您克服了管理困难,直接使用 Direct3D 11.x 绘制位图就很容易了。如果您不需要 Direct2D 的主要功能(文本、图层、没有着色器的简单渲染模型),那么一定要走 D3D 路线。一个医疗应用程序的奖励,您可以使用更高精度的图像、轻松控制传输函数、使用计算着色器等。
猜你喜欢
  • 2012-04-21
  • 2016-06-11
  • 2012-03-28
  • 2011-02-06
  • 2010-09-23
  • 1970-01-01
  • 1970-01-01
  • 2016-09-14
  • 2011-02-04
相关资源
最近更新 更多