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