1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program Tester Core 3 * ---------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Win32 EGL native display factory 22 *//*--------------------------------------------------------------------*/ 23 24 #include "tcuWin32EGLNativeDisplayFactory.hpp" 25 26 #include "egluDefs.hpp" 27 #include "tcuWin32Window.hpp" 28 #include "tcuWin32API.h" 29 #include "tcuTexture.hpp" 30 #include "deMemory.h" 31 #include "deThread.h" 32 #include "deClock.h" 33 34 namespace tcu 35 { 36 namespace 37 { 38 39 enum 40 { 41 DEFAULT_SURFACE_WIDTH = 400, 42 DEFAULT_SURFACE_HEIGHT = 300, 43 WAIT_WINDOW_VISIBLE_MS = 500 //!< Time to wait before issuing screenshot after changing window visibility (hack for DWM) 44 }; 45 46 static const eglu::NativeDisplay::Capability DISPLAY_CAPABILITIES = eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY; 47 static const eglu::NativePixmap::Capability BITMAP_CAPABILITIES = eglu::NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY; 48 static const eglu::NativeWindow::Capability WINDOW_CAPABILITIES = (eglu::NativeWindow::Capability) 49 (eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY | 50 eglu::NativeWindow::CAPABILITY_GET_SURFACE_SIZE | 51 eglu::NativeWindow::CAPABILITY_GET_SCREEN_SIZE | 52 eglu::NativeWindow::CAPABILITY_READ_SCREEN_PIXELS | 53 eglu::NativeWindow::CAPABILITY_SET_SURFACE_SIZE | 54 eglu::NativeWindow::CAPABILITY_CHANGE_VISIBILITY); 55 56 class NativeDisplay : public eglu::NativeDisplay 57 { 58 public: 59 NativeDisplay (void); 60 virtual ~NativeDisplay (void) {} 61 62 virtual EGLNativeDisplayType getLegacyNative (void) { return m_deviceContext; } 63 64 HDC getDeviceContext (void) { return m_deviceContext; } 65 66 private: 67 HDC m_deviceContext; 68 }; 69 70 class NativePixmapFactory : public eglu::NativePixmapFactory 71 { 72 public: 73 NativePixmapFactory (void); 74 ~NativePixmapFactory (void) {} 75 76 virtual eglu::NativePixmap* createPixmap (eglu::NativeDisplay* nativeDisplay, int width, int height) const; 77 virtual eglu::NativePixmap* createPixmap (eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height) const; 78 }; 79 80 class NativePixmap : public eglu::NativePixmap 81 { 82 public: 83 NativePixmap (NativeDisplay* nativeDisplay, int width, int height, int bitDepth); 84 virtual ~NativePixmap (void); 85 86 EGLNativePixmapType getLegacyNative (void) { return m_bitmap; } 87 88 private: 89 HBITMAP m_bitmap; 90 }; 91 92 class NativeWindowFactory : public eglu::NativeWindowFactory 93 { 94 public: 95 NativeWindowFactory (HINSTANCE instance); 96 virtual ~NativeWindowFactory (void) {} 97 98 virtual eglu::NativeWindow* createWindow (eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const; 99 100 private: 101 const HINSTANCE m_instance; 102 }; 103 104 class NativeWindow : public eglu::NativeWindow 105 { 106 public: 107 NativeWindow (NativeDisplay* nativeDisplay, HINSTANCE instance, const eglu::WindowParams& params); 108 virtual ~NativeWindow (void); 109 110 EGLNativeWindowType getLegacyNative (void) { return m_window.getHandle(); } 111 virtual IVec2 getSurfaceSize (void) const; 112 virtual IVec2 getScreenSize (void) const { return getSurfaceSize(); } 113 virtual void processEvents (void); 114 virtual void setSurfaceSize (IVec2 size); 115 virtual void setVisibility (eglu::WindowParams::Visibility visibility); 116 virtual void readScreenPixels (tcu::TextureLevel* dst) const; 117 118 private: 119 Win32Window m_window; 120 eglu::WindowParams::Visibility m_curVisibility; 121 deUint64 m_setVisibleTime; //!< Time window was set visible. 122 }; 123 124 // NativeDisplay 125 126 NativeDisplay::NativeDisplay (void) 127 : eglu::NativeDisplay (DISPLAY_CAPABILITIES) 128 , m_deviceContext (EGL_DEFAULT_DISPLAY) 129 { 130 } 131 132 // NativePixmap 133 134 NativePixmap::NativePixmap (NativeDisplay* nativeDisplay, int width, int height, int bitDepth) 135 : eglu::NativePixmap (BITMAP_CAPABILITIES) 136 , m_bitmap (DE_NULL) 137 { 138 const HDC deviceCtx = nativeDisplay->getDeviceContext(); 139 BITMAPINFO bitmapInfo; 140 141 memset(&bitmapInfo, 0, sizeof(bitmapInfo)); 142 143 if (bitDepth != 24 && bitDepth != 32) 144 throw NotSupportedError("Unsupported pixmap bit depth", DE_NULL, __FILE__, __LINE__); 145 146 bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo); 147 bitmapInfo.bmiHeader.biWidth = width; 148 bitmapInfo.bmiHeader.biHeight = height; 149 bitmapInfo.bmiHeader.biPlanes = 1; 150 bitmapInfo.bmiHeader.biBitCount = bitDepth; 151 bitmapInfo.bmiHeader.biCompression = BI_RGB; 152 bitmapInfo.bmiHeader.biSizeImage = 0; 153 bitmapInfo.bmiHeader.biXPelsPerMeter = 1; 154 bitmapInfo.bmiHeader.biYPelsPerMeter = 1; 155 bitmapInfo.bmiHeader.biClrUsed = 0; 156 bitmapInfo.bmiHeader.biClrImportant = 0; 157 158 void* bitmapPtr = DE_NULL; 159 m_bitmap = CreateDIBSection(deviceCtx, &bitmapInfo, DIB_RGB_COLORS, &bitmapPtr, NULL, 0); 160 161 if (!m_bitmap) 162 throw ResourceError("Failed to create bitmap", DE_NULL, __FILE__, __LINE__); 163 } 164 165 NativePixmap::~NativePixmap (void) 166 { 167 DeleteObject(m_bitmap); 168 } 169 170 // NativePixmapFactory 171 172 NativePixmapFactory::NativePixmapFactory (void) 173 : eglu::NativePixmapFactory ("bitmap", "Win32 Bitmap", BITMAP_CAPABILITIES) 174 { 175 } 176 177 eglu::NativePixmap* NativePixmapFactory::createPixmap (eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height) const 178 { 179 int redBits = 0; 180 int greenBits = 0; 181 int blueBits = 0; 182 int alphaBits = 0; 183 int bitSum = 0; 184 185 DE_ASSERT(display != EGL_NO_DISPLAY); 186 187 EGLU_CHECK_CALL(eglGetConfigAttrib(display, config, EGL_RED_SIZE, &redBits)); 188 EGLU_CHECK_CALL(eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &greenBits)); 189 EGLU_CHECK_CALL(eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blueBits)); 190 EGLU_CHECK_CALL(eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaBits)); 191 bitSum = redBits+greenBits+blueBits+alphaBits; 192 193 return new NativePixmap(dynamic_cast<NativeDisplay*>(nativeDisplay), width, height, bitSum); 194 } 195 196 eglu::NativePixmap* NativePixmapFactory::createPixmap (eglu::NativeDisplay* nativeDisplay, int width, int height) const 197 { 198 const int defaultDepth = 32; 199 return new NativePixmap(dynamic_cast<NativeDisplay*>(nativeDisplay), width, height, defaultDepth); 200 } 201 202 // NativeWindowFactory 203 204 NativeWindowFactory::NativeWindowFactory (HINSTANCE instance) 205 : eglu::NativeWindowFactory ("window", "Win32 Window", WINDOW_CAPABILITIES) 206 , m_instance (instance) 207 { 208 } 209 210 eglu::NativeWindow* NativeWindowFactory::createWindow (eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const 211 { 212 return new NativeWindow(dynamic_cast<NativeDisplay*>(nativeDisplay), m_instance, params); 213 } 214 215 // NativeWindow 216 217 NativeWindow::NativeWindow (NativeDisplay* nativeDisplay, HINSTANCE instance, const eglu::WindowParams& params) 218 : eglu::NativeWindow (WINDOW_CAPABILITIES) 219 , m_window (instance, 220 params.width == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_WIDTH : params.width, 221 params.height == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_HEIGHT : params.height) 222 , m_curVisibility (eglu::WindowParams::VISIBILITY_HIDDEN) 223 , m_setVisibleTime (0) 224 { 225 if (params.visibility != eglu::WindowParams::VISIBILITY_DONT_CARE) 226 setVisibility(params.visibility); 227 } 228 229 void NativeWindow::setVisibility (eglu::WindowParams::Visibility visibility) 230 { 231 switch (visibility) 232 { 233 case eglu::WindowParams::VISIBILITY_HIDDEN: 234 m_window.setVisible(false); 235 m_curVisibility = visibility; 236 break; 237 238 case eglu::WindowParams::VISIBILITY_VISIBLE: 239 case eglu::WindowParams::VISIBILITY_FULLSCREEN: 240 // \todo [2014-03-12 pyry] Implement FULLSCREEN, or at least SW_MAXIMIZE. 241 m_window.setVisible(true); 242 m_curVisibility = eglu::WindowParams::VISIBILITY_VISIBLE; 243 m_setVisibleTime = deGetMicroseconds(); 244 break; 245 246 default: 247 DE_ASSERT(DE_FALSE); 248 } 249 } 250 251 NativeWindow::~NativeWindow (void) 252 { 253 } 254 255 IVec2 NativeWindow::getSurfaceSize (void) const 256 { 257 return m_window.getSize(); 258 } 259 260 void NativeWindow::processEvents (void) 261 { 262 m_window.processEvents(); 263 } 264 265 void NativeWindow::setSurfaceSize (IVec2 size) 266 { 267 m_window.setSize(size.x(), size.y()); 268 } 269 270 void NativeWindow::readScreenPixels (tcu::TextureLevel* dst) const 271 { 272 HDC windowDC = DE_NULL; 273 HDC screenDC = DE_NULL; 274 HDC tmpDC = DE_NULL; 275 HBITMAP tmpBitmap = DE_NULL; 276 RECT rect; 277 278 TCU_CHECK_INTERNAL(m_curVisibility != eglu::WindowParams::VISIBILITY_HIDDEN); 279 280 // Hack for DWM: There is no way to wait for DWM animations to finish, so we just have to wait 281 // for a while before issuing screenshot if window was just made visible. 282 { 283 const deInt64 timeSinceVisibleUs = (deInt64)(deGetMicroseconds()-m_setVisibleTime); 284 285 if (timeSinceVisibleUs < (deInt64)WAIT_WINDOW_VISIBLE_MS*1000) 286 deSleep(WAIT_WINDOW_VISIBLE_MS - (deUint32)(timeSinceVisibleUs/1000)); 287 } 288 289 TCU_CHECK(GetClientRect(m_window.getHandle(), &rect)); 290 291 try 292 { 293 const int width = rect.right - rect.left; 294 const int height = rect.bottom - rect.top; 295 BITMAPINFOHEADER bitmapInfo; 296 297 deMemset(&bitmapInfo, 0, sizeof(bitmapInfo)); 298 299 screenDC = GetDC(DE_NULL); 300 TCU_CHECK(screenDC); 301 302 windowDC = GetDC(m_window.getHandle()); 303 TCU_CHECK(windowDC); 304 305 tmpDC = CreateCompatibleDC(screenDC); 306 TCU_CHECK(tmpDC != DE_NULL); 307 308 MapWindowPoints(m_window.getHandle(), DE_NULL, (LPPOINT)&rect, 2); 309 310 tmpBitmap = CreateCompatibleBitmap(screenDC, width, height); 311 TCU_CHECK(tmpBitmap != DE_NULL); 312 313 TCU_CHECK(SelectObject(tmpDC, tmpBitmap) != DE_NULL); 314 315 TCU_CHECK(BitBlt(tmpDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY)); 316 317 318 bitmapInfo.biSize = sizeof(BITMAPINFOHEADER); 319 bitmapInfo.biWidth = width; 320 bitmapInfo.biHeight = -height; 321 bitmapInfo.biPlanes = 1; 322 bitmapInfo.biBitCount = 32; 323 bitmapInfo.biCompression = BI_RGB; 324 bitmapInfo.biSizeImage = 0; 325 bitmapInfo.biXPelsPerMeter = 0; 326 bitmapInfo.biYPelsPerMeter = 0; 327 bitmapInfo.biClrUsed = 0; 328 bitmapInfo.biClrImportant = 0; 329 330 dst->setStorage(TextureFormat(TextureFormat::BGRA, TextureFormat::UNORM_INT8), width, height); 331 332 TCU_CHECK(GetDIBits(screenDC, tmpBitmap, 0, height, dst->getAccess().getDataPtr(), (BITMAPINFO*)&bitmapInfo, DIB_RGB_COLORS)); 333 334 DeleteObject(tmpBitmap); 335 tmpBitmap = DE_NULL; 336 337 ReleaseDC(DE_NULL, screenDC); 338 screenDC = DE_NULL; 339 340 ReleaseDC(m_window.getHandle(), windowDC); 341 windowDC = DE_NULL; 342 343 DeleteDC(tmpDC); 344 tmpDC = DE_NULL; 345 } 346 catch (...) 347 { 348 if (screenDC) 349 ReleaseDC(DE_NULL, screenDC); 350 351 if (windowDC) 352 ReleaseDC(m_window.getHandle(), windowDC); 353 354 if (tmpBitmap) 355 DeleteObject(tmpBitmap); 356 357 if (tmpDC) 358 DeleteDC(tmpDC); 359 360 throw; 361 } 362 } 363 364 } // anonymous 365 366 Win32EGLNativeDisplayFactory::Win32EGLNativeDisplayFactory (HINSTANCE instance) 367 : eglu::NativeDisplayFactory ("win32", "Native Win32 Display", DISPLAY_CAPABILITIES) 368 , m_instance (instance) 369 { 370 m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(m_instance)); 371 m_nativePixmapRegistry.registerFactory(new NativePixmapFactory()); 372 } 373 374 Win32EGLNativeDisplayFactory::~Win32EGLNativeDisplayFactory (void) 375 { 376 } 377 378 eglu::NativeDisplay* Win32EGLNativeDisplayFactory::createDisplay (const EGLAttrib* attribList) const 379 { 380 DE_UNREF(attribList); 381 return new NativeDisplay(); 382 } 383 384 } // tcu 385