blob: c08135e4eb87149eb90e5e5498ea8a893ed7449f [file] [log] [blame]
daniel@transgaming.come979ead2010-09-23 18:03:14 +00001//
daniel@transgaming.comc6f7f9d2012-01-27 15:40:00 +00002// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.come979ead2010-09-23 18:03:14 +00003// 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>
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +000014#include <map>
daniel@transgaming.come979ead2010-09-23 18:03:14 +000015#include <vector>
16
17#include "common/debug.h"
jbauman@chromium.org06d7a752011-04-30 01:02:52 +000018#include "libGLESv2/mathutil.h"
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +000019#include "libGLESv2/utilities.h"
daniel@transgaming.come979ead2010-09-23 18:03:14 +000020
21#include "libEGL/main.h"
22
daniel@transgaming.come979ead2010-09-23 18:03:14 +000023
24namespace egl
25{
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +000026namespace
27{
28 typedef std::map<EGLNativeDisplayType, Display*> DisplayMap;
29 DisplayMap displays;
30}
31
32egl::Display *Display::getDisplay(EGLNativeDisplayType displayId)
33{
34 if (displays.find(displayId) != displays.end())
35 {
36 return displays[displayId];
37 }
38
39 egl::Display *display = NULL;
40
41 if (displayId == EGL_DEFAULT_DISPLAY)
42 {
43 display = new egl::Display(displayId, (HDC)NULL, false);
44 }
45 else if (displayId == EGL_SOFTWARE_DISPLAY_ANGLE)
46 {
47 display = new egl::Display(displayId, (HDC)NULL, true);
48 }
49 else
50 {
51 // FIXME: Check if displayId is a valid display device context
52
53 display = new egl::Display(displayId, (HDC)displayId, false);
54 }
55
56 displays[displayId] = display;
57 return display;
58}
59
60Display::Display(EGLNativeDisplayType displayId, HDC deviceContext, bool software) : mDc(deviceContext)
daniel@transgaming.come979ead2010-09-23 18:03:14 +000061{
daniel@transgaming.come979ead2010-09-23 18:03:14 +000062
63 mMinSwapInterval = 1;
64 mMaxSwapInterval = 1;
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +000065 mSoftwareDevice = software;
66 mDisplayId = displayId;
daniel@transgaming.com621ce052012-10-31 17:52:29 +000067 mRenderer = NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +000068}
69
70Display::~Display()
71{
72 terminate();
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +000073
74 DisplayMap::iterator thisDisplay = displays.find(mDisplayId);
75
76 if (thisDisplay != displays.end())
77 {
78 displays.erase(thisDisplay);
79 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +000080}
81
82bool Display::initialize()
83{
84 if (isInitialized())
85 {
86 return true;
87 }
88
daniel@transgaming.com621ce052012-10-31 17:52:29 +000089 HMODULE hModule = NULL;
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +000090 if (mSoftwareDevice)
91 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +000092 hModule = GetModuleHandle(TEXT("swiftshader_d3d9.dll"));
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +000093 }
94 else
95 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +000096 hModule = GetModuleHandle(TEXT("d3d9.dll"));
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +000097 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +000098 if (hModule == NULL)
daniel@transgaming.come979ead2010-09-23 18:03:14 +000099 {
100 terminate();
101 return false;
102 }
103
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000104 mRenderer = glCreateRenderer(hModule, mDc);
105 EGLint status = EGL_BAD_ALLOC;
106 if (mRenderer)
107 status = mRenderer->initialize();
108 if (status != EGL_SUCCESS)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000109 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000110 terminate();
111 return error(status, false);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000112 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000113 D3DCAPS9 deviceCaps = mRenderer->getDeviceCaps(); // D3D9_REPLACE
114 IDirect3D9 *d3d9 = mRenderer->getD3D(); // D3D9_REPLACE
115 UINT adapter = mRenderer->getAdapter(); // D3D9_REPLACE
116 D3DDEVTYPE deviceType = mRenderer->getDeviceType(); // D3D9_REPLACE
117 IDirect3DDevice9 *device = mRenderer->getDevice(); // D3D9_REPLACE
118
119 mMinSwapInterval = 4;
120 mMaxSwapInterval = 0;
121
122 // START D3D9_REPLACE
123 if (deviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) {mMinSwapInterval = std::min(mMinSwapInterval, 0); mMaxSwapInterval = std::max(mMaxSwapInterval, 0);}
124 if (deviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) {mMinSwapInterval = std::min(mMinSwapInterval, 1); mMaxSwapInterval = std::max(mMaxSwapInterval, 1);}
125 if (deviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) {mMinSwapInterval = std::min(mMinSwapInterval, 2); mMaxSwapInterval = std::max(mMaxSwapInterval, 2);}
126 if (deviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) {mMinSwapInterval = std::min(mMinSwapInterval, 3); mMaxSwapInterval = std::max(mMaxSwapInterval, 3);}
127 if (deviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) {mMinSwapInterval = std::min(mMinSwapInterval, 4); mMaxSwapInterval = std::max(mMaxSwapInterval, 4);}
128
129 const D3DFORMAT renderTargetFormats[] =
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000130 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000131 D3DFMT_A1R5G5B5,
132 // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
133 D3DFMT_A8R8G8B8,
134 D3DFMT_R5G6B5,
135 // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format
136 D3DFMT_X8R8G8B8
137 };
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000138
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000139 const D3DFORMAT depthStencilFormats[] =
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000140 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000141 D3DFMT_UNKNOWN,
142 // D3DFMT_D16_LOCKABLE,
143 D3DFMT_D32,
144 // D3DFMT_D15S1,
145 D3DFMT_D24S8,
146 D3DFMT_D24X8,
147 // D3DFMT_D24X4S4,
148 D3DFMT_D16,
149 // D3DFMT_D32F_LOCKABLE,
150 // D3DFMT_D24FS8
151 };
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000152
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000153 D3DDISPLAYMODE currentDisplayMode;
154 d3d9->GetAdapterDisplayMode(adapter, &currentDisplayMode);
155
156 ConfigSet configSet;
157
158 for (int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(D3DFORMAT); formatIndex++)
159 {
160 D3DFORMAT renderTargetFormat = renderTargetFormats[formatIndex];
161
162 HRESULT result = d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat);
163
164 if (SUCCEEDED(result))
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000165 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000166 for (int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(D3DFORMAT); depthStencilIndex++)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000167 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000168 D3DFORMAT depthStencilFormat = depthStencilFormats[depthStencilIndex];
169 HRESULT result = D3D_OK;
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000170
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000171 if(depthStencilFormat != D3DFMT_UNKNOWN)
172 {
173 result = d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat);
174 }
175
176 if (SUCCEEDED(result))
177 {
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000178 if(depthStencilFormat != D3DFMT_UNKNOWN)
179 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000180 result = d3d9->CheckDepthStencilMatch(adapter, deviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat);
daniel@transgaming.coma114c272011-04-22 04:18:50 +0000181 }
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000182
183 if (SUCCEEDED(result))
184 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000185 // FIXME: enumerate multi-sampling
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000186
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000187 configSet.add(currentDisplayMode, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, 0,
188 deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000189 }
190 }
191 }
192 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000193 }
194 // END D3D9_REPLACE
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000195
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000196 // Give the sorted configs a unique ID and store them internally
197 EGLint index = 1;
198 for (ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
199 {
200 Config configuration = *config;
201 configuration.mConfigID = index;
202 index++;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000203
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000204 mConfigSet.mSet.insert(configuration);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000205 }
206
207 if (!isInitialized())
208 {
209 terminate();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000210 return false;
211 }
212
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000213 initExtensionString();
214
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000215 mVertexShaderCache.initialize(device);
216 mPixelShaderCache.initialize(device);
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +0000217
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000218 return true;
219}
220
221void Display::terminate()
222{
223 while (!mSurfaceSet.empty())
224 {
225 destroySurface(*mSurfaceSet.begin());
226 }
227
228 while (!mContextSet.empty())
229 {
230 destroyContext(*mContextSet.begin());
231 }
232
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000233 while (!mEventQueryPool.empty())
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000234 {
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000235 mEventQueryPool.back()->Release();
236 mEventQueryPool.pop_back();
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000237 }
238
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +0000239 mVertexShaderCache.clear();
240 mPixelShaderCache.clear();
241
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000242 glDestroyRenderer(mRenderer);
243 mRenderer = NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000244}
245
246bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
247{
248 return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
249}
250
251bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
252{
253 const egl::Config *configuration = mConfigSet.get(config);
254
255 switch (attribute)
256 {
257 case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break;
258 case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break;
259 case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break;
260 case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break;
261 case EGL_RED_SIZE: *value = configuration->mRedSize; break;
262 case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break;
263 case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break;
264 case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break;
265 case EGL_CONFIG_ID: *value = configuration->mConfigID; break;
266 case EGL_LEVEL: *value = configuration->mLevel; break;
267 case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break;
268 case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break;
269 case EGL_SAMPLES: *value = configuration->mSamples; break;
270 case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break;
271 case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break;
272 case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break;
273 case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break;
274 case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break;
275 case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break;
276 case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break;
277 case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break;
278 case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break;
279 case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break;
280 case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break;
281 case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break;
282 case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break;
283 case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break;
284 case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break;
285 case EGL_CONFORMANT: *value = configuration->mConformant; break;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000286 case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break;
287 case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break;
288 case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000289 default:
290 return false;
291 }
292
293 return true;
294}
295
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000296
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000297
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000298EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000299{
300 const Config *configuration = mConfigSet.get(config);
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +0000301 EGLint postSubBufferSupported = EGL_FALSE;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000302
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000303 if (attribList)
304 {
305 while (*attribList != EGL_NONE)
306 {
307 switch (attribList[0])
308 {
309 case EGL_RENDER_BUFFER:
310 switch (attribList[1])
311 {
312 case EGL_BACK_BUFFER:
313 break;
314 case EGL_SINGLE_BUFFER:
315 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported
316 default:
317 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
318 }
319 break;
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +0000320 case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
321 postSubBufferSupported = attribList[1];
322 break;
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000323 case EGL_VG_COLORSPACE:
324 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
325 case EGL_VG_ALPHA_FORMAT:
326 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
327 default:
328 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
329 }
330
331 attribList += 2;
332 }
333 }
334
335 if (hasExistingWindowSurface(window))
336 {
337 return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
338 }
339
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000340 if (mRenderer->testDeviceLost())
daniel@transgaming.comcf23c452011-11-09 17:47:26 +0000341 {
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000342 if (!restoreLostDevice())
343 return EGL_NO_SURFACE;
344 }
345
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +0000346 Surface *surface = new Surface(this, configuration, window, postSubBufferSupported);
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000347
348 if (!surface->initialize())
349 {
350 delete surface;
351 return EGL_NO_SURFACE;
352 }
353
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000354 mSurfaceSet.insert(surface);
355
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000356 return success(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000357}
358
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000359EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList)
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000360{
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000361 EGLint width = 0, height = 0;
362 EGLenum textureFormat = EGL_NO_TEXTURE;
363 EGLenum textureTarget = EGL_NO_TEXTURE;
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000364 const Config *configuration = mConfigSet.get(config);
365
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000366 if (attribList)
367 {
368 while (*attribList != EGL_NONE)
369 {
370 switch (attribList[0])
371 {
372 case EGL_WIDTH:
373 width = attribList[1];
374 break;
375 case EGL_HEIGHT:
376 height = attribList[1];
377 break;
378 case EGL_LARGEST_PBUFFER:
379 if (attribList[1] != EGL_FALSE)
380 UNIMPLEMENTED(); // FIXME
381 break;
382 case EGL_TEXTURE_FORMAT:
383 switch (attribList[1])
384 {
385 case EGL_NO_TEXTURE:
386 case EGL_TEXTURE_RGB:
387 case EGL_TEXTURE_RGBA:
388 textureFormat = attribList[1];
389 break;
390 default:
391 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
392 }
393 break;
394 case EGL_TEXTURE_TARGET:
395 switch (attribList[1])
396 {
397 case EGL_NO_TEXTURE:
398 case EGL_TEXTURE_2D:
399 textureTarget = attribList[1];
400 break;
401 default:
402 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
403 }
404 break;
405 case EGL_MIPMAP_TEXTURE:
406 if (attribList[1] != EGL_FALSE)
407 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
408 break;
409 case EGL_VG_COLORSPACE:
410 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
411 case EGL_VG_ALPHA_FORMAT:
412 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
413 default:
414 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
415 }
416
417 attribList += 2;
418 }
419 }
420
421 if (width < 0 || height < 0)
422 {
423 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
424 }
425
426 if (width == 0 || height == 0)
427 {
428 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
429 }
430
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000431 if (textureFormat != EGL_NO_TEXTURE && !mRenderer->getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height)))
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000432 {
433 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
434 }
435
436 if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
437 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
438 {
439 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
440 }
441
442 if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
443 {
444 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
445 }
446
447 if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
448 (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
449 {
450 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
451 }
452
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000453 if (mRenderer->testDeviceLost())
daniel@transgaming.comcf23c452011-11-09 17:47:26 +0000454 {
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000455 if (!restoreLostDevice())
456 return EGL_NO_SURFACE;
457 }
458
jbauman@chromium.org4e297702011-05-12 23:04:07 +0000459 Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget);
460
461 if (!surface->initialize())
462 {
463 delete surface;
464 return EGL_NO_SURFACE;
465 }
466
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000467 mSurfaceSet.insert(surface);
468
jbauman@chromium.org06d7a752011-04-30 01:02:52 +0000469 return success(surface);
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000470}
471
daniel@transgaming.com4ff960d2011-11-09 17:47:09 +0000472EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000473{
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000474 if (!mRenderer)
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000475 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000476 return NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000477 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000478 else if (mRenderer->testDeviceLost()) // Lost device
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000479 {
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000480 if (!restoreLostDevice())
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000481 return NULL;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000482 }
483
484 const egl::Config *config = mConfigSet.get(configHandle);
485
daniel@transgaming.com4ff960d2011-11-09 17:47:09 +0000486 gl::Context *context = glCreateContext(config, shareContext, notifyResets, robustAccess);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000487 mContextSet.insert(context);
488
489 return context;
490}
491
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000492bool Display::restoreLostDevice()
493{
daniel@transgaming.comcf23c452011-11-09 17:47:26 +0000494 for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
495 {
496 if ((*ctx)->isResetNotificationEnabled())
497 return false; // If reset notifications have been requested, application must delete all contexts first
498 }
499
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000500 // Release surface resources to make the Reset() succeed
501 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
502 {
503 (*surface)->release();
504 }
505
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000506 while (!mEventQueryPool.empty())
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000507 {
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000508 mEventQueryPool.back()->Release();
509 mEventQueryPool.pop_back();
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000510 }
511
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +0000512 mVertexShaderCache.clear();
513 mPixelShaderCache.clear();
514
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000515 if (!mRenderer->resetDevice())
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000516 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000517 return error(EGL_BAD_ALLOC, false);
vangelis@google.com8c9c4522011-09-09 18:22:28 +0000518 }
519
520 // Restore any surfaces that may have been lost
521 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
522 {
523 (*surface)->resetSwapChain();
524 }
525
526 return true;
527}
528
529
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000530void Display::destroySurface(egl::Surface *surface)
531{
daniel@transgaming.comc556fa52011-05-26 14:13:29 +0000532 delete surface;
533 mSurfaceSet.erase(surface);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000534}
535
536void Display::destroyContext(gl::Context *context)
537{
538 glDestroyContext(context);
539 mContextSet.erase(context);
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000540}
541
daniel@transgaming.com09fcc9f2011-11-09 17:46:47 +0000542void Display::notifyDeviceLost()
543{
544 for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++)
545 {
546 (*context)->markContextLost();
547 }
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000548 mRenderer->markDeviceLost();
daniel@transgaming.com09fcc9f2011-11-09 17:46:47 +0000549 error(EGL_CONTEXT_LOST);
550}
551
daniel@transgaming.com3b1703f2011-05-11 15:36:26 +0000552bool Display::isInitialized() const
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000553{
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000554 return mRenderer != NULL && mConfigSet.size() > 0;
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000555}
556
557bool Display::isValidConfig(EGLConfig config)
558{
559 return mConfigSet.get(config) != NULL;
560}
561
562bool Display::isValidContext(gl::Context *context)
563{
564 return mContextSet.find(context) != mContextSet.end();
565}
566
567bool Display::isValidSurface(egl::Surface *surface)
568{
daniel@transgaming.comc556fa52011-05-26 14:13:29 +0000569 return mSurfaceSet.find(surface) != mSurfaceSet.end();
daniel@transgaming.come979ead2010-09-23 18:03:14 +0000570}
571
572bool Display::hasExistingWindowSurface(HWND window)
573{
574 for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
575 {
576 if ((*surface)->getWindowHandle() == window)
577 {
578 return true;
579 }
580 }
581
582 return false;
583}
584
585EGLint Display::getMinSwapInterval()
586{
587 return mMinSwapInterval;
588}
589
590EGLint Display::getMaxSwapInterval()
591{
592 return mMaxSwapInterval;
593}
594
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000595// D3D9_REPLACE
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000596void Display::sync(bool block)
597{
598 HRESULT result;
599
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000600 IDirect3DQuery9* query = allocateEventQuery();
601 if (!query)
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000602 {
603 return;
604 }
605
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000606 result = query->Issue(D3DISSUE_END);
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000607 ASSERT(SUCCEEDED(result));
608
609 do
610 {
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000611 result = query->GetData(NULL, 0, D3DGETDATA_FLUSH);
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000612
613 if(block && result == S_FALSE)
614 {
615 // Keep polling, but allow other threads to do something useful first
616 Sleep(0);
617 // explicitly check for device loss
618 // some drivers seem to return S_FALSE even if the device is lost
619 // instead of D3DERR_DEVICELOST like they should
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000620 if (mRenderer->testDeviceLost())
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000621 {
622 result = D3DERR_DEVICELOST;
623 }
624 }
625 }
626 while(block && result == S_FALSE);
627
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000628 freeEventQuery(query);
629
daniel@transgaming.com2678b342012-01-18 16:29:40 +0000630 if (isDeviceLostError(result))
631 {
632 notifyDeviceLost();
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000633 }
634}
635
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000636// D3D9_REPLACE
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000637IDirect3DQuery9* Display::allocateEventQuery()
638{
639 IDirect3DQuery9 *query = NULL;
640
641 if (mEventQueryPool.empty())
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000642 {
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000643 HRESULT result = mRenderer->getDevice()->CreateQuery(D3DQUERYTYPE_EVENT, &query);
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000644 ASSERT(SUCCEEDED(result));
645 }
646 else
647 {
648 query = mEventQueryPool.back();
649 mEventQueryPool.pop_back();
650 }
651
652 return query;
653}
654
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000655// D3D9_REPLACE
apatrick@chromium.orgf289ee82012-01-11 20:03:29 +0000656void Display::freeEventQuery(IDirect3DQuery9* query)
657{
658 if (mEventQueryPool.size() > 1000)
659 {
660 query->Release();
661 }
662 else
663 {
664 mEventQueryPool.push_back(query);
apatrick@chromium.orga5ddde92012-01-10 23:00:07 +0000665 }
666}
667
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000668
669void Display::initExtensionString()
670{
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +0000671 HMODULE swiftShader = GetModuleHandle(TEXT("swiftshader_d3d9.dll"));
daniel@transgaming.com1a1fe242011-09-26 18:25:45 +0000672
673 mExtensionString = "";
674
daniel@transgaming.com8747f182011-11-09 17:50:38 +0000675 // Multi-vendor (EXT) extensions
676 mExtensionString += "EGL_EXT_create_context_robustness ";
677
678 // ANGLE-specific extensions
jbauman@chromium.org6c762d02012-02-03 23:31:53 +0000679 if (shareHandleSupported())
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +0000680 {
daniel@transgaming.com1a1fe242011-09-26 18:25:45 +0000681 mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer ";
682 }
683
684 mExtensionString += "EGL_ANGLE_query_surface_pointer ";
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +0000685
686 if (swiftShader)
687 {
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +0000688 mExtensionString += "EGL_ANGLE_software_display ";
jbauman@chromium.org84d7cbc2011-07-14 22:53:19 +0000689 }
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000690
jbauman@chromium.org6c762d02012-02-03 23:31:53 +0000691 if (shareHandleSupported())
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +0000692 {
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000693 mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle ";
694 }
695
apatrick@chromium.orgf4490e22011-12-06 02:05:22 +0000696 mExtensionString += "EGL_NV_post_sub_buffer";
697
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000698 std::string::size_type end = mExtensionString.find_last_not_of(' ');
699 if (end != std::string::npos)
700 {
701 mExtensionString.resize(end+1);
702 }
703}
704
705const char *Display::getExtensionString() const
706{
707 return mExtensionString.c_str();
708}
709
jbauman@chromium.org6c762d02012-02-03 23:31:53 +0000710bool Display::shareHandleSupported() const
711{
712 // PIX doesn't seem to support using share handles, so disable them.
daniel@transgaming.com621ce052012-10-31 17:52:29 +0000713 // D3D9_REPLACE
714 return mRenderer->isD3d9ExDevice() && !gl::perfActive();
jbauman@chromium.org6c762d02012-02-03 23:31:53 +0000715}
716
apatrick@chromium.org3cfd7222012-07-13 22:36:58 +0000717IDirect3DVertexShader9 *Display::createVertexShader(const DWORD *function, size_t length)
718{
719 return mVertexShaderCache.create(function, length);
720}
721
722IDirect3DPixelShader9 *Display::createPixelShader(const DWORD *function, size_t length)
723{
724 return mPixelShaderCache.create(function, length);
725}
726
daniel@transgaming.comc6f7f9d2012-01-27 15:40:00 +0000727
vladimirv@gmail.com721b7f22011-02-11 00:54:47 +0000728}