2014-01-06 3 views
2

Я изучаю, как использовать Direct2D и DirectWrite. Я написал пример приложения, которое использует эти библиотеки для рендеринга контента непосредственно в главном (верхнем уровне) окне. Он работает нормально.Direct2D отображается в главном окне, но не дочернем окне

Теперь я пытаюсь переписать код рисования для дочернего окна в другом приложении. Исходный код использует GDI и отлично работает. Но когда я конвертирую его в Direct2D, ничего не появляется (дочернее окно выглядит черным).

Я упростил код картины до простой заливки клиентской области.

LRESULT PlotWnd::OnPaint(UINT, WPARAM, LPARAM, BOOL &) { 
    ATL::CComPtr<ID2D1Factory> pD2DFactory; 
    HRESULT hr = ::D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory); 
    assert(SUCCEEDED(hr)); 
    ATL::CComPtr<ID2D1HwndRenderTarget> pRT; 
    RECT rc; 
    GetClientRect(&rc); 
    D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top); 
    hr = pD2DFactory->CreateHwndRenderTarget(
     D2D1::RenderTargetProperties(/* D2D1_RENDER_TARGET_TYPE_SOFTWARE */), 
     D2D1::HwndRenderTargetProperties(m_hWnd, size), &pRT); 
    assert(SUCCEEDED(hr)); 

    pRT->BeginDraw(); 
    pRT->Clear(D2D1::ColorF(D2D1::ColorF::Beige)); 
    hr = pRT->EndDraw(); 
    assert(SUCCEEDED(hr)); 
    ValidateRect(nullptr); 

    return 0; 
} 

Все Direct2D вызовов успеха с S_OK, так что я вроде в недоумении, где искать проблему. На данный момент единственное существенное различие, которое я вижу в моем рабочем эксперименте и этой программе, заключается в том, что в этом я использую Direct2D только в одном дочернем окне.

Так что мои вопросы: есть ли проблема, которую я пропускаю при использовании Direct2D в дочернем окне? Какие-нибудь советы по дальнейшему отладке?

Обновление: Я удалил статику, чтобы избежать путаницы. Я полностью настраиваю и разрываю Direct2D с каждой краской. Существует ровно один вызов краски с реальным размером.

Если я переключусь на рендеринг программного обеспечения (используя D2D1_RENDER_TARGET_TYPE_SOFTWARE в целевых свойствах рендеринга), проблема исчезнет - я получаю бежевую заливку, как ожидалось.

Это привело меня к подозрению в моем графическом драйвере, который устарел. Но теперь я обновил свой графический драйвер, и он по-прежнему терпит неудачу таким же образом. Что еще может привести к отказу аппаратного рендеринга, если рендеринг программного обеспечения работает так, как ожидалось?

Обновление 2: Я все еще пытаюсь воспроизвести это небольшой, самодостаточный пример. Между тем, я заметил, что просто запуск Spy ++ будет иногда заставляет окно фактически отображать на экран (один раз).

+0

Вы переопределили обработчик 'WM_ERASEBKGND', чтобы он не закрывал окно? –

+0

@Roger Rowland: Да, мой обработчик WM_ERASKBKGND ничего не делает. Если у меня он заполняется произвольным цветом, тогда я вижу этот цвет вместо бежевой заливки, которую я ожидаю от команды Direct2D Clear. –

+0

Хорошо, просто просматривая некоторые «очевидные» вещи - имеет ли родительское окно стиль 'WS_CLIPCHILDREN'? –

ответ

0

У меня все еще нет решения, кроме как использовать рендеринг программного обеспечения. Я вполне уверен, что это ошибка графического драйвера, в частности, состояние гонки.

Evidence:

  • О один раз в десять, он рисует хорошо, так что проблема часто, но периодически, наводит на мысль о проблеме синхронизации.
  • Проблема возникает только с первой краской после запуска приложения. (Да, размер окна в данный момент правильный.) Позже репайнеры работают нормально. К счастью, мое приложение разбивает окно каждые несколько минут, поэтому оно остается черным только через несколько минут после его запуска. Это указывает на необходимость синхронизации при запуске приложения.
  • Я не смог воспроизвести крошечную программу, поэтому проблема может быть чувствительной к времени, которое требуется для инициализации приложения. Возможно, драйвер выполняет некоторую асинхронную инициализацию, которая не всегда завершается вовремя, чтобы обрабатывать начальные команды рисования.
  • Этого не произошло на других компьютерах, которые я пробовал, используя разные видеокарты.
  • При использовании программной рендеринга картина прекрасно работает каждый раз. Это говорит о том, что ошибка не в моем коде.

Счетчик Evidence:

  • Несколько раундов обновления драйверов за прошедший год не сделал никакой разницы в поведении.

Я отправляю это как «ответ», потому что некоторые другие видели подобные симптомы и спрашивали меня, не нашел ли я когда-либо ответ. Я все еще открыт для чтения других идей и буду отвечать хорошим ответам.

2

Ну, для начала, вы должны создать завод при запуске приложения, а цель рендеринга - с помощью окна (HWND). Они не должны быть «временными» объектами, которые живут только до тех пор, пока выполняется ваш OnPaint (WM_PAINT).

+0

И вот как я начал с самого начала, но когда это не сработало, я упростил код до этого, чтобы представить все это в одном месте. Это не должно меняться, если я создаю эти объекты по требованию, тем более, что обработчик краски вызывается только один раз. И, фактически, все это в обработчике WM_PAINT прекрасно работает в исходном образце, который я построил (где я использую Direct2D для рисования главного окна). –

+1

Я не удивлюсь, если выпустить HwndRenderTarget из-за проблем с картинкой. Цитата из http://msdn.microsoft.com/en-us/library/windows/desktop/dd371461(v=vs.85).aspx: ваше приложение должно создавать целевые объекты рендеринга один раз и удерживать их в течение всего срока действия приложения или до тех пор, пока метод EndDraw объекта рендеринга не вернет ошибку D2DERR_RECREATE_TARGET. –

+0

@vt. Я понимаю, что цель рендеринга должна длиться всю жизнь окна, но это не изменило поведение. –

0

В дополнение к рекомендации Рика преобразовать HWNDRenderTarget к неподвижному объекту, я предлагаю называть BeginPaint() - EndPaint() (или создать локальный CPaintDC объект, который делает это автоматически), даже если вы не используете PAINTSTRUCT. См. MainWindow::OnPainthere.

Если это не поможет, вы можете всегда активировать Direct2D Debug Layer для получения дополнительной информации об отладке.

+0

Ни один из образцов MSDN Direct2D не использует BeginPaint/EndPaint. BeginPaint получает окно DC, устанавливает область отсечения, отправляет WM_ERASEBKGND и заполняет PAINTSTUCT. EndPaint затем проверяет область. При использовании Direct2D важна только валидация (и я это делаю). Тем не менее, я попытался изменить код, чтобы использовать BeginPaint/EndPaint, как вы предложили, и это не повлияло. –

Смежные вопросы