|
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 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 |
|
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 |
|
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 |
|
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 |
|
410 void Display::destroySurface(egl::Surface *surface) |
|
411 { |
|
412 delete surface; |
|
413 mSurfaceSet.erase(surface); |
|
414 } |
|
415 |
|
416 void Display::destroyContext(gl::Context *context) |
|
417 { |
|
418 glDestroyContext(context); |
|
419 mContextSet.erase(context); |
|
420 } |
|
421 |
|
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 |
|
431 void Display::recreateSwapChains() |
|
432 { |
|
433 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) |
|
434 { |
|
435 (*surface)->getSwapChain()->recreate(); |
|
436 } |
|
437 } |
|
438 |
|
439 bool Display::isInitialized() const |
|
440 { |
|
441 return mRenderer != NULL && mConfigSet.size() > 0; |
|
442 } |
|
443 |
|
444 bool Display::isValidConfig(EGLConfig config) |
|
445 { |
|
446 return mConfigSet.get(config) != NULL; |
|
447 } |
|
448 |
|
449 bool Display::isValidContext(gl::Context *context) |
|
450 { |
|
451 return mContextSet.find(context) != mContextSet.end(); |
|
452 } |
|
453 |
|
454 bool Display::isValidSurface(egl::Surface *surface) |
|
455 { |
|
456 return mSurfaceSet.find(surface) != mSurfaceSet.end(); |
|
457 } |
|
458 |
|
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 |
|
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 |
|
512 const char *Display::getExtensionString() const |
|
513 { |
|
514 return mExtensionString.c_str(); |
|
515 } |
|
516 |
|
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 |
|
532 const char *Display::getVendorString() const |
|
533 { |
|
534 return mVendorString.c_str(); |
|
535 } |
|
536 |
|
537 } |