1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
4 *
5 * Copyright (c) 2024 NVIDIA CORPORATION.
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 QNX Screen Platform implementation.
22 *//*--------------------------------------------------------------------*/
23
24 #include "tcuQnxScreenPlatform.hpp"
25
26 // Define pointers to libscreen functions
27 extern "C"
28 {
29 typedef int (*PFNSCREENCREATECONTEXT)(screen_context_t *, int);
30 typedef int (*PFNSCREENDESTROYCONTEXT)(screen_context_t);
31 typedef int (*PFNSCREENCREATEWINDOW)(screen_window_t *, screen_context_t);
32 typedef int (*PFNSCREENSETWINDOWPROPERTYIV)(screen_window_t, int, const int *);
33 typedef int (*PFNXSCREENCREATEWINDOWBUFFERS)(screen_window_t, int);
34 typedef int (*PFNSCREENDESTROYWINDOW)(screen_window_t);
35 };
36
37 static PFNSCREENCREATECONTEXT pscreen_create_context = NULL;
38 static PFNSCREENDESTROYCONTEXT pscreen_destroy_context = NULL;
39 static PFNSCREENCREATEWINDOW pscreen_create_window = NULL;
40 static PFNSCREENSETWINDOWPROPERTYIV pscreen_set_window_property_iv = NULL;
41 static PFNXSCREENCREATEWINDOWBUFFERS pscreen_create_window_buffers = NULL;
42 static PFNSCREENDESTROYWINDOW pscreen_destroy_window = NULL;
43
44 static bool loadedLibscreen{false};
45 static screen_context_t screenContext{nullptr};
46 static void *libScreen{nullptr};
47
createPlatform(void)48 tcu::Platform *createPlatform(void)
49 {
50 return new tcu::QnxScreen::Platform();
51 }
52
53 namespace tcu
54 {
55 namespace QnxScreen
56 {
57
58 enum
59 {
60 DEFAULT_WINDOW_WIDTH = 400,
61 DEFAULT_WINDOW_HEIGHT = 300
62 };
63
64 // Macro to load function pointers from library
65 #define LOAD_FUNC_PTR(lib, name, type) \
66 do \
67 { \
68 p##name = (type)dlsym(lib, #name); \
69 if (!p##name) \
70 { \
71 throw ResourceError("Could not load required function from libscreen"); \
72 } \
73 } while (0)
74
DisplayFactory(void)75 DisplayFactory::DisplayFactory(void)
76 : eglu::NativeDisplayFactory("QNX", "QNX Screen Display", eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY)
77 {
78 m_nativeWindowRegistry.registerFactory(new WindowFactory());
79 }
80
createDisplay(const eglw::EGLAttrib *) const81 eglu::NativeDisplay *DisplayFactory::createDisplay(const eglw::EGLAttrib *) const
82 {
83 return new Display();
84 }
85
createWindow(eglu::NativeDisplay * display,const eglu::WindowParams & params) const86 eglu::NativeWindow *WindowFactory::createWindow(eglu::NativeDisplay *display, const eglu::WindowParams ¶ms) const
87 {
88 const int width = params.width != eglu::WindowParams::SIZE_DONT_CARE ? params.width : DEFAULT_WINDOW_WIDTH;
89 const int height = params.height != eglu::WindowParams::SIZE_DONT_CARE ? params.height : DEFAULT_WINDOW_HEIGHT;
90
91 return new Window(display, width, height, NULL, NULL);
92 }
93
createWindow(eglu::NativeDisplay * display,eglw::EGLDisplay eglDisplay,eglw::EGLConfig config,const eglw::EGLAttrib * attribList,const eglu::WindowParams & params) const94 eglu::NativeWindow *WindowFactory::createWindow(eglu::NativeDisplay *display, eglw::EGLDisplay eglDisplay,
95 eglw::EGLConfig config, const eglw::EGLAttrib *attribList,
96 const eglu::WindowParams ¶ms) const
97 {
98 DE_UNREF(attribList);
99
100 const int width = params.width != eglu::WindowParams::SIZE_DONT_CARE ? params.width : DEFAULT_WINDOW_WIDTH;
101 const int height = params.height != eglu::WindowParams::SIZE_DONT_CARE ? params.height : DEFAULT_WINDOW_HEIGHT;
102
103 return new Window(display, width, height, eglDisplay, config);
104 }
105
LoadLibscreen(void)106 void Display::LoadLibscreen(void)
107 {
108 if (!loadedLibscreen)
109 {
110 if (!libScreen)
111 {
112 libScreen = dlopen("libscreen.so", RTLD_LAZY);
113 if (!libScreen)
114 {
115 libScreen = dlopen("libscreen.so.1", RTLD_LAZY);
116 }
117 if (!libScreen)
118 {
119 throw ResourceError("Could not find / open libscreen");
120 }
121 }
122 LOAD_FUNC_PTR(libScreen, screen_create_context, PFNSCREENCREATECONTEXT);
123 LOAD_FUNC_PTR(libScreen, screen_destroy_context, PFNSCREENDESTROYCONTEXT);
124 LOAD_FUNC_PTR(libScreen, screen_create_window, PFNSCREENCREATEWINDOW);
125 LOAD_FUNC_PTR(libScreen, screen_set_window_property_iv, PFNSCREENSETWINDOWPROPERTYIV);
126 LOAD_FUNC_PTR(libScreen, screen_create_window_buffers, PFNXSCREENCREATEWINDOWBUFFERS);
127 LOAD_FUNC_PTR(libScreen, screen_destroy_window, PFNSCREENDESTROYWINDOW);
128 loadedLibscreen = true;
129 }
130 }
131
CreateScreenContext(void)132 void Display::CreateScreenContext(void)
133 {
134 if (!screenContext)
135 {
136 const int ret{pscreen_create_context(&screenContext, 0)};
137 if (ret)
138 {
139 throw ResourceError("Failed to create QNX Screen context");
140 }
141 }
142 }
143
DestroyScreenContext(void)144 void Display::DestroyScreenContext(void)
145 {
146 if (screenContext)
147 {
148 pscreen_destroy_context(screenContext);
149 screenContext = nullptr;
150 }
151 }
152
Display(void)153 Display::Display(void) : eglu::NativeDisplay(eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY), m_display(0)
154 {
155 try
156 {
157 LoadLibscreen();
158 CreateScreenContext();
159 }
160 catch (...)
161 {
162 if (loadedLibscreen)
163 {
164 DestroyScreenContext();
165 }
166 throw; // Re-throw caught exception
167 }
168 }
169
~Display(void)170 Display::~Display(void)
171 {
172 DestroyScreenContext();
173 }
174
Window(eglu::NativeDisplay * display,int width,int height,eglw::EGLDisplay eglDisplay,eglw::EGLConfig config)175 Window::Window(eglu::NativeDisplay *display, int width, int height, eglw::EGLDisplay eglDisplay, eglw::EGLConfig config)
176 : eglu::NativeWindow(eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY)
177 , m_screenWindow(nullptr)
178 {
179 // offset is 0
180 // sizeX and sizeY is width and height
181 eglw::EGLint abits{};
182 eglw::EGLint rbits{};
183 eglw::EGLint gbits{};
184 eglw::EGLint bbits{};
185
186 display->getLibrary().getConfigAttrib(eglDisplay, config, EGL_ALPHA_SIZE, &abits);
187 display->getLibrary().getConfigAttrib(eglDisplay, config, EGL_RED_SIZE, &rbits);
188 display->getLibrary().getConfigAttrib(eglDisplay, config, EGL_GREEN_SIZE, &gbits);
189 display->getLibrary().getConfigAttrib(eglDisplay, config, EGL_BLUE_SIZE, &bbits);
190
191 try
192 {
193 int rc{pscreen_create_window(&m_screenWindow, screenContext)};
194 if (rc)
195 {
196 throw ResourceError("Failed to create QNX Screen window.");
197 }
198
199 int screenFormat{};
200 if ((rbits == 8) && (gbits == 8) && (bbits == 8))
201 {
202 // RGB888. Check for alpha
203 if (abits == 8)
204 {
205 screenFormat = SCREEN_FORMAT_RGBA8888;
206 }
207 else
208 {
209 screenFormat = SCREEN_FORMAT_RGBX8888;
210 }
211 }
212 else if ((rbits == 5) && (gbits == 6) && (bbits == 5))
213 {
214 screenFormat = SCREEN_FORMAT_RGB565;
215 }
216 else if ((rbits == 4) && (gbits == 4) && (bbits == 4))
217 {
218 // RGB444. Check for alpha
219 if (abits == 4)
220 {
221 screenFormat = SCREEN_FORMAT_RGBA4444;
222 }
223 else
224 {
225 screenFormat = SCREEN_FORMAT_RGBX4444;
226 }
227 }
228 else if ((rbits == 5) && (gbits == 5) && (bbits == 5))
229 {
230 // RGB555. Check for alpha
231 if (abits == 1)
232 {
233 screenFormat = SCREEN_FORMAT_RGBA5551;
234 }
235 else
236 {
237 screenFormat = SCREEN_FORMAT_RGBX5551;
238 }
239 }
240 else
241 {
242 throw ResourceError("Unsupported SCREEN_PROPERTY_FORMAT requested");
243 }
244
245 rc = pscreen_set_window_property_iv(m_screenWindow, SCREEN_PROPERTY_FORMAT, (const int *)&screenFormat);
246 if (rc)
247 {
248 throw ResourceError("Failed to set SCREEN_PROPERTY_FORMAT");
249 }
250
251 int usage{SCREEN_USAGE_OPENGL_ES2};
252 rc = pscreen_set_window_property_iv(m_screenWindow, SCREEN_PROPERTY_USAGE, &usage);
253 if (rc)
254 {
255 throw ResourceError("Failed to set SCREEN_PROPERTY_USAGE");
256 }
257
258 int interval{1};
259 rc = pscreen_set_window_property_iv(m_screenWindow, SCREEN_PROPERTY_SWAP_INTERVAL, &interval);
260 if (rc)
261 {
262 throw ResourceError("Failed to set SCREEN_PROPERTY_SWAP_INTERVAL");
263 }
264
265 int size[]{width, height};
266 rc = pscreen_set_window_property_iv(m_screenWindow, SCREEN_PROPERTY_SIZE, (const int *)size);
267 if (rc)
268 {
269 throw ResourceError("Failed to set SCREEN_PROPERTY_SIZE");
270 }
271
272 int offset[]{0, 0};
273 rc = pscreen_set_window_property_iv(m_screenWindow, SCREEN_PROPERTY_POSITION, offset);
274 if (rc)
275 {
276 throw ResourceError("Failed to set SCREEN_PROPERTY_POSITION");
277 }
278
279 rc = pscreen_create_window_buffers(m_screenWindow, 2);
280 if (rc)
281 {
282 throw ResourceError("Failed to create QNX Screen window buffers");
283 }
284
285 m_nativeWindow = (eglw::EGLNativeWindowType)(void *)m_screenWindow;
286 }
287 catch (...)
288 {
289 if (m_screenWindow)
290 {
291 pscreen_destroy_window(m_screenWindow);
292 m_screenWindow = nullptr;
293 }
294 throw;
295 }
296 }
297
~Window(void)298 Window::~Window(void)
299 {
300 if (m_screenWindow)
301 {
302 pscreen_destroy_window(m_screenWindow);
303 m_screenWindow = nullptr;
304 }
305 }
306
Platform(void)307 Platform::Platform(void)
308 {
309 m_nativeDisplayFactoryRegistry.registerFactory(new DisplayFactory());
310 m_contextFactoryRegistry.registerFactory(new eglu::GLContextFactory(m_nativeDisplayFactoryRegistry));
311 }
312
~Platform(void)313 Platform::~Platform(void)
314 {
315 if (screenContext)
316 {
317 pscreen_destroy_context(screenContext);
318 }
319 screenContext = nullptr;
320 }
321
322 } // namespace QnxScreen
323 } // namespace tcu
324