Add multiple contexts tests
[platform/upstream/VK-GL-CTS.git] / framework / platform / win32 / tcuWin32EGLNativeDisplayFactory.cpp
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 #include "eglwLibrary.hpp"
34 #include "eglwEnums.hpp"
35
36 // Assume no call translation is needed
37 DE_STATIC_ASSERT(sizeof(eglw::EGLNativeDisplayType) == sizeof(HDC));
38 DE_STATIC_ASSERT(sizeof(eglw::EGLNativePixmapType) == sizeof(HBITMAP));
39 DE_STATIC_ASSERT(sizeof(eglw::EGLNativeWindowType) == sizeof(HWND));
40
41 namespace tcu
42 {
43 namespace win32
44 {
45 namespace
46 {
47
48 using namespace eglw;
49
50 enum
51 {
52         DEFAULT_SURFACE_WIDTH           = 400,
53         DEFAULT_SURFACE_HEIGHT          = 300,
54         WAIT_WINDOW_VISIBLE_MS          = 500   //!< Time to wait before issuing screenshot after changing window visibility (hack for DWM)
55 };
56
57 static const eglu::NativeDisplay::Capability    DISPLAY_CAPABILITIES    = eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY;
58 static const eglu::NativePixmap::Capability             BITMAP_CAPABILITIES             = eglu::NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY;
59 static const eglu::NativeWindow::Capability             WINDOW_CAPABILITIES             = (eglu::NativeWindow::Capability)
60                                                                                                                                                    (eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY        |
61                                                                                                                                                     eglu::NativeWindow::CAPABILITY_GET_SURFACE_SIZE                     |
62                                                                                                                                                     eglu::NativeWindow::CAPABILITY_GET_SCREEN_SIZE                      |
63                                                                                                                                                         eglu::NativeWindow::CAPABILITY_READ_SCREEN_PIXELS               |
64                                                                                                                                                     eglu::NativeWindow::CAPABILITY_SET_SURFACE_SIZE                     |
65                                                                                                                                                         eglu::NativeWindow::CAPABILITY_CHANGE_VISIBILITY);
66
67 class NativeDisplay : public eglu::NativeDisplay
68 {
69 public:
70                                                                         NativeDisplay                   (void);
71         virtual                                                 ~NativeDisplay                  (void) {}
72
73         virtual EGLNativeDisplayType    getLegacyNative                 (void)                  { return m_deviceContext;       }
74         const eglw::Library&                    getLibrary                              (void) const    { return m_library;                     }
75
76         HDC                                                             getDeviceContext                (void)                  { return m_deviceContext;       }
77
78 private:
79         HDC                                                             m_deviceContext;
80         eglw::DefaultLibrary                    m_library;
81 };
82
83 class NativePixmapFactory : public eglu::NativePixmapFactory
84 {
85 public:
86                                                                 NativePixmapFactory             (void);
87                                                                 ~NativePixmapFactory    (void) {}
88
89         virtual eglu::NativePixmap*     createPixmap                    (eglu::NativeDisplay* nativeDisplay, int width, int height) const;
90         virtual eglu::NativePixmap*     createPixmap                    (eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height) const;
91 };
92
93 class NativePixmap : public eglu::NativePixmap
94 {
95 public:
96                                                                 NativePixmap                    (NativeDisplay* nativeDisplay, int width, int height, int bitDepth);
97         virtual                                         ~NativePixmap                   (void);
98
99         EGLNativePixmapType                     getLegacyNative                 (void) { return m_bitmap; }
100
101 private:
102         HBITMAP                                         m_bitmap;
103 };
104
105 class NativeWindowFactory : public eglu::NativeWindowFactory
106 {
107 public:
108                                                                 NativeWindowFactory             (HINSTANCE instance);
109         virtual                                         ~NativeWindowFactory    (void) {}
110
111         virtual eglu::NativeWindow*     createWindow                    (eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const;
112
113 private:
114         const HINSTANCE                         m_instance;
115 };
116
117 class NativeWindow : public eglu::NativeWindow
118 {
119 public:
120                                                                         NativeWindow                    (NativeDisplay* nativeDisplay, HINSTANCE instance, const eglu::WindowParams& params);
121         virtual                                                 ~NativeWindow                   (void);
122
123         EGLNativeWindowType                             getLegacyNative                 (void) { return m_window.getHandle(); }
124         virtual IVec2                                   getSurfaceSize                  (void) const;
125         virtual IVec2                                   getScreenSize                   (void) const { return getSurfaceSize(); }
126         virtual void                                    processEvents                   (void);
127         virtual void                                    setSurfaceSize                  (IVec2 size);
128         virtual void                                    setVisibility                   (eglu::WindowParams::Visibility visibility);
129         virtual void                                    readScreenPixels                (tcu::TextureLevel* dst) const;
130
131 private:
132         win32::Window                                   m_window;
133         eglu::WindowParams::Visibility  m_curVisibility;
134         deUint64                                                m_setVisibleTime;               //!< Time window was set visible.
135 };
136
137 // NativeDisplay
138
139 NativeDisplay::NativeDisplay (void)
140         : eglu::NativeDisplay   (DISPLAY_CAPABILITIES)
141         , m_deviceContext               ((HDC)EGL_DEFAULT_DISPLAY)
142         , m_library                             ("libEGL.dll")
143 {
144 }
145
146 // NativePixmap
147
148 NativePixmap::NativePixmap (NativeDisplay* nativeDisplay, int width, int height, int bitDepth)
149         : eglu::NativePixmap    (BITMAP_CAPABILITIES)
150         , m_bitmap                              (DE_NULL)
151 {
152         const HDC               deviceCtx       = nativeDisplay->getDeviceContext();
153         BITMAPINFO              bitmapInfo;
154
155         memset(&bitmapInfo, 0, sizeof(bitmapInfo));
156
157         if (bitDepth != 24 && bitDepth != 32)
158                 throw NotSupportedError("Unsupported pixmap bit depth", DE_NULL, __FILE__, __LINE__);
159
160         bitmapInfo.bmiHeader.biSize                             = sizeof(bitmapInfo);
161         bitmapInfo.bmiHeader.biWidth                    = width;
162         bitmapInfo.bmiHeader.biHeight                   = height;
163         bitmapInfo.bmiHeader.biPlanes                   = 1;
164         bitmapInfo.bmiHeader.biBitCount                 = bitDepth;
165         bitmapInfo.bmiHeader.biCompression              = BI_RGB;
166         bitmapInfo.bmiHeader.biSizeImage                = 0;
167         bitmapInfo.bmiHeader.biXPelsPerMeter    = 1;
168         bitmapInfo.bmiHeader.biYPelsPerMeter    = 1;
169         bitmapInfo.bmiHeader.biClrUsed                  = 0;
170         bitmapInfo.bmiHeader.biClrImportant             = 0;
171
172         void* bitmapPtr = DE_NULL;
173         m_bitmap = CreateDIBSection(deviceCtx, &bitmapInfo, DIB_RGB_COLORS, &bitmapPtr, NULL, 0);
174
175         if (!m_bitmap)
176                 throw ResourceError("Failed to create bitmap", DE_NULL, __FILE__, __LINE__);
177 }
178
179 NativePixmap::~NativePixmap (void)
180 {
181         DeleteObject(m_bitmap);
182 }
183
184 // NativePixmapFactory
185
186 NativePixmapFactory::NativePixmapFactory (void)
187         : eglu::NativePixmapFactory     ("bitmap", "Win32 Bitmap", BITMAP_CAPABILITIES)
188 {
189 }
190
191 eglu::NativePixmap* NativePixmapFactory::createPixmap (eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height) const
192 {
193         const Library&  egl                     = nativeDisplay->getLibrary();
194         int                             redBits         = 0;
195         int                             greenBits       = 0;
196         int                             blueBits        = 0;
197         int                             alphaBits       = 0;
198         int                             bitSum          = 0;
199
200         DE_ASSERT(display != EGL_NO_DISPLAY);
201
202         egl.getConfigAttrib(display, config, EGL_RED_SIZE,              &redBits);
203         egl.getConfigAttrib(display, config, EGL_GREEN_SIZE,    &greenBits);
204         egl.getConfigAttrib(display, config, EGL_BLUE_SIZE,             &blueBits);
205         egl.getConfigAttrib(display, config, EGL_ALPHA_SIZE,    &alphaBits);
206         EGLU_CHECK_MSG(egl, "eglGetConfigAttrib()");
207
208         bitSum = redBits+greenBits+blueBits+alphaBits;
209
210         return new NativePixmap(dynamic_cast<NativeDisplay*>(nativeDisplay), width, height, bitSum);
211 }
212
213 eglu::NativePixmap* NativePixmapFactory::createPixmap (eglu::NativeDisplay* nativeDisplay, int width, int height) const
214 {
215         const int defaultDepth = 32;
216         return new NativePixmap(dynamic_cast<NativeDisplay*>(nativeDisplay), width, height, defaultDepth);
217 }
218
219 // NativeWindowFactory
220
221 NativeWindowFactory::NativeWindowFactory (HINSTANCE instance)
222         : eglu::NativeWindowFactory     ("window", "Win32 Window", WINDOW_CAPABILITIES)
223         , m_instance                            (instance)
224 {
225 }
226
227 eglu::NativeWindow* NativeWindowFactory::createWindow (eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const
228 {
229         return new NativeWindow(dynamic_cast<NativeDisplay*>(nativeDisplay), m_instance, params);
230 }
231
232 // NativeWindow
233
234 NativeWindow::NativeWindow (NativeDisplay* nativeDisplay, HINSTANCE instance, const eglu::WindowParams& params)
235         : eglu::NativeWindow    (WINDOW_CAPABILITIES)
236         , m_window                              (instance,
237                                                          params.width   == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_WIDTH   : params.width,
238                                                          params.height  == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_HEIGHT  : params.height)
239         , m_curVisibility               (eglu::WindowParams::VISIBILITY_HIDDEN)
240         , m_setVisibleTime              (0)
241 {
242         if (params.visibility != eglu::WindowParams::VISIBILITY_DONT_CARE)
243                 setVisibility(params.visibility);
244 }
245
246 void NativeWindow::setVisibility (eglu::WindowParams::Visibility visibility)
247 {
248         switch (visibility)
249         {
250                 case eglu::WindowParams::VISIBILITY_HIDDEN:
251                         m_window.setVisible(false);
252                         m_curVisibility         = visibility;
253                         break;
254
255                 case eglu::WindowParams::VISIBILITY_VISIBLE:
256                 case eglu::WindowParams::VISIBILITY_FULLSCREEN:
257                         // \todo [2014-03-12 pyry] Implement FULLSCREEN, or at least SW_MAXIMIZE.
258                         m_window.setVisible(true);
259                         m_curVisibility         = eglu::WindowParams::VISIBILITY_VISIBLE;
260                         m_setVisibleTime        = deGetMicroseconds();
261                         break;
262
263                 default:
264                         DE_ASSERT(DE_FALSE);
265         }
266 }
267
268 NativeWindow::~NativeWindow (void)
269 {
270 }
271
272 IVec2 NativeWindow::getSurfaceSize (void) const
273 {
274         return m_window.getSize();
275 }
276
277 void NativeWindow::processEvents (void)
278 {
279         m_window.processEvents();
280 }
281
282 void NativeWindow::setSurfaceSize (IVec2 size)
283 {
284         m_window.setSize(size.x(), size.y());
285 }
286
287 void NativeWindow::readScreenPixels (tcu::TextureLevel* dst) const
288 {
289         HDC                     windowDC        = DE_NULL;
290         HDC                     screenDC        = DE_NULL;
291         HDC                     tmpDC           = DE_NULL;
292         HBITMAP         tmpBitmap       = DE_NULL;
293         RECT            rect;
294
295         TCU_CHECK_INTERNAL(m_curVisibility != eglu::WindowParams::VISIBILITY_HIDDEN);
296
297         // Hack for DWM: There is no way to wait for DWM animations to finish, so we just have to wait
298         // for a while before issuing screenshot if window was just made visible.
299         {
300                 const deInt64 timeSinceVisibleUs = (deInt64)(deGetMicroseconds()-m_setVisibleTime);
301
302                 if (timeSinceVisibleUs < (deInt64)WAIT_WINDOW_VISIBLE_MS*1000)
303                         deSleep(WAIT_WINDOW_VISIBLE_MS - (deUint32)(timeSinceVisibleUs/1000));
304         }
305
306         TCU_CHECK(GetClientRect(m_window.getHandle(), &rect));
307
308         try
309         {
310                 const int                       width           = rect.right - rect.left;
311                 const int                       height          = rect.bottom - rect.top;
312                 BITMAPINFOHEADER        bitmapInfo;
313
314                 deMemset(&bitmapInfo, 0, sizeof(bitmapInfo));
315
316                 screenDC = GetDC(DE_NULL);
317                 TCU_CHECK(screenDC);
318
319                 windowDC = GetDC(m_window.getHandle());
320                 TCU_CHECK(windowDC);
321
322                 tmpDC = CreateCompatibleDC(screenDC);
323                 TCU_CHECK(tmpDC != DE_NULL);
324
325                 MapWindowPoints(m_window.getHandle(), DE_NULL, (LPPOINT)&rect, 2);
326
327                 tmpBitmap = CreateCompatibleBitmap(screenDC, width, height);
328                 TCU_CHECK(tmpBitmap != DE_NULL);
329
330                 TCU_CHECK(SelectObject(tmpDC, tmpBitmap) != DE_NULL);
331
332                 TCU_CHECK(BitBlt(tmpDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY));
333
334
335                 bitmapInfo.biSize                       = sizeof(BITMAPINFOHEADER);
336                 bitmapInfo.biWidth                      = width;
337                 bitmapInfo.biHeight                     = -height;
338                 bitmapInfo.biPlanes                     = 1;
339                 bitmapInfo.biBitCount           = 32;
340                 bitmapInfo.biCompression        = BI_RGB;
341                 bitmapInfo.biSizeImage          = 0;
342                 bitmapInfo.biXPelsPerMeter      = 0;
343                 bitmapInfo.biYPelsPerMeter      = 0;
344                 bitmapInfo.biClrUsed            = 0;
345                 bitmapInfo.biClrImportant       = 0;
346
347                 dst->setStorage(TextureFormat(TextureFormat::BGRA, TextureFormat::UNORM_INT8), width, height);
348
349                 TCU_CHECK(GetDIBits(screenDC, tmpBitmap, 0, height, dst->getAccess().getDataPtr(), (BITMAPINFO*)&bitmapInfo, DIB_RGB_COLORS));
350
351                 DeleteObject(tmpBitmap);
352                 tmpBitmap = DE_NULL;
353
354                 ReleaseDC(DE_NULL, screenDC);
355                 screenDC = DE_NULL;
356
357                 ReleaseDC(m_window.getHandle(), windowDC);
358                 windowDC = DE_NULL;
359
360                 DeleteDC(tmpDC);
361                 tmpDC = DE_NULL;
362         }
363         catch (...)
364         {
365                 if (screenDC)
366                         ReleaseDC(DE_NULL, screenDC);
367
368                 if (windowDC)
369                         ReleaseDC(m_window.getHandle(), windowDC);
370
371                 if (tmpBitmap)
372                         DeleteObject(tmpBitmap);
373
374                 if (tmpDC)
375                         DeleteDC(tmpDC);
376
377                 throw;
378         }
379 }
380
381 } // anonymous
382
383 EGLNativeDisplayFactory::EGLNativeDisplayFactory (HINSTANCE instance)
384         : eglu::NativeDisplayFactory    ("win32", "Native Win32 Display", DISPLAY_CAPABILITIES)
385         , m_instance                                    (instance)
386 {
387         m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(m_instance));
388         m_nativePixmapRegistry.registerFactory(new NativePixmapFactory());
389 }
390
391 EGLNativeDisplayFactory::~EGLNativeDisplayFactory (void)
392 {
393 }
394
395 eglu::NativeDisplay* EGLNativeDisplayFactory::createDisplay (const EGLAttrib* attribList) const
396 {
397         DE_UNREF(attribList);
398         return new NativeDisplay();
399 }
400
401 } // win32
402 } // tcu