1//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// libEGL.cpp: Implements the exported EGL functions.
8
9#include <exception>
10
11#include "common/debug.h"
12#include "common/version.h"
13#include "libGLESv2/Context.h"
14#include "libGLESv2/Texture.h"
15#include "libGLESv2/main.h"
16#include "libGLESv2/renderer/SwapChain.h"
17
18#include "libEGL/main.h"
19#include "libEGL/Display.h"
20#include "libEGL/Surface.h"
21
22bool validateDisplay(egl::Display *display)
23{
24    if (display == EGL_NO_DISPLAY)
25    {
26        return egl::error(EGL_BAD_DISPLAY, false);
27    }
28
29    if (!display->isInitialized())
30    {
31        return egl::error(EGL_NOT_INITIALIZED, false);
32    }
33
34    return true;
35}
36
37bool validateConfig(egl::Display *display, EGLConfig config)
38{
39    if (!validateDisplay(display))
40    {
41        return false;
42    }
43
44    if (!display->isValidConfig(config))
45    {
46        return egl::error(EGL_BAD_CONFIG, false);
47    }
48
49    return true;
50}
51
52bool validateContext(egl::Display *display, gl::Context *context)
53{
54    if (!validateDisplay(display))
55    {
56        return false;
57    }
58
59    if (!display->isValidContext(context))
60    {
61        return egl::error(EGL_BAD_CONTEXT, false);
62    }
63
64    return true;
65}
66
67bool validateSurface(egl::Display *display, egl::Surface *surface)
68{
69    if (!validateDisplay(display))
70    {
71        return false;
72    }
73
74    if (!display->isValidSurface(surface))
75    {
76        return egl::error(EGL_BAD_SURFACE, false);
77    }
78
79    return true;
80}
81
82extern "C"
83{
84EGLint __stdcall eglGetError(void)
85{
86    EVENT("()");
87
88    EGLint error = egl::getCurrentError();
89
90    if (error != EGL_SUCCESS)
91    {
92        egl::setCurrentError(EGL_SUCCESS);
93    }
94
95    return error;
96}
97
98EGLDisplay __stdcall eglGetDisplay(EGLNativeDisplayType display_id)
99{
100    EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id);
101
102    return egl::Display::getDisplay(display_id, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
103}
104
105EGLDisplay __stdcall eglGetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list)
106{
107    EVENT("(EGLenum platform = %d, void* native_display = 0x%0.8p, const EGLint* attrib_list = 0x%0.8p)",
108          platform, native_display, attrib_list);
109
110    switch (platform)
111    {
112      case EGL_PLATFORM_ANGLE_ANGLE:
113        break;
114
115      default:
116        return egl::error(EGL_BAD_CONFIG, EGL_NO_DISPLAY);
117    }
118
119    EGLNativeDisplayType displayId = static_cast<EGLNativeDisplayType>(native_display);
120
121    // Validate the display device context
122    if (WindowFromDC(displayId) == NULL)
123    {
124        return egl::success(EGL_NO_DISPLAY);
125    }
126
127    EGLint requestedDisplayType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
128    if (attrib_list)
129    {
130        for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2)
131        {
132            switch (curAttrib[0])
133            {
134              case EGL_PLATFORM_ANGLE_TYPE_ANGLE:
135                requestedDisplayType = curAttrib[1];
136                break;
137
138              default:
139                break;
140            }
141        }
142    }
143
144    switch (requestedDisplayType)
145    {
146      case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE:
147        break;
148
149      case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
150      case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
151      case EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE:
152        if (!egl::Display::supportsPlatformD3D())
153        {
154            return egl::success(EGL_NO_DISPLAY);
155        }
156        break;
157
158      case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
159      case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE:
160        if (!egl::Display::supportsPlatformOpenGL())
161        {
162            return egl::success(EGL_NO_DISPLAY);
163        }
164        break;
165
166      default:
167        return egl::success(EGL_NO_DISPLAY);
168    }
169
170    return egl::Display::getDisplay(displayId, requestedDisplayType);
171}
172
173EGLBoolean __stdcall eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
174{
175    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint *major = 0x%0.8p, EGLint *minor = 0x%0.8p)",
176          dpy, major, minor);
177
178    if (dpy == EGL_NO_DISPLAY)
179    {
180        return egl::error(EGL_BAD_DISPLAY, EGL_FALSE);
181    }
182
183    egl::Display *display = static_cast<egl::Display*>(dpy);
184
185    if (!display->initialize())
186    {
187        return egl::error(EGL_NOT_INITIALIZED, EGL_FALSE);
188    }
189
190    if (major) *major = 1;
191    if (minor) *minor = 4;
192
193    return egl::success(EGL_TRUE);
194}
195
196EGLBoolean __stdcall eglTerminate(EGLDisplay dpy)
197{
198    EVENT("(EGLDisplay dpy = 0x%0.8p)", dpy);
199
200    if (dpy == EGL_NO_DISPLAY)
201    {
202        return egl::error(EGL_BAD_DISPLAY, EGL_FALSE);
203    }
204
205    egl::Display *display = static_cast<egl::Display*>(dpy);
206
207    display->terminate();
208
209    return egl::success(EGL_TRUE);
210}
211
212const char *__stdcall eglQueryString(EGLDisplay dpy, EGLint name)
213{
214    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint name = %d)", dpy, name);
215
216    egl::Display *display = static_cast<egl::Display*>(dpy);
217    if (!(display == EGL_NO_DISPLAY && name == EGL_EXTENSIONS) && !validateDisplay(display))
218    {
219        return NULL;
220    }
221
222    switch (name)
223    {
224      case EGL_CLIENT_APIS:
225        return egl::success("OpenGL_ES");
226      case EGL_EXTENSIONS:
227        return egl::success(egl::Display::getExtensionString(display));
228      case EGL_VENDOR:
229        return egl::success(display->getVendorString());
230      case EGL_VERSION:
231        return egl::success("1.4 (ANGLE " ANGLE_VERSION_STRING ")");
232      default:
233        return egl::error(EGL_BAD_PARAMETER, (const char*)NULL);
234    }
235}
236
237EGLBoolean __stdcall eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
238{
239    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig *configs = 0x%0.8p, "
240          "EGLint config_size = %d, EGLint *num_config = 0x%0.8p)",
241          dpy, configs, config_size, num_config);
242
243    egl::Display *display = static_cast<egl::Display*>(dpy);
244
245    if (!validateDisplay(display))
246    {
247        return EGL_FALSE;
248    }
249
250    if (!num_config)
251    {
252        return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);
253    }
254
255    const EGLint attribList[] =    {EGL_NONE};
256
257    if (!display->getConfigs(configs, attribList, config_size, num_config))
258    {
259        return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
260    }
261
262    return egl::success(EGL_TRUE);
263}
264
265EGLBoolean __stdcall eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
266{
267    EVENT("(EGLDisplay dpy = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p, "
268          "EGLConfig *configs = 0x%0.8p, EGLint config_size = %d, EGLint *num_config = 0x%0.8p)",
269          dpy, attrib_list, configs, config_size, num_config);
270
271    egl::Display *display = static_cast<egl::Display*>(dpy);
272
273    if (!validateDisplay(display))
274    {
275        return EGL_FALSE;
276    }
277
278    if (!num_config)
279    {
280        return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);
281    }
282
283    const EGLint attribList[] =    {EGL_NONE};
284
285    if (!attrib_list)
286    {
287        attrib_list = attribList;
288    }
289
290    display->getConfigs(configs, attrib_list, config_size, num_config);
291
292    return egl::success(EGL_TRUE);
293}
294
295EGLBoolean __stdcall eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
296{
297    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)",
298          dpy, config, attribute, value);
299
300    egl::Display *display = static_cast<egl::Display*>(dpy);
301
302    if (!validateConfig(display, config))
303    {
304        return EGL_FALSE;
305    }
306
307    if (!display->getConfigAttrib(config, attribute, value))
308    {
309        return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
310    }
311
312    return egl::success(EGL_TRUE);
313}
314
315EGLSurface __stdcall eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
316{
317    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativeWindowType win = 0x%0.8p, "
318          "const EGLint *attrib_list = 0x%0.8p)", dpy, config, win, attrib_list);
319
320    egl::Display *display = static_cast<egl::Display*>(dpy);
321
322    if (!validateConfig(display, config))
323    {
324        return EGL_NO_SURFACE;
325    }
326
327    HWND window = (HWND)win;
328
329    if (!IsWindow(window))
330    {
331        return egl::error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
332    }
333
334    return display->createWindowSurface(window, config, attrib_list);
335}
336
337EGLSurface __stdcall eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
338{
339    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)",
340          dpy, config, attrib_list);
341
342    egl::Display *display = static_cast<egl::Display*>(dpy);
343
344    if (!validateConfig(display, config))
345    {
346        return EGL_NO_SURFACE;
347    }
348
349    return display->createOffscreenSurface(config, NULL, attrib_list);
350}
351
352EGLSurface __stdcall eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
353{
354    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativePixmapType pixmap = 0x%0.8p, "
355          "const EGLint *attrib_list = 0x%0.8p)", dpy, config, pixmap, attrib_list);
356
357    egl::Display *display = static_cast<egl::Display*>(dpy);
358
359    if (!validateConfig(display, config))
360    {
361        return EGL_NO_SURFACE;
362    }
363
364    UNIMPLEMENTED();   // FIXME
365
366    return egl::success(EGL_NO_SURFACE);
367}
368
369EGLBoolean __stdcall eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
370{
371    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface);
372
373    egl::Display *display = static_cast<egl::Display*>(dpy);
374    egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
375
376    if (!validateSurface(display, eglSurface))
377    {
378        return EGL_FALSE;
379    }
380
381    if (surface == EGL_NO_SURFACE)
382    {
383        return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
384    }
385
386    display->destroySurface((egl::Surface*)surface);
387
388    return egl::success(EGL_TRUE);
389}
390
391EGLBoolean __stdcall eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value)
392{
393    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)",
394          dpy, surface, attribute, value);
395
396    egl::Display *display = static_cast<egl::Display*>(dpy);
397    egl::Surface *eglSurface = (egl::Surface*)surface;
398
399    if (!validateSurface(display, eglSurface))
400    {
401        return EGL_FALSE;
402    }
403
404    if (surface == EGL_NO_SURFACE)
405    {
406        return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
407    }
408
409    switch (attribute)
410    {
411      case EGL_VG_ALPHA_FORMAT:
412        UNIMPLEMENTED();   // FIXME
413        break;
414      case EGL_VG_COLORSPACE:
415        UNIMPLEMENTED();   // FIXME
416        break;
417      case EGL_CONFIG_ID:
418        *value = eglSurface->getConfigID();
419        break;
420      case EGL_HEIGHT:
421        *value = eglSurface->getHeight();
422        break;
423      case EGL_HORIZONTAL_RESOLUTION:
424        UNIMPLEMENTED();   // FIXME
425        break;
426      case EGL_LARGEST_PBUFFER:
427        UNIMPLEMENTED();   // FIXME
428        break;
429      case EGL_MIPMAP_TEXTURE:
430        UNIMPLEMENTED();   // FIXME
431        break;
432      case EGL_MIPMAP_LEVEL:
433        UNIMPLEMENTED();   // FIXME
434        break;
435      case EGL_MULTISAMPLE_RESOLVE:
436        UNIMPLEMENTED();   // FIXME
437        break;
438      case EGL_PIXEL_ASPECT_RATIO:
439        *value = eglSurface->getPixelAspectRatio();
440        break;
441      case EGL_RENDER_BUFFER:
442        *value = eglSurface->getRenderBuffer();
443        break;
444      case EGL_SWAP_BEHAVIOR:
445        *value = eglSurface->getSwapBehavior();
446        break;
447      case EGL_TEXTURE_FORMAT:
448        *value = eglSurface->getTextureFormat();
449        break;
450      case EGL_TEXTURE_TARGET:
451        *value = eglSurface->getTextureTarget();
452        break;
453      case EGL_VERTICAL_RESOLUTION:
454        UNIMPLEMENTED();   // FIXME
455        break;
456      case EGL_WIDTH:
457        *value = eglSurface->getWidth();
458        break;
459      case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
460        *value = eglSurface->isPostSubBufferSupported();
461        break;
462      case EGL_FIXED_SIZE_ANGLE:
463        *value = eglSurface->isFixedSize();
464        break;
465      default:
466        return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
467    }
468
469    return egl::success(EGL_TRUE);
470}
471
472EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value)
473{
474    TRACE("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, void **value = 0x%0.8p)",
475          dpy, surface, attribute, value);
476
477    egl::Display *display = static_cast<egl::Display*>(dpy);
478    egl::Surface *eglSurface = (egl::Surface*)surface;
479
480    if (!validateSurface(display, eglSurface))
481    {
482        return EGL_FALSE;
483    }
484
485    if (surface == EGL_NO_SURFACE)
486    {
487        return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
488    }
489
490    switch (attribute)
491    {
492      case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
493        {
494            rx::SwapChain *swapchain = eglSurface->getSwapChain();
495            *value = (void*) (swapchain ? swapchain->getShareHandle() : NULL);
496        }
497        break;
498      default:
499        return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
500    }
501
502    return egl::success(EGL_TRUE);
503}
504
505EGLBoolean __stdcall eglBindAPI(EGLenum api)
506{
507    EVENT("(EGLenum api = 0x%X)", api);
508
509    switch (api)
510    {
511      case EGL_OPENGL_API:
512      case EGL_OPENVG_API:
513        return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);   // Not supported by this implementation
514      case EGL_OPENGL_ES_API:
515        break;
516      default:
517        return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);
518    }
519
520    egl::setCurrentAPI(api);
521
522    return egl::success(EGL_TRUE);
523}
524
525EGLenum __stdcall eglQueryAPI(void)
526{
527    EVENT("()");
528
529    EGLenum API = egl::getCurrentAPI();
530
531    return egl::success(API);
532}
533
534EGLBoolean __stdcall eglWaitClient(void)
535{
536    EVENT("()");
537
538    UNIMPLEMENTED();   // FIXME
539
540    return egl::success(0);
541}
542
543EGLBoolean __stdcall eglReleaseThread(void)
544{
545    EVENT("()");
546
547    eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE);
548
549    return egl::success(EGL_TRUE);
550}
551
552EGLSurface __stdcall eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
553{
554    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = 0x%0.8p, "
555          "EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)",
556          dpy, buftype, buffer, config, attrib_list);
557
558    egl::Display *display = static_cast<egl::Display*>(dpy);
559
560    if (!validateConfig(display, config))
561    {
562        return EGL_NO_SURFACE;
563    }
564
565    if (buftype != EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE || !buffer)
566    {
567        return egl::error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
568    }
569
570    return display->createOffscreenSurface(config, (HANDLE)buffer, attrib_list);
571}
572
573EGLBoolean __stdcall eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
574{
575    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint value = %d)",
576          dpy, surface, attribute, value);
577
578    egl::Display *display = static_cast<egl::Display*>(dpy);
579    egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
580
581    if (!validateSurface(display, eglSurface))
582    {
583        return EGL_FALSE;
584    }
585
586    UNIMPLEMENTED();   // FIXME
587
588    return egl::success(EGL_TRUE);
589}
590
591EGLBoolean __stdcall eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
592{
593    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer);
594
595    egl::Display *display = static_cast<egl::Display*>(dpy);
596    egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
597
598    if (!validateSurface(display, eglSurface))
599    {
600        return EGL_FALSE;
601    }
602
603    if (buffer != EGL_BACK_BUFFER)
604    {
605        return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);
606    }
607
608    if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle())
609    {
610        return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
611    }
612
613    if (eglSurface->getBoundTexture())
614    {
615        return egl::error(EGL_BAD_ACCESS, EGL_FALSE);
616    }
617
618    if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
619    {
620        return egl::error(EGL_BAD_MATCH, EGL_FALSE);
621    }
622
623    if (!glBindTexImage(eglSurface))
624    {
625        return egl::error(EGL_BAD_MATCH, EGL_FALSE);
626    }
627
628    return egl::success(EGL_TRUE);
629}
630
631EGLBoolean __stdcall eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
632{
633    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer);
634
635    egl::Display *display = static_cast<egl::Display*>(dpy);
636    egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
637
638    if (!validateSurface(display, eglSurface))
639    {
640        return EGL_FALSE;
641    }
642
643    if (buffer != EGL_BACK_BUFFER)
644    {
645        return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);
646    }
647
648    if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle())
649    {
650        return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
651    }
652
653    if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
654    {
655        return egl::error(EGL_BAD_MATCH, EGL_FALSE);
656    }
657
658    gl::Texture2D *texture = eglSurface->getBoundTexture();
659
660    if (texture)
661    {
662        texture->releaseTexImage();
663    }
664
665    return egl::success(EGL_TRUE);
666}
667
668EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval)
669{
670    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint interval = %d)", dpy, interval);
671
672    egl::Display *display = static_cast<egl::Display*>(dpy);
673
674    if (!validateDisplay(display))
675    {
676        return EGL_FALSE;
677    }
678
679    egl::Surface *draw_surface = static_cast<egl::Surface*>(egl::getCurrentDrawSurface());
680
681    if (draw_surface == NULL)
682    {
683        return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
684    }
685
686    draw_surface->setSwapInterval(interval);
687
688    return egl::success(EGL_TRUE);
689}
690
691EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
692{
693    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLContext share_context = 0x%0.8p, "
694          "const EGLint *attrib_list = 0x%0.8p)", dpy, config, share_context, attrib_list);
695
696    // Get the requested client version (default is 1) and check it is 2 or 3.
697    EGLint client_version = 1;
698    bool reset_notification = false;
699    bool robust_access = false;
700
701    if (attrib_list)
702    {
703        for (const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2)
704        {
705            switch (attribute[0])
706            {
707              case EGL_CONTEXT_CLIENT_VERSION:
708                client_version = attribute[1];
709                break;
710              case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
711                if (attribute[1] == EGL_TRUE)
712                {
713                    return egl::error(EGL_BAD_CONFIG, EGL_NO_CONTEXT);   // Unimplemented
714                    // robust_access = true;
715                }
716                else if (attribute[1] != EGL_FALSE)
717                    return egl::error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
718                break;
719              case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
720                if (attribute[1] == EGL_LOSE_CONTEXT_ON_RESET_EXT)
721                    reset_notification = true;
722                else if (attribute[1] != EGL_NO_RESET_NOTIFICATION_EXT)
723                    return egl::error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
724                break;
725              default:
726                return egl::error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
727            }
728        }
729    }
730
731    if (client_version != 2 && client_version != 3)
732    {
733        return egl::error(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
734    }
735
736    egl::Display *display = static_cast<egl::Display*>(dpy);
737
738    if (share_context)
739    {
740        gl::Context* sharedGLContext = static_cast<gl::Context*>(share_context);
741
742        if (sharedGLContext->isResetNotificationEnabled() != reset_notification)
743        {
744            return egl::error(EGL_BAD_MATCH, EGL_NO_CONTEXT);
745        }
746
747        if (sharedGLContext->getClientVersion() != client_version)
748        {
749            return egl::error(EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
750        }
751
752        // Can not share contexts between displays
753        if (sharedGLContext->getRenderer() != display->getRenderer())
754        {
755            return egl::error(EGL_BAD_MATCH, EGL_NO_CONTEXT);
756        }
757    }
758
759    if (!validateConfig(display, config))
760    {
761        return EGL_NO_CONTEXT;
762    }
763
764    return display->createContext(config, client_version, static_cast<gl::Context*>(share_context), reset_notification, robust_access);
765}
766
767EGLBoolean __stdcall eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
768{
769    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, ctx);
770
771    egl::Display *display = static_cast<egl::Display*>(dpy);
772    gl::Context *context = static_cast<gl::Context*>(ctx);
773
774    if (!validateContext(display, context))
775    {
776        return EGL_FALSE;
777    }
778
779    if (ctx == EGL_NO_CONTEXT)
780    {
781        return egl::error(EGL_BAD_CONTEXT, EGL_FALSE);
782    }
783
784    display->destroyContext(context);
785
786    return egl::success(EGL_TRUE);
787}
788
789EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
790{
791    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, EGLContext ctx = 0x%0.8p)",
792          dpy, draw, read, ctx);
793
794    egl::Display *display = static_cast<egl::Display*>(dpy);
795    gl::Context *context = static_cast<gl::Context*>(ctx);
796
797    bool noContext = (ctx == EGL_NO_CONTEXT);
798    bool noSurface = (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE);
799    if (noContext != noSurface)
800    {
801        return egl::error(EGL_BAD_MATCH, EGL_FALSE);
802    }
803
804    if (ctx != EGL_NO_CONTEXT && !validateContext(display, context))
805    {
806        return EGL_FALSE;
807    }
808
809    if (dpy != EGL_NO_DISPLAY && display->isInitialized())
810    {
811        rx::Renderer *renderer = display->getRenderer();
812        if (renderer->testDeviceLost(true))
813        {
814            return EGL_FALSE;
815        }
816
817        if (renderer->isDeviceLost())
818        {
819            return egl::error(EGL_CONTEXT_LOST, EGL_FALSE);
820        }
821    }
822
823    if ((draw != EGL_NO_SURFACE && !validateSurface(display, static_cast<egl::Surface*>(draw))) ||
824        (read != EGL_NO_SURFACE && !validateSurface(display, static_cast<egl::Surface*>(read))))
825    {
826        return EGL_FALSE;
827    }
828
829    if (draw != read)
830    {
831        UNIMPLEMENTED();   // FIXME
832    }
833
834    egl::setCurrentDisplay(dpy);
835    egl::setCurrentDrawSurface(draw);
836    egl::setCurrentReadSurface(read);
837
838    glMakeCurrent(context, display, static_cast<egl::Surface*>(draw));
839
840    return egl::success(EGL_TRUE);
841}
842
843EGLContext __stdcall eglGetCurrentContext(void)
844{
845    EVENT("()");
846
847    EGLContext context = glGetCurrentContext();
848
849    return egl::success(context);
850}
851
852EGLSurface __stdcall eglGetCurrentSurface(EGLint readdraw)
853{
854    EVENT("(EGLint readdraw = %d)", readdraw);
855
856    if (readdraw == EGL_READ)
857    {
858        EGLSurface read = egl::getCurrentReadSurface();
859        return egl::success(read);
860    }
861    else if (readdraw == EGL_DRAW)
862    {
863        EGLSurface draw = egl::getCurrentDrawSurface();
864        return egl::success(draw);
865    }
866    else
867    {
868        return egl::error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
869    }
870}
871
872EGLDisplay __stdcall eglGetCurrentDisplay(void)
873{
874    EVENT("()");
875
876    EGLDisplay dpy = egl::getCurrentDisplay();
877
878    return egl::success(dpy);
879}
880
881EGLBoolean __stdcall eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
882{
883    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)",
884          dpy, ctx, attribute, value);
885
886    egl::Display *display = static_cast<egl::Display*>(dpy);
887    gl::Context *context = static_cast<gl::Context*>(ctx);
888
889    if (!validateContext(display, context))
890    {
891        return EGL_FALSE;
892    }
893
894    UNIMPLEMENTED();   // FIXME
895
896    return egl::success(0);
897}
898
899EGLBoolean __stdcall eglWaitGL(void)
900{
901    EVENT("()");
902
903    UNIMPLEMENTED();   // FIXME
904
905    return egl::success(0);
906}
907
908EGLBoolean __stdcall eglWaitNative(EGLint engine)
909{
910    EVENT("(EGLint engine = %d)", engine);
911
912    UNIMPLEMENTED();   // FIXME
913
914    return egl::success(0);
915}
916
917EGLBoolean __stdcall eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
918{
919    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface);
920
921    egl::Display *display = static_cast<egl::Display*>(dpy);
922    egl::Surface *eglSurface = (egl::Surface*)surface;
923
924    if (!validateSurface(display, eglSurface))
925    {
926        return EGL_FALSE;
927    }
928
929    if (display->getRenderer()->isDeviceLost())
930    {
931        return egl::error(EGL_CONTEXT_LOST, EGL_FALSE);
932    }
933
934    if (surface == EGL_NO_SURFACE)
935    {
936        return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
937    }
938
939    if (eglSurface->swap())
940    {
941        return egl::success(EGL_TRUE);
942    }
943
944    return EGL_FALSE;
945}
946
947EGLBoolean __stdcall eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
948{
949    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLNativePixmapType target = 0x%0.8p)", dpy, surface, target);
950
951    egl::Display *display = static_cast<egl::Display*>(dpy);
952    egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
953
954    if (!validateSurface(display, eglSurface))
955    {
956        return EGL_FALSE;
957    }
958
959    if (display->getRenderer()->isDeviceLost())
960    {
961        return egl::error(EGL_CONTEXT_LOST, EGL_FALSE);
962    }
963
964    UNIMPLEMENTED();   // FIXME
965
966    return egl::success(0);
967}
968
969EGLBoolean __stdcall eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height)
970{
971    EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint x = %d, EGLint y = %d, EGLint width = %d, EGLint height = %d)", dpy, surface, x, y, width, height);
972
973    if (x < 0 || y < 0 || width < 0 || height < 0)
974    {
975        return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);
976    }
977
978    egl::Display *display = static_cast<egl::Display*>(dpy);
979    egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
980
981    if (!validateSurface(display, eglSurface))
982    {
983        return EGL_FALSE;
984    }
985
986    if (display->getRenderer()->isDeviceLost())
987    {
988        return egl::error(EGL_CONTEXT_LOST, EGL_FALSE);
989    }
990
991    if (surface == EGL_NO_SURFACE)
992    {
993        return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
994    }
995
996    if (eglSurface->postSubBuffer(x, y, width, height))
997    {
998        return egl::success(EGL_TRUE);
999    }
1000
1001    return EGL_FALSE;
1002}
1003
1004__eglMustCastToProperFunctionPointerType __stdcall eglGetProcAddress(const char *procname)
1005{
1006    EVENT("(const char *procname = \"%s\")", procname);
1007
1008    struct Extension
1009    {
1010        const char *name;
1011        __eglMustCastToProperFunctionPointerType address;
1012    };
1013
1014    static const Extension eglExtensions[] =
1015    {
1016        { "eglQuerySurfacePointerANGLE", (__eglMustCastToProperFunctionPointerType)eglQuerySurfacePointerANGLE },
1017        { "eglPostSubBufferNV", (__eglMustCastToProperFunctionPointerType)eglPostSubBufferNV },
1018        { "eglGetPlatformDisplayEXT", (__eglMustCastToProperFunctionPointerType)eglGetPlatformDisplayEXT },
1019        { "", NULL },
1020    };
1021
1022    for (unsigned int ext = 0; ext < ArraySize(eglExtensions); ext++)
1023    {
1024        if (strcmp(procname, eglExtensions[ext].name) == 0)
1025        {
1026            return (__eglMustCastToProperFunctionPointerType)eglExtensions[ext].address;
1027        }
1028    }
1029
1030    return glGetProcAddress(procname);
1031}
1032}
1033