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
21 #include "egluNativeDisplay.hpp"
22
23 #include "tcuANGLENativeDisplayFactory.h"
24
25 #include <EGL/egl.h>
26 #include <EGL/eglext.h>
27
28 #include "deClock.h"
29 #include "deMemory.h"
30 #include "egluDefs.hpp"
31 #include "eglwLibrary.hpp"
32 #include "tcuTexture.hpp"
33 #include "util/OSPixmap.h"
34 #include "util/OSWindow.h"
35
36 // clang-format off
37 #if (DE_OS == DE_OS_WIN32)
38 #define ANGLE_EGL_LIBRARY_FULL_NAME ANGLE_EGL_LIBRARY_NAME ".dll"
39 #elif (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_ANDROID)
40 #define ANGLE_EGL_LIBRARY_FULL_NAME ANGLE_EGL_LIBRARY_NAME ".so"
41 #elif (DE_OS == DE_OS_OSX)
42 #define ANGLE_EGL_LIBRARY_FULL_NAME ANGLE_EGL_LIBRARY_NAME ".dylib"
43 #else
44 #error "Unsupported platform"
45 #endif
46 // clang-format on
47
48 namespace tcu
49 {
50 namespace
51 {
52
53 enum
54 {
55 DEFAULT_SURFACE_WIDTH = 400,
56 DEFAULT_SURFACE_HEIGHT = 300,
57 };
58
59 constexpr eglu::NativeDisplay::Capability kDisplayCapabilities =
60 static_cast<eglu::NativeDisplay::Capability>(
61 eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM |
62 eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM_EXT);
63 constexpr eglu::NativePixmap::Capability kBitmapCapabilities =
64 eglu::NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY;
65 constexpr eglu::NativeWindow::Capability kWindowCapabilities =
66 static_cast<eglu::NativeWindow::Capability>(
67 eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY |
68 eglu::NativeWindow::CAPABILITY_GET_SURFACE_SIZE |
69 eglu::NativeWindow::CAPABILITY_GET_SCREEN_SIZE |
70 eglu::NativeWindow::CAPABILITY_READ_SCREEN_PIXELS |
71 eglu::NativeWindow::CAPABILITY_SET_SURFACE_SIZE |
72 eglu::NativeWindow::CAPABILITY_CHANGE_VISIBILITY);
73
74 class ANGLENativeDisplay : public eglu::NativeDisplay
75 {
76 public:
77 explicit ANGLENativeDisplay(std::vector<eglw::EGLAttrib> attribs);
78 ~ANGLENativeDisplay() override = default;
79
getPlatformNative()80 void *getPlatformNative() override
81 {
82 // On OSX 64bits mDeviceContext is a 32 bit integer, so we can't simply
83 // use reinterpret_cast<void*>.
84 void *result = nullptr;
85 memcpy(&result, &mDeviceContext, sizeof(mDeviceContext));
86 return result;
87 }
getPlatformAttributes() const88 const eglw::EGLAttrib *getPlatformAttributes() const override
89 {
90 return &mPlatformAttributes[0];
91 }
getLibrary() const92 const eglw::Library &getLibrary() const override { return mLibrary; }
93
getDeviceContext() const94 EGLNativeDisplayType getDeviceContext() const { return mDeviceContext; }
95
96 private:
97 EGLNativeDisplayType mDeviceContext;
98 eglw::DefaultLibrary mLibrary;
99 std::vector<eglw::EGLAttrib> mPlatformAttributes;
100 };
101
102 class NativePixmapFactory : public eglu::NativePixmapFactory
103 {
104 public:
105 NativePixmapFactory();
106 ~NativePixmapFactory() override = default;
107
108 eglu::NativePixmap *createPixmap(eglu::NativeDisplay *nativeDisplay,
109 int width,
110 int height) const override;
111 eglu::NativePixmap *createPixmap(eglu::NativeDisplay *nativeDisplay,
112 eglw::EGLDisplay display,
113 eglw::EGLConfig config,
114 const eglw::EGLAttrib *attribList,
115 int width,
116 int height) const override;
117 };
118
119 class NativePixmap : public eglu::NativePixmap
120 {
121 public:
122 NativePixmap(EGLNativeDisplayType display, int width, int height, int bitDepth);
123 virtual ~NativePixmap();
124
125 eglw::EGLNativePixmapType getLegacyNative() override;
126
127 private:
128 OSPixmap *mPixmap;
129 };
130
131 class NativeWindowFactory : public eglu::NativeWindowFactory
132 {
133 public:
134 explicit NativeWindowFactory(EventState *eventState);
135 ~NativeWindowFactory() override = default;
136
137 eglu::NativeWindow *createWindow(eglu::NativeDisplay *nativeDisplay,
138 const eglu::WindowParams ¶ms) const override;
139 eglu::NativeWindow *createWindow(eglu::NativeDisplay *nativeDisplay,
140 eglw::EGLDisplay display,
141 eglw::EGLConfig config,
142 const eglw::EGLAttrib *attribList,
143 const eglu::WindowParams ¶ms) const override;
144
145 private:
146 EventState *mEvents;
147 };
148
149 class NativeWindow : public eglu::NativeWindow
150 {
151 public:
152 NativeWindow(ANGLENativeDisplay *nativeDisplay,
153 const eglu::WindowParams ¶ms,
154 EventState *eventState);
155 ~NativeWindow() override;
156
157 eglw::EGLNativeWindowType getLegacyNative() override;
158 IVec2 getSurfaceSize() const override;
getScreenSize() const159 IVec2 getScreenSize() const override { return getSurfaceSize(); }
160 void processEvents() override;
161 void setSurfaceSize(IVec2 size) override;
162 void setVisibility(eglu::WindowParams::Visibility visibility) override;
163 void readScreenPixels(tcu::TextureLevel *dst) const override;
164
165 private:
166 OSWindow *mWindow;
167 EventState *mEvents;
168 };
169
170 // ANGLE NativeDisplay
171
ANGLENativeDisplay(std::vector<EGLAttrib> attribs)172 ANGLENativeDisplay::ANGLENativeDisplay(std::vector<EGLAttrib> attribs)
173 : eglu::NativeDisplay(kDisplayCapabilities, EGL_PLATFORM_ANGLE_ANGLE, "EGL_EXT_platform_base"),
174 mDeviceContext(EGL_DEFAULT_DISPLAY),
175 mLibrary(ANGLE_EGL_LIBRARY_FULL_NAME),
176 mPlatformAttributes(std::move(attribs))
177 {}
178
179 // NativePixmap
180
NativePixmap(EGLNativeDisplayType display,int width,int height,int bitDepth)181 NativePixmap::NativePixmap(EGLNativeDisplayType display, int width, int height, int bitDepth)
182 : eglu::NativePixmap(kBitmapCapabilities), mPixmap(CreateOSPixmap())
183 {
184 #if (DE_OS != DE_OS_UNIX)
185 throw tcu::NotSupportedError("Pixmap not supported");
186 #else
187 if (!mPixmap)
188 {
189 throw ResourceError("Failed to create pixmap", DE_NULL, __FILE__, __LINE__);
190 }
191
192 if (!mPixmap->initialize(display, width, height, bitDepth))
193 {
194 throw ResourceError("Failed to initialize pixmap", DE_NULL, __FILE__, __LINE__);
195 }
196 #endif
197 }
198
~NativePixmap()199 NativePixmap::~NativePixmap()
200 {
201 delete mPixmap;
202 }
203
getLegacyNative()204 eglw::EGLNativePixmapType NativePixmap::getLegacyNative()
205 {
206 return reinterpret_cast<eglw::EGLNativePixmapType>(mPixmap->getNativePixmap());
207 }
208
209 // NativePixmapFactory
210
NativePixmapFactory()211 NativePixmapFactory::NativePixmapFactory()
212 : eglu::NativePixmapFactory("bitmap", "ANGLE Bitmap", kBitmapCapabilities)
213 {}
214
createPixmap(eglu::NativeDisplay * nativeDisplay,eglw::EGLDisplay display,eglw::EGLConfig config,const eglw::EGLAttrib * attribList,int width,int height) const215 eglu::NativePixmap *NativePixmapFactory::createPixmap(eglu::NativeDisplay *nativeDisplay,
216 eglw::EGLDisplay display,
217 eglw::EGLConfig config,
218 const eglw::EGLAttrib *attribList,
219 int width,
220 int height) const
221 {
222 const eglw::Library &egl = nativeDisplay->getLibrary();
223 int redBits = 0;
224 int greenBits = 0;
225 int blueBits = 0;
226 int alphaBits = 0;
227 int bitSum = 0;
228
229 DE_ASSERT(display != EGL_NO_DISPLAY);
230
231 egl.getConfigAttrib(display, config, EGL_RED_SIZE, &redBits);
232 egl.getConfigAttrib(display, config, EGL_GREEN_SIZE, &greenBits);
233 egl.getConfigAttrib(display, config, EGL_BLUE_SIZE, &blueBits);
234 egl.getConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaBits);
235 EGLU_CHECK_MSG(egl, "eglGetConfigAttrib()");
236
237 bitSum = redBits + greenBits + blueBits + alphaBits;
238
239 return new NativePixmap(dynamic_cast<ANGLENativeDisplay *>(nativeDisplay)->getDeviceContext(),
240 width, height, bitSum);
241 }
242
createPixmap(eglu::NativeDisplay * nativeDisplay,int width,int height) const243 eglu::NativePixmap *NativePixmapFactory::createPixmap(eglu::NativeDisplay *nativeDisplay,
244 int width,
245 int height) const
246 {
247 const int defaultDepth = 32;
248 return new NativePixmap(dynamic_cast<ANGLENativeDisplay *>(nativeDisplay)->getDeviceContext(),
249 width, height, defaultDepth);
250 }
251
252 // NativeWindowFactory
253
NativeWindowFactory(EventState * eventState)254 NativeWindowFactory::NativeWindowFactory(EventState *eventState)
255 : eglu::NativeWindowFactory("window", "ANGLE Window", kWindowCapabilities), mEvents(eventState)
256 {}
257
createWindow(eglu::NativeDisplay * nativeDisplay,const eglu::WindowParams & params) const258 eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay *nativeDisplay,
259 const eglu::WindowParams ¶ms) const
260 {
261 DE_ASSERT(DE_FALSE);
262 return nullptr;
263 }
264
createWindow(eglu::NativeDisplay * nativeDisplay,eglw::EGLDisplay display,eglw::EGLConfig config,const eglw::EGLAttrib * attribList,const eglu::WindowParams & params) const265 eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay *nativeDisplay,
266 eglw::EGLDisplay display,
267 eglw::EGLConfig config,
268 const eglw::EGLAttrib *attribList,
269 const eglu::WindowParams ¶ms) const
270 {
271 return new NativeWindow(dynamic_cast<ANGLENativeDisplay *>(nativeDisplay), params, mEvents);
272 }
273
274 // NativeWindow
275
NativeWindow(ANGLENativeDisplay * nativeDisplay,const eglu::WindowParams & params,EventState * eventState)276 NativeWindow::NativeWindow(ANGLENativeDisplay *nativeDisplay,
277 const eglu::WindowParams ¶ms,
278 EventState *eventState)
279 : eglu::NativeWindow(kWindowCapabilities), mWindow(OSWindow::New()), mEvents(eventState)
280 {
281 bool initialized = mWindow->initialize(
282 "dEQP ANGLE Tests",
283 params.width == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_WIDTH : params.width,
284 params.height == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_HEIGHT
285 : params.height);
286 TCU_CHECK(initialized);
287
288 if (params.visibility != eglu::WindowParams::VISIBILITY_DONT_CARE)
289 NativeWindow::setVisibility(params.visibility);
290 }
291
setVisibility(eglu::WindowParams::Visibility visibility)292 void NativeWindow::setVisibility(eglu::WindowParams::Visibility visibility)
293 {
294 switch (visibility)
295 {
296 case eglu::WindowParams::VISIBILITY_HIDDEN:
297 mWindow->setVisible(false);
298 break;
299
300 case eglu::WindowParams::VISIBILITY_VISIBLE:
301 case eglu::WindowParams::VISIBILITY_FULLSCREEN:
302 mWindow->setVisible(true);
303 break;
304
305 default:
306 DE_ASSERT(DE_FALSE);
307 }
308 }
309
~NativeWindow()310 NativeWindow::~NativeWindow()
311 {
312 OSWindow::Delete(&mWindow);
313 }
314
getLegacyNative()315 eglw::EGLNativeWindowType NativeWindow::getLegacyNative()
316 {
317 return reinterpret_cast<eglw::EGLNativeWindowType>(mWindow->getNativeWindow());
318 }
319
getSurfaceSize() const320 IVec2 NativeWindow::getSurfaceSize() const
321 {
322 return IVec2(mWindow->getWidth(), mWindow->getHeight());
323 }
324
processEvents()325 void NativeWindow::processEvents()
326 {
327 mWindow->messageLoop();
328
329 // Look for a quit event to forward to the EventState
330 Event event = {};
331 while (mWindow->popEvent(&event))
332 {
333 if (event.Type == Event::EVENT_CLOSED)
334 {
335 mEvents->signalQuitEvent();
336 }
337 }
338 }
339
setSurfaceSize(IVec2 size)340 void NativeWindow::setSurfaceSize(IVec2 size)
341 {
342 mWindow->resize(size.x(), size.y());
343 }
344
readScreenPixels(tcu::TextureLevel * dst) const345 void NativeWindow::readScreenPixels(tcu::TextureLevel *dst) const
346 {
347 dst->setStorage(TextureFormat(TextureFormat::BGRA, TextureFormat::UNORM_INT8),
348 mWindow->getWidth(), mWindow->getHeight());
349 if (!mWindow->takeScreenshot(reinterpret_cast<uint8_t *>(dst->getAccess().getDataPtr())))
350 {
351 throw InternalError("Failed to read screen pixels", DE_NULL, __FILE__, __LINE__);
352 }
353 }
354
355 } // namespace
356
ANGLENativeDisplayFactory(const std::string & name,const std::string & description,std::vector<eglw::EGLAttrib> platformAttributes,EventState * eventState)357 ANGLENativeDisplayFactory::ANGLENativeDisplayFactory(
358 const std::string &name,
359 const std::string &description,
360 std::vector<eglw::EGLAttrib> platformAttributes,
361 EventState *eventState)
362 : eglu::NativeDisplayFactory(name,
363 description,
364 kDisplayCapabilities,
365 EGL_PLATFORM_ANGLE_ANGLE,
366 "EGL_EXT_platform_base"),
367 mPlatformAttributes(std::move(platformAttributes))
368 {
369 m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(eventState));
370 m_nativePixmapRegistry.registerFactory(new NativePixmapFactory());
371 }
372
373 ANGLENativeDisplayFactory::~ANGLENativeDisplayFactory() = default;
374
createDisplay(const eglw::EGLAttrib * attribList) const375 eglu::NativeDisplay *ANGLENativeDisplayFactory::createDisplay(
376 const eglw::EGLAttrib *attribList) const
377 {
378 DE_UNREF(attribList);
379 return new ANGLENativeDisplay(mPlatformAttributes);
380 }
381
382 } // namespace tcu
383