OSDN Git Service

Implement a Radiance prototype.
[android-x86/external-swiftshader.git] / src / Radiance / libEGL / Display.cpp
1 // SwiftShader Software Renderer\r
2 //\r
3 // Copyright(c) 2005-2013 TransGaming Inc.\r
4 //\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
10 //\r
11 \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
15 \r
16 #include "Display.h"\r
17 \r
18 #include "main.h"\r
19 #include "libEGL/Surface.h"\r
20 #include "libEGL/Context.hpp"\r
21 #include "common/debug.h"\r
22 \r
23 #include <algorithm>\r
24 #include <vector>\r
25 #include <map>\r
26 \r
27 namespace egl\r
28 {\r
29 typedef std::map<EGLNativeDisplayType, Display*> DisplayMap; \r
30 DisplayMap displays;\r
31 \r
32 egl::Display *Display::getDisplay(EGLNativeDisplayType displayId)\r
33 {\r
34     if(displays.find(displayId) != displays.end())\r
35     {\r
36         return displays[displayId];\r
37     }\r
38 \r
39     egl::Display *display = NULL;\r
40 \r
41     if(displayId == EGL_DEFAULT_DISPLAY)\r
42     {\r
43         display = new egl::Display(displayId);\r
44     }\r
45     else\r
46     {\r
47         // FIXME: Check if displayId is a valid display device context\r
48 \r
49         display = new egl::Display(displayId);\r
50     }\r
51 \r
52     displays[displayId] = display;\r
53     return display;\r
54 }\r
55 \r
56 Display::Display(EGLNativeDisplayType displayId) : displayId(displayId)\r
57 {\r
58     mMinSwapInterval = 1;\r
59     mMaxSwapInterval = 1;\r
60 }\r
61 \r
62 Display::~Display()\r
63 {\r
64     terminate();\r
65 \r
66         displays.erase(displayId);\r
67 }\r
68 \r
69 static void cpuid(int registers[4], int info)\r
70 {\r
71         #if defined(_WIN32)\r
72         __cpuid(registers, info);\r
73     #else\r
74         __asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info));\r
75     #endif\r
76 }\r
77 \r
78 static bool detectSSE()\r
79 {\r
80         #if defined(__APPLE__)\r
81                 int SSE = false;\r
82                 size_t length = sizeof(SSE);\r
83                 sysctlbyname("hw.optional.sse", &SSE, &length, 0, 0);\r
84                 return SSE;\r
85         #else\r
86                 int registers[4];\r
87                 cpuid(registers, 1);\r
88                 return (registers[3] & 0x02000000) != 0;\r
89         #endif\r
90 }\r
91 \r
92 bool Display::initialize()\r
93 {\r
94     if(isInitialized())\r
95     {\r
96         return true;\r
97     }\r
98 \r
99         if(!detectSSE())\r
100         {\r
101                  return false;\r
102         }\r
103                 \r
104     mMinSwapInterval = 0;\r
105     mMaxSwapInterval = 4;\r
106 \r
107     const sw::Format renderTargetFormats[] =\r
108     {\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
112         sw::FORMAT_R5G6B5,\r
113     //  sw::FORMAT_X1R5G5B5,      // Has no compatible OpenGL ES renderbuffer format\r
114         sw::FORMAT_X8R8G8B8\r
115     };\r
116 \r
117     const sw::Format depthStencilFormats[] =\r
118     {\r
119         sw::FORMAT_NULL,\r
120     //  sw::FORMAT_D16_LOCKABLE,\r
121         sw::FORMAT_D32,\r
122     //  sw::FORMAT_D15S1,\r
123         sw::FORMAT_D24S8,\r
124         sw::FORMAT_D24X8,\r
125     //  sw::FORMAT_D24X4S4,\r
126         sw::FORMAT_D16,\r
127     //  sw::FORMAT_D32F_LOCKABLE,\r
128     //  sw::FORMAT_D24FS8\r
129     };\r
130 \r
131         DisplayMode currentDisplayMode = getDisplayMode();\r
132     ConfigSet configSet;\r
133 \r
134     for(int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(sw::Format); formatIndex++)\r
135     {\r
136         sw::Format renderTargetFormat = renderTargetFormats[formatIndex];\r
137 \r
138         for(int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(sw::Format); depthStencilIndex++)\r
139         {\r
140             sw::Format depthStencilFormat = depthStencilFormats[depthStencilIndex];\r
141              \r
142             // FIXME: enumerate multi-sampling\r
143 \r
144             configSet.add(currentDisplayMode, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, 0);\r
145         }\r
146     }\r
147 \r
148     // Give the sorted configs a unique ID and store them internally\r
149     EGLint index = 1;\r
150     for(ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)\r
151     {\r
152         Config configuration = *config;\r
153         configuration.mConfigID = index;\r
154         index++;\r
155 \r
156         mConfigSet.mSet.insert(configuration);\r
157     }\r
158 \r
159     if(!isInitialized())\r
160     {\r
161         terminate();\r
162 \r
163         return false;\r
164     }\r
165 \r
166     return true;\r
167 }\r
168 \r
169 void Display::terminate()\r
170 {\r
171     while(!mSurfaceSet.empty())\r
172     {\r
173         destroySurface(*mSurfaceSet.begin());\r
174     }\r
175 \r
176     while(!mContextSet.empty())\r
177     {\r
178         destroyContext(*mContextSet.begin());\r
179     }\r
180 }\r
181 \r
182 bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)\r
183 {\r
184     return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);\r
185 }\r
186 \r
187 bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)\r
188 {\r
189     const egl::Config *configuration = mConfigSet.get(config);\r
190 \r
191     switch (attribute)\r
192     {\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
226       default:\r
227         return false;\r
228     }\r
229 \r
230     return true;\r
231 }\r
232 \r
233 EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList)\r
234 {\r
235     const Config *configuration = mConfigSet.get(config);\r
236 \r
237     if(attribList)\r
238     {\r
239         while(*attribList != EGL_NONE)\r
240         {\r
241             switch (attribList[0])\r
242             {\r
243               case EGL_RENDER_BUFFER:\r
244                 switch (attribList[1])\r
245                 {\r
246                   case EGL_BACK_BUFFER:\r
247                     break;\r
248                   case EGL_SINGLE_BUFFER:\r
249                     return error(EGL_BAD_MATCH, EGL_NO_SURFACE);   // Rendering directly to front buffer not supported\r
250                   default:\r
251                     return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);\r
252                 }\r
253                 break;\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
258               default:\r
259                 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);\r
260             }\r
261 \r
262             attribList += 2;\r
263         }\r
264     }\r
265 \r
266     if(hasExistingWindowSurface(window))\r
267     {\r
268         return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);\r
269     }\r
270 \r
271     Surface *surface = new Surface(this, configuration, window);\r
272 \r
273     if(!surface->initialize())\r
274     {\r
275         delete surface;\r
276         return EGL_NO_SURFACE;\r
277     }\r
278 \r
279     mSurfaceSet.insert(surface);\r
280 \r
281     return success(surface);\r
282 }\r
283 \r
284 EGLSurface Display::createOffscreenSurface(EGLConfig config, const EGLint *attribList)\r
285 {\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
290 \r
291     if(attribList)\r
292     {\r
293         while(*attribList != EGL_NONE)\r
294         {\r
295             switch (attribList[0])\r
296             {\r
297               case EGL_WIDTH:\r
298                 width = attribList[1];\r
299                 break;\r
300               case EGL_HEIGHT:\r
301                 height = attribList[1];\r
302                 break;\r
303               case EGL_LARGEST_PBUFFER:\r
304                 if(attribList[1] != EGL_FALSE)\r
305                   UNIMPLEMENTED(); // FIXME\r
306                 break;\r
307               case EGL_TEXTURE_FORMAT:\r
308                 switch (attribList[1])\r
309                 {\r
310                   case EGL_NO_TEXTURE:\r
311                   case EGL_TEXTURE_RGB:\r
312                   case EGL_TEXTURE_RGBA:\r
313                     textureFormat = attribList[1];\r
314                     break;\r
315                   default:\r
316                     return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);\r
317                 }\r
318                 break;\r
319               case EGL_TEXTURE_TARGET:\r
320                 switch (attribList[1])\r
321                 {\r
322                   case EGL_NO_TEXTURE:\r
323                   case EGL_TEXTURE_2D:\r
324                     textureTarget = attribList[1];\r
325                     break;\r
326                   default:\r
327                     return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);\r
328                 }\r
329                 break;\r
330               case EGL_MIPMAP_TEXTURE:\r
331                 if(attribList[1] != EGL_FALSE)\r
332                   return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);\r
333                 break;\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
338               default:\r
339                 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);\r
340             }\r
341 \r
342             attribList += 2;\r
343         }\r
344     }\r
345 \r
346     if(width < 0 || height < 0)\r
347     {\r
348         return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);\r
349     }\r
350 \r
351     if(width == 0 || height == 0)\r
352     {\r
353         return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);\r
354     }\r
355 \r
356     if((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||\r
357        (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))\r
358     {\r
359         return error(EGL_BAD_MATCH, EGL_NO_SURFACE);\r
360     }\r
361 \r
362     if(!(configuration->mSurfaceType & EGL_PBUFFER_BIT))\r
363     {\r
364         return error(EGL_BAD_MATCH, EGL_NO_SURFACE);\r
365     }\r
366 \r
367     if((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||\r
368        (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))\r
369     {\r
370         return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);\r
371     }\r
372 \r
373     Surface *surface = new Surface(this, configuration, width, height, textureFormat, textureTarget);\r
374 \r
375     if(!surface->initialize())\r
376     {\r
377         delete surface;\r
378         return EGL_NO_SURFACE;\r
379     }\r
380 \r
381     mSurfaceSet.insert(surface);\r
382 \r
383     return success(surface);\r
384 }\r
385 \r
386 EGLContext Display::createContext(EGLConfig configHandle, const egl::Context *shareContext, EGLint clientVersion)\r
387 {\r
388     const egl::Config *config = mConfigSet.get(configHandle);\r
389         egl::Context *context = 0;\r
390 \r
391         if(clientVersion == 2 && config->mRenderableType & EGL_OPENGL_ES2_BIT)\r
392         {\r
393                 if(es2::createContext != 0)\r
394                 {\r
395                         context = es2::createContext(config, shareContext);\r
396                 }\r
397         }\r
398         else\r
399         {\r
400                 return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT);\r
401         }\r
402 \r
403         if(!context)\r
404         {\r
405                 return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT);\r
406         }\r
407 \r
408         mContextSet.insert(context);\r
409 \r
410     return success(context);;\r
411 }\r
412 \r
413 void Display::destroySurface(egl::Surface *surface)\r
414 {\r
415     delete surface;\r
416     mSurfaceSet.erase(surface);\r
417 }\r
418 \r
419 void Display::destroyContext(egl::Context *context)\r
420 {\r
421     context->destroy();\r
422     mContextSet.erase(context);\r
423 }\r
424 \r
425 bool Display::isInitialized() const\r
426 {\r
427     return mConfigSet.size() > 0;\r
428 }\r
429 \r
430 bool Display::isValidConfig(EGLConfig config)\r
431 {\r
432     return mConfigSet.get(config) != NULL;\r
433 }\r
434 \r
435 bool Display::isValidContext(egl::Context *context)\r
436 {\r
437     return mContextSet.find(context) != mContextSet.end();\r
438 }\r
439 \r
440 bool Display::isValidSurface(egl::Surface *surface)\r
441 {\r
442     return mSurfaceSet.find(surface) != mSurfaceSet.end();\r
443 }\r
444 \r
445 bool Display::isValidWindow(EGLNativeWindowType window)\r
446 {\r
447         #if defined(_WIN32)\r
448                 return IsWindow(window) == TRUE;\r
449         #else\r
450                 XWindowAttributes windowAttributes;\r
451                 Status status = XGetWindowAttributes(displayId, window, &windowAttributes);\r
452                         \r
453                 return status == True;\r
454         #endif\r
455 }\r
456 \r
457 bool Display::hasExistingWindowSurface(EGLNativeWindowType window)\r
458 {\r
459     for(SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)\r
460     {\r
461         if((*surface)->getWindowHandle() == window)\r
462         {\r
463             return true;\r
464         }\r
465     }\r
466 \r
467     return false;\r
468 }\r
469 \r
470 EGLint Display::getMinSwapInterval()\r
471 {\r
472     return mMinSwapInterval;\r
473 }\r
474 \r
475 EGLint Display::getMaxSwapInterval()\r
476 {\r
477     return mMaxSwapInterval;\r
478 }\r
479 \r
480 EGLNativeDisplayType Display::getNativeDisplay() const\r
481 {\r
482         return displayId;\r
483 }\r
484 \r
485 DisplayMode Display::getDisplayMode() const\r
486 {\r
487         DisplayMode displayMode = {0};\r
488 \r
489         #if defined(_WIN32)\r
490                 HDC deviceContext = GetDC(0);\r
491         \r
492                 displayMode.width = ::GetDeviceCaps(deviceContext, HORZRES);\r
493                 displayMode.height = ::GetDeviceCaps(deviceContext, VERTRES);\r
494                 unsigned int bpp = ::GetDeviceCaps(deviceContext, BITSPIXEL);\r
495         \r
496                 switch(bpp)\r
497                 {\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
501                 default:\r
502                         ASSERT(false);   // Unexpected display mode color depth\r
503                 }\r
504         \r
505                 ReleaseDC(0, deviceContext);\r
506         #else\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
511 \r
512                 switch(bpp)\r
513                 {\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
517                 default:\r
518                         ASSERT(false);   // Unexpected display mode color depth\r
519                 }\r
520         #endif\r
521 \r
522         return displayMode;\r
523 }\r
524 \r
525 }\r