blob: e311662844b8064da841709411866fb153b5e2cf [file] [log] [blame]
Nicolas Capensa86d5e12014-11-16 23:28:38 -05001// SwiftShader Software Renderer
2//
3// Copyright(c) 2005-2013 TransGaming Inc.
4//
5// All rights reserved. No part of this software may be copied, distributed, transmitted,
6// transcribed, stored in a retrieval system, translated into any human or computer
7// language by any means, or disclosed to third parties without the explicit written
8// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
9// or implied, including but not limited to any patent rights, are granted to you.
10//
11
12// Display.cpp: Implements the egl::Display class, representing the abstract
13// display on which graphics are drawn. Implements EGLDisplay.
14// [EGL 1.4] section 2.1.2 page 3.
15
16#include "Display.h"
17
18#include "main.h"
19#include "libEGL/Surface.h"
20#include "libEGL/Context.hpp"
21#include "common/debug.h"
Greg Hartman8aac4552015-11-09 18:10:30 -080022#include "Common/MutexLock.hpp"
Nicolas Capensa86d5e12014-11-16 23:28:38 -050023
Greg Hartman029d3532015-03-20 13:25:37 -070024#ifdef __ANDROID__
25#include <system/window.h>
Nicolas Capensaaec29d2015-10-30 13:39:52 -040026#include <sys/ioctl.h>
27#include <linux/fb.h>
28#include <fcntl.h>
Nicolas Capens26177e92016-01-06 17:34:03 -050029#elif defined(__linux__)
Nicolas Capens7154c1c2015-12-30 11:42:43 -050030#include "Main/libX11.hpp"
31#elif defined(__APPLE__)
Corentin Wallezcd0a4572015-12-10 15:59:28 -050032#include "OSXUtils.hpp"
33#endif
34
Nicolas Capensa86d5e12014-11-16 23:28:38 -050035#include <algorithm>
36#include <vector>
37#include <map>
38
39namespace egl
40{
Greg Hartman8aac4552015-11-09 18:10:30 -080041
Nicolas Capens26177e92016-01-06 17:34:03 -050042Display *Display::get(EGLDisplay dpy)
Nicolas Capensa86d5e12014-11-16 23:28:38 -050043{
Nicolas Capens26177e92016-01-06 17:34:03 -050044 if(dpy != (EGLDisplay)1) // We only support the default display
Nicolas Capense63db962015-12-11 17:24:40 -050045 {
Nicolas Capens26177e92016-01-06 17:34:03 -050046 return nullptr;
47 }
Nicolas Capense63db962015-12-11 17:24:40 -050048
Nicolas Capens26177e92016-01-06 17:34:03 -050049 static void *nativeDisplay = nullptr;
Nicolas Capense63db962015-12-11 17:24:40 -050050
Nicolas Capens26177e92016-01-06 17:34:03 -050051 #if defined(__linux__) && !defined(__ANDROID__)
52 // Even if the application provides a native display handle, we open (and close) our own connection
53 if(!nativeDisplay && libX11->XOpenDisplay)
54 {
55 nativeDisplay = libX11->XOpenDisplay(NULL);
56 }
57 #endif
58
59 static Display display(nativeDisplay);
60
61 return &display;
Nicolas Capensa86d5e12014-11-16 23:28:38 -050062}
63
Nicolas Capens26177e92016-01-06 17:34:03 -050064Display::Display(void *nativeDisplay) : nativeDisplay(nativeDisplay)
Nicolas Capensa86d5e12014-11-16 23:28:38 -050065{
66 mMinSwapInterval = 1;
67 mMaxSwapInterval = 1;
68}
69
70Display::~Display()
71{
72 terminate();
Nicolas Capens26177e92016-01-06 17:34:03 -050073
74 #if defined(__linux__) && !defined(__ANDROID__)
75 if(nativeDisplay && libX11->XCloseDisplay)
76 {
77 libX11->XCloseDisplay((::Display*)nativeDisplay);
78 }
79 #endif
Nicolas Capensa86d5e12014-11-16 23:28:38 -050080}
81
82static void cpuid(int registers[4], int info)
83{
84 #if defined(_WIN32)
85 __cpuid(registers, info);
86 #else
87 __asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info));
88 #endif
89}
90
91static bool detectSSE()
92{
Nicolas Capensc71c4502014-12-11 14:44:35 -050093 int registers[4];
94 cpuid(registers, 1);
95 return (registers[3] & 0x02000000) != 0;
Nicolas Capensa86d5e12014-11-16 23:28:38 -050096}
97
98bool Display::initialize()
99{
100 if(isInitialized())
101 {
102 return true;
103 }
104
105 if(!detectSSE())
106 {
107 return false;
108 }
Nicolas Capensc71c4502014-12-11 14:44:35 -0500109
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500110 mMinSwapInterval = 0;
111 mMaxSwapInterval = 4;
112
Nicolas Capensb602f0d2015-09-01 01:38:00 -0400113 const int samples[] =
114 {
115 0,
116 2,
117 4
118 };
119
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500120 const sw::Format renderTargetFormats[] =
121 {
122 sw::FORMAT_A1R5G5B5,
123 // sw::FORMAT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
124 sw::FORMAT_A8R8G8B8,
Nicolas Capens5716cf02015-10-30 13:54:24 -0400125 sw::FORMAT_A8B8G8R8,
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500126 sw::FORMAT_R5G6B5,
127 // sw::FORMAT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format
Nicolas Capens5716cf02015-10-30 13:54:24 -0400128 sw::FORMAT_X8R8G8B8,
129 sw::FORMAT_X8B8G8R8
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500130 };
131
132 const sw::Format depthStencilFormats[] =
133 {
134 sw::FORMAT_NULL,
135 // sw::FORMAT_D16_LOCKABLE,
136 sw::FORMAT_D32,
137 // sw::FORMAT_D15S1,
138 sw::FORMAT_D24S8,
139 sw::FORMAT_D24X8,
140 // sw::FORMAT_D24X4S4,
141 sw::FORMAT_D16,
142 // sw::FORMAT_D32F_LOCKABLE,
143 // sw::FORMAT_D24FS8
144 };
145
Nicolas Capens8b4ea002015-10-01 01:09:27 -0400146 sw::Format currentDisplayFormat = getDisplayFormat();
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500147 ConfigSet configSet;
148
Nicolas Capensb602f0d2015-09-01 01:38:00 -0400149 for(int samplesIndex = 0; samplesIndex < sizeof(samples) / sizeof(int); samplesIndex++)
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500150 {
Nicolas Capensb602f0d2015-09-01 01:38:00 -0400151 for(int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(sw::Format); formatIndex++)
152 {
153 sw::Format renderTargetFormat = renderTargetFormats[formatIndex];
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500154
Nicolas Capensb602f0d2015-09-01 01:38:00 -0400155 for(int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(sw::Format); depthStencilIndex++)
156 {
157 sw::Format depthStencilFormat = depthStencilFormats[depthStencilIndex];
Nicolas Capensc71c4502014-12-11 14:44:35 -0500158
Nicolas Capens8b4ea002015-10-01 01:09:27 -0400159 configSet.add(currentDisplayFormat, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, samples[samplesIndex]);
Nicolas Capensb602f0d2015-09-01 01:38:00 -0400160 }
161 }
162 }
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500163
164 // Give the sorted configs a unique ID and store them internally
165 EGLint index = 1;
166 for(ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
167 {
168 Config configuration = *config;
169 configuration.mConfigID = index;
170 index++;
171
172 mConfigSet.mSet.insert(configuration);
173 }
174
175 if(!isInitialized())
176 {
177 terminate();
178
179 return false;
180 }
181
182 return true;
183}
184
185void Display::terminate()
186{
187 while(!mSurfaceSet.empty())
188 {
189 destroySurface(*mSurfaceSet.begin());
190 }
191
192 while(!mContextSet.empty())
193 {
194 destroyContext(*mContextSet.begin());
195 }
Nicolas Capens6ed03042015-04-01 16:32:53 -0400196
197 if(this == getCurrentDisplay())
198 {
Nicolas Capens9cc8c962015-04-02 13:18:21 -0400199 setCurrentDisplay(nullptr);
Nicolas Capens6ed03042015-04-01 16:32:53 -0400200 }
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500201}
202
203bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
204{
205 return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
206}
207
208bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
209{
210 const egl::Config *configuration = mConfigSet.get(config);
211
Nicolas Capens9a74a0e2015-08-12 16:36:52 -0400212 switch(attribute)
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500213 {
Nicolas Capens9a74a0e2015-08-12 16:36:52 -0400214 case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break;
215 case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break;
216 case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break;
217 case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break;
218 case EGL_RED_SIZE: *value = configuration->mRedSize; break;
219 case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break;
220 case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break;
221 case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break;
222 case EGL_CONFIG_ID: *value = configuration->mConfigID; break;
223 case EGL_LEVEL: *value = configuration->mLevel; break;
224 case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break;
225 case EGL_NATIVE_VISUAL_ID: *value = configuration->mNativeVisualID; break;
226 case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break;
227 case EGL_SAMPLES: *value = configuration->mSamples; break;
228 case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break;
229 case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break;
230 case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break;
231 case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break;
232 case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break;
233 case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break;
234 case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break;
235 case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break;
236 case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break;
237 case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break;
238 case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break;
239 case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break;
240 case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break;
241 case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break;
242 case EGL_MATCH_NATIVE_PIXMAP: *value = EGL_FALSE; UNIMPLEMENTED(); break;
243 case EGL_CONFORMANT: *value = configuration->mConformant; break;
244 case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break;
245 case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break;
246 case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break;
247 case EGL_RECORDABLE_ANDROID: *value = configuration->mRecordableAndroid; break;
248 case EGL_FRAMEBUFFER_TARGET_ANDROID: *value = configuration->mFramebufferTargetAndroid; break;
249 default:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500250 return false;
251 }
252
253 return true;
254}
255
256EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList)
257{
258 const Config *configuration = mConfigSet.get(config);
259
260 if(attribList)
261 {
262 while(*attribList != EGL_NONE)
263 {
264 switch (attribList[0])
265 {
Nicolas Capensb602f0d2015-09-01 01:38:00 -0400266 case EGL_RENDER_BUFFER:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500267 switch (attribList[1])
268 {
Nicolas Capensb602f0d2015-09-01 01:38:00 -0400269 case EGL_BACK_BUFFER:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500270 break;
Nicolas Capensb602f0d2015-09-01 01:38:00 -0400271 case EGL_SINGLE_BUFFER:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500272 return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported
Nicolas Capensb602f0d2015-09-01 01:38:00 -0400273 default:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500274 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
275 }
276 break;
Nicolas Capensb602f0d2015-09-01 01:38:00 -0400277 case EGL_VG_COLORSPACE:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500278 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
Nicolas Capensb602f0d2015-09-01 01:38:00 -0400279 case EGL_VG_ALPHA_FORMAT:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500280 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
Nicolas Capensb602f0d2015-09-01 01:38:00 -0400281 default:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500282 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
283 }
284
285 attribList += 2;
286 }
287 }
288
289 if(hasExistingWindowSurface(window))
290 {
291 return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
292 }
293
Nicolas Capens79c7e272015-08-28 14:23:52 -0400294 Surface *surface = new WindowSurface(this, configuration, window);
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500295
296 if(!surface->initialize())
297 {
Nicolas Capens5d9b4de2015-04-02 15:29:13 -0400298 surface->release();
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500299 return EGL_NO_SURFACE;
300 }
301
Nicolas Capens5d9b4de2015-04-02 15:29:13 -0400302 surface->addRef();
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500303 mSurfaceSet.insert(surface);
304
305 return success(surface);
306}
307
Nicolas Capens79c7e272015-08-28 14:23:52 -0400308EGLSurface Display::createPBufferSurface(EGLConfig config, const EGLint *attribList)
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500309{
310 EGLint width = 0, height = 0;
311 EGLenum textureFormat = EGL_NO_TEXTURE;
312 EGLenum textureTarget = EGL_NO_TEXTURE;
Nicolas Capens79c7e272015-08-28 14:23:52 -0400313 EGLBoolean largestPBuffer = EGL_FALSE;
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500314 const Config *configuration = mConfigSet.get(config);
315
316 if(attribList)
317 {
318 while(*attribList != EGL_NONE)
319 {
Nicolas Capens79c7e272015-08-28 14:23:52 -0400320 switch(attribList[0])
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500321 {
Nicolas Capens79c7e272015-08-28 14:23:52 -0400322 case EGL_WIDTH:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500323 width = attribList[1];
324 break;
Nicolas Capens79c7e272015-08-28 14:23:52 -0400325 case EGL_HEIGHT:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500326 height = attribList[1];
327 break;
Nicolas Capens79c7e272015-08-28 14:23:52 -0400328 case EGL_LARGEST_PBUFFER:
329 largestPBuffer = attribList[1];
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500330 break;
Nicolas Capens79c7e272015-08-28 14:23:52 -0400331 case EGL_TEXTURE_FORMAT:
332 switch(attribList[1])
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500333 {
Nicolas Capens79c7e272015-08-28 14:23:52 -0400334 case EGL_NO_TEXTURE:
335 case EGL_TEXTURE_RGB:
336 case EGL_TEXTURE_RGBA:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500337 textureFormat = attribList[1];
338 break;
Nicolas Capens79c7e272015-08-28 14:23:52 -0400339 default:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500340 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
341 }
342 break;
Nicolas Capens79c7e272015-08-28 14:23:52 -0400343 case EGL_TEXTURE_TARGET:
344 switch(attribList[1])
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500345 {
Nicolas Capens79c7e272015-08-28 14:23:52 -0400346 case EGL_NO_TEXTURE:
347 case EGL_TEXTURE_2D:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500348 textureTarget = attribList[1];
349 break;
Nicolas Capens79c7e272015-08-28 14:23:52 -0400350 default:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500351 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
352 }
353 break;
Nicolas Capens79c7e272015-08-28 14:23:52 -0400354 case EGL_MIPMAP_TEXTURE:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500355 if(attribList[1] != EGL_FALSE)
Nicolas Capens79c7e272015-08-28 14:23:52 -0400356 {
357 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
358 }
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500359 break;
Nicolas Capens79c7e272015-08-28 14:23:52 -0400360 case EGL_VG_COLORSPACE:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500361 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
Nicolas Capens79c7e272015-08-28 14:23:52 -0400362 case EGL_VG_ALPHA_FORMAT:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500363 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
Nicolas Capens79c7e272015-08-28 14:23:52 -0400364 default:
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500365 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
366 }
367
368 attribList += 2;
369 }
370 }
371
372 if(width < 0 || height < 0)
373 {
374 return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
375 }
376
377 if(width == 0 || height == 0)
378 {
379 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
380 }
381
382 if((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
383 (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
384 {
385 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
386 }
387
388 if(!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
389 {
390 return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
391 }
392
393 if((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
394 (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
395 {
396 return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
397 }
398
Nicolas Capens79c7e272015-08-28 14:23:52 -0400399 Surface *surface = new PBufferSurface(this, configuration, width, height, textureFormat, textureTarget, largestPBuffer);
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500400
401 if(!surface->initialize())
402 {
Nicolas Capens5d9b4de2015-04-02 15:29:13 -0400403 surface->release();
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500404 return EGL_NO_SURFACE;
405 }
406
Nicolas Capens5d9b4de2015-04-02 15:29:13 -0400407 surface->addRef();
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500408 mSurfaceSet.insert(surface);
409
410 return success(surface);
411}
412
413EGLContext Display::createContext(EGLConfig configHandle, const egl::Context *shareContext, EGLint clientVersion)
414{
415 const egl::Config *config = mConfigSet.get(configHandle);
416 egl::Context *context = 0;
417
418 if(clientVersion == 1 && config->mRenderableType & EGL_OPENGL_ES_BIT)
419 {
Nicolas Capensa2308052015-04-15 16:50:21 -0400420 if(libGLES_CM)
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500421 {
Nicolas Capensa2308052015-04-15 16:50:21 -0400422 context = libGLES_CM->es1CreateContext(config, shareContext);
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500423 }
424 }
Alexis Hetua1961522015-05-20 12:58:27 -0400425 else if((clientVersion == 2 && config->mRenderableType & EGL_OPENGL_ES2_BIT)
426#ifndef __ANDROID__ // Do not allow GLES 3.0 on Android
427 || (clientVersion == 3 && config->mRenderableType & EGL_OPENGL_ES3_BIT)
428#endif
429 )
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500430 {
Nicolas Capensa2308052015-04-15 16:50:21 -0400431 if(libGLESv2)
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500432 {
Nicolas Capensa2308052015-04-15 16:50:21 -0400433 context = libGLESv2->es2CreateContext(config, shareContext, clientVersion);
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500434 }
435 }
436 else
437 {
438 return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
439 }
440
441 if(!context)
442 {
443 return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
444 }
445
Nicolas Capens5d9b4de2015-04-02 15:29:13 -0400446 context->addRef();
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500447 mContextSet.insert(context);
448
Nicolas Capens5d9b4de2015-04-02 15:29:13 -0400449 return success(context);
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500450}
451
452void Display::destroySurface(egl::Surface *surface)
453{
Nicolas Capens5d9b4de2015-04-02 15:29:13 -0400454 surface->release();
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500455 mSurfaceSet.erase(surface);
Nicolas Capens6ed03042015-04-01 16:32:53 -0400456
457 if(surface == getCurrentDrawSurface())
458 {
Nicolas Capens9cc8c962015-04-02 13:18:21 -0400459 setCurrentDrawSurface(nullptr);
Nicolas Capens6ed03042015-04-01 16:32:53 -0400460 }
461
462 if(surface == getCurrentReadSurface())
463 {
Nicolas Capens9cc8c962015-04-02 13:18:21 -0400464 setCurrentReadSurface(nullptr);
Nicolas Capens6ed03042015-04-01 16:32:53 -0400465 }
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500466}
467
468void Display::destroyContext(egl::Context *context)
469{
Nicolas Capens5d9b4de2015-04-02 15:29:13 -0400470 context->release();
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500471 mContextSet.erase(context);
Nicolas Capens6ed03042015-04-01 16:32:53 -0400472
473 if(context == getCurrentContext())
474 {
Nicolas Capens9cc8c962015-04-02 13:18:21 -0400475 setCurrentContext(nullptr);
476 setCurrentDrawSurface(nullptr);
477 setCurrentReadSurface(nullptr);
Nicolas Capens6ed03042015-04-01 16:32:53 -0400478 }
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500479}
480
481bool Display::isInitialized() const
482{
483 return mConfigSet.size() > 0;
484}
485
486bool Display::isValidConfig(EGLConfig config)
487{
488 return mConfigSet.get(config) != NULL;
489}
490
491bool Display::isValidContext(egl::Context *context)
492{
493 return mContextSet.find(context) != mContextSet.end();
494}
495
496bool Display::isValidSurface(egl::Surface *surface)
497{
498 return mSurfaceSet.find(surface) != mSurfaceSet.end();
499}
500
501bool Display::isValidWindow(EGLNativeWindowType window)
502{
Nicolas Capens43989202014-11-20 17:58:45 -0500503 #if defined(_WIN32)
504 return IsWindow(window) == TRUE;
Greg Hartman029d3532015-03-20 13:25:37 -0700505 #elif defined(__ANDROID__)
506 if(!window)
507 {
508 ALOGE("%s called with window==NULL %s:%d", __FUNCTION__, __FILE__, __LINE__);
509 return false;
510 }
511 if(static_cast<ANativeWindow*>(window)->common.magic != ANDROID_NATIVE_WINDOW_MAGIC)
512 {
513 ALOGE("%s called with window==%p bad magic %s:%d", __FUNCTION__, window, __FILE__, __LINE__);
514 return false;
515 }
516 return true;
Corentin Wallez27654c22015-12-09 15:22:08 -0500517 #elif defined(__linux__)
Nicolas Capens26177e92016-01-06 17:34:03 -0500518 if(nativeDisplay)
Nicolas Capens43989202014-11-20 17:58:45 -0500519 {
520 XWindowAttributes windowAttributes;
Nicolas Capense63db962015-12-11 17:24:40 -0500521 Status status = libX11->XGetWindowAttributes((::Display*)nativeDisplay, window, &windowAttributes);
Nicolas Capens43989202014-11-20 17:58:45 -0500522
523 return status == True;
524 }
Corentin Wallez27654c22015-12-09 15:22:08 -0500525 #elif defined(__APPLE__)
Corentin Wallezcd0a4572015-12-10 15:59:28 -0500526 return sw::OSX::IsValidWindow(window);
Corentin Wallez27654c22015-12-09 15:22:08 -0500527 #else
528 #error "Display::isValidWindow unimplemented for this platform"
Greg Hartman029d3532015-03-20 13:25:37 -0700529 #endif
Nicolas Capens43989202014-11-20 17:58:45 -0500530
531 return false;
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500532}
533
534bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
535{
536 for(SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
537 {
Nicolas Capens79c7e272015-08-28 14:23:52 -0400538 if((*surface)->isWindowSurface())
539 {
540 if((*surface)->getWindowHandle() == window)
541 {
542 return true;
543 }
544 }
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500545 }
546
547 return false;
548}
549
Nicolas Capens79c7e272015-08-28 14:23:52 -0400550EGLint Display::getMinSwapInterval() const
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500551{
552 return mMinSwapInterval;
553}
554
Nicolas Capens79c7e272015-08-28 14:23:52 -0400555EGLint Display::getMaxSwapInterval() const
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500556{
557 return mMaxSwapInterval;
558}
559
Nicolas Capense63db962015-12-11 17:24:40 -0500560void *Display::getNativeDisplay() const
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500561{
Nicolas Capense63db962015-12-11 17:24:40 -0500562 return nativeDisplay;
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500563}
564
Nicolas Capens8b4ea002015-10-01 01:09:27 -0400565sw::Format Display::getDisplayFormat() const
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500566{
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500567 #if defined(_WIN32)
568 HDC deviceContext = GetDC(0);
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500569 unsigned int bpp = ::GetDeviceCaps(deviceContext, BITSPIXEL);
Nicolas Capens8b4ea002015-10-01 01:09:27 -0400570 ReleaseDC(0, deviceContext);
Nicolas Capensc71c4502014-12-11 14:44:35 -0500571
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500572 switch(bpp)
573 {
Nicolas Capens8b4ea002015-10-01 01:09:27 -0400574 case 32: return sw::FORMAT_X8R8G8B8;
575 case 24: return sw::FORMAT_R8G8B8;
576 case 16: return sw::FORMAT_R5G6B5;
577 default: UNREACHABLE(bpp); // Unexpected display mode color depth
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500578 }
Greg Hartman029d3532015-03-20 13:25:37 -0700579 #elif defined(__ANDROID__)
Nicolas Capensaaec29d2015-10-30 13:39:52 -0400580 static const char *const framebuffer[] =
581 {
582 "/dev/graphics/fb0",
583 "/dev/fb0",
584 0
585 };
586
587 for(int i = 0; framebuffer[i]; i++)
588 {
589 int fd = open(framebuffer[i], O_RDONLY, 0);
590
591 if(fd != -1)
592 {
593 struct fb_var_screeninfo info;
594 if(ioctl(fd, FBIOGET_VSCREENINFO, &info) >= 0)
595 {
596 switch(info.bits_per_pixel)
597 {
598 case 16:
599 return sw::FORMAT_R5G6B5;
600 case 32:
601 if(info.red.length == 8 && info.red.offset == 16 &&
602 info.green.length == 8 && info.green.offset == 8 &&
603 info.blue.length == 8 && info.blue.offset == 0 &&
604 info.transp.length == 0)
605 {
606 return sw::FORMAT_X8R8G8B8;
607 }
608 if(info.red.length == 8 && info.red.offset == 0 &&
609 info.green.length == 8 && info.green.offset == 8 &&
610 info.blue.length == 8 && info.blue.offset == 16 &&
611 info.transp.length == 0)
612 {
613 return sw::FORMAT_X8B8G8R8;
614 }
615 if(info.red.length == 8 && info.red.offset == 16 &&
616 info.green.length == 8 && info.green.offset == 8 &&
617 info.blue.length == 8 && info.blue.offset == 0 &&
618 info.transp.length == 8 && info.transp.offset == 24)
619 {
620 return sw::FORMAT_A8R8G8B8;
621 }
622 if(info.red.length == 8 && info.red.offset == 0 &&
623 info.green.length == 8 && info.green.offset == 8 &&
624 info.blue.length == 8 && info.blue.offset == 16 &&
625 info.transp.length == 8 && info.transp.offset == 24)
626 {
627 return sw::FORMAT_A8B8G8R8;
628 }
629 else UNIMPLEMENTED();
630 default:
631 UNIMPLEMENTED();
632 }
633 }
634
635 close(fd);
636 }
637 }
638
639 // No framebuffer device found, or we're in user space
Greg Hartman96c91692015-11-03 09:59:28 -0800640 return sw::FORMAT_X8B8G8R8;
Corentin Wallez27654c22015-12-09 15:22:08 -0500641 #elif defined(__linux__)
Nicolas Capens26177e92016-01-06 17:34:03 -0500642 if(nativeDisplay)
Nicolas Capens43989202014-11-20 17:58:45 -0500643 {
Nicolas Capense63db962015-12-11 17:24:40 -0500644 Screen *screen = libX11->XDefaultScreenOfDisplay((::Display*)nativeDisplay);
Nicolas Capensa36c9902015-04-13 03:51:45 -0400645 unsigned int bpp = libX11->XPlanesOfScreen(screen);
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500646
Nicolas Capens43989202014-11-20 17:58:45 -0500647 switch(bpp)
648 {
Nicolas Capens8b4ea002015-10-01 01:09:27 -0400649 case 32: return sw::FORMAT_X8R8G8B8;
650 case 24: return sw::FORMAT_R8G8B8;
651 case 16: return sw::FORMAT_R5G6B5;
652 default: UNREACHABLE(bpp); // Unexpected display mode color depth
Nicolas Capens43989202014-11-20 17:58:45 -0500653 }
654 }
Nicolas Capens26177e92016-01-06 17:34:03 -0500655 else
Nicolas Capens43989202014-11-20 17:58:45 -0500656 {
Nicolas Capens8b4ea002015-10-01 01:09:27 -0400657 return sw::FORMAT_X8R8G8B8;
Nicolas Capens43989202014-11-20 17:58:45 -0500658 }
Corentin Wallez27654c22015-12-09 15:22:08 -0500659 #elif defined(__APPLE__)
Corentin Wallezcd0a4572015-12-10 15:59:28 -0500660 return sw::FORMAT_A8B8G8R8;
Corentin Wallez27654c22015-12-09 15:22:08 -0500661 #else
662 #error "Display::isValidWindow unimplemented for this platform"
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500663 #endif
664
Nicolas Capens8b4ea002015-10-01 01:09:27 -0400665 return sw::FORMAT_X8R8G8B8;
Nicolas Capensa86d5e12014-11-16 23:28:38 -0500666}
667
Nicolas Capensc71c4502014-12-11 14:44:35 -0500668}