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 33 namespace gl 34 { 35 36 Surface::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 50 Surface::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 65 Surface::~Surface() 66 { 67 release(); 68 } 69 70 bool Surface::initialize() 71 { 72 ASSERT(!frameBuffer && !backBuffer && !mDepthStencil); 73 74 return reset(); 75 } 76 77 void 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 95 bool 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 116 bool 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 159 void Surface::swap() 160 { 161 if(backBuffer) 162 { 163 frameBuffer->flip(backBuffer); 164 165 checkForResize(); 166 } 167 } 168 169 Image *Surface::getRenderTarget() 170 { 171 if(backBuffer) 172 { 173 backBuffer->addRef(); 174 } 175 176 return backBuffer; 177 } 178 179 Image *Surface::getDepthStencil() 180 { 181 if(mDepthStencil) 182 { 183 mDepthStencil->addRef(); 184 } 185 186 return mDepthStencil; 187 } 188 189 void 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 201 GLint Surface::getWidth() const 202 { 203 return mWidth; 204 } 205 206 GLint Surface::getHeight() const 207 { 208 return mHeight; 209 } 210 211 GLenum Surface::getTextureFormat() const 212 { 213 return mTextureFormat; 214 } 215 216 GLenum Surface::getTextureTarget() const 217 { 218 return mTextureTarget; 219 } 220 221 bool 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