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// Surface.cpp: Implements the Surface class, representing a drawing surface 16// such as the client area of a window, including any back buffers. 17 18#include "Surface.h" 19 20#include "main.h" 21#include "Display.h" 22#include "Image.hpp" 23#include "Context.h" 24#include "common/debug.h" 25#include "Main/FrameBuffer.hpp" 26 27#if defined(_WIN32) 28#include <tchar.h> 29#endif 30 31#include <algorithm> 32 33namespace gl 34{ 35 36Surface::Surface(Display *display, NativeWindowType window) 37 : mDisplay(display), mWindow(window) 38{ 39 frameBuffer = 0; 40 backBuffer = 0; 41 42 mDepthStencil = nullptr; 43 mTextureFormat = GL_NONE; 44 mTextureTarget = GL_NONE; 45 46 mSwapInterval = -1; 47 setSwapInterval(1); 48} 49 50Surface::Surface(Display *display, GLint width, GLint height, GLenum textureFormat, GLenum textureType) 51 : mDisplay(display), mWindow(nullptr), mWidth(width), mHeight(height) 52{ 53 frameBuffer = 0; 54 backBuffer = 0; 55 56 mDepthStencil = nullptr; 57 mWindowSubclassed = false; 58 mTextureFormat = textureFormat; 59 mTextureTarget = textureType; 60 61 mSwapInterval = -1; 62 setSwapInterval(1); 63} 64 65Surface::~Surface() 66{ 67 release(); 68} 69 70bool Surface::initialize() 71{ 72 ASSERT(!frameBuffer && !backBuffer && !mDepthStencil); 73 74 return reset(); 75} 76 77void Surface::release() 78{ 79 if(mDepthStencil) 80 { 81 mDepthStencil->release(); 82 mDepthStencil = nullptr; 83 } 84 85 if(backBuffer) 86 { 87 backBuffer->release(); 88 backBuffer = 0; 89 } 90 91 delete frameBuffer; 92 frameBuffer = 0; 93} 94 95bool Surface::reset() 96{ 97 if(!mWindow) 98 { 99 return reset(mWidth, mHeight); 100 } 101 102 // FIXME: Wrap into an abstract Window class 103 #if defined(_WIN32) 104 RECT windowRect; 105 GetClientRect(mWindow, &windowRect); 106 107 return reset(windowRect.right - windowRect.left, windowRect.bottom - windowRect.top); 108 #else 109 XWindowAttributes windowAttributes; 110 XGetWindowAttributes(mDisplay->getNativeDisplay(), mWindow, &windowAttributes); 111 112 return reset(windowAttributes.width, windowAttributes.height); 113 #endif 114} 115 116bool Surface::reset(int backBufferWidth, int backBufferHeight) 117{ 118 release(); 119 120 if(mWindow) 121 { 122 frameBuffer = ::createFrameBuffer(mDisplay->getNativeDisplay(), mWindow, backBufferWidth, backBufferHeight); 123 124 if(!frameBuffer) 125 { 126 ERR("Could not create frame buffer"); 127 release(); 128 return error(GL_OUT_OF_MEMORY, false); 129 } 130 } 131 132 backBuffer = new Image(0, backBufferWidth, backBufferHeight, GL_RGB, GL_UNSIGNED_BYTE); 133 134 if(!backBuffer) 135 { 136 ERR("Could not create back buffer"); 137 release(); 138 return error(GL_OUT_OF_MEMORY, false); 139 } 140 141 if(true) // Always provide a depth/stencil buffer 142 { 143 mDepthStencil = new Image(0, backBufferWidth, backBufferHeight, sw::FORMAT_D24S8, 1, false, true); 144 145 if(!mDepthStencil) 146 { 147 ERR("Could not create depth/stencil buffer for surface"); 148 release(); 149 return error(GL_OUT_OF_MEMORY, false); 150 } 151 } 152 153 mWidth = backBufferWidth; 154 mHeight = backBufferHeight; 155 156 return true; 157} 158 159void Surface::swap() 160{ 161 if(backBuffer) 162 { 163 frameBuffer->flip(backBuffer); 164 165 checkForResize(); 166 } 167} 168 169Image *Surface::getRenderTarget() 170{ 171 if(backBuffer) 172 { 173 backBuffer->addRef(); 174 } 175 176 return backBuffer; 177} 178 179Image *Surface::getDepthStencil() 180{ 181 if(mDepthStencil) 182 { 183 mDepthStencil->addRef(); 184 } 185 186 return mDepthStencil; 187} 188 189void Surface::setSwapInterval(GLint interval) 190{ 191 if(mSwapInterval == interval) 192 { 193 return; 194 } 195 196 mSwapInterval = interval; 197 mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval()); 198 mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval()); 199} 200 201GLint Surface::getWidth() const 202{ 203 return mWidth; 204} 205 206GLint Surface::getHeight() const 207{ 208 return mHeight; 209} 210 211GLenum Surface::getTextureFormat() const 212{ 213 return mTextureFormat; 214} 215 216GLenum Surface::getTextureTarget() const 217{ 218 return mTextureTarget; 219} 220 221bool Surface::checkForResize() 222{ 223 #if defined(_WIN32) 224 RECT client; 225 if(!GetClientRect(mWindow, &client)) 226 { 227 ASSERT(false); 228 return false; 229 } 230 231 int clientWidth = client.right - client.left; 232 int clientHeight = client.bottom - client.top; 233 #else 234 XWindowAttributes windowAttributes; 235 XGetWindowAttributes(mDisplay->getNativeDisplay(), mWindow, &windowAttributes); 236 237 int clientWidth = windowAttributes.width; 238 int clientHeight = windowAttributes.height; 239 #endif 240 241 bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); 242 243 if(sizeDirty) 244 { 245 reset(clientWidth, clientHeight); 246 247 if(getCurrentDrawSurface() == this) 248 { 249 getContext()->makeCurrent(this); 250 } 251 252 return true; 253 } 254 255 return false; 256} 257} 258