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 egl::Surface class, representing a drawing surface 16 // such as the client area of a window, including any back buffers. 17 // Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3. 18 19 #include "Surface.hpp" 20 21 #include "main.h" 22 #include "Display.h" 23 #include "Texture.hpp" 24 #include "common/Image.hpp" 25 #include "Context.hpp" 26 #include "common/debug.h" 27 #include "Main/FrameBuffer.hpp" 28 29 #if defined(__linux__) && !defined(__ANDROID__) 30 #include "Main/libX11.hpp" 31 #elif defined(_WIN32) 32 #include <tchar.h> 33 #elif defined(__APPLE__) 34 #include "OSXUtils.hpp" 35 #endif 36 37 #include <algorithm> 38 39 namespace gl 40 { 41 Surface::Surface() 42 { 43 } 44 45 Surface::~Surface() 46 { 47 } 48 } 49 50 namespace egl 51 { 52 Surface::Surface(const Display *display, const Config *config) : display(display), config(config) 53 { 54 backBuffer = nullptr; 55 depthStencil = nullptr; 56 texture = nullptr; 57 58 width = 0; 59 height = 0; 60 largestPBuffer = EGL_FALSE; 61 pixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio 62 renderBuffer = EGL_BACK_BUFFER; 63 swapBehavior = EGL_BUFFER_PRESERVED; 64 textureFormat = EGL_NO_TEXTURE; 65 textureTarget = EGL_NO_TEXTURE; 66 swapInterval = -1; 67 setSwapInterval(1); 68 } 69 70 Surface::~Surface() 71 { 72 Surface::deleteResources(); 73 } 74 75 bool Surface::initialize() 76 { 77 ASSERT(!backBuffer && !depthStencil); 78 79 if(libGLES_CM) 80 { 81 backBuffer = libGLES_CM->createBackBuffer(width, height, config->mRenderTargetFormat, config->mSamples); 82 } 83 else if(libGLESv2) 84 { 85 backBuffer = libGLESv2->createBackBuffer(width, height, config->mRenderTargetFormat, config->mSamples); 86 } 87 88 if(!backBuffer) 89 { 90 ERR("Could not create back buffer"); 91 deleteResources(); 92 return error(EGL_BAD_ALLOC, false); 93 } 94 95 if(config->mDepthStencilFormat != sw::FORMAT_NULL) 96 { 97 if(libGLES_CM) 98 { 99 depthStencil = libGLES_CM->createDepthStencil(width, height, config->mDepthStencilFormat, config->mSamples); 100 } 101 else if(libGLESv2) 102 { 103 depthStencil = libGLESv2->createDepthStencil(width, height, config->mDepthStencilFormat, config->mSamples); 104 } 105 106 if(!depthStencil) 107 { 108 ERR("Could not create depth/stencil buffer for surface"); 109 deleteResources(); 110 return error(EGL_BAD_ALLOC, false); 111 } 112 } 113 114 return true; 115 } 116 117 void Surface::deleteResources() 118 { 119 if(depthStencil) 120 { 121 depthStencil->release(); 122 depthStencil = nullptr; 123 } 124 125 if(texture) 126 { 127 texture->releaseTexImage(); 128 texture = nullptr; 129 } 130 131 if(backBuffer) 132 { 133 backBuffer->release(); 134 backBuffer = nullptr; 135 } 136 } 137 138 egl::Image *Surface::getRenderTarget() 139 { 140 if(backBuffer) 141 { 142 backBuffer->addRef(); 143 } 144 145 return backBuffer; 146 } 147 148 egl::Image *Surface::getDepthStencil() 149 { 150 if(depthStencil) 151 { 152 depthStencil->addRef(); 153 } 154 155 return depthStencil; 156 } 157 158 void Surface::setSwapBehavior(EGLenum swapBehavior) 159 { 160 this->swapBehavior = swapBehavior; 161 } 162 163 void Surface::setSwapInterval(EGLint interval) 164 { 165 if(swapInterval == interval) 166 { 167 return; 168 } 169 170 swapInterval = interval; 171 swapInterval = std::max(swapInterval, display->getMinSwapInterval()); 172 swapInterval = std::min(swapInterval, display->getMaxSwapInterval()); 173 } 174 175 EGLint Surface::getConfigID() const 176 { 177 return config->mConfigID; 178 } 179 180 EGLenum Surface::getSurfaceType() const 181 { 182 return config->mSurfaceType; 183 } 184 185 sw::Format Surface::getInternalFormat() const 186 { 187 return config->mRenderTargetFormat; 188 } 189 190 EGLint Surface::getWidth() const 191 { 192 return width; 193 } 194 195 EGLint Surface::getHeight() const 196 { 197 return height; 198 } 199 200 EGLint Surface::getPixelAspectRatio() const 201 { 202 return pixelAspectRatio; 203 } 204 205 EGLenum Surface::getRenderBuffer() const 206 { 207 return renderBuffer; 208 } 209 210 EGLenum Surface::getSwapBehavior() const 211 { 212 return swapBehavior; 213 } 214 215 EGLenum Surface::getTextureFormat() const 216 { 217 return textureFormat; 218 } 219 220 EGLenum Surface::getTextureTarget() const 221 { 222 return textureTarget; 223 } 224 225 EGLBoolean Surface::getLargestPBuffer() const 226 { 227 return largestPBuffer; 228 } 229 230 void Surface::setBoundTexture(egl::Texture *texture) 231 { 232 this->texture = texture; 233 } 234 235 egl::Texture *Surface::getBoundTexture() const 236 { 237 return texture; 238 } 239 240 WindowSurface::WindowSurface(Display *display, const Config *config, EGLNativeWindowType window) 241 : Surface(display, config), window(window) 242 { 243 frameBuffer = nullptr; 244 } 245 246 WindowSurface::~WindowSurface() 247 { 248 WindowSurface::deleteResources(); 249 } 250 251 bool WindowSurface::initialize() 252 { 253 ASSERT(!frameBuffer && !backBuffer && !depthStencil); 254 255 return checkForResize(); 256 } 257 258 void WindowSurface::swap() 259 { 260 if(backBuffer && frameBuffer) 261 { 262 void *source = backBuffer->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC); 263 frameBuffer->flip(source, backBuffer->sw::Surface::getInternalFormat(), backBuffer->getInternalPitchB()); 264 backBuffer->unlockInternal(); 265 266 checkForResize(); 267 } 268 } 269 270 EGLNativeWindowType WindowSurface::getWindowHandle() const 271 { 272 return window; 273 } 274 275 bool WindowSurface::checkForResize() 276 { 277 #if defined(_WIN32) 278 RECT client; 279 if(!GetClientRect(window, &client)) 280 { 281 ASSERT(false); 282 return false; 283 } 284 285 int windowWidth = client.right - client.left; 286 int windowHeight = client.bottom - client.top; 287 #elif defined(__ANDROID__) 288 int windowWidth; window->query(window, NATIVE_WINDOW_WIDTH, &windowWidth); 289 int windowHeight; window->query(window, NATIVE_WINDOW_HEIGHT, &windowHeight); 290 #elif defined(__linux__) 291 XWindowAttributes windowAttributes; 292 libX11->XGetWindowAttributes((::Display*)display->getNativeDisplay(), window, &windowAttributes); 293 294 int windowWidth = windowAttributes.width; 295 int windowHeight = windowAttributes.height; 296 #elif defined(__APPLE__) 297 int windowWidth; 298 int windowHeight; 299 sw::OSX::GetNativeWindowSize(window, windowWidth, windowHeight); 300 #else 301 #error "WindowSurface::checkForResize unimplemented for this platform" 302 #endif 303 304 if((windowWidth != width) || (windowHeight != height)) 305 { 306 bool success = reset(windowWidth, windowHeight); 307 308 if(getCurrentDrawSurface() == this) 309 { 310 getCurrentContext()->makeCurrent(this); 311 } 312 313 return success; 314 } 315 316 return true; // Success 317 } 318 319 void WindowSurface::deleteResources() 320 { 321 delete frameBuffer; 322 frameBuffer = nullptr; 323 324 Surface::deleteResources(); 325 } 326 327 bool WindowSurface::reset(int backBufferWidth, int backBufferHeight) 328 { 329 width = backBufferWidth; 330 height = backBufferHeight; 331 332 deleteResources(); 333 334 if(window) 335 { 336 if(libGLES_CM) 337 { 338 frameBuffer = libGLES_CM->createFrameBuffer(display->getNativeDisplay(), window, width, height); 339 } 340 else if(libGLESv2) 341 { 342 frameBuffer = libGLESv2->createFrameBuffer(display->getNativeDisplay(), window, width, height); 343 } 344 345 if(!frameBuffer) 346 { 347 ERR("Could not create frame buffer"); 348 deleteResources(); 349 return error(EGL_BAD_ALLOC, false); 350 } 351 } 352 353 return Surface::initialize(); 354 } 355 356 PBufferSurface::PBufferSurface(Display *display, const Config *config, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType, EGLBoolean largestPBuffer) 357 : Surface(display, config) 358 { 359 this->width = width; 360 this->height = height; 361 this->largestPBuffer = largestPBuffer; 362 } 363 364 PBufferSurface::~PBufferSurface() 365 { 366 PBufferSurface::deleteResources(); 367 } 368 369 void PBufferSurface::swap() 370 { 371 // No effect 372 } 373 374 EGLNativeWindowType PBufferSurface::getWindowHandle() const 375 { 376 UNREACHABLE(-1); // Should not be called. Only WindowSurface has a window handle. 377 378 return 0; 379 } 380 381 void PBufferSurface::deleteResources() 382 { 383 Surface::deleteResources(); 384 } 385 386 } 387