РЕДАКТИРОВАТЬ: Как указывает ozeanix в комментариях, невозможно скопировать поверхность D24S8 в системную память. К сожалению, вы также не можете привязать поверхность (точнее, содержащую ее текстуру) к пиксельному шейдеру.
В итоге я пошел по пути повторной реализации, перехватив все вызовы D3D9. Если графическая карта поддерживает его (подходят все карты с DX10+), иногда можно заменить формат D24S8 форматом FOURCC INTZ, который имеет такую же структуру памяти, но может быть привязан к сэмплеру текстуры пиксельного шейдера и, таким образом, скопирован в другой текстуры в видеопамяти. Затем содержимое этой текстуры можно скопировать в текстуру системной памяти с помощью GetRenderTargetData.
Исходный пост:
Я разрабатываю плагин, который должен вычислять мировую позицию каждого пикселя, содержащегося на поверхности Direct3D. Плагин вызывается через обратный вызов, когда в заднем буфере находится новое отрендеренное изображение.
Даны два указателя (IDirect3DSurface9*) на целевую поверхность рендеринга (D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE) и поверхность буфера глубины (D3DFMT_D24S8, D3DMULTISAMPLE_NONMASKABLE). Режим отображения связанного устройства также установлен на «D3DFMT_X8R8G8B8».
Вышеуказанные настройки изменить нельзя!
Чтобы иметь возможность вычислить мировую позицию, мне также нужен доступ к значениям буфера глубины. Поэтому моей первой попыткой было создать в системной памяти закадровую плоскую поверхность в формате «D24S8», использовать «GetRenderTargetData» для копирования данных, а затем заблокировать эту закадровую поверхность (с помощью LockRect). К сожалению, самая первая команда уже не удалась — видимо, этот формат не разрешен в системной памяти (создание такой закадровой поверхности в дефолтном пуле — не проблема). Поэтому я использовал средство просмотра заглавных букв DirectX...
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 "REF" для простых поверхностей указано несколько форматов глубины и трафарета (D16_LOCKABLE, D16, D32F_LOCKABLE, D32_LOCKABLE, S8_LOCKABLE), а в списке форматов текстур нет записей глубины/трафарета, но мне нужно использовать аппаратное ускорение, иначе мое приложение будет работать слишком медленно.
D24S8
, находится на самом графическом процессоре, поэтому единственное, что приходит мне в голову, — это использовать пиксельный шейдер для преобразования. Я не знаю, возможно ли это в рамках вашей реализации. Есть ли способ сделать проход рендеринга с помощью пиксельного шейдера, который получаетD24S8
как 2D-текстуру и преобразует ее в текстуруD32F_LOCKABLE
? Если эта общая концепция работает, вы также можете рендеритьD24S8
наX8R8G8B8
закадровую плоскую поверхность иLockRect
эту поверхность, а затем реструктурировать данные на стороне процессора. - person ozeanix   schedule 13.06.2017