Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libEGL / Display.cpp
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
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
49 Display::Display(EGLNativeDisplayType displayId, HDC deviceContext) : mDc(deviceContext)
50 {
51     mDisplayId = displayId;
52     mRenderer = NULL;
53 }
54
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
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
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
137 bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
138 {
139     return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
140 }
141
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
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
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
387 EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess)
388 {
389     if (!mRenderer)
390     {
391         return NULL;
392     }
393     else if (mRenderer->testDeviceLost(false))   // Lost device
394     {
395         if (!restoreLostDevice())
396             return NULL;
397     }
398
399     gl::Context *context = glCreateContext(shareContext, mRenderer, notifyResets, robustAccess);
400     mContextSet.insert(context);
401
402     return context;
403 }
404
405 bool Display::restoreLostDevice()
406 {
407     for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
408     {
409         if ((*ctx)->isResetNotificationEnabled())
410             return false;   // If reset notifications have been requested, application must delete all contexts first
411     }
412  
413     // Release surface resources to make the Reset() succeed
414     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
415     {
416         (*surface)->release();
417     }
418
419     if (!mRenderer->resetDevice())
420     {
421         return error(EGL_BAD_ALLOC, false);
422     }
423
424     // Restore any surfaces that may have been lost
425     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
426     {
427         (*surface)->resetSwapChain();
428     }
429
430     return true;
431 }
432
433
434 void Display::destroySurface(egl::Surface *surface)
435 {
436     delete surface;
437     mSurfaceSet.erase(surface);
438 }
439
440 void Display::destroyContext(gl::Context *context)
441 {
442     glDestroyContext(context);
443     mContextSet.erase(context);
444 }
445
446 void Display::notifyDeviceLost()
447 {
448     for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++)
449     {
450         (*context)->markContextLost();
451     }
452     egl::error(EGL_CONTEXT_LOST);
453 }
454
455 void Display::recreateSwapChains()
456 {
457     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
458     {
459         (*surface)->getSwapChain()->recreate();
460     }
461 }
462
463 bool Display::isInitialized() const
464 {
465     return mRenderer != NULL && mConfigSet.size() > 0;
466 }
467
468 bool Display::isValidConfig(EGLConfig config)
469 {
470     return mConfigSet.get(config) != NULL;
471 }
472
473 bool Display::isValidContext(gl::Context *context)
474 {
475     return mContextSet.find(context) != mContextSet.end();
476 }
477
478 bool Display::isValidSurface(egl::Surface *surface)
479 {
480     return mSurfaceSet.find(surface) != mSurfaceSet.end();
481 }
482
483 bool Display::hasExistingWindowSurface(HWND window)
484 {
485     for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
486     {
487         if ((*surface)->getWindowHandle() == window)
488         {
489             return true;
490         }
491     }
492
493     return false;
494 }
495
496 void Display::initExtensionString()
497 {
498     HMODULE swiftShader = GetModuleHandle(TEXT("swiftshader_d3d9.dll"));
499     bool shareHandleSupported = mRenderer->getShareHandleSupport();
500
501     mExtensionString = "";
502
503     // Multi-vendor (EXT) extensions
504     mExtensionString += "EGL_EXT_create_context_robustness ";
505
506     // ANGLE-specific extensions
507     if (shareHandleSupported)
508     {
509         mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer ";
510     }
511
512     mExtensionString += "EGL_ANGLE_query_surface_pointer ";
513
514     mExtensionString += "EGL_ANGLE_window_fixed_size ";
515
516     if (swiftShader)
517     {
518         mExtensionString += "EGL_ANGLE_software_display ";
519     }
520
521     if (shareHandleSupported)
522     {
523         mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle ";
524     }
525
526     if (mRenderer->getPostSubBufferSupport())
527     {
528         mExtensionString += "EGL_NV_post_sub_buffer";
529     }
530
531     std::string::size_type end = mExtensionString.find_last_not_of(' ');
532     if (end != std::string::npos)
533     {
534         mExtensionString.resize(end+1);
535     }
536 }
537
538 const char *Display::getExtensionString() const
539 {
540     return mExtensionString.c_str();
541 }
542
543 void Display::initVendorString()
544 {
545     mVendorString = "Google Inc.";
546
547     LUID adapterLuid = {0};
548
549     if (mRenderer && mRenderer->getLUID(&adapterLuid))
550     {
551         char adapterLuidString[64];
552         sprintf_s(adapterLuidString, sizeof(adapterLuidString), " (adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart);
553
554         mVendorString += adapterLuidString;
555     }
556 }
557
558 const char *Display::getVendorString() const
559 {
560     return mVendorString.c_str();
561 }
562
563 }