1 // SwiftShader Software Renderer
\r
3 // Copyright(c) 2005-2013 TransGaming Inc.
\r
5 // All rights reserved. No part of this software may be copied, distributed, transmitted,
\r
6 // transcribed, stored in a retrieval system, translated into any human or computer
\r
7 // language by any means, or disclosed to third parties without the explicit written
\r
8 // agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
\r
9 // or implied, including but not limited to any patent rights, are granted to you.
\r
12 // Display.cpp: Implements the egl::Display class, representing the abstract
\r
13 // display on which graphics are drawn. Implements EGLDisplay.
\r
14 // [EGL 1.4] section 2.1.2 page 3.
\r
16 #include "Display.h"
\r
19 #include "libEGL/Surface.h"
\r
20 #include "libEGL/Context.hpp"
\r
21 #include "common/debug.h"
\r
23 #include <algorithm>
\r
29 typedef std::map<EGLNativeDisplayType, Display*> DisplayMap;
\r
30 DisplayMap displays;
\r
32 egl::Display *Display::getDisplay(EGLNativeDisplayType displayId)
\r
34 if(displays.find(displayId) != displays.end())
\r
36 return displays[displayId];
\r
39 egl::Display *display = NULL;
\r
41 if(displayId == EGL_DEFAULT_DISPLAY)
\r
43 display = new egl::Display(displayId);
\r
47 // FIXME: Check if displayId is a valid display device context
\r
49 display = new egl::Display(displayId);
\r
52 displays[displayId] = display;
\r
56 Display::Display(EGLNativeDisplayType displayId) : displayId(displayId)
\r
58 mMinSwapInterval = 1;
\r
59 mMaxSwapInterval = 1;
\r
66 displays.erase(displayId);
\r
69 static void cpuid(int registers[4], int info)
\r
72 __cpuid(registers, info);
\r
74 __asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info));
\r
78 static bool detectSSE()
\r
80 #if defined(__APPLE__)
\r
82 size_t length = sizeof(SSE);
\r
83 sysctlbyname("hw.optional.sse", &SSE, &length, 0, 0);
\r
87 cpuid(registers, 1);
\r
88 return (registers[3] & 0x02000000) != 0;
\r
92 bool Display::initialize()
\r
104 mMinSwapInterval = 0;
\r
105 mMaxSwapInterval = 4;
\r
107 const sw::Format renderTargetFormats[] =
\r
109 sw::FORMAT_A1R5G5B5,
\r
110 // sw::FORMAT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
\r
111 sw::FORMAT_A8R8G8B8,
\r
113 // sw::FORMAT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format
\r
114 sw::FORMAT_X8R8G8B8
\r
117 const sw::Format depthStencilFormats[] =
\r
120 // sw::FORMAT_D16_LOCKABLE,
\r
122 // sw::FORMAT_D15S1,
\r
125 // sw::FORMAT_D24X4S4,
\r
127 // sw::FORMAT_D32F_LOCKABLE,
\r
128 // sw::FORMAT_D24FS8
\r
131 DisplayMode currentDisplayMode = getDisplayMode();
\r
132 ConfigSet configSet;
\r
134 for(int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(sw::Format); formatIndex++)
\r
136 sw::Format renderTargetFormat = renderTargetFormats[formatIndex];
\r
138 for(int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(sw::Format); depthStencilIndex++)
\r
140 sw::Format depthStencilFormat = depthStencilFormats[depthStencilIndex];
\r
142 // FIXME: enumerate multi-sampling
\r
144 configSet.add(currentDisplayMode, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, 0);
\r
148 // Give the sorted configs a unique ID and store them internally
\r
150 for(ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
\r
152 Config configuration = *config;
\r
153 configuration.mConfigID = index;
\r
156 mConfigSet.mSet.insert(configuration);
\r
159 if(!isInitialized())
\r
169 void Display::terminate()
\r
171 while(!mSurfaceSet.empty())
\r
173 destroySurface(*mSurfaceSet.begin());
\r
176 while(!mContextSet.empty())
\r
178 destroyContext(*mContextSet.begin());
\r
182 bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
\r
184 return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
\r
187 bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
\r
189 const egl::Config *configuration = mConfigSet.get(config);
\r
193 case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break;
\r
194 case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break;
\r
195 case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break;
\r
196 case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break;
\r
197 case EGL_RED_SIZE: *value = configuration->mRedSize; break;
\r
198 case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break;
\r
199 case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break;
\r
200 case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break;
\r
201 case EGL_CONFIG_ID: *value = configuration->mConfigID; break;
\r
202 case EGL_LEVEL: *value = configuration->mLevel; break;
\r
203 case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break;
\r
204 case EGL_NATIVE_VISUAL_ID: *value = configuration->mNativeVisualID; break;
\r
205 case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break;
\r
206 case EGL_SAMPLES: *value = configuration->mSamples; break;
\r
207 case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break;
\r
208 case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break;
\r
209 case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break;
\r
210 case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break;
\r
211 case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break;
\r
212 case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break;
\r
213 case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break;
\r
214 case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break;
\r
215 case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break;
\r
216 case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break;
\r
217 case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break;
\r
218 case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break;
\r
219 case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break;
\r
220 case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break;
\r
221 case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break;
\r
222 case EGL_CONFORMANT: *value = configuration->mConformant; break;
\r
223 case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break;
\r
224 case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break;
\r
225 case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break;
\r
233 EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList)
\r
235 const Config *configuration = mConfigSet.get(config);
\r
239 while(*attribList != EGL_NONE)
\r
241 switch (attribList[0])
\r
243 case EGL_RENDER_BUFFER:
\r
244 switch (attribList[1])
\r
246 case EGL_BACK_BUFFER:
\r
248 case EGL_SINGLE_BUFFER:
\r
249 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported
\r
251 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
\r
254 case EGL_VG_COLORSPACE:
\r
255 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
\r
256 case EGL_VG_ALPHA_FORMAT:
\r
257 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
\r
259 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
\r
266 if(hasExistingWindowSurface(window))
\r
268 return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
\r
271 Surface *surface = new Surface(this, configuration, window);
\r
273 if(!surface->initialize())
\r
276 return EGL_NO_SURFACE;
\r
279 mSurfaceSet.insert(surface);
\r
281 return success(surface);
\r
284 EGLSurface Display::createOffscreenSurface(EGLConfig config, const EGLint *attribList)
\r
286 EGLint width = 0, height = 0;
\r
287 EGLenum textureFormat = EGL_NO_TEXTURE;
\r
288 EGLenum textureTarget = EGL_NO_TEXTURE;
\r
289 const Config *configuration = mConfigSet.get(config);
\r
293 while(*attribList != EGL_NONE)
\r
295 switch (attribList[0])
\r
298 width = attribList[1];
\r
301 height = attribList[1];
\r
303 case EGL_LARGEST_PBUFFER:
\r
304 if(attribList[1] != EGL_FALSE)
\r
305 UNIMPLEMENTED(); // FIXME
\r
307 case EGL_TEXTURE_FORMAT:
\r
308 switch (attribList[1])
\r
310 case EGL_NO_TEXTURE:
\r
311 case EGL_TEXTURE_RGB:
\r
312 case EGL_TEXTURE_RGBA:
\r
313 textureFormat = attribList[1];
\r
316 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
\r
319 case EGL_TEXTURE_TARGET:
\r
320 switch (attribList[1])
\r
322 case EGL_NO_TEXTURE:
\r
323 case EGL_TEXTURE_2D:
\r
324 textureTarget = attribList[1];
\r
327 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
\r
330 case EGL_MIPMAP_TEXTURE:
\r
331 if(attribList[1] != EGL_FALSE)
\r
332 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
\r
334 case EGL_VG_COLORSPACE:
\r
335 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
\r
336 case EGL_VG_ALPHA_FORMAT:
\r
337 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
\r
339 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
\r
346 if(width < 0 || height < 0)
\r
348 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
\r
351 if(width == 0 || height == 0)
\r
353 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
\r
356 if((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
\r
357 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
\r
359 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
\r
362 if(!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
\r
364 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
\r
367 if((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
\r
368 (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
\r
370 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
\r
373 Surface *surface = new Surface(this, configuration, width, height, textureFormat, textureTarget);
\r
375 if(!surface->initialize())
\r
378 return EGL_NO_SURFACE;
\r
381 mSurfaceSet.insert(surface);
\r
383 return success(surface);
\r
386 EGLContext Display::createContext(EGLConfig configHandle, const egl::Context *shareContext, EGLint clientVersion)
\r
388 const egl::Config *config = mConfigSet.get(configHandle);
\r
389 egl::Context *context = 0;
\r
391 if(clientVersion == 2 && config->mRenderableType & EGL_OPENGL_ES2_BIT)
\r
393 if(es2::createContext != 0)
\r
395 context = es2::createContext(config, shareContext);
\r
400 return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
\r
405 return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
\r
408 mContextSet.insert(context);
\r
410 return success(context);;
\r
413 void Display::destroySurface(egl::Surface *surface)
\r
416 mSurfaceSet.erase(surface);
\r
419 void Display::destroyContext(egl::Context *context)
\r
421 context->destroy();
\r
422 mContextSet.erase(context);
\r
425 bool Display::isInitialized() const
\r
427 return mConfigSet.size() > 0;
\r
430 bool Display::isValidConfig(EGLConfig config)
\r
432 return mConfigSet.get(config) != NULL;
\r
435 bool Display::isValidContext(egl::Context *context)
\r
437 return mContextSet.find(context) != mContextSet.end();
\r
440 bool Display::isValidSurface(egl::Surface *surface)
\r
442 return mSurfaceSet.find(surface) != mSurfaceSet.end();
\r
445 bool Display::isValidWindow(EGLNativeWindowType window)
\r
447 #if defined(_WIN32)
\r
448 return IsWindow(window) == TRUE;
\r
450 XWindowAttributes windowAttributes;
\r
451 Status status = XGetWindowAttributes(displayId, window, &windowAttributes);
\r
453 return status == True;
\r
457 bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
\r
459 for(SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
\r
461 if((*surface)->getWindowHandle() == window)
\r
470 EGLint Display::getMinSwapInterval()
\r
472 return mMinSwapInterval;
\r
475 EGLint Display::getMaxSwapInterval()
\r
477 return mMaxSwapInterval;
\r
480 EGLNativeDisplayType Display::getNativeDisplay() const
\r
485 DisplayMode Display::getDisplayMode() const
\r
487 DisplayMode displayMode = {0};
\r
489 #if defined(_WIN32)
\r
490 HDC deviceContext = GetDC(0);
\r
492 displayMode.width = ::GetDeviceCaps(deviceContext, HORZRES);
\r
493 displayMode.height = ::GetDeviceCaps(deviceContext, VERTRES);
\r
494 unsigned int bpp = ::GetDeviceCaps(deviceContext, BITSPIXEL);
\r
498 case 32: displayMode.format = sw::FORMAT_X8R8G8B8; break;
\r
499 case 24: displayMode.format = sw::FORMAT_R8G8B8; break;
\r
500 case 16: displayMode.format = sw::FORMAT_R5G6B5; break;
\r
502 ASSERT(false); // Unexpected display mode color depth
\r
505 ReleaseDC(0, deviceContext);
\r
507 Screen *screen = XDefaultScreenOfDisplay(displayId);
\r
508 displayMode.width = XWidthOfScreen(screen);
\r
509 displayMode.height = XHeightOfScreen(screen);
\r
510 unsigned int bpp = XPlanesOfScreen(screen);
\r
514 case 32: displayMode.format = sw::FORMAT_X8R8G8B8; break;
\r
515 case 24: displayMode.format = sw::FORMAT_R8G8B8; break;
\r
516 case 16: displayMode.format = sw::FORMAT_R5G6B5; break;
\r
518 ASSERT(false); // Unexpected display mode color depth
\r
522 return displayMode;
\r