403 lines
12 KiB
C++
403 lines
12 KiB
C++
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program Tester Core
|
|
* ----------------------------------------
|
|
*
|
|
* Copyright 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*//*!
|
|
* \file
|
|
* \brief Win32 EGL native display factory
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "tcuWin32EGLNativeDisplayFactory.hpp"
|
|
|
|
#include "egluDefs.hpp"
|
|
#include "tcuWin32Window.hpp"
|
|
#include "tcuWin32API.h"
|
|
#include "tcuTexture.hpp"
|
|
#include "deMemory.h"
|
|
#include "deThread.h"
|
|
#include "deClock.h"
|
|
#include "eglwLibrary.hpp"
|
|
#include "eglwEnums.hpp"
|
|
|
|
// Assume no call translation is needed
|
|
DE_STATIC_ASSERT(sizeof(eglw::EGLNativeDisplayType) == sizeof(HDC));
|
|
DE_STATIC_ASSERT(sizeof(eglw::EGLNativePixmapType) == sizeof(HBITMAP));
|
|
DE_STATIC_ASSERT(sizeof(eglw::EGLNativeWindowType) == sizeof(HWND));
|
|
|
|
namespace tcu
|
|
{
|
|
namespace win32
|
|
{
|
|
namespace
|
|
{
|
|
|
|
using namespace eglw;
|
|
|
|
enum
|
|
{
|
|
DEFAULT_SURFACE_WIDTH = 400,
|
|
DEFAULT_SURFACE_HEIGHT = 300,
|
|
WAIT_WINDOW_VISIBLE_MS = 500 //!< Time to wait before issuing screenshot after changing window visibility (hack for DWM)
|
|
};
|
|
|
|
static const eglu::NativeDisplay::Capability DISPLAY_CAPABILITIES = eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY;
|
|
static const eglu::NativePixmap::Capability BITMAP_CAPABILITIES = eglu::NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY;
|
|
static const eglu::NativeWindow::Capability WINDOW_CAPABILITIES = (eglu::NativeWindow::Capability)
|
|
(eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY |
|
|
eglu::NativeWindow::CAPABILITY_GET_SURFACE_SIZE |
|
|
eglu::NativeWindow::CAPABILITY_GET_SCREEN_SIZE |
|
|
eglu::NativeWindow::CAPABILITY_READ_SCREEN_PIXELS |
|
|
eglu::NativeWindow::CAPABILITY_SET_SURFACE_SIZE |
|
|
eglu::NativeWindow::CAPABILITY_CHANGE_VISIBILITY);
|
|
|
|
class NativeDisplay : public eglu::NativeDisplay
|
|
{
|
|
public:
|
|
NativeDisplay (void);
|
|
virtual ~NativeDisplay (void) {}
|
|
|
|
virtual EGLNativeDisplayType getLegacyNative (void) { return m_deviceContext; }
|
|
const eglw::Library& getLibrary (void) const { return m_library; }
|
|
|
|
HDC getDeviceContext (void) { return m_deviceContext; }
|
|
|
|
private:
|
|
HDC m_deviceContext;
|
|
eglw::DefaultLibrary m_library;
|
|
};
|
|
|
|
class NativePixmapFactory : public eglu::NativePixmapFactory
|
|
{
|
|
public:
|
|
NativePixmapFactory (void);
|
|
~NativePixmapFactory (void) {}
|
|
|
|
virtual eglu::NativePixmap* createPixmap (eglu::NativeDisplay* nativeDisplay, int width, int height) const;
|
|
virtual eglu::NativePixmap* createPixmap (eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height) const;
|
|
};
|
|
|
|
class NativePixmap : public eglu::NativePixmap
|
|
{
|
|
public:
|
|
NativePixmap (NativeDisplay* nativeDisplay, int width, int height, int bitDepth);
|
|
virtual ~NativePixmap (void);
|
|
|
|
EGLNativePixmapType getLegacyNative (void) { return m_bitmap; }
|
|
|
|
private:
|
|
HBITMAP m_bitmap;
|
|
};
|
|
|
|
class NativeWindowFactory : public eglu::NativeWindowFactory
|
|
{
|
|
public:
|
|
NativeWindowFactory (HINSTANCE instance);
|
|
virtual ~NativeWindowFactory (void) {}
|
|
|
|
virtual eglu::NativeWindow* createWindow (eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const;
|
|
|
|
private:
|
|
const HINSTANCE m_instance;
|
|
};
|
|
|
|
class NativeWindow : public eglu::NativeWindow
|
|
{
|
|
public:
|
|
NativeWindow (NativeDisplay* nativeDisplay, HINSTANCE instance, const eglu::WindowParams& params);
|
|
virtual ~NativeWindow (void);
|
|
|
|
EGLNativeWindowType getLegacyNative (void) { return m_window.getHandle(); }
|
|
virtual IVec2 getSurfaceSize (void) const;
|
|
virtual IVec2 getScreenSize (void) const { return getSurfaceSize(); }
|
|
virtual void processEvents (void);
|
|
virtual void setSurfaceSize (IVec2 size);
|
|
virtual void setVisibility (eglu::WindowParams::Visibility visibility);
|
|
virtual void readScreenPixels (tcu::TextureLevel* dst) const;
|
|
|
|
private:
|
|
win32::Window m_window;
|
|
eglu::WindowParams::Visibility m_curVisibility;
|
|
deUint64 m_setVisibleTime; //!< Time window was set visible.
|
|
};
|
|
|
|
// NativeDisplay
|
|
|
|
NativeDisplay::NativeDisplay (void)
|
|
: eglu::NativeDisplay (DISPLAY_CAPABILITIES)
|
|
, m_deviceContext ((HDC)EGL_DEFAULT_DISPLAY)
|
|
, m_library ("libEGL.dll")
|
|
{
|
|
}
|
|
|
|
// NativePixmap
|
|
|
|
NativePixmap::NativePixmap (NativeDisplay* nativeDisplay, int width, int height, int bitDepth)
|
|
: eglu::NativePixmap (BITMAP_CAPABILITIES)
|
|
, m_bitmap (DE_NULL)
|
|
{
|
|
const HDC deviceCtx = nativeDisplay->getDeviceContext();
|
|
BITMAPINFO bitmapInfo;
|
|
|
|
memset(&bitmapInfo, 0, sizeof(bitmapInfo));
|
|
|
|
if (bitDepth != 24 && bitDepth != 32)
|
|
throw NotSupportedError("Unsupported pixmap bit depth", DE_NULL, __FILE__, __LINE__);
|
|
|
|
bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo);
|
|
bitmapInfo.bmiHeader.biWidth = width;
|
|
bitmapInfo.bmiHeader.biHeight = height;
|
|
bitmapInfo.bmiHeader.biPlanes = 1;
|
|
bitmapInfo.bmiHeader.biBitCount = bitDepth;
|
|
bitmapInfo.bmiHeader.biCompression = BI_RGB;
|
|
bitmapInfo.bmiHeader.biSizeImage = 0;
|
|
bitmapInfo.bmiHeader.biXPelsPerMeter = 1;
|
|
bitmapInfo.bmiHeader.biYPelsPerMeter = 1;
|
|
bitmapInfo.bmiHeader.biClrUsed = 0;
|
|
bitmapInfo.bmiHeader.biClrImportant = 0;
|
|
|
|
void* bitmapPtr = DE_NULL;
|
|
m_bitmap = CreateDIBSection(deviceCtx, &bitmapInfo, DIB_RGB_COLORS, &bitmapPtr, NULL, 0);
|
|
|
|
if (!m_bitmap)
|
|
throw ResourceError("Failed to create bitmap", DE_NULL, __FILE__, __LINE__);
|
|
}
|
|
|
|
NativePixmap::~NativePixmap (void)
|
|
{
|
|
DeleteObject(m_bitmap);
|
|
}
|
|
|
|
// NativePixmapFactory
|
|
|
|
NativePixmapFactory::NativePixmapFactory (void)
|
|
: eglu::NativePixmapFactory ("bitmap", "Win32 Bitmap", BITMAP_CAPABILITIES)
|
|
{
|
|
}
|
|
|
|
eglu::NativePixmap* NativePixmapFactory::createPixmap (eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height) const
|
|
{
|
|
const Library& egl = nativeDisplay->getLibrary();
|
|
int redBits = 0;
|
|
int greenBits = 0;
|
|
int blueBits = 0;
|
|
int alphaBits = 0;
|
|
int bitSum = 0;
|
|
|
|
DE_ASSERT(display != EGL_NO_DISPLAY);
|
|
|
|
egl.getConfigAttrib(display, config, EGL_RED_SIZE, &redBits);
|
|
egl.getConfigAttrib(display, config, EGL_GREEN_SIZE, &greenBits);
|
|
egl.getConfigAttrib(display, config, EGL_BLUE_SIZE, &blueBits);
|
|
egl.getConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaBits);
|
|
EGLU_CHECK_MSG(egl, "eglGetConfigAttrib()");
|
|
|
|
bitSum = redBits+greenBits+blueBits+alphaBits;
|
|
|
|
return new NativePixmap(dynamic_cast<NativeDisplay*>(nativeDisplay), width, height, bitSum);
|
|
}
|
|
|
|
eglu::NativePixmap* NativePixmapFactory::createPixmap (eglu::NativeDisplay* nativeDisplay, int width, int height) const
|
|
{
|
|
const int defaultDepth = 32;
|
|
return new NativePixmap(dynamic_cast<NativeDisplay*>(nativeDisplay), width, height, defaultDepth);
|
|
}
|
|
|
|
// NativeWindowFactory
|
|
|
|
NativeWindowFactory::NativeWindowFactory (HINSTANCE instance)
|
|
: eglu::NativeWindowFactory ("window", "Win32 Window", WINDOW_CAPABILITIES)
|
|
, m_instance (instance)
|
|
{
|
|
}
|
|
|
|
eglu::NativeWindow* NativeWindowFactory::createWindow (eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const
|
|
{
|
|
return new NativeWindow(dynamic_cast<NativeDisplay*>(nativeDisplay), m_instance, params);
|
|
}
|
|
|
|
// NativeWindow
|
|
|
|
NativeWindow::NativeWindow (NativeDisplay* nativeDisplay, HINSTANCE instance, const eglu::WindowParams& params)
|
|
: eglu::NativeWindow (WINDOW_CAPABILITIES)
|
|
, m_window (instance,
|
|
params.width == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_WIDTH : params.width,
|
|
params.height == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_HEIGHT : params.height)
|
|
, m_curVisibility (eglu::WindowParams::VISIBILITY_HIDDEN)
|
|
, m_setVisibleTime (0)
|
|
{
|
|
if (params.visibility != eglu::WindowParams::VISIBILITY_DONT_CARE)
|
|
setVisibility(params.visibility);
|
|
}
|
|
|
|
void NativeWindow::setVisibility (eglu::WindowParams::Visibility visibility)
|
|
{
|
|
switch (visibility)
|
|
{
|
|
case eglu::WindowParams::VISIBILITY_HIDDEN:
|
|
m_window.setVisible(false);
|
|
m_curVisibility = visibility;
|
|
break;
|
|
|
|
case eglu::WindowParams::VISIBILITY_VISIBLE:
|
|
case eglu::WindowParams::VISIBILITY_FULLSCREEN:
|
|
// \todo [2014-03-12 pyry] Implement FULLSCREEN, or at least SW_MAXIMIZE.
|
|
m_window.setVisible(true);
|
|
m_curVisibility = eglu::WindowParams::VISIBILITY_VISIBLE;
|
|
m_setVisibleTime = deGetMicroseconds();
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
}
|
|
}
|
|
|
|
NativeWindow::~NativeWindow (void)
|
|
{
|
|
}
|
|
|
|
IVec2 NativeWindow::getSurfaceSize (void) const
|
|
{
|
|
return m_window.getSize();
|
|
}
|
|
|
|
void NativeWindow::processEvents (void)
|
|
{
|
|
m_window.processEvents();
|
|
}
|
|
|
|
void NativeWindow::setSurfaceSize (IVec2 size)
|
|
{
|
|
m_window.setSize(size.x(), size.y());
|
|
}
|
|
|
|
void NativeWindow::readScreenPixels (tcu::TextureLevel* dst) const
|
|
{
|
|
HDC windowDC = DE_NULL;
|
|
HDC screenDC = DE_NULL;
|
|
HDC tmpDC = DE_NULL;
|
|
HBITMAP tmpBitmap = DE_NULL;
|
|
RECT rect;
|
|
|
|
TCU_CHECK_INTERNAL(m_curVisibility != 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()-m_setVisibleTime);
|
|
|
|
if (timeSinceVisibleUs < (deInt64)WAIT_WINDOW_VISIBLE_MS*1000)
|
|
deSleep(WAIT_WINDOW_VISIBLE_MS - (deUint32)(timeSinceVisibleUs/1000));
|
|
}
|
|
|
|
TCU_CHECK(GetClientRect(m_window.getHandle(), &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(m_window.getHandle());
|
|
TCU_CHECK(windowDC);
|
|
|
|
tmpDC = CreateCompatibleDC(screenDC);
|
|
TCU_CHECK(tmpDC != DE_NULL);
|
|
|
|
MapWindowPoints(m_window.getHandle(), 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(m_window.getHandle(), windowDC);
|
|
windowDC = DE_NULL;
|
|
|
|
DeleteDC(tmpDC);
|
|
tmpDC = DE_NULL;
|
|
}
|
|
catch (...)
|
|
{
|
|
if (screenDC)
|
|
ReleaseDC(DE_NULL, screenDC);
|
|
|
|
if (windowDC)
|
|
ReleaseDC(m_window.getHandle(), windowDC);
|
|
|
|
if (tmpBitmap)
|
|
DeleteObject(tmpBitmap);
|
|
|
|
if (tmpDC)
|
|
DeleteDC(tmpDC);
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
} // anonymous
|
|
|
|
EGLNativeDisplayFactory::EGLNativeDisplayFactory (HINSTANCE instance)
|
|
: eglu::NativeDisplayFactory ("win32", "Native Win32 Display", DISPLAY_CAPABILITIES)
|
|
, m_instance (instance)
|
|
{
|
|
m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(m_instance));
|
|
m_nativePixmapRegistry.registerFactory(new NativePixmapFactory());
|
|
}
|
|
|
|
EGLNativeDisplayFactory::~EGLNativeDisplayFactory (void)
|
|
{
|
|
}
|
|
|
|
eglu::NativeDisplay* EGLNativeDisplayFactory::createDisplay (const EGLAttrib* attribList) const
|
|
{
|
|
DE_UNREF(attribList);
|
|
return new NativeDisplay();
|
|
}
|
|
|
|
} // win32
|
|
} // tcu
|