Limit changes by xor to upper 8 bits in mixed atomic tests am: 6bc3c7a634 am: ebc8257...
[platform/upstream/VK-GL-CTS.git] / framework / egl / egluGLContextFactory.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 GL context factory using EGL.
22  *//*--------------------------------------------------------------------*/
23
24 #include "egluGLContextFactory.hpp"
25
26 #include "tcuRenderTarget.hpp"
27 #include "tcuPlatform.hpp"
28 #include "tcuCommandLine.hpp"
29
30 #include "gluDefs.hpp"
31
32 #include "egluDefs.hpp"
33 #include "egluUtil.hpp"
34 #include "egluGLUtil.hpp"
35 #include "egluNativeWindow.hpp"
36 #include "egluNativePixmap.hpp"
37 #include "egluStrUtil.hpp"
38
39 #include "eglwLibrary.hpp"
40 #include "eglwEnums.hpp"
41
42 #include "glwInitFunctions.hpp"
43 #include "glwInitES20Direct.hpp"
44 #include "glwInitES30Direct.hpp"
45
46 #include "deDynamicLibrary.hpp"
47 #include "deSTLUtil.hpp"
48
49 #include <string>
50 #include <string>
51 #include <sstream>
52
53 using std::string;
54 using std::vector;
55
56 // \todo [2014-03-12 pyry] Use command line arguments for libraries?
57
58 // Default library names
59 #if !defined(DEQP_GLES2_LIBRARY_PATH)
60 #       if (DE_OS == DE_OS_WIN32)
61 #               define DEQP_GLES2_LIBRARY_PATH "libGLESv2.dll"
62 #       else
63 #               define DEQP_GLES2_LIBRARY_PATH "libGLESv2.so"
64 #       endif
65 #endif
66
67 #if !defined(DEQP_GLES3_LIBRARY_PATH)
68 #       define DEQP_GLES3_LIBRARY_PATH DEQP_GLES2_LIBRARY_PATH
69 #endif
70
71 #if !defined(DEQP_OPENGL_LIBRARY_PATH)
72 #       if (DE_OS == DE_OS_WIN32)
73 #               define DEQP_OPENGL_LIBRARY_PATH "opengl32.dll"
74 #       else
75 #               define DEQP_OPENGL_LIBRARY_PATH "libGL.so"
76 #       endif
77 #endif
78
79 namespace eglu
80 {
81
82 using namespace eglw;
83
84 namespace
85 {
86
87 enum
88 {
89         DEFAULT_OFFSCREEN_WIDTH         = 512,
90         DEFAULT_OFFSCREEN_HEIGHT        = 512
91 };
92
93 class GetProcFuncLoader : public glw::FunctionLoader
94 {
95 public:
96         GetProcFuncLoader (const Library& egl)
97                 : m_egl(egl)
98         {
99         }
100
101         glw::GenericFuncType get (const char* name) const
102         {
103                 return (glw::GenericFuncType)m_egl.getProcAddress(name);
104         }
105
106 protected:
107         const Library& m_egl;
108 };
109
110 class DynamicFuncLoader : public glw::FunctionLoader
111 {
112 public:
113         DynamicFuncLoader       (de::DynamicLibrary* library)
114                 : m_library(library)
115         {
116         }
117
118         glw::GenericFuncType get (const char* name) const
119         {
120                 return (glw::GenericFuncType)m_library->getFunction(name);
121         }
122
123 private:
124         de::DynamicLibrary*     m_library;
125 };
126
127 class RenderContext : public GLRenderContext
128 {
129 public:
130                                                                                 RenderContext                   (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config);
131         virtual                                                         ~RenderContext                  (void);
132
133         virtual glu::ContextType                        getType                                 (void) const { return m_renderConfig.type;      }
134         virtual const glw::Functions&           getFunctions                    (void) const { return m_glFunctions;            }
135         virtual const tcu::RenderTarget&        getRenderTarget                 (void) const { return m_glRenderTarget;         }
136         virtual void                                            postIterate                             (void);
137
138         virtual EGLDisplay                                      getEGLDisplay                   (void) const { return m_eglDisplay;                     }
139         virtual EGLContext                                      getEGLContext                   (void) const { return m_eglContext;                     }
140
141 private:
142         void                                                            create                                  (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config);
143         void                                                            destroy                                 (void);
144
145         const glu::RenderConfig                         m_renderConfig;
146         const NativeWindowFactory* const        m_nativeWindowFactory;  // Stored in case window must be re-created
147
148         NativeDisplay*                                          m_display;
149         NativeWindow*                                           m_window;
150         NativePixmap*                                           m_pixmap;
151
152         EGLDisplay                                                      m_eglDisplay;
153         EGLConfig                                                       m_eglConfig;
154         EGLSurface                                                      m_eglSurface;
155         EGLContext                                                      m_eglContext;
156
157         tcu::RenderTarget                                       m_glRenderTarget;
158         de::DynamicLibrary*                                     m_dynamicGLLibrary;
159         glw::Functions                                          m_glFunctions;
160 };
161
162 RenderContext::RenderContext (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config)
163         : m_renderConfig                (config)
164         , m_nativeWindowFactory (windowFactory)
165         , m_display                             (DE_NULL)
166         , m_window                              (DE_NULL)
167         , m_pixmap                              (DE_NULL)
168
169         , m_eglDisplay                  (EGL_NO_DISPLAY)
170         , m_eglSurface                  (EGL_NO_SURFACE)
171         , m_eglContext                  (EGL_NO_CONTEXT)
172
173         , m_dynamicGLLibrary    (DE_NULL)
174 {
175         DE_ASSERT(displayFactory);
176
177         try
178         {
179                 create(displayFactory, windowFactory, pixmapFactory, config);
180         }
181         catch (...)
182         {
183                 destroy();
184                 throw;
185         }
186 }
187
188 RenderContext::~RenderContext(void)
189 {
190         try
191         {
192                 destroy();
193         }
194         catch (...)
195         {
196                 // destroy() calls EGL functions that are checked and may throw exceptions
197         }
198
199         delete m_window;
200         delete m_pixmap;
201         delete m_display;
202         delete m_dynamicGLLibrary;
203 }
204
205 static WindowParams::Visibility getNativeWindowVisibility (glu::RenderConfig::Visibility visibility)
206 {
207         using glu::RenderConfig;
208
209         switch (visibility)
210         {
211                 case RenderConfig::VISIBILITY_HIDDEN:           return WindowParams::VISIBILITY_HIDDEN;
212                 case RenderConfig::VISIBILITY_VISIBLE:          return WindowParams::VISIBILITY_VISIBLE;
213                 case RenderConfig::VISIBILITY_FULLSCREEN:       return WindowParams::VISIBILITY_FULLSCREEN;
214                 default:
215                         DE_ASSERT((int)visibility == RenderConfig::DONT_CARE);
216                         return WindowParams::VISIBILITY_DONT_CARE;
217         }
218 }
219
220 typedef std::pair<NativeWindow*, EGLSurface> WindowSurfacePair;
221 typedef std::pair<NativePixmap*, EGLSurface> PixmapSurfacePair;
222
223 WindowSurfacePair createWindow (NativeDisplay* nativeDisplay, const NativeWindowFactory* windowFactory, EGLDisplay eglDisplay, EGLConfig eglConfig, const glu::RenderConfig& config)
224 {
225         const int                                               width                   = (config.width         == glu::RenderConfig::DONT_CARE ? WindowParams::SIZE_DONT_CARE  : config.width);
226         const int                                               height                  = (config.height        == glu::RenderConfig::DONT_CARE ? WindowParams::SIZE_DONT_CARE  : config.height);
227         const WindowParams::Visibility  visibility              = getNativeWindowVisibility(config.windowVisibility);
228         NativeWindow*                                   nativeWindow    = DE_NULL;
229         EGLSurface                                              surface                 = EGL_NO_SURFACE;
230         const EGLAttrib                                 attribList[]    = { EGL_NONE };
231
232         nativeWindow = windowFactory->createWindow(nativeDisplay, eglDisplay, eglConfig, &attribList[0], WindowParams(width, height, visibility));
233
234         try
235         {
236                 surface = eglu::createWindowSurface(*nativeDisplay, *nativeWindow, eglDisplay, eglConfig, attribList);
237         }
238         catch (...)
239         {
240                 delete nativeWindow;
241                 throw;
242         }
243
244         return WindowSurfacePair(nativeWindow, surface);
245 }
246
247 PixmapSurfacePair createPixmap (NativeDisplay* nativeDisplay, const NativePixmapFactory* pixmapFactory, EGLDisplay eglDisplay, EGLConfig eglConfig, const glu::RenderConfig& config)
248 {
249         const int                       width                   = (config.width         == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_WIDTH       : config.width);
250         const int                       height                  = (config.height        == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_HEIGHT      : config.height);
251         NativePixmap*           nativePixmap    = DE_NULL;
252         EGLSurface                      surface                 = EGL_NO_SURFACE;
253         const EGLAttrib         attribList[]    = { EGL_NONE };
254
255         nativePixmap = pixmapFactory->createPixmap(nativeDisplay, eglDisplay, eglConfig, &attribList[0], width, height);
256
257         try
258         {
259                 surface = eglu::createPixmapSurface(*nativeDisplay, *nativePixmap, eglDisplay, eglConfig, attribList);
260         }
261         catch (...)
262         {
263                 delete nativePixmap;
264                 throw;
265         }
266
267         return PixmapSurfacePair(nativePixmap, surface);
268 }
269
270 EGLSurface createPBuffer (const Library& egl, EGLDisplay display, EGLConfig eglConfig, const glu::RenderConfig& config)
271 {
272         const int               width                   = (config.width         == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_WIDTH       : config.width);
273         const int               height                  = (config.height        == glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_HEIGHT      : config.height);
274         EGLSurface              surface;
275         const EGLint    attribList[]    =
276         {
277                 EGL_WIDTH,      width,
278                 EGL_HEIGHT,     height,
279                 EGL_NONE
280         };
281
282         surface = egl.createPbufferSurface(display, eglConfig, &(attribList[0]));
283         EGLU_CHECK_MSG(egl, "eglCreatePbufferSurface()");
284
285         return surface;
286 }
287
288 void RenderContext::create (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config)
289 {
290         glu::RenderConfig::SurfaceType  surfaceType     = config.surfaceType;
291
292         DE_ASSERT(displayFactory);
293
294         m_display               = displayFactory->createDisplay();
295         m_eglDisplay    = eglu::getDisplay(*m_display);
296
297         const Library& egl = m_display->getLibrary();
298
299         {
300                 EGLint major = 0;
301                 EGLint minor = 0;
302                 EGLU_CHECK_CALL(egl, initialize(m_eglDisplay, &major, &minor));
303         }
304
305         m_eglConfig     = chooseConfig(egl, m_eglDisplay, config);
306
307         if (surfaceType == glu::RenderConfig::SURFACETYPE_DONT_CARE)
308         {
309                 // Choose based on what selected configuration supports
310                 const EGLint supportedTypes = eglu::getConfigAttribInt(egl, m_eglDisplay, m_eglConfig, EGL_SURFACE_TYPE);
311
312                 if ((supportedTypes & EGL_WINDOW_BIT) != 0)
313                         surfaceType = glu::RenderConfig::SURFACETYPE_WINDOW;
314                 else if ((supportedTypes & EGL_PBUFFER_BIT) != 0)
315                         surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC;
316                 else if ((supportedTypes & EGL_PIXMAP_BIT) != 0)
317                         surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE;
318                 else
319                         throw tcu::NotSupportedError("Selected EGL config doesn't support any surface types", DE_NULL, __FILE__, __LINE__);
320         }
321
322         switch (surfaceType)
323         {
324                 case glu::RenderConfig::SURFACETYPE_WINDOW:
325                 {
326                         if (windowFactory)
327                         {
328                                 const WindowSurfacePair windowSurface = createWindow(m_display, windowFactory, m_eglDisplay, m_eglConfig, config);
329                                 m_window                = windowSurface.first;
330                                 m_eglSurface    = windowSurface.second;
331                         }
332                         else
333                                 throw tcu::NotSupportedError("EGL platform doesn't support windows", DE_NULL, __FILE__, __LINE__);
334                         break;
335                 }
336
337                 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
338                 {
339                         if (pixmapFactory)
340                         {
341                                 const PixmapSurfacePair pixmapSurface = createPixmap(m_display, pixmapFactory, m_eglDisplay, m_eglConfig, config);
342                                 m_pixmap                = pixmapSurface.first;
343                                 m_eglSurface    = pixmapSurface.second;
344                         }
345                         else
346                                 throw tcu::NotSupportedError("EGL platform doesn't support pixmaps", DE_NULL, __FILE__, __LINE__);
347                         break;
348                 }
349
350                 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
351                         m_eglSurface = createPBuffer(egl, m_eglDisplay, m_eglConfig, config);
352                         break;
353
354                 default:
355                         throw tcu::InternalError("Invalid surface type");
356         }
357
358         m_eglContext = createGLContext(egl, m_eglDisplay, m_eglConfig, config.type);
359
360         EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
361
362         // Init core functions
363
364         if (hasExtension(egl, m_eglDisplay, "EGL_KHR_get_all_proc_addresses"))
365         {
366                 // Use eglGetProcAddress() for core functions
367                 GetProcFuncLoader funcLoader(egl);
368                 glu::initCoreFunctions(&m_glFunctions, &funcLoader, config.type.getAPI());
369         }
370 #if !defined(DEQP_GLES2_RUNTIME_LOAD)
371         else if (config.type.getAPI() == glu::ApiType::es(2,0))
372         {
373                 glw::initES20Direct(&m_glFunctions);
374         }
375 #endif
376 #if !defined(DEQP_GLES3_RUNTIME_LOAD)
377         else if (config.type.getAPI() == glu::ApiType::es(3,0))
378         {
379                 glw::initES30Direct(&m_glFunctions);
380         }
381 #endif
382         else
383         {
384                 const char* libraryPath = DE_NULL;
385
386                 if (glu::isContextTypeES(config.type))
387                 {
388                         if (config.type.getMinorVersion() <= 2)
389                                 libraryPath = DEQP_GLES2_LIBRARY_PATH;
390                         else
391                                 libraryPath = DEQP_GLES3_LIBRARY_PATH;
392                 }
393                 else
394                         libraryPath = DEQP_OPENGL_LIBRARY_PATH;
395
396                 m_dynamicGLLibrary = new de::DynamicLibrary(libraryPath);
397
398                 DynamicFuncLoader funcLoader(m_dynamicGLLibrary);
399                 glu::initCoreFunctions(&m_glFunctions, &funcLoader, config.type.getAPI());
400         }
401
402         // Init extension functions
403         {
404                 GetProcFuncLoader extLoader(egl);
405                 glu::initExtensionFunctions(&m_glFunctions, &extLoader, config.type.getAPI());
406         }
407
408         {
409                 EGLint                          width, height, depthBits, stencilBits, numSamples;
410                 tcu::PixelFormat        pixelFmt;
411
412                 egl.querySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH,         &width);
413                 egl.querySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT,        &height);
414
415                 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_RED_SIZE,            &pixelFmt.redBits);
416                 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_GREEN_SIZE,          &pixelFmt.greenBits);
417                 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_BLUE_SIZE,           &pixelFmt.blueBits);
418                 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_ALPHA_SIZE,          &pixelFmt.alphaBits);
419
420                 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_DEPTH_SIZE,          &depthBits);
421                 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_STENCIL_SIZE,        &stencilBits);
422                 egl.getConfigAttrib(m_eglDisplay, m_eglConfig, EGL_SAMPLES,                     &numSamples);
423
424                 EGLU_CHECK_MSG(egl, "Failed to query config attributes");
425
426                 m_glRenderTarget = tcu::RenderTarget(width, height, pixelFmt, depthBits, stencilBits, numSamples);
427         }
428 }
429
430 void RenderContext::destroy (void)
431 {
432         const Library& egl = m_display->getLibrary();
433
434         if (m_eglDisplay != EGL_NO_DISPLAY)
435         {
436                 EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
437
438                 if (m_eglSurface != EGL_NO_SURFACE)
439                         EGLU_CHECK_CALL(egl, destroySurface(m_eglDisplay, m_eglSurface));
440
441                 if (m_eglContext != EGL_NO_CONTEXT)
442                         EGLU_CHECK_CALL(egl, destroyContext(m_eglDisplay, m_eglContext));
443
444                 EGLU_CHECK_CALL(egl, terminate(m_eglDisplay));
445
446                 m_eglDisplay    = EGL_NO_DISPLAY;
447                 m_eglSurface    = EGL_NO_SURFACE;
448                 m_eglContext    = EGL_NO_CONTEXT;
449         }
450
451         delete m_window;
452         delete m_pixmap;
453         delete m_display;
454         delete m_dynamicGLLibrary;
455
456         m_window                        = DE_NULL;
457         m_pixmap                        = DE_NULL;
458         m_display                       = DE_NULL;
459         m_dynamicGLLibrary      = DE_NULL;
460 }
461
462 void RenderContext::postIterate (void)
463 {
464         const Library& egl = m_display->getLibrary();
465
466         if (m_window)
467         {
468                 EGLBoolean      swapOk          = egl.swapBuffers(m_eglDisplay, m_eglSurface);
469                 EGLint          error           = egl.getError();
470                 const bool      badWindow       = error == EGL_BAD_SURFACE || error == EGL_BAD_NATIVE_WINDOW;
471
472                 if (!swapOk && !badWindow)
473                         throw tcu::ResourceError(string("eglSwapBuffers() failed: ") + getErrorStr(error).toString());
474
475                 try
476                 {
477                         m_window->processEvents();
478                 }
479                 catch (const WindowDestroyedError&)
480                 {
481                         tcu::print("Warning: Window destroyed, recreating...\n");
482
483                         EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
484                         EGLU_CHECK_CALL(egl, destroySurface(m_eglDisplay, m_eglSurface));
485                         m_eglSurface = EGL_NO_SURFACE;
486
487                         delete m_window;
488                         m_window = DE_NULL;
489
490                         try
491                         {
492                                 WindowSurfacePair windowSurface = createWindow(m_display, m_nativeWindowFactory, m_eglDisplay, m_eglConfig, m_renderConfig);
493                                 m_window                = windowSurface.first;
494                                 m_eglSurface    = windowSurface.second;
495
496                                 EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
497
498                                 swapOk  = EGL_TRUE;
499                                 error   = EGL_SUCCESS;
500                         }
501                         catch (const std::exception& e)
502                         {
503                                 if (m_eglSurface)
504                                 {
505                                         egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
506                                         egl.destroySurface(m_eglDisplay, m_eglSurface);
507                                         m_eglSurface = EGL_NO_SURFACE;
508                                 }
509
510                                 delete m_window;
511                                 m_window = DE_NULL;
512
513                                 throw tcu::ResourceError(string("Failed to re-create window: ") + e.what());
514                         }
515                 }
516
517                 if (!swapOk)
518                 {
519                         DE_ASSERT(badWindow);
520                         throw tcu::ResourceError(string("eglSwapBuffers() failed: ") + getErrorStr(error).toString());
521                 }
522
523                 // Refresh dimensions
524                 {
525                         int     newWidth        = 0;
526                         int     newHeight       = 0;
527
528                         egl.querySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH,         &newWidth);
529                         egl.querySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT,        &newHeight);
530                         EGLU_CHECK_MSG(egl, "Failed to query window size");
531
532                         if (newWidth    != m_glRenderTarget.getWidth() ||
533                                 newHeight       != m_glRenderTarget.getHeight())
534                         {
535                                 tcu::print("Warning: Window size changed (%dx%d -> %dx%d), test results might be invalid!\n",
536                                                    m_glRenderTarget.getWidth(), m_glRenderTarget.getHeight(), newWidth, newHeight);
537
538                                 m_glRenderTarget = tcu::RenderTarget(newWidth, newHeight,
539                                                                                                          m_glRenderTarget.getPixelFormat(),
540                                                                                                          m_glRenderTarget.getDepthBits(),
541                                                                                                          m_glRenderTarget.getStencilBits(),
542                                                                                                          m_glRenderTarget.getNumSamples());
543                         }
544                 }
545         }
546         else
547                 m_glFunctions.flush();
548 }
549
550 } // anonymous
551
552 GLContextFactory::GLContextFactory (const NativeDisplayFactoryRegistry& displayFactoryRegistry)
553         : glu::ContextFactory           ("egl", "EGL OpenGL Context")
554         , m_displayFactoryRegistry      (displayFactoryRegistry)
555 {
556 }
557
558 glu::RenderContext* GLContextFactory::createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const
559 {
560         const NativeDisplayFactory& displayFactory = selectNativeDisplayFactory(m_displayFactoryRegistry, cmdLine);
561
562         const NativeWindowFactory*      windowFactory;
563         const NativePixmapFactory*      pixmapFactory;
564
565         try
566         {
567                 windowFactory = &selectNativeWindowFactory(displayFactory, cmdLine);
568         }
569         catch (const tcu::NotSupportedError&)
570         {
571                 windowFactory = DE_NULL;
572         }
573
574         try
575         {
576                 pixmapFactory = &selectNativePixmapFactory(displayFactory, cmdLine);
577         }
578         catch (const tcu::NotSupportedError&)
579         {
580                 pixmapFactory = DE_NULL;
581         }
582
583         return new RenderContext(&displayFactory, windowFactory, pixmapFactory, config);
584 }
585
586 } // eglu