• 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 "common/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     EGLint width = 0;
195     EGLint height = 0;
196     EGLint fixedSize = EGL_FALSE;
197 
198     if (attribList)
199     {
200         while (*attribList != EGL_NONE)
201         {
202             switch (attribList[0])
203             {
204               case EGL_RENDER_BUFFER:
205                 switch (attribList[1])
206                 {
207                   case EGL_BACK_BUFFER:
208                     break;
209                   case EGL_SINGLE_BUFFER:
210                     return error(EGL_BAD_MATCH, EGL_NO_SURFACE);   // Rendering directly to front buffer not supported
211                   default:
212                     return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
213                 }
214                 break;
215               case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
216                 postSubBufferSupported = attribList[1];
217                 break;
218               case EGL_WIDTH:
219                 width = attribList[1];
220                 break;
221               case EGL_HEIGHT:
222                 height = attribList[1];
223                 break;
224               case EGL_FIXED_SIZE_ANGLE:
225                 fixedSize = attribList[1];
226                 break;
227               case EGL_VG_COLORSPACE:
228                 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
229               case EGL_VG_ALPHA_FORMAT:
230                 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
231               default:
232                 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
233             }
234 
235             attribList += 2;
236         }
237     }
238 
239     if (width < 0 || height < 0)
240     {
241         return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
242     }
243 
244     if (!fixedSize)
245     {
246         width = -1;
247         height = -1;
248     }
249 
250     if (hasExistingWindowSurface(window))
251     {
252         return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
253     }
254 
255     if (mRenderer->testDeviceLost(false))
256     {
257         if (!restoreLostDevice())
258             return EGL_NO_SURFACE;
259     }
260 
261     Surface *surface = new Surface(this, configuration, window, fixedSize, width, height, postSubBufferSupported);
262 
263     if (!surface->initialize())
264     {
265         delete surface;
266         return EGL_NO_SURFACE;
267     }
268 
269     mSurfaceSet.insert(surface);
270 
271     return success(surface);
272 }
273 
createOffscreenSurface(EGLConfig config,HANDLE shareHandle,const EGLint * attribList)274 EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList)
275 {
276     EGLint width = 0, height = 0;
277     EGLenum textureFormat = EGL_NO_TEXTURE;
278     EGLenum textureTarget = EGL_NO_TEXTURE;
279     const Config *configuration = mConfigSet.get(config);
280 
281     if (attribList)
282     {
283         while (*attribList != EGL_NONE)
284         {
285             switch (attribList[0])
286             {
287               case EGL_WIDTH:
288                 width = attribList[1];
289                 break;
290               case EGL_HEIGHT:
291                 height = attribList[1];
292                 break;
293               case EGL_LARGEST_PBUFFER:
294                 if (attribList[1] != EGL_FALSE)
295                   UNIMPLEMENTED(); // FIXME
296                 break;
297               case EGL_TEXTURE_FORMAT:
298                 switch (attribList[1])
299                 {
300                   case EGL_NO_TEXTURE:
301                   case EGL_TEXTURE_RGB:
302                   case EGL_TEXTURE_RGBA:
303                     textureFormat = attribList[1];
304                     break;
305                   default:
306                     return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
307                 }
308                 break;
309               case EGL_TEXTURE_TARGET:
310                 switch (attribList[1])
311                 {
312                   case EGL_NO_TEXTURE:
313                   case EGL_TEXTURE_2D:
314                     textureTarget = attribList[1];
315                     break;
316                   default:
317                     return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
318                 }
319                 break;
320               case EGL_MIPMAP_TEXTURE:
321                 if (attribList[1] != EGL_FALSE)
322                   return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
323                 break;
324               case EGL_VG_COLORSPACE:
325                 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
326               case EGL_VG_ALPHA_FORMAT:
327                 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
328               default:
329                 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
330             }
331 
332             attribList += 2;
333         }
334     }
335 
336     if (width < 0 || height < 0)
337     {
338         return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
339     }
340 
341     if (width == 0 || height == 0)
342     {
343         return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
344     }
345 
346     if (textureFormat != EGL_NO_TEXTURE && !mRenderer->getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height)))
347     {
348         return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
349     }
350 
351     if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
352         (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
353     {
354         return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
355     }
356 
357     if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
358     {
359         return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
360     }
361 
362     if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
363         (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
364     {
365         return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
366     }
367 
368     if (mRenderer->testDeviceLost(false))
369     {
370         if (!restoreLostDevice())
371             return EGL_NO_SURFACE;
372     }
373 
374     Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget);
375 
376     if (!surface->initialize())
377     {
378         delete surface;
379         return EGL_NO_SURFACE;
380     }
381 
382     mSurfaceSet.insert(surface);
383 
384     return success(surface);
385 }
386 
createContext(EGLConfig configHandle,EGLint clientVersion,const gl::Context * shareContext,bool notifyResets,bool robustAccess)387 EGLContext Display::createContext(EGLConfig configHandle, EGLint clientVersion, const gl::Context *shareContext, bool notifyResets, bool robustAccess)
388 {
389     if (!mRenderer)
390     {
391         return EGL_NO_CONTEXT;
392     }
393     else if (mRenderer->testDeviceLost(false))   // Lost device
394     {
395         if (!restoreLostDevice())
396         {
397             return error(EGL_CONTEXT_LOST, EGL_NO_CONTEXT);
398         }
399     }
400 
401     if (clientVersion > 2 && mRenderer->getMajorShaderModel() < 4)
402     {
403         return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
404     }
405 
406     gl::Context *context = glCreateContext(clientVersion, shareContext, mRenderer, notifyResets, robustAccess);
407     mContextSet.insert(context);
408 
409     return success(context);
410 }
411 
restoreLostDevice()412 bool Display::restoreLostDevice()
413 {
414     for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
415     {
416         if ((*ctx)->isResetNotificationEnabled())
417             return false;   // If reset notifications have been requested, application must delete all contexts first
418     }
419 
420     // Release surface resources to make the Reset() succeed
421     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
422     {
423         (*surface)->release();
424     }
425 
426     if (!mRenderer->resetDevice())
427     {
428         return error(EGL_BAD_ALLOC, false);
429     }
430 
431     // Restore any surfaces that may have been lost
432     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
433     {
434         (*surface)->resetSwapChain();
435     }
436 
437     return true;
438 }
439 
440 
destroySurface(egl::Surface * surface)441 void Display::destroySurface(egl::Surface *surface)
442 {
443     delete surface;
444     mSurfaceSet.erase(surface);
445 }
446 
destroyContext(gl::Context * context)447 void Display::destroyContext(gl::Context *context)
448 {
449     glDestroyContext(context);
450     mContextSet.erase(context);
451 }
452 
notifyDeviceLost()453 void Display::notifyDeviceLost()
454 {
455     for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++)
456     {
457         (*context)->markContextLost();
458     }
459     egl::error(EGL_CONTEXT_LOST);
460 }
461 
recreateSwapChains()462 void Display::recreateSwapChains()
463 {
464     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
465     {
466         (*surface)->getSwapChain()->recreate();
467     }
468 }
469 
isInitialized() const470 bool Display::isInitialized() const
471 {
472     return mRenderer != NULL && mConfigSet.size() > 0;
473 }
474 
isValidConfig(EGLConfig config)475 bool Display::isValidConfig(EGLConfig config)
476 {
477     return mConfigSet.get(config) != NULL;
478 }
479 
isValidContext(gl::Context * context)480 bool Display::isValidContext(gl::Context *context)
481 {
482     return mContextSet.find(context) != mContextSet.end();
483 }
484 
isValidSurface(egl::Surface * surface)485 bool Display::isValidSurface(egl::Surface *surface)
486 {
487     return mSurfaceSet.find(surface) != mSurfaceSet.end();
488 }
489 
hasExistingWindowSurface(HWND window)490 bool Display::hasExistingWindowSurface(HWND window)
491 {
492     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
493     {
494         if ((*surface)->getWindowHandle() == window)
495         {
496             return true;
497         }
498     }
499 
500     return false;
501 }
502 
initExtensionString()503 void Display::initExtensionString()
504 {
505     bool shareHandleSupported = mRenderer->getShareHandleSupport();
506 
507     mExtensionString = "";
508 
509     // Multi-vendor (EXT) extensions
510     mExtensionString += "EGL_EXT_create_context_robustness ";
511 
512     // ANGLE-specific extensions
513     if (shareHandleSupported)
514     {
515         mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer ";
516     }
517 
518     mExtensionString += "EGL_ANGLE_query_surface_pointer ";
519 
520     mExtensionString += "EGL_ANGLE_window_fixed_size ";
521 
522     if (shareHandleSupported)
523     {
524         mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle ";
525     }
526 
527     if (mRenderer->getPostSubBufferSupport())
528     {
529         mExtensionString += "EGL_NV_post_sub_buffer ";
530     }
531 
532     // TODO: complete support for the EGL_KHR_create_context extension
533     mExtensionString += "EGL_KHR_create_context ";
534 
535     std::string::size_type end = mExtensionString.find_last_not_of(' ');
536     if (end != std::string::npos)
537     {
538         mExtensionString.resize(end+1);
539     }
540 }
541 
getExtensionString() const542 const char *Display::getExtensionString() const
543 {
544     return mExtensionString.c_str();
545 }
546 
initVendorString()547 void Display::initVendorString()
548 {
549     mVendorString = "Google Inc.";
550 
551     LUID adapterLuid = {0};
552 
553     if (mRenderer && mRenderer->getLUID(&adapterLuid))
554     {
555         char adapterLuidString[64];
556         sprintf_s(adapterLuidString, sizeof(adapterLuidString), " (adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart);
557 
558         mVendorString += adapterLuidString;
559     }
560 }
561 
getVendorString() const562 const char *Display::getVendorString() const
563 {
564     return mVendorString.c_str();
565 }
566 
567 }
568