РЕДАКТИРОВАТЬ: Как указывает ozeanix в комментариях, невозможно скопировать поверхность D24S8 в системную память. К сожалению, вы также не можете привязать поверхность (или, скорее, содержащую ее текстуру) к пиксельному шейдеру.
В итоге я пошел по пути повторной реализации, перехватывая все вызовы D3D9. Если видеокарта поддерживает это — все карты с DX10 + должны делать — иногда возможно обменять формат D24S8 с FOURCC INTZ, который имеет ту же схему памяти, но может быть связан с образцом текстуры пиксельного шейдера и, таким образом, скопирован в другой текстура в видеопамяти. Содержимое этой текстуры затем можно скопировать в текстуру системной памяти с помощью GetRenderTargetData.
Исходное сообщение:
Я разрабатываю плагин, который должен вычислять мировое положение каждого пикселя, содержащегося в поверхности Direct3D. Плагин вызывается с помощью обратного вызова, когда в заднем буфере находится вновь отрендеренное изображение.
Даны два указателя (IDirect3DSurface9 *) на целевую поверхность рендеринга (D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE) и буферную поверхность глубины (D3DFMT_D24S8, D3DMULTISAMPLE_NONMASKABLE). Режим отображения связанного устройства также установлен на «D3DFMT_X8R8G8B8»
Указанные выше настройки не могут быть изменены!
Чтобы иметь возможность рассчитать мировую позицию, мне также нужен доступ к значениям буфера глубины.
Поэтому моей первой попыткой было создать в системной памяти неэкранную плоскую поверхность с форматом «D24S8», использовать «GetRenderTargetData», чтобы скопировать данные, а затем заблокировать эту неэкранную поверхность (с помощью LockRect).
К сожалению, самая первая команда уже потерпела неудачу — очевидно, этот формат не разрешен в системной памяти (нет проблем с созданием такой неэкранной поверхности в пуле по умолчанию). Так что я использовал DirectX Caps Viewer …
D3D Device Type "HAL" and Adapter Format "D3DFMT_X8R8G8B8":
Depth/Stencil Formats:
"D3DFMT_D24S8", "D3DFMT_D24X8", "D3DFMT_D16", "D3DFMT_D32F_LOCKABLE"
Texture Formats (only mentioning the depth/stencil & depth formats):
"D3DFMT_D24S8", "D3DFMT_D24X8", "D3DFMT_D16", "D3DFMT_D32F_LOCKABLE",
"DXT1" through "DXT5"- but all are only supported in conjunction with usage type "0 (Plain)".
Plain Surface Formats: No depth stencil formats at all are listed.
Что я тоже пробовал:
Создайте текстуру только с одним уровнем и форматом D3DFMT_D24S8, помещенным в D3DPOOL_SYSTEMMEM (также не удалось)
Создайте поверхность типа D32F_LOCKABLE в D3DPOOL_DEFAULT (успешно) и используйте D3DXLoadSurfaceFromSurface для преобразования и копирования данных, чтобы последующий вызов LockRect предоставил дескриптор данных (не удалось)
Создайте поверхность глубины / трафарета с отключенным мультисэмплированием (успешно) и используйте StretchRect для копирования из источника в место назначения (не удалось) и проверьте, является ли мультисэмплинг частью проблемы
Мои вопросы
Согласно DirectX Caps Viewer D24S8 должен поддерживаться на текстурах. Эти списки применимы только для ресурсов в пуле памяти по умолчанию?
Можно ли вообще как-то скопировать значения глубины в системную память?
Есть ли возможность включить расширенные отчеты об ошибках для вызовов DirectX в Windows 8.1? Я знаю, что начиная с Win8.1, сама ОС использует тот же API, и поэтому среда выполнения DirectX не может быть переведена в режим отладки, но, возможно, я пропустил соответствующую опцию
Кстати, с D3DDevice Type «REF» есть несколько форматов глубины и трафарета, перечисленных для простых поверхностей (D16_LOCKABLE, D16, D32F_LOCKABLE, D32_LOCKABLE, S8_LOCKABLE) и нет записей глубины / трафарета, доступных в списке форматов текстур, но мне нужно использовать аппаратное ускорение, иначе мое приложение будет работать слишком медленно.
Задача ещё не решена.
Других решений пока нет …