1// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Display.cpp: Implements the Display class, representing the abstract
16// display on which graphics are drawn.
17
18#include "Display.h"
19
20#include "main.h"
21#include "mathutil.h"
22#include "Device.hpp"
23#include "common/debug.h"
24
25#include <algorithm>
26#include <vector>
27#include <map>
28
29namespace gl
30{
31typedef std::map<NativeDisplayType, Display*> DisplayMap;
32DisplayMap displays;
33
34Display *Display::getDisplay(NativeDisplayType 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	Display *display = new Display(displayId);
43
44	displays[displayId] = display;
45	return display;
46}
47
48Display::Display(NativeDisplayType displayId) : displayId(displayId)
49{
50	mMinSwapInterval = 1;
51	mMaxSwapInterval = 0;
52}
53
54Display::~Display()
55{
56	terminate();
57
58	displays.erase(displayId);
59}
60
61static void cpuid(int registers[4], int info)
62{
63	#if defined(_WIN32)
64		__cpuid(registers, info);
65	#else
66		__asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info));
67	#endif
68}
69
70static bool detectSSE()
71{
72	#if defined(__APPLE__)
73		int SSE = false;
74		size_t length = sizeof(SSE);
75		sysctlbyname("hw.optional.sse", &SSE, &length, 0, 0);
76		return SSE;
77	#else
78		int registers[4];
79		cpuid(registers, 1);
80		return (registers[3] & 0x02000000) != 0;
81	#endif
82}
83
84bool Display::initialize()
85{
86	if(isInitialized())
87	{
88		return true;
89	}
90
91	if(!detectSSE())
92	{
93		 return false;
94	}
95
96	mMinSwapInterval = 0;
97	mMaxSwapInterval = 4;
98
99	if(!isInitialized())
100	{
101		terminate();
102
103		return false;
104	}
105
106	return true;
107}
108
109void Display::terminate()
110{
111	while(!mSurfaceSet.empty())
112	{
113		destroySurface(*mSurfaceSet.begin());
114	}
115
116	while(!mContextSet.empty())
117	{
118		destroyContext(*mContextSet.begin());
119	}
120}
121
122gl::Context *Display::createContext(const gl::Context *shareContext)
123{
124	gl::Context *context = new gl::Context(shareContext);
125	mContextSet.insert(context);
126
127	return context;
128}
129
130void Display::destroySurface(Surface *surface)
131{
132	delete surface;
133	mSurfaceSet.erase(surface);
134}
135
136void Display::destroyContext(gl::Context *context)
137{
138	delete context;
139
140	if(context == gl::getContext())
141	{
142		gl::makeCurrent(nullptr, nullptr, nullptr);
143	}
144
145	mContextSet.erase(context);
146}
147
148bool Display::isInitialized() const
149{
150	return mMinSwapInterval <= mMaxSwapInterval;
151}
152
153bool Display::isValidContext(gl::Context *context)
154{
155	return mContextSet.find(context) != mContextSet.end();
156}
157
158bool Display::isValidSurface(Surface *surface)
159{
160	return mSurfaceSet.find(surface) != mSurfaceSet.end();
161}
162
163bool Display::isValidWindow(NativeWindowType window)
164{
165	#if defined(_WIN32)
166		return IsWindow(window) == TRUE;
167	#else
168		XWindowAttributes windowAttributes;
169		Status status = XGetWindowAttributes(displayId, window, &windowAttributes);
170
171		return status == True;
172	#endif
173}
174
175GLint Display::getMinSwapInterval()
176{
177	return mMinSwapInterval;
178}
179
180GLint Display::getMaxSwapInterval()
181{
182	return mMaxSwapInterval;
183}
184
185Surface *Display::getPrimarySurface()
186{
187	if(mSurfaceSet.size() == 0)
188	{
189		Surface *surface = new Surface(this, WindowFromDC(displayId));
190
191		if(!surface->initialize())
192		{
193			delete surface;
194			return 0;
195		}
196
197		mSurfaceSet.insert(surface);
198
199		gl::setCurrentDrawSurface(surface);
200	}
201
202	return *mSurfaceSet.begin();
203}
204
205NativeDisplayType Display::getNativeDisplay() const
206{
207	return displayId;
208}
209
210DisplayMode Display::getDisplayMode() const
211{
212	DisplayMode displayMode = {0};
213
214	#if defined(_WIN32)
215		HDC deviceContext = GetDC(0);
216
217		displayMode.width = ::GetDeviceCaps(deviceContext, HORZRES);
218		displayMode.height = ::GetDeviceCaps(deviceContext, VERTRES);
219		unsigned int bpp = ::GetDeviceCaps(deviceContext, BITSPIXEL);
220
221		switch(bpp)
222		{
223		case 32: displayMode.format = sw::FORMAT_X8R8G8B8; break;
224		case 24: displayMode.format = sw::FORMAT_R8G8B8;   break;
225		case 16: displayMode.format = sw::FORMAT_R5G6B5;   break;
226		default:
227			ASSERT(false);   // Unexpected display mode color depth
228		}
229
230		ReleaseDC(0, deviceContext);
231	#else
232		Screen *screen = XDefaultScreenOfDisplay(displayId);
233		displayMode.width = XWidthOfScreen(screen);
234		displayMode.height = XHeightOfScreen(screen);
235		unsigned int bpp = XPlanesOfScreen(screen);
236
237		switch(bpp)
238		{
239		case 32: displayMode.format = sw::FORMAT_X8R8G8B8; break;
240		case 24: displayMode.format = sw::FORMAT_R8G8B8;   break;
241		case 16: displayMode.format = sw::FORMAT_R5G6B5;   break;
242		default:
243			ASSERT(false);   // Unexpected display mode color depth
244		}
245	#endif
246
247	return displayMode;
248}
249
250}
251