|  | // 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. | 
|  |  | 
|  | // Surface.cpp: Implements the Surface class, representing a drawing surface | 
|  | // such as the client area of a window, including any back buffers. | 
|  |  | 
|  | #include "Surface.h" | 
|  |  | 
|  | #include "main.h" | 
|  | #include "Display.h" | 
|  | #include "Image.hpp" | 
|  | #include "Context.h" | 
|  | #include "common/debug.h" | 
|  | #include "Main/FrameBuffer.hpp" | 
|  |  | 
|  | #if defined(_WIN32) | 
|  | #include <tchar.h> | 
|  | #endif | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | namespace gl | 
|  | { | 
|  |  | 
|  | Surface::Surface(Display *display, NativeWindowType window) | 
|  | : mDisplay(display), mWindow(window) | 
|  | { | 
|  | frameBuffer = 0; | 
|  | backBuffer = 0; | 
|  |  | 
|  | mDepthStencil = nullptr; | 
|  | mTextureFormat = GL_NONE; | 
|  | mTextureTarget = GL_NONE; | 
|  |  | 
|  | mSwapInterval = -1; | 
|  | setSwapInterval(1); | 
|  | } | 
|  |  | 
|  | Surface::Surface(Display *display, GLint width, GLint height, GLenum textureFormat, GLenum textureType) | 
|  | : mDisplay(display), mWindow(nullptr), mWidth(width), mHeight(height) | 
|  | { | 
|  | frameBuffer = 0; | 
|  | backBuffer = 0; | 
|  |  | 
|  | mDepthStencil = nullptr; | 
|  | mWindowSubclassed = false; | 
|  | mTextureFormat = textureFormat; | 
|  | mTextureTarget = textureType; | 
|  |  | 
|  | mSwapInterval = -1; | 
|  | setSwapInterval(1); | 
|  | } | 
|  |  | 
|  | Surface::~Surface() | 
|  | { | 
|  | release(); | 
|  | } | 
|  |  | 
|  | bool Surface::initialize() | 
|  | { | 
|  | ASSERT(!frameBuffer && !backBuffer && !mDepthStencil); | 
|  |  | 
|  | return reset(); | 
|  | } | 
|  |  | 
|  | void Surface::release() | 
|  | { | 
|  | if(mDepthStencil) | 
|  | { | 
|  | mDepthStencil->release(); | 
|  | mDepthStencil = nullptr; | 
|  | } | 
|  |  | 
|  | if(backBuffer) | 
|  | { | 
|  | backBuffer->release(); | 
|  | backBuffer = 0; | 
|  | } | 
|  |  | 
|  | delete frameBuffer; | 
|  | frameBuffer = 0; | 
|  | } | 
|  |  | 
|  | bool Surface::reset() | 
|  | { | 
|  | if(!mWindow) | 
|  | { | 
|  | return reset(mWidth, mHeight); | 
|  | } | 
|  |  | 
|  | // FIXME: Wrap into an abstract Window class | 
|  | #if defined(_WIN32) | 
|  | RECT windowRect; | 
|  | GetClientRect(mWindow, &windowRect); | 
|  |  | 
|  | return reset(windowRect.right - windowRect.left, windowRect.bottom - windowRect.top); | 
|  | #else | 
|  | XWindowAttributes windowAttributes; | 
|  | XGetWindowAttributes(mDisplay->getNativeDisplay(), mWindow, &windowAttributes); | 
|  |  | 
|  | return reset(windowAttributes.width, windowAttributes.height); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | bool Surface::reset(int backBufferWidth, int backBufferHeight) | 
|  | { | 
|  | release(); | 
|  |  | 
|  | if(mWindow) | 
|  | { | 
|  | frameBuffer = ::createFrameBuffer(mDisplay->getNativeDisplay(), mWindow, backBufferWidth, backBufferHeight); | 
|  |  | 
|  | if(!frameBuffer) | 
|  | { | 
|  | ERR("Could not create frame buffer"); | 
|  | release(); | 
|  | return error(GL_OUT_OF_MEMORY, false); | 
|  | } | 
|  | } | 
|  |  | 
|  | backBuffer = new Image(0, backBufferWidth, backBufferHeight, GL_RGB, GL_UNSIGNED_BYTE); | 
|  |  | 
|  | if(!backBuffer) | 
|  | { | 
|  | ERR("Could not create back buffer"); | 
|  | release(); | 
|  | return error(GL_OUT_OF_MEMORY, false); | 
|  | } | 
|  |  | 
|  | if(true)   // Always provide a depth/stencil buffer | 
|  | { | 
|  | mDepthStencil = new Image(0, backBufferWidth, backBufferHeight, sw::FORMAT_D24S8, 1, false, true); | 
|  |  | 
|  | if(!mDepthStencil) | 
|  | { | 
|  | ERR("Could not create depth/stencil buffer for surface"); | 
|  | release(); | 
|  | return error(GL_OUT_OF_MEMORY, false); | 
|  | } | 
|  | } | 
|  |  | 
|  | mWidth = backBufferWidth; | 
|  | mHeight = backBufferHeight; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void Surface::swap() | 
|  | { | 
|  | if(backBuffer) | 
|  | { | 
|  | frameBuffer->flip(backBuffer); | 
|  |  | 
|  | checkForResize(); | 
|  | } | 
|  | } | 
|  |  | 
|  | Image *Surface::getRenderTarget() | 
|  | { | 
|  | if(backBuffer) | 
|  | { | 
|  | backBuffer->addRef(); | 
|  | } | 
|  |  | 
|  | return backBuffer; | 
|  | } | 
|  |  | 
|  | Image *Surface::getDepthStencil() | 
|  | { | 
|  | if(mDepthStencil) | 
|  | { | 
|  | mDepthStencil->addRef(); | 
|  | } | 
|  |  | 
|  | return mDepthStencil; | 
|  | } | 
|  |  | 
|  | void Surface::setSwapInterval(GLint interval) | 
|  | { | 
|  | if(mSwapInterval == interval) | 
|  | { | 
|  | return; | 
|  | } | 
|  |  | 
|  | mSwapInterval = interval; | 
|  | mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval()); | 
|  | mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval()); | 
|  | } | 
|  |  | 
|  | GLint Surface::getWidth() const | 
|  | { | 
|  | return mWidth; | 
|  | } | 
|  |  | 
|  | GLint Surface::getHeight() const | 
|  | { | 
|  | return mHeight; | 
|  | } | 
|  |  | 
|  | GLenum Surface::getTextureFormat() const | 
|  | { | 
|  | return mTextureFormat; | 
|  | } | 
|  |  | 
|  | GLenum Surface::getTextureTarget() const | 
|  | { | 
|  | return mTextureTarget; | 
|  | } | 
|  |  | 
|  | bool Surface::checkForResize() | 
|  | { | 
|  | #if defined(_WIN32) | 
|  | RECT client; | 
|  | if(!GetClientRect(mWindow, &client)) | 
|  | { | 
|  | ASSERT(false); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | int clientWidth = client.right - client.left; | 
|  | int clientHeight = client.bottom - client.top; | 
|  | #else | 
|  | XWindowAttributes windowAttributes; | 
|  | XGetWindowAttributes(mDisplay->getNativeDisplay(), mWindow, &windowAttributes); | 
|  |  | 
|  | int clientWidth = windowAttributes.width; | 
|  | int clientHeight = windowAttributes.height; | 
|  | #endif | 
|  |  | 
|  | bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); | 
|  |  | 
|  | if(sizeDirty) | 
|  | { | 
|  | reset(clientWidth, clientHeight); | 
|  |  | 
|  | if(getCurrentDrawSurface() == this) | 
|  | { | 
|  | getContext()->makeCurrent(this); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  | } |