Commit ce991cf6 by Corentin Wallez

Add OSWindow::takeScreenshot to be used by some dEQP egl tests

This helps make dEQP support platform agnostic BUG=angleproject:892 Change-Id: Ifd9436caa8c79018a053c27e32b514ef9ebee707 Reviewed-on: https://chromium-review.googlesource.com/273596Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 3c85635d
...@@ -127,8 +127,6 @@ class NativeWindow : public eglu::NativeWindow ...@@ -127,8 +127,6 @@ class NativeWindow : public eglu::NativeWindow
private: private:
OSWindow *mWindow; OSWindow *mWindow;
eglu::WindowParams::Visibility mCurVisibility;
deUint64 mSetVisibleTime; //!< Time window was set visible.
EventState *mEvents; EventState *mEvents;
}; };
...@@ -233,8 +231,6 @@ eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay* nativ ...@@ -233,8 +231,6 @@ eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay* nativ
NativeWindow::NativeWindow(ANGLENativeDisplay *nativeDisplay, const eglu::WindowParams& params, EventState *eventState) NativeWindow::NativeWindow(ANGLENativeDisplay *nativeDisplay, const eglu::WindowParams& params, EventState *eventState)
: eglu::NativeWindow(WINDOW_CAPABILITIES), : eglu::NativeWindow(WINDOW_CAPABILITIES),
mWindow(CreateOSWindow()), mWindow(CreateOSWindow()),
mCurVisibility(eglu::WindowParams::VISIBILITY_HIDDEN),
mSetVisibleTime(0),
mEvents(eventState) mEvents(eventState)
{ {
bool initialized = mWindow->initialize("dEQP ANGLE Tests", bool initialized = mWindow->initialize("dEQP ANGLE Tests",
...@@ -252,15 +248,12 @@ void NativeWindow::setVisibility(eglu::WindowParams::Visibility visibility) ...@@ -252,15 +248,12 @@ void NativeWindow::setVisibility(eglu::WindowParams::Visibility visibility)
{ {
case eglu::WindowParams::VISIBILITY_HIDDEN: case eglu::WindowParams::VISIBILITY_HIDDEN:
mWindow->setVisible(false); mWindow->setVisible(false);
mCurVisibility = visibility;
break; break;
case eglu::WindowParams::VISIBILITY_VISIBLE: case eglu::WindowParams::VISIBILITY_VISIBLE:
case eglu::WindowParams::VISIBILITY_FULLSCREEN: case eglu::WindowParams::VISIBILITY_FULLSCREEN:
// \todo [2014-03-12 pyry] Implement FULLSCREEN, or at least SW_MAXIMIZE. // \todo [2014-03-12 pyry] Implement FULLSCREEN, or at least SW_MAXIMIZE.
mWindow->setVisible(true); mWindow->setVisible(true);
mCurVisibility = eglu::WindowParams::VISIBILITY_VISIBLE;
mSetVisibleTime = deGetMicroseconds();
break; break;
default: default:
...@@ -300,96 +293,10 @@ void NativeWindow::setSurfaceSize(IVec2 size) ...@@ -300,96 +293,10 @@ void NativeWindow::setSurfaceSize(IVec2 size)
void NativeWindow::readScreenPixels(tcu::TextureLevel *dst) const void NativeWindow::readScreenPixels(tcu::TextureLevel *dst) const
{ {
HDC windowDC = DE_NULL; dst->setStorage(TextureFormat(TextureFormat::BGRA, TextureFormat::UNORM_INT8), mWindow->getWidth(), mWindow->getHeight());
HDC screenDC = DE_NULL; bool success = mWindow->takeScreenshot(reinterpret_cast<uint8_t*>(dst->getAccess().getDataPtr()));
HDC tmpDC = DE_NULL; DE_ASSERT(success);
HBITMAP tmpBitmap = DE_NULL; DE_UNREF(success);
RECT rect;
TCU_CHECK_INTERNAL(mCurVisibility != eglu::WindowParams::VISIBILITY_HIDDEN);
// Hack for DWM: There is no way to wait for DWM animations to finish, so we just have to wait
// for a while before issuing screenshot if window was just made visible.
{
const deInt64 timeSinceVisibleUs = (deInt64)(deGetMicroseconds()-mSetVisibleTime);
if (timeSinceVisibleUs < (deInt64)WAIT_WINDOW_VISIBLE_MS*1000)
deSleep(WAIT_WINDOW_VISIBLE_MS - (deUint32)(timeSinceVisibleUs/1000));
}
TCU_CHECK(GetClientRect(mWindow->getNativeWindow(), &rect));
try
{
const int width = rect.right - rect.left;
const int height = rect.bottom - rect.top;
BITMAPINFOHEADER bitmapInfo;
deMemset(&bitmapInfo, 0, sizeof(bitmapInfo));
screenDC = GetDC(DE_NULL);
TCU_CHECK(screenDC);
windowDC = GetDC(mWindow->getNativeWindow());
TCU_CHECK(windowDC);
tmpDC = CreateCompatibleDC(screenDC);
TCU_CHECK(tmpDC != DE_NULL);
MapWindowPoints(mWindow->getNativeWindow() , DE_NULL, (LPPOINT)&rect, 2);
tmpBitmap = CreateCompatibleBitmap(screenDC, width, height);
TCU_CHECK(tmpBitmap != DE_NULL);
TCU_CHECK(SelectObject(tmpDC, tmpBitmap) != DE_NULL);
TCU_CHECK(BitBlt(tmpDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY));
bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.biWidth = width;
bitmapInfo.biHeight = -height;
bitmapInfo.biPlanes = 1;
bitmapInfo.biBitCount = 32;
bitmapInfo.biCompression = BI_RGB;
bitmapInfo.biSizeImage = 0;
bitmapInfo.biXPelsPerMeter = 0;
bitmapInfo.biYPelsPerMeter = 0;
bitmapInfo.biClrUsed = 0;
bitmapInfo.biClrImportant = 0;
dst->setStorage(TextureFormat(TextureFormat::BGRA, TextureFormat::UNORM_INT8), width, height);
TCU_CHECK(GetDIBits(screenDC, tmpBitmap, 0, height, dst->getAccess().getDataPtr(), (BITMAPINFO*)&bitmapInfo, DIB_RGB_COLORS));
DeleteObject(tmpBitmap);
tmpBitmap = DE_NULL;
ReleaseDC(DE_NULL, screenDC);
screenDC = DE_NULL;
ReleaseDC(mWindow->getNativeWindow(), windowDC);
windowDC = DE_NULL;
DeleteDC(tmpDC);
tmpDC = DE_NULL;
}
catch (...)
{
if (screenDC)
ReleaseDC(DE_NULL, screenDC);
if (windowDC)
ReleaseDC(mWindow->getNativeWindow(), windowDC);
if (tmpBitmap)
DeleteObject(tmpBitmap);
if (tmpDC)
DeleteDC(tmpDC);
throw;
}
} }
} // anonymous } // anonymous
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <EGL/egl.h> #include <EGL/egl.h>
#include <EGL/eglext.h> #include <EGL/eglext.h>
#include <cstdint>
#include <list> #include <list>
#include <string> #include <string>
...@@ -28,6 +29,12 @@ class OSWindow ...@@ -28,6 +29,12 @@ class OSWindow
int getWidth() const; int getWidth() const;
int getHeight() const; int getHeight() const;
// Takes a screenshot of the window, returning the result as a mWidth * mHeight * 4
// normalized unsigned byte BGRA array. Note that it will be used to test the window
// manager's behavior so it needs to take an actual screenshot of the screen and not
// just grab the pixels of the window. Returns if it was successful.
virtual bool takeScreenshot(uint8_t *pixelData) { return false; }
virtual EGLNativeWindowType getNativeWindow() const = 0; virtual EGLNativeWindowType getNativeWindow() const = 0;
virtual EGLNativeDisplayType getNativeDisplay() const = 0; virtual EGLNativeDisplayType getNativeDisplay() const = 0;
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <sstream> #include <sstream>
#include "common/debug.h"
Key VirtualKeyCodeToKey(WPARAM key, LPARAM flags) Key VirtualKeyCodeToKey(WPARAM key, LPARAM flags)
{ {
switch (key) switch (key)
...@@ -374,7 +376,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) ...@@ -374,7 +376,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
Win32Window::Win32Window() Win32Window::Win32Window()
: mNativeWindow(0), : mIsVisible(false),
mSetVisibleTimer(CreateTimer()),
mNativeWindow(0),
mParentWindow(0), mParentWindow(0),
mNativeDisplay(0) mNativeDisplay(0)
{ {
...@@ -383,6 +387,7 @@ Win32Window::Win32Window() ...@@ -383,6 +387,7 @@ Win32Window::Win32Window()
Win32Window::~Win32Window() Win32Window::~Win32Window()
{ {
destroy(); destroy();
delete mSetVisibleTimer;
} }
bool Win32Window::initialize(const std::string &name, size_t width, size_t height) bool Win32Window::initialize(const std::string &name, size_t width, size_t height)
...@@ -482,6 +487,108 @@ void Win32Window::destroy() ...@@ -482,6 +487,108 @@ void Win32Window::destroy()
UnregisterClassA(mChildClassName.c_str(), NULL); UnregisterClassA(mChildClassName.c_str(), NULL);
} }
bool Win32Window::takeScreenshot(uint8_t *pixelData)
{
if (mIsVisible)
{
return false;
}
bool error = false;
// Hack for DWM: There is no way to wait for DWM animations to finish, so we just have to wait
// for a while before issuing screenshot if window was just made visible.
{
static const double WAIT_WINDOW_VISIBLE_MS = 0.5; // Half a second for the animation
double timeSinceVisible = mSetVisibleTimer->getElapsedTime();
if (timeSinceVisible < WAIT_WINDOW_VISIBLE_MS)
{
Sleep(static_cast<DWORD>((WAIT_WINDOW_VISIBLE_MS - timeSinceVisible) * 1000));
}
}
HDC screenDC = nullptr;
HDC windowDC = nullptr;
HDC tmpDC = nullptr;
HBITMAP tmpBitmap = nullptr;
if (!error)
{
screenDC = GetDC(nullptr);
error = screenDC == nullptr;
}
if (!error)
{
windowDC = GetDC(mNativeWindow);
error = windowDC == nullptr;
}
if (!error)
{
tmpDC = CreateCompatibleDC(screenDC);
error = tmpDC == nullptr;
}
if (!error)
{
tmpBitmap = CreateCompatibleBitmap(screenDC, mWidth, mHeight);
error = tmpBitmap == nullptr;
}
RECT rect = {0, 0, 0, 0};
if (!error)
{
MapWindowPoints(mNativeWindow, nullptr, reinterpret_cast<LPPOINT>(&rect), 0);
error = SelectObject(tmpDC, tmpBitmap) == nullptr;
}
if (!error)
{
error = BitBlt(tmpDC, 0, 0, mWidth, mHeight, screenDC, rect.left, rect.top, SRCCOPY) == TRUE;
}
if (!error)
{
BITMAPINFOHEADER bitmapInfo;
bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.biWidth = mWidth;
bitmapInfo.biHeight = -mHeight;
bitmapInfo.biPlanes = 1;
bitmapInfo.biBitCount = 32;
bitmapInfo.biCompression = BI_RGB;
bitmapInfo.biSizeImage = 0;
bitmapInfo.biXPelsPerMeter = 0;
bitmapInfo.biYPelsPerMeter = 0;
bitmapInfo.biClrUsed = 0;
bitmapInfo.biClrImportant = 0;
int getBitsResult = GetDIBits(screenDC, tmpBitmap, 0, mHeight, pixelData,
reinterpret_cast<BITMAPINFO*>(&bitmapInfo), DIB_RGB_COLORS);
error = getBitsResult != 0;
}
if (tmpBitmap != nullptr)
{
DeleteObject(tmpBitmap);
}
if (tmpDC != nullptr)
{
DeleteDC(tmpDC);
}
if (screenDC != nullptr)
{
ReleaseDC(nullptr, screenDC);
}
if (windowDC != nullptr)
{
ReleaseDC(mNativeWindow, windowDC);
}
return !error;
}
EGLNativeWindowType Win32Window::getNativeWindow() const EGLNativeWindowType Win32Window::getNativeWindow() const
{ {
return mNativeWindow; return mNativeWindow;
...@@ -581,6 +688,12 @@ void Win32Window::setVisible(bool isVisible) ...@@ -581,6 +688,12 @@ void Win32Window::setVisible(bool isVisible)
ShowWindow(mParentWindow, flag); ShowWindow(mParentWindow, flag);
ShowWindow(mNativeWindow, flag); ShowWindow(mNativeWindow, flag);
if (isVisible)
{
mSetVisibleTimer->stop();
mSetVisibleTimer->start();
}
} }
void Win32Window::pushEvent(Event event) void Win32Window::pushEvent(Event event)
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <string> #include <string>
#include "OSWindow.h" #include "OSWindow.h"
#include "Timer.h"
class Win32Window : public OSWindow class Win32Window : public OSWindow
{ {
...@@ -23,6 +24,8 @@ class Win32Window : public OSWindow ...@@ -23,6 +24,8 @@ class Win32Window : public OSWindow
bool initialize(const std::string &name, size_t width, size_t height) override; bool initialize(const std::string &name, size_t width, size_t height) override;
void destroy() override; void destroy() override;
bool takeScreenshot(uint8_t *pixelData) override;
EGLNativeWindowType getNativeWindow() const override; EGLNativeWindowType getNativeWindow() const override;
EGLNativeDisplayType getNativeDisplay() const override; EGLNativeDisplayType getNativeDisplay() const override;
...@@ -41,6 +44,9 @@ class Win32Window : public OSWindow ...@@ -41,6 +44,9 @@ class Win32Window : public OSWindow
std::string mParentClassName; std::string mParentClassName;
std::string mChildClassName; std::string mChildClassName;
bool mIsVisible;
Timer *mSetVisibleTimer;
EGLNativeWindowType mNativeWindow; EGLNativeWindowType mNativeWindow;
EGLNativeWindowType mParentWindow; EGLNativeWindowType mParentWindow;
EGLNativeDisplayType mNativeDisplay; EGLNativeDisplayType mNativeDisplay;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment