2014-02-03 2 views
2

Возможно, вы знаете, что при попытке захвата приложений в полноэкранном режиме DirectX способ GDI (с использованием BitBlt()) дает черный скриншот.Почему приложения Fullscreen для DirectX дают черные скриншоты?

Мой вопрос довольно прост, но я не нашел ответа: почему? Я имею в виду технически, почему он дает черный снимок экрана?

Я читаю учебник DirectX здесь: http://www.directxtutorial.com/Lesson.aspx?lessonid=9-4-1. Написано:

[...] Функция BeginScene() [...] выполняет функцию блокировки, где буфер в видеопамяти «заблокирован», предоставляя вам эксклюзивный доступ к этой памяти.

Это причина? VRAM заблокирован, поэтому GDI не может получить к нему доступ, и он дает черный снимок экрана? Или есть еще одна причина? Как DirectX прямо «разговаривает» с графической картой, а GDI не понимает?

спасибо.

ответ

3

Причина проста: возможности.

Идея заключается в рендеринге сцены как можно больше на графическом процессоре из блокировки с CPU. Вы используете CPU для отправки буферов рендеринга в GPU (вершины, индексы, шейдеры и т. Д.), Что в целом очень дешево, потому что они маленькие, тогда вы делаете все, что хотите, физику, многопользовательскую синхронизацию и т. Д. Графический процессор может просто хрустить данные и сделать это самостоятельно.

Если требуется, чтобы сцена была нарисована в окне, вам необходимо прервать работу графического процессора, запросить байты буфера обработки (LockRect), запросить графический объект для окна (больше помех с графическим процессором), визуализировать он и бесплатно каждый замок. Вы просто потеряли какой-то выигрыш, который у вас был, если на GPU не синхронизироваться с CPU. Еще хуже, когда вы думаете обо всех различных ядрах процессора, просто сидите без дела, потому что вы заняты «рендерингом» (более похожим на ожидание передачи буфера).

Итак, какие графические драйверы делают, они рисуют область рендеринга волшебным цветом и сообщают графическому процессору положение сцены, а графический процессор заботится о наложении сцены поверх отображаемого экрана на основе волшебных цветовых пикселей (сортировка многошагового пиксельного шейдера, который берет из второй текстуры, когда 1-я текстура имеет определенный цвет для x, y, но не так медленно). Вы полностью не выполняете синхронизацию, но когда вы запрашиваете ОС для своей видеопамяти, вы получаете волшебный цвет, где сцена, потому что это то, что на самом деле используется.

Ссылка: http://en.wikipedia.org/wiki/Hardware_overlay

+0

Я действительно не знал, что они переключились с волшебной системы цвета, хотя это имеет смысл, учитывая, насколько она хакерская. TIL! Теория остается неизменной, хотя независимо от того, как вы определяете свою область оверлея. – Blindy

+0

Сначала я не понял ваше сообщение, поэтому переформулирую. На самом деле GDI ** использует ** ту же самую память для рендеринга ** все ** графики из ** всех ** процессов (начальное меню, окна и т. Д.). Однако, поскольку все процессы используют одну и ту же память, для этого требуется некоторый ** механизм синхронизации ** (блокировка/разблокировка памяти), чтобы гарантировать, что память не считывается/записывается одновременно с помощью двух потоков. Этот механизм занимает ВРЕМЯ! Чтобы получить лучшие характеристики, DirectX использует ** выделенную ** память, поэтому нет необходимости в синхронизации! Общая память заполнена ** магическим цветом ** (например, черным), поэтому скриншоты черные. – GuiTeK

+1

Вы совершенно не поняли, GDI не владеет чем-либо за пределами маленьких оконных игр, которые даже не используются. GDI работает на процессоре, все, что он затрагивает, обрабатывается процессором, чего мы хотим избежать. Таким образом, вместо этого на GPU подается почти черный прямоугольник (ваше окно), который никогда не меняется (никогда не будет перерисовываться), и графическая карта просто рисует поверх почти черных пикселей сама по себе. – Blindy

0

Я считаю, что это на самом деле из-за двойной буферизации. Я не уверен на 100%, но на самом деле это был случай, когда я тестировал скриншоты в OpenGL. Я бы заметил, что DC на моем окне не то же самое. Он использовал два разных DC для этой игры. Для других игр я не был уверен, что он делает. DC был тем же, но swapbuffers называли так много раз, что я не думаю, что GDI был даже достаточно быстрым, чтобы сделать снимок экрана. Иногда я получал половину снимка экрана и половину черного.

Однако, когда я подключился к клиент, я смог просто попросить пиксели, как обычно. Нет GDI или что-то еще. Я думаю, что есть причина, по которой мы не используем GDI при рисовании в играх, которые используют DirectX или OpenGL.

Вы всегда можете посмотреть на способы захвата экрана здесь: http://www.codeproject.com/Articles/5051/Various-methods-for-capturing-the-screen

Во всяком случае, я использую следующие для захвата данных с DirectX:

HRESULT DXI_Capture(IDirect3DDevice9* Device, const char* FilePath) 
{ 
    IDirect3DSurface9* RenderTarget = nullptr; 
    HRESULT result = Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &RenderTarget); 
    result = D3DXSaveSurfaceToFile(FilePath, D3DXIFF_PNG, RenderTarget, nullptr, nullptr); 
    SafeRelease(RenderTarget); 
    return result; 
} 

Тогда в моем зацепили EndScene я называю это как так :

HRESULT Direct3DDevice9Proxy::EndScene() 
{ 
    DXI_Capture(ptr_Direct3DDevice9, "C:/Ssers/School/Desktop/Screenshot.png"); 

    return ptr_Direct3DDevice9->EndScene(); 
} 

вы можете использовать Microsoft объездов для подключения EndScene некоторого внешнего приложения или вы можете использовать оболочку .dll.

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