Я использую Angle OpenGL ES 2.x в Windows 7/10 для создания приложения, которое открывает окно для рисования анимации на экране.Из другого приложения (мой регистратор скриншотов) я получаю идентификатор процесса приложения Angle, устанавливаю ловушку Windows, которая использует инъекцию DLL, и заставляет приложение Angle загружать мою пользовательскую библиотеку DLL, которая ожидает команду от моего рекордера скриншотов, чтобы принятьСкриншот.Когда эта команда получена, моя DLL выполняется, и данные пикселей снимка экрана возвращаются в мой регистратор снимков экрана через сообщение Windows.Это все прекрасно работает, когда эмулятор OpenGL ES 2.x PowerVR.Однако при использовании Angle для создания целевого приложения (которое отображает анимацию и которое я хочу сделать на снимке экрана), я получаю только пустые, средне-серые снимки экрана.Вот фрагмент кода DLL, который пытается сделать снимок экрана:
......
......
if (message_info->message == WM_TAKESCREENSHOT)
{
// We will respond to the window specified in the wParam.
HWND respond_to = HWND(message_info->wParam);
RECT client_rect;
GetClientRect(message_info->hwnd, &client_rect);
int width = client_rect.right - client_rect.left;
int height = client_rect.bottom - client_rect.top;
// 4 bytes for width, 4 bytes for height
//int padded_row_size = _getPaddedRowSize(width, 3); // Account for the stride -> this works for PowerVR and RGB
int padded_row_size = _getPaddedRowSize(width, 4); // Account for the stride -> this works for Angle and RGBA
BYTE* response_message = new BYTE[4 + 4 + padded_row_size * height];
*reinterpret_cast<int*>(response_message) = width;
*reinterpret_cast<int*>(response_message + 4) = height;
BYTE* pixels = response_message + 8;
// The following statement has been found experimentally, and is needed to
// take screenshots from back-buffered OpenGL ES apps (like the Windows
// OpenGL ES target built with the PowerVR libs).
// This configuration works for PowerVR executables, but not for Angle
//glReadBuffer(GL_FRONT);
// This configuration works for PowerVR executables, but not for Angle
//glReadPixels(0, 0, width, height, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
// This configuration works for Angle???
// This code will be executed only when the executable has been pushed to a deterministic animation state
// by the application C-code. The executable will remain in that frozen state until the screenshot capture is completed
// and the bind back to the original framebuffer has completed.
// For Angle
GLuint framebufferName;
GLenum err;
FILE *fp;
char errs[30];
// For Angle
// Get the name of the currently bound framebuffer
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *)&framebufferName);
err = glGetError();
if (GL_NO_ERROR != err)
{
fopen_s(&fp, "F:\\errors.log", "a");
sprintf(errs, "GLGetBind->%d\n", err);
fprintf(fp, "%s", errs);
fflush(fp);
fclose(fp);
}
// For Angle
// Bind to the final render framebuffer - 0 = the screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
err = glGetError();
if (GL_NO_ERROR != err)
{
fopen_s(&fp, "F:\\errors.log", "a");
sprintf(errs, "GLBind->%d\n", err);
fprintf(fp, "%s", errs);
fflush(fp);
fclose(fp);
}
// For Angle
// Read the pixels
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// For Angle debugging
err = glGetError();
if (GL_NO_ERROR != err)
{
fopen_s(&fp, "F:\\errors.log", "a");
sprintf(errs, "GLrpxl->%d\n", err);
fprintf(fp, "%s", errs);
fflush(fp);
fclose(fp);
}
// For Angle
// Bind back to the original framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, framebufferName);
err = glGetError();
if (GL_NO_ERROR != err)
{
fopen_s(&fp, "F:\\errors.log", "a");
sprintf(errs, "GLreBind->%d\n", err);
fprintf(fp, "%s", errs);
fflush(fp);
fclose(fp);
}
COPYDATASTRUCT data_to_send;
data_to_send.dwData = 0;
data_to_send.cbData = 4 + 4 + padded_row_size * height;
data_to_send.lpData = LPVOID(response_message);
SendMessage(respond_to, WM_COPYDATA, WPARAM(message_info->hwnd), reinterpret_cast<LPARAM>(static_cast<LPVOID>(&data_to_send)));
GetLastError();
GetCurrentThreadId();
GetCurrentThreadId();
delete[] response_message;
}
return ::CallNextHookEx(nullptr, nCode, wParam, lParam);
}
Почти независимо от того, какой вызов OpenGL я делаю, glGetError () возвращает код ошибки 1282, недопустимая операция.На самом деле, в самом начале моей DLL, если я помещу туда glGetError (), я получу ошибку 1282, прежде чем я сделаю что-нибудь в моей DLL.Однако я могу сделать вызов, например, glIsFramebuffer (), чтобы определить, какие кадровые буферы в настоящее время связаны, и этот вызов дает мне правильное возвращаемое значение.Я пытался зацикливать glGetError () до тех пор, пока он не возвращает GL_NO_ERROR, но цикл будет работать вечно.
Я попытался связать кадровый буфер 0 (экран) и выполнить glReadPixels (), чтобы получить скриншот,и я также попробовал кадровый буфер 1, который отображается как единственный связанный кадровый буфер, но результат всегда один и тот же - «пустой» снимок экрана со средне-серыми пикселями.
(Прошу прощения за уродливый код инструментария регистрации ошибок- это помогло в отладке DLL.)
Почему я не могу привязаться к кадровому буферу, который имеет содержимое экрана, и захватить данные пикселей?