我在通过 D3D11 调整 D2D 渲染目标的大小时遇到问题。我制作了调整交换链缓冲区大小的函数。它工作得很好,但是当我激活 D2D 时,调整大小就坏了。
当我缩小窗口时,所有网格都会从窗口中消失 - 只显示文本。当我制作更大的网格时 - 渲染了网格,但比例不正确,尽管我重新创建了投影矩阵。
我的问题是 - 如何在窗口大小更改后正确调整 D2D 渲染目标和文本的大小?
这是我创建 D3D11Device、swapchain1 和 D2D 的代码。
bool D3D11::InitializeD3D11(HWND hwnd, SettingsContainer* settingsContainer)
{
this->hwnd = hwnd;
HRESULT result;
IDXGIFactory2* factory;
IDXGIAdapter* adapter;
IDXGIOutput* adapterOutput;
D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_UNKNOWN;
unsigned int numModes, numerator, denominator;
DXGI_MODE_DESC* displayModeList;
DXGI_ADAPTER_DESC adapterDesc;
DXGI_OUTPUT_DESC displayDesc;
DXGI_SWAP_CHAIN_DESC1 swapChainDescription;
D3D_FEATURE_LEVEL featureLevel;
ID3D11Texture2D* backBufferPtr;
D3D11_TEXTURE2D_DESC depthBufferDescription;
D3D11_DEPTH_STENCIL_DESC depthStencilDescription;
D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDescription;
D3D11_RASTERIZER_DESC rasterizerDescription;
D3D11_VIEWPORT viewPort;
D3D11_DEPTH_STENCIL_DESC depthStencilDescriptionDisabled;
D3D11_BLEND_DESC blendStateDescrition;
AdapterInfo* adapterInfo;
DisplayInfo* displayInfo;
adapterInfo = NULL;
//Создаём фабрику графических интерфейсов DX
result = CreateDXGIFactory1(__uuidof(IDXGIFactory2), (void**)&factory);
if (FAILED(result))
{
return false;
}
/*IDXGIDevice2 * pDXGIDevice;
result = d3d11_Device->QueryInterface(__uuidof(IDXGIDevice2), (void **)&pDXGIDevice);*/
/*IDXGIAdapter * pDXGIAdapter;
result = pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&pDXGIAdapter);*/
/*IDXGIFactory2 * pIDXGIFactory;
pDXGIAdapter->GetParent(__uuidof(IDXGIFactory2), (void **)&pIDXGIFactory);*/
//pIDXGIFactory->EnumAdapters1(0,&adapter);
//adapter->EnumOutputs(0, &adapterOutput);
//Достаём все графические адаптеры
for (UINT i = 0; factory->EnumAdapters(i,&adapter)!= DXGI_ERROR_NOT_FOUND;++i)
{
adapterInfo = new AdapterInfo(adapter);
adapter->GetDesc(&adapterDesc);
adapterInfo->Name = adapterDesc.Description;
adapterInfo->InternalMemory = (float)adapterDesc.DedicatedVideoMemory/1024/1024;
for (UINT j = 0; adapter->EnumOutputs(j, &adapterOutput) != DXGI_ERROR_NOT_FOUND;++j)
{
displayInfo = new DisplayInfo;
adapterOutput->GetDesc(&displayDesc);
displayInfo->MonitorHWND = displayDesc.Monitor;
DWORD cPhysicalMonitors;
LPPHYSICAL_MONITOR pPhysicalMonitors = NULL;
BOOL bSuccess = GetNumberOfPhysicalMonitorsFromHMONITOR(displayInfo->MonitorHWND, &cPhysicalMonitors);
ZeroMemory(&pPhysicalMonitors, sizeof(pPhysicalMonitors));
pPhysicalMonitors = (LPPHYSICAL_MONITOR)malloc(
cPhysicalMonitors* sizeof(PHYSICAL_MONITOR));
GetPhysicalMonitorsFromHMONITOR(displayInfo->MonitorHWND, cPhysicalMonitors, pPhysicalMonitors);
displayInfo->Name = pPhysicalMonitors->szPhysicalMonitorDescription;
//Получаем количество режимов которые удовлетворяют формату монитора DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM
adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, NULL );
displayModeList = new DXGI_MODE_DESC[numModes];
if (!displayModeList)
{
return false;
}
//Заполняем структуру display mode list
result = adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, displayModeList);
//Проходимся по всем режимам дисплея и находим тот, который совпадает с высотой и шириной экрана
//Когда совпадение найдено сохраняем нумератор и деноминатор частоты обновления для монитора
std::ofstream input_file("file.txt");
for(int k=0; k<numModes; k++)
{
if (input_file.is_open())
{
input_file << displayModeList[k].Width<<" "<<displayModeList[k].Height<<" "<<displayModeList[k].RefreshRate.Numerator<<" "<<displayModeList[k].RefreshRate.Denominator
<<" "<<displayModeList[k].ScanlineOrdering<<" "<<displayModeList[k].Format<<" "<<displayModeList[k].Scaling<<std::endl;
}
if (displayModeList[k].Width >= 1024)
{
if ((displayModeList[k].RefreshRate.Numerator/displayModeList[k].RefreshRate.Denominator)>59)
{
if (displayModeList[k].Scaling == DXGI_MODE_SCALING_CENTERED)
{
DisplayMode displayMode;
displayMode.Width = displayModeList[k].Width;
displayMode.Height = displayModeList[k].Height;
displayMode.Numerator = displayModeList[k].RefreshRate.Numerator;
displayMode.Denominator = displayModeList[k].RefreshRate.Denominator;
displayInfo->DisplayModes.push_back(displayMode);
/*numerator = displayModeList[k].RefreshRate.Numerator;
denominator = displayModeList[k].RefreshRate.Denominator;*/
}
}
}
}
//Удаляем display mode list
delete[] displayModeList;
displayModeList = NULL;
adapterInfo->displayList.push_back(displayInfo);
input_file.close ();
}
//добавляем в вектор всю собранную информацию по видеокарте
adapterList.push_back(adapterInfo);
}
//Удаляем адаптер и адаптер output
//adapter->Release();
adapter = 0;
//adapterOutput->Release();
adapterOutput = 0;
//Удаляем фабрику
/*factory->Release();
factory = 0;*/
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0
};
UINT numFeatureLevels = ARRAYSIZE(featureLevels);
factory->EnumAdapters(0,&adapter);
//Создаём устройство Direct3D и контекст устройства Direct3D
/*result = D3D11CreateDevice(NULL, driverType,NULL,D3D11_CREATE_DEVICE_DEBUG|D3D11_CREATE_DEVICE_BGRA_SUPPORT, featureLevels,numFeatureLevels,
D3D11_SDK_VERSION, &d3d11_Device, &featureLevel, &d3d11_DeviceContext );*/
result = D3D11CreateDevice(adapterList[0]->adapter, driverType, NULL, D3D11_CREATE_DEVICE_DEBUG|D3D11_CREATE_DEVICE_BGRA_SUPPORT, featureLevels,numFeatureLevels,
D3D11_SDK_VERSION, &d3d11_Device, &featureLevel, &d3d11_DeviceContext );
if (FAILED(result))
{
return false;
}
UINT qualityLevels;
d3d11_Device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, 4, &qualityLevels);
//Инициализируем структуру swap chain description
ZeroMemory(&swapChainDescription, sizeof(swapChainDescription));
//Устанавливаем количество буферов
swapChainDescription.BufferCount = 1;
//устанавливаем ширину и высоту заднего буфера
swapChainDescription.Width = settingsContainer->renderSettingsDX11->GetScreenWidth();
swapChainDescription.Height = settingsContainer->renderSettingsDX11->GetScreenHeight();
//устанавливаем формат пикселей
swapChainDescription.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDescription.SampleDesc.Count = 1;
swapChainDescription.SampleDesc.Quality = 0;
//Устанавливаем использование заднего буфера
swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDescription.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDescription.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen;
fullscreen.RefreshRate.Numerator = 0;
fullscreen.RefreshRate.Denominator = 1;
fullscreen.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
fullscreen.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
//Устанавливаем в полноэкранный режим и оконный
if (settingsContainer->renderSettingsDX11->IsFullScreenEnabled())
{
fullscreen.Windowed = FALSE;
}
else
{
fullscreen.Windowed = TRUE;
}
//Создаём swap chain
result = factory->CreateSwapChainForHwnd(d3d11_Device, hwnd, &swapChainDescription, &fullscreen, NULL, &swapChain);
if(FAILED(result))
return false;
//Получаем указатель на задний буфер
result = swapChain->GetBuffer(0,__uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr);
if (FAILED(result))
return false;
//Создаём render target view с указателем на задний буфер
result = d3d11_Device->CreateRenderTargetView(backBufferPtr, NULL, &d3d11_RenderTargetView);
if(FAILED(result))
return false;
//Освобождаем указатель на задний буфер, так как он больше не нужен
backBufferPtr->Release();
backBufferPtr = 0;
//Инициализируем описание структуры Depth_Buffer
ZeroMemory(&depthBufferDescription, sizeof(depthBufferDescription));
//Заполняем описание структуры
depthBufferDescription.Width = settingsContainer->renderSettingsDX11->GetScreenWidth();
depthBufferDescription.Height = settingsContainer->renderSettingsDX11->GetScreenHeight();
depthBufferDescription.MipLevels = 1;
depthBufferDescription.ArraySize = 1;
depthBufferDescription.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthBufferDescription.SampleDesc.Count = 1;
depthBufferDescription.SampleDesc.Quality = 0;
depthBufferDescription.Usage = D3D11_USAGE_DEFAULT;
depthBufferDescription.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthBufferDescription.CPUAccessFlags = 0;
depthBufferDescription.MiscFlags = 0;
//Создаём текстуру для буфера глубины используя заполненную структуру
result = d3d11_Device->CreateTexture2D(&depthBufferDescription, NULL, &d3d11_DepthStencilBuffer);
if (FAILED(result))
return false;
//Инициализируем описание stencil state
ZeroMemory(&depthStencilDescription, sizeof(depthStencilDescription));
//Вводим описание структуры stencil_state
depthStencilDescription.DepthEnable = true;
depthStencilDescription.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
depthStencilDescription.DepthFunc = D3D11_COMPARISON_LESS;
depthStencilDescription.StencilEnable = true;
depthStencilDescription.StencilReadMask = 0xFF;
depthStencilDescription.StencilWriteMask = 0xFF;
//Шаблонные операции если пиксель впереди
depthStencilDescription.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDescription.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
depthStencilDescription.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthStencilDescription.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
//Швблонные операции, если пиксель на обратной стороне
depthStencilDescription.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDescription.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
depthStencilDescription.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthStencilDescription.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
//Создаём Depth_Stencil_State
result = d3d11_Device->CreateDepthStencilState(&depthStencilDescription, &d3d11_DepthStencilState);
if (FAILED(result))
{
return false;
}
//Задаём состояние Depth Stencil State
d3d11_DeviceContext->OMSetDepthStencilState(d3d11_DepthStencilState,1);
//Инициализируем структуру Depth Stencil View
ZeroMemory (&depthStencilViewDescription, sizeof(depthStencilViewDescription));
//Заполняем описание структуры Depth_Stencil_View
depthStencilViewDescription.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilViewDescription.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
depthStencilViewDescription.Texture2D.MipSlice = 0;
//Задаём описание структуры Depth_Stencil_View
result = d3d11_Device->CreateDepthStencilView(d3d11_DepthStencilBuffer, &depthStencilViewDescription, &d3d11_DepthStencilView);
if (FAILED(result))
return false;
//Привязываем render target view и depth stencil buffer к output pipeline
d3d11_DeviceContext->OMSetRenderTargets(1, &d3d11_RenderTargetView, d3d11_DepthStencilView);
//Заполняем структуру Raster_Description, которая будет определять как и какие полигоны будут нарисованы
rasterizerDescription.AntialiasedLineEnable = false;
rasterizerDescription.CullMode = D3D11_CULL_BACK;
rasterizerDescription.DepthBias = 0;
rasterizerDescription.DepthBiasClamp = 0.0f;
rasterizerDescription.DepthClipEnable = true;
rasterizerDescription.FillMode = D3D11_FILL_SOLID;
rasterizerDescription.FrontCounterClockwise = false;
rasterizerDescription.MultisampleEnable = true;
rasterizerDescription.ScissorEnable = false;
rasterizerDescription.SlopeScaledDepthBias = 0.0f;
//Создаём rasterizerState из описания, которое только что заполнили
result = d3d11_Device->CreateRasterizerState(&rasterizerDescription, &d3d11_RasterizerState);
if(FAILED(result))
{
return false;
}
//Устанавливаем rasterizer state (можно менять состояние с D3D11_FILL_SOLID на D3D11_FILL_WIREFRAME)
d3d11_DeviceContext->RSSetState(d3d11_RasterizerState);
//Устанавливаем вьюпорт для рендеринга
viewPort.Width = (float)settingsContainer->renderSettingsDX11->GetScreenWidth();
viewPort.Height = (float)settingsContainer->renderSettingsDX11->GetScreenHeight();
viewPort.MinDepth = 0.0f;
viewPort.MaxDepth = 1.0f;
viewPort.TopLeftX = 0.0f;
viewPort.TopLeftY = 0.0f;
//Создаём ViewPort
d3d11_DeviceContext->RSSetViewports(1,&viewPort);
return true;
}
void D3D11::ResizeSwapChain()
{
HRESULT result;
if (swapChain)
{
RECT rc;
GetClientRect(hwnd, &rc);
UINT width = rc.right - rc.left;
UINT height = rc.bottom - rc.top;
d3d11_DeviceContext->OMSetRenderTargets(0,0,0);
d3d11_RenderTargetView->Release();
swapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr);
d3d11_Device->CreateRenderTargetView(backBufferPtr, NULL, &d3d11_RenderTargetView);
//Инициализируем описание структуры Depth_Buffer
ZeroMemory(&depthBufferDescription, sizeof(depthBufferDescription));
//Заполняем описание структуры
depthBufferDescription.Width = width;
depthBufferDescription.Height = height;
depthBufferDescription.MipLevels = 1;
depthBufferDescription.ArraySize = 1;
depthBufferDescription.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthBufferDescription.SampleDesc.Count = 1;
depthBufferDescription.SampleDesc.Quality = 0;
depthBufferDescription.Usage = D3D11_USAGE_DEFAULT;
depthBufferDescription.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthBufferDescription.CPUAccessFlags = 0;
depthBufferDescription.MiscFlags = 0;
d3d11_DepthStencilBuffer->Release();
d3d11_DepthStencilBuffer = NULL;
//Создаём текстуру для буфера глубины используя заполненную структуру
result = d3d11_Device->CreateTexture2D(&depthBufferDescription, NULL, &d3d11_DepthStencilBuffer);
bool D3D11::InitializeD2D11()
{
options.debugLevel = D2D1_DEBUG_LEVEL_ERROR;
D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, options, &d2dfactory);
swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackbuffer));
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_HARDWARE,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));
d2dfactory->CreateDxgiSurfaceRenderTarget(dxgiBackbuffer, props, &d2dRenderTarget);
dxgiBackbuffer->Release();
dxgiBackbuffer = NULL;
d2dfactory->Release();
d2dfactory = NULL;
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(DWriteFactory), (IUnknown**)(&DWriteFactory));
DWriteFactory->CreateTextFormat(
L"Cambria",
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
12,
L"",
&textFormat);
DWriteFactory->CreateTextFormat(
L"Cambria",
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
12,
L"",
&textFormat2);
textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
textFormat2->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_FAR);
textFormat2->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
d2dRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), &Brush);
return true;
}
//Задаём состояние Depth Stencil State
d3d11_DeviceContext->OMSetDepthStencilState(d3d11_DepthStencilState, 1);
//Инициализируем структуру Depth Stencil View
ZeroMemory (&depthStencilViewDescription, sizeof(depthStencilViewDescription));
//Заполняем описание структуры Depth_Stencil_View
depthStencilViewDescription.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilViewDescription.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
depthStencilViewDescription.Texture2D.MipSlice = 0;
d3d11_DepthStencilView->Release();
d3d11_DepthStencilView = NULL;
//Задаём описание структуры Depth_Stencil_View
result = d3d11_Device->CreateDepthStencilView(d3d11_DepthStencilBuffer, &depthStencilViewDescription, &d3d11_DepthStencilView);
//Освобождаем указатель на задний буфер, так как он больше не нужен
backBufferPtr->Release();
backBufferPtr = 0;
d3d11_DeviceContext->OMSetRenderTargets(1, &d3d11_RenderTargetView, d3d11_DepthStencilView);
//d3d11_DeviceContext->OMSetRenderTargets(1, &d3d11_RenderTargetView, NULL);
//Устанавливаем вьюпорт для рендеринга
D3D11_VIEWPORT viewPort;
viewPort.Width = (float)width;
viewPort.Height = (float)height;
viewPort.MinDepth = 0.0f;
viewPort.MaxDepth = 1.0f;
viewPort.TopLeftX = 0.0f;
viewPort.TopLeftY = 0.0f;
//Создаём ViewPort
d3d11_DeviceContext->RSSetViewports(1,&viewPort);
}
}
我在 WM_SIZE 事件上调整缓冲区大小:
case WM_SIZE:
{
int Width = LOWORD(lparam);
int Height = HIWORD(lparam);
WCHAR* str = NULL;
if (wparam == SIZE_RESTORED)
{
if (system->application)
{
system->application->d3d11->ResizeSwapChain();
system->application->d3d11->ResizeD2DBuffer();
system->application->cameraDX_Free->perspective(system->application->cameraDX_Free->m_fovx,
static_cast<float>(Width) / static_cast<float>(Height),
system->application->cameraDX_Free->m_znear,
system->application->cameraDX_Free->m_zfar);
}
}
}