• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2002-2013 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 // Display.cpp: Implements the egl::Display class, representing the abstract
8 // display on which graphics are drawn. Implements EGLDisplay.
9 // [EGL 1.4] section 2.1.2 page 3.
10 
11 #include "libEGL/Display.h"
12 
13 #include <algorithm>
14 #include <map>
15 #include <vector>
16 
17 #include "common/debug.h"
18 #include "libGLESv2/mathutil.h"
19 #include "libGLESv2/main.h"
20 #include "libGLESv2/Context.h"
21 #include "libGLESv2/renderer/SwapChain.h"
22 
23 #include "libEGL/main.h"
24 #include "libEGL/Surface.h"
25 
26 namespace egl
27 {
28 namespace
29 {
30     typedef std::map<EGLNativeDisplayType, Display*> DisplayMap;
31     DisplayMap displays;
32 }
33 
getDisplay(EGLNativeDisplayType displayId)34 egl::Display *Display::getDisplay(EGLNativeDisplayType displayId)
35 {
36     if (displays.find(displayId) != displays.end())
37     {
38         return displays[displayId];
39     }
40 
41     // FIXME: Check if displayId is a valid display device context
42 
43     egl::Display *display = new egl::Display(displayId, (HDC)displayId);
44 
45     displays[displayId] = display;
46     return display;
47 }
48 
Display(EGLNativeDisplayType displayId,HDC deviceContext)49 Display::Display(EGLNativeDisplayType displayId, HDC deviceContext) : mDc(deviceContext)
50 {
51     mDisplayId = displayId;
52     mRenderer = NULL;
53 }
54 
~Display()55 Display::~Display()
56 {
57     terminate();
58 
59     DisplayMap::iterator thisDisplay = displays.find(mDisplayId);
60 
61     if (thisDisplay != displays.end())
62     {
63         displays.erase(thisDisplay);
64     }
65 }
66 
initialize()67 bool Display::initialize()
68 {
69     if (isInitialized())
70     {
71         return true;
72     }
73 
74     mRenderer = glCreateRenderer(this, mDc, mDisplayId);
75 
76     if (!mRenderer)
77     {
78         terminate();
79         return error(EGL_NOT_INITIALIZED, false);
80     }
81 
82     EGLint minSwapInterval = mRenderer->getMinSwapInterval();
83     EGLint maxSwapInterval = mRenderer->getMaxSwapInterval();
84     EGLint maxTextureWidth = mRenderer->getMaxTextureWidth();
85     EGLint maxTextureHeight = mRenderer->getMaxTextureHeight();
86 
87     rx::ConfigDesc *descList;
88     int numConfigs = mRenderer->generateConfigs(&descList);
89     ConfigSet configSet;
90 
91     for (int i = 0; i < numConfigs; ++i)
92         configSet.add(descList[i], minSwapInterval, maxSwapInterval,
93                       maxTextureWidth, maxTextureHeight);
94 
95     // Give the sorted configs a unique ID and store them internally
96     EGLint index = 1;
97     for (ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
98     {
99         Config configuration = *config;
100         configuration.mConfigID = index;
101         index++;
102 
103         mConfigSet.mSet.insert(configuration);
104     }
105 
106     mRenderer->deleteConfigs(descList);
107     descList = NULL;
108 
109     if (!isInitialized())
110     {
111         terminate();
112         return false;
113     }
114 
115     initExtensionString();
116     initVendorString();
117 
118     return true;
119 }
120 
terminate()121 void Display::terminate()
122 {
123     while (!mSurfaceSet.empty())
124     {
125         destroySurface(*mSurfaceSet.begin());
126     }
127 
128     while (!mContextSet.empty())
129     {
130         destroyContext(*mContextSet.begin());
131     }
132 
133     glDestroyRenderer(mRenderer);
134     mRenderer = NULL;
135 }
136 
getConfigs(EGLConfig * configs,const EGLint * attribList,EGLint configSize,EGLint * numConfig)137 bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
138 {
139     return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
140 }
141 
getConfigAttrib(EGLConfig config,EGLint attribute,EGLint * value)142 bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
143 {
144     const egl::Config *configuration = mConfigSet.get(config);
145 
146     switch (attribute)
147     {
148       case EGL_BUFFER_SIZE:               *value = configuration->mBufferSize;             break;
149       case EGL_ALPHA_SIZE:                *value = configuration->mAlphaSize;              break;
150       case EGL_BLUE_SIZE:                 *value = configuration->mBlueSize;               break;
151       case EGL_GREEN_SIZE:                *value = configuration->mGreenSize;              break;
152       case EGL_RED_SIZE:                  *value = configuration->mRedSize;                break;
153       case EGL_DEPTH_SIZE:                *value = configuration->mDepthSize;              break;
154       case EGL_STENCIL_SIZE:              *value = configuration->mStencilSize;            break;
155       case EGL_CONFIG_CAVEAT:             *value = configuration->mConfigCaveat;           break;
156       case EGL_CONFIG_ID:                 *value = configuration->mConfigID;               break;
157       case EGL_LEVEL:                     *value = configuration->mLevel;                  break;
158       case EGL_NATIVE_RENDERABLE:         *value = configuration->mNativeRenderable;       break;
159       case EGL_NATIVE_VISUAL_TYPE:        *value = configuration->mNativeVisualType;       break;
160       case EGL_SAMPLES:                   *value = configuration->mSamples;                break;
161       case EGL_SAMPLE_BUFFERS:            *value = configuration->mSampleBuffers;          break;
162       case EGL_SURFACE_TYPE:              *value = configuration->mSurfaceType;            break;
163       case EGL_TRANSPARENT_TYPE:          *value = configuration->mTransparentType;        break;
164       case EGL_TRANSPARENT_BLUE_VALUE:    *value = configuration->mTransparentBlueValue;   break;
165       case EGL_TRANSPARENT_GREEN_VALUE:   *value = configuration->mTransparentGreenValue;  break;
166       case EGL_TRANSPARENT_RED_VALUE:     *value = configuration->mTransparentRedValue;    break;
167       case EGL_BIND_TO_TEXTURE_RGB:       *value = configuration->mBindToTextureRGB;       break;
168       case EGL_BIND_TO_TEXTURE_RGBA:      *value = configuration->mBindToTextureRGBA;      break;
169       case EGL_MIN_SWAP_INTERVAL:         *value = configuration->mMinSwapInterval;        break;
170       case EGL_MAX_SWAP_INTERVAL:         *value = configuration->mMaxSwapInterval;        break;
171       case EGL_LUMINANCE_SIZE:            *value = configuration->mLuminanceSize;          break;
172       case EGL_ALPHA_MASK_SIZE:           *value = configuration->mAlphaMaskSize;          break;
173       case EGL_COLOR_BUFFER_TYPE:         *value = configuration->mColorBufferType;        break;
174       case EGL_RENDERABLE_TYPE:           *value = configuration->mRenderableType;         break;
175       case EGL_MATCH_NATIVE_PIXMAP:       *value = false; UNIMPLEMENTED();                 break;
176       case EGL_CONFORMANT:                *value = configuration->mConformant;             break;
177       case EGL_MAX_PBUFFER_WIDTH:         *value = configuration->mMaxPBufferWidth;        break;
178       case EGL_MAX_PBUFFER_HEIGHT:        *value = configuration->mMaxPBufferHeight;       break;
179       case EGL_MAX_PBUFFER_PIXELS:        *value = configuration->mMaxPBufferPixels;       break;
180       default:
181         return false;
182     }
183 
184     return true;
185 }
186 
187 
188 
createWindowSurface(HWND window,EGLConfig config,const EGLint * attribList)189 EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList)
190 {
191     const Config *configuration = mConfigSet.get(config);
192     EGLint postSubBufferSupported = EGL_FALSE;
193 
194     if (attribList)
195     {
196         while (*attribList != EGL_NONE)
197         {
198             switch (attribList[0])
199             {
200               case EGL_RENDER_BUFFER:
201                 switch (attribList[1])
202                 {
203                   case EGL_BACK_BUFFER:
204                     break;
205                   case EGL_SINGLE_BUFFER:
206                     return error(EGL_BAD_MATCH, EGL_NO_SURFACE);   // Rendering directly to front buffer not supported
207                   default:
208                     return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
209                 }
210                 break;
211               case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
212                 postSubBufferSupported = attribList[1];
213                 break;
214               case EGL_VG_COLORSPACE:
215                 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
216               case EGL_VG_ALPHA_FORMAT:
217                 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
218               default:
219                 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
220             }
221 
222             attribList += 2;
223         }
224     }
225 
226     if (hasExistingWindowSurface(window))
227     {
228         return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
229     }
230 
231     if (mRenderer->testDeviceLost(false))
232     {
233         if (!restoreLostDevice())
234             return EGL_NO_SURFACE;
235     }
236 
237     Surface *surface = new Surface(this, configuration, window, postSubBufferSupported);
238 
239     if (!surface->initialize())
240     {
241         delete surface;
242         return EGL_NO_SURFACE;
243     }
244 
245     mSurfaceSet.insert(surface);
246 
247     return success(surface);
248 }
249 
createOffscreenSurface(EGLConfig config,HANDLE shareHandle,const EGLint * attribList)250 EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList)
251 {
252     EGLint width = 0, height = 0;
253     EGLenum textureFormat = EGL_NO_TEXTURE;
254     EGLenum textureTarget = EGL_NO_TEXTURE;
255     const Config *configuration = mConfigSet.get(config);
256 
257     if (attribList)
258     {
259         while (*attribList != EGL_NONE)
260         {
261             switch (attribList[0])
262             {
263               case EGL_WIDTH:
264                 width = attribList[1];
265                 break;
266               case EGL_HEIGHT:
267                 height = attribList[1];
268                 break;
269               case EGL_LARGEST_PBUFFER:
270                 if (attribList[1] != EGL_FALSE)
271                   UNIMPLEMENTED(); // FIXME
272                 break;
273               case EGL_TEXTURE_FORMAT:
274                 switch (attribList[1])
275                 {
276                   case EGL_NO_TEXTURE:
277                   case EGL_TEXTURE_RGB:
278                   case EGL_TEXTURE_RGBA:
279                     textureFormat = attribList[1];
280                     break;
281                   default:
282                     return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
283                 }
284                 break;
285               case EGL_TEXTURE_TARGET:
286                 switch (attribList[1])
287                 {
288                   case EGL_NO_TEXTURE:
289                   case EGL_TEXTURE_2D:
290                     textureTarget = attribList[1];
291                     break;
292                   default:
293                     return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
294                 }
295                 break;
296               case EGL_MIPMAP_TEXTURE:
297                 if (attribList[1] != EGL_FALSE)
298                   return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
299                 break;
300               case EGL_VG_COLORSPACE:
301                 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
302               case EGL_VG_ALPHA_FORMAT:
303                 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
304               default:
305                 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
306             }
307 
308             attribList += 2;
309         }
310     }
311 
312     if (width < 0 || height < 0)
313     {
314         return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
315     }
316 
317     if (width == 0 || height == 0)
318     {
319         return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
320     }
321 
322     if (textureFormat != EGL_NO_TEXTURE && !mRenderer->getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height)))
323     {
324         return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
325     }
326 
327     if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
328         (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
329     {
330         return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
331     }
332 
333     if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
334     {
335         return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
336     }
337 
338     if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
339         (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
340     {
341         return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
342     }
343 
344     if (mRenderer->testDeviceLost(false))
345     {
346         if (!restoreLostDevice())
347             return EGL_NO_SURFACE;
348     }
349 
350     Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget);
351 
352     if (!surface->initialize())
353     {
354         delete surface;
355         return EGL_NO_SURFACE;
356     }
357 
358     mSurfaceSet.insert(surface);
359 
360     return success(surface);
361 }
362 
createContext(EGLConfig configHandle,const gl::Context * shareContext,bool notifyResets,bool robustAccess)363 EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess)
364 {
365     if (!mRenderer)
366     {
367         return NULL;
368     }
369     else if (mRenderer->testDeviceLost(false))   // Lost device
370     {
371         if (!restoreLostDevice())
372             return NULL;
373     }
374 
375     gl::Context *context = glCreateContext(shareContext, mRenderer, notifyResets, robustAccess);
376     mContextSet.insert(context);
377 
378     return context;
379 }
380 
restoreLostDevice()381 bool Display::restoreLostDevice()
382 {
383     for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
384     {
385         if ((*ctx)->isResetNotificationEnabled())
386             return false;   // If reset notifications have been requested, application must delete all contexts first
387     }
388 
389     // Release surface resources to make the Reset() succeed
390     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
391     {
392         (*surface)->release();
393     }
394 
395     if (!mRenderer->resetDevice())
396     {
397         return error(EGL_BAD_ALLOC, false);
398     }
399 
400     // Restore any surfaces that may have been lost
401     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
402     {
403         (*surface)->resetSwapChain();
404     }
405 
406     return true;
407 }
408 
409 
destroySurface(egl::Surface * surface)410 void Display::destroySurface(egl::Surface *surface)
411 {
412     delete surface;
413     mSurfaceSet.erase(surface);
414 }
415 
destroyContext(gl::Context * context)416 void Display::destroyContext(gl::Context *context)
417 {
418     glDestroyContext(context);
419     mContextSet.erase(context);
420 }
421 
notifyDeviceLost()422 void Display::notifyDeviceLost()
423 {
424     for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++)
425     {
426         (*context)->markContextLost();
427     }
428     egl::error(EGL_CONTEXT_LOST);
429 }
430 
recreateSwapChains()431 void Display::recreateSwapChains()
432 {
433     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
434     {
435         (*surface)->getSwapChain()->recreate();
436     }
437 }
438 
isInitialized() const439 bool Display::isInitialized() const
440 {
441     return mRenderer != NULL && mConfigSet.size() > 0;
442 }
443 
isValidConfig(EGLConfig config)444 bool Display::isValidConfig(EGLConfig config)
445 {
446     return mConfigSet.get(config) != NULL;
447 }
448 
isValidContext(gl::Context * context)449 bool Display::isValidContext(gl::Context *context)
450 {
451     return mContextSet.find(context) != mContextSet.end();
452 }
453 
isValidSurface(egl::Surface * surface)454 bool Display::isValidSurface(egl::Surface *surface)
455 {
456     return mSurfaceSet.find(surface) != mSurfaceSet.end();
457 }
458 
hasExistingWindowSurface(HWND window)459 bool Display::hasExistingWindowSurface(HWND window)
460 {
461     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
462     {
463         if ((*surface)->getWindowHandle() == window)
464         {
465             return true;
466         }
467     }
468 
469     return false;
470 }
471 
initExtensionString()472 void Display::initExtensionString()
473 {
474     HMODULE swiftShader = GetModuleHandle(TEXT("swiftshader_d3d9.dll"));
475     bool shareHandleSupported = mRenderer->getShareHandleSupport();
476 
477     mExtensionString = "";
478 
479     // Multi-vendor (EXT) extensions
480     mExtensionString += "EGL_EXT_create_context_robustness ";
481 
482     // ANGLE-specific extensions
483     if (shareHandleSupported)
484     {
485         mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer ";
486     }
487 
488     mExtensionString += "EGL_ANGLE_query_surface_pointer ";
489 
490     if (swiftShader)
491     {
492         mExtensionString += "EGL_ANGLE_software_display ";
493     }
494 
495     if (shareHandleSupported)
496     {
497         mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle ";
498     }
499 
500     if (mRenderer->getPostSubBufferSupport())
501     {
502         mExtensionString += "EGL_NV_post_sub_buffer";
503     }
504 
505     std::string::size_type end = mExtensionString.find_last_not_of(' ');
506     if (end != std::string::npos)
507     {
508         mExtensionString.resize(end+1);
509     }
510 }
511 
getExtensionString() const512 const char *Display::getExtensionString() const
513 {
514     return mExtensionString.c_str();
515 }
516 
initVendorString()517 void Display::initVendorString()
518 {
519     mVendorString = "Google Inc.";
520 
521     LUID adapterLuid = {0};
522 
523     if (mRenderer && mRenderer->getLUID(&adapterLuid))
524     {
525         char adapterLuidString[64];
526         sprintf_s(adapterLuidString, sizeof(adapterLuidString), " (adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart);
527 
528         mVendorString += adapterLuidString;
529     }
530 }
531 
getVendorString() const532 const char *Display::getVendorString() const
533 {
534     return mVendorString.c_str();
535 }
536 
537 }
538