// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Display.cpp: Implements the Display class, representing the abstract // display on which graphics are drawn. #include "Display.h" #include "main.h" #include "mathutil.h" #include "Device.hpp" #include "common/debug.h" #include <algorithm> #include <vector> #include <map> namespace gl { typedef std::map<NativeDisplayType, Display*> DisplayMap; DisplayMap displays; Display *Display::getDisplay(NativeDisplayType displayId) { if(displays.find(displayId) != displays.end()) { return displays[displayId]; } // FIXME: Check if displayId is a valid display device context Display *display = new Display(displayId); displays[displayId] = display; return display; } Display::Display(NativeDisplayType displayId) : displayId(displayId) { mMinSwapInterval = 1; mMaxSwapInterval = 0; } Display::~Display() { terminate(); displays.erase(displayId); } static void cpuid(int registers[4], int info) { #if defined(_WIN32) __cpuid(registers, info); #else __asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info)); #endif } static bool detectSSE() { #if defined(__APPLE__) int SSE = false; size_t length = sizeof(SSE); sysctlbyname("hw.optional.sse", &SSE, &length, 0, 0); return SSE; #else int registers[4]; cpuid(registers, 1); return (registers[3] & 0x02000000) != 0; #endif } bool Display::initialize() { if(isInitialized()) { return true; } if(!detectSSE()) { return false; } mMinSwapInterval = 0; mMaxSwapInterval = 4; if(!isInitialized()) { terminate(); return false; } return true; } void Display::terminate() { while(!mSurfaceSet.empty()) { destroySurface(*mSurfaceSet.begin()); } while(!mContextSet.empty()) { destroyContext(*mContextSet.begin()); } } gl::Context *Display::createContext(const gl::Context *shareContext) { gl::Context *context = new gl::Context(shareContext); mContextSet.insert(context); return context; } void Display::destroySurface(Surface *surface) { delete surface; mSurfaceSet.erase(surface); } void Display::destroyContext(gl::Context *context) { delete context; if(context == gl::getContext()) { gl::makeCurrent(nullptr, nullptr, nullptr); } mContextSet.erase(context); } bool Display::isInitialized() const { return mMinSwapInterval <= mMaxSwapInterval; } bool Display::isValidContext(gl::Context *context) { return mContextSet.find(context) != mContextSet.end(); } bool Display::isValidSurface(Surface *surface) { return mSurfaceSet.find(surface) != mSurfaceSet.end(); } bool Display::isValidWindow(NativeWindowType window) { #if defined(_WIN32) return IsWindow(window) == TRUE; #else XWindowAttributes windowAttributes; Status status = XGetWindowAttributes(displayId, window, &windowAttributes); return status == True; #endif } GLint Display::getMinSwapInterval() { return mMinSwapInterval; } GLint Display::getMaxSwapInterval() { return mMaxSwapInterval; } Surface *Display::getPrimarySurface() { if(mSurfaceSet.size() == 0) { Surface *surface = new Surface(this, WindowFromDC(displayId)); if(!surface->initialize()) { delete surface; return 0; } mSurfaceSet.insert(surface); gl::setCurrentDrawSurface(surface); } return *mSurfaceSet.begin(); } NativeDisplayType Display::getNativeDisplay() const { return displayId; } DisplayMode Display::getDisplayMode() const { DisplayMode displayMode = {0}; #if defined(_WIN32) HDC deviceContext = GetDC(0); displayMode.width = ::GetDeviceCaps(deviceContext, HORZRES); displayMode.height = ::GetDeviceCaps(deviceContext, VERTRES); unsigned int bpp = ::GetDeviceCaps(deviceContext, BITSPIXEL); switch(bpp) { case 32: displayMode.format = sw::FORMAT_X8R8G8B8; break; case 24: displayMode.format = sw::FORMAT_R8G8B8; break; case 16: displayMode.format = sw::FORMAT_R5G6B5; break; default: ASSERT(false); // Unexpected display mode color depth } ReleaseDC(0, deviceContext); #else Screen *screen = XDefaultScreenOfDisplay(displayId); displayMode.width = XWidthOfScreen(screen); displayMode.height = XHeightOfScreen(screen); unsigned int bpp = XPlanesOfScreen(screen); switch(bpp) { case 32: displayMode.format = sw::FORMAT_X8R8G8B8; break; case 24: displayMode.format = sw::FORMAT_R8G8B8; break; case 16: displayMode.format = sw::FORMAT_R5G6B5; break; default: ASSERT(false); // Unexpected display mode color depth } #endif return displayMode; } }