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