blob: 8c0f425bd70d1d55074a64f748f771091ee347ab [file] [log] [blame]
// 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;
}
}