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 clientBufferFormat = EGL_NO_TEXTURE; 67 clientBufferType = EGL_NO_TEXTURE; 68 clientBuffer = nullptr; 69 clientBufferPlane = -1; 70 swapInterval = -1; 71 setSwapInterval(1); 72 } 73 74 Surface::~Surface() 75 { 76 Surface::deleteResources(); 77 } 78 79 bool Surface::initialize() 80 { 81 ASSERT(!backBuffer && !depthStencil); 82 83 if(libGLESv2) 84 { 85 if(clientBuffer) 86 { 87 backBuffer = libGLESv2->createBackBufferFromClientBuffer( 88 egl::ClientBuffer(width, height, getClientBufferFormat(), clientBuffer, clientBufferPlane)); 89 } 90 else 91 { 92 backBuffer = libGLESv2->createBackBuffer(width, height, config->mRenderTargetFormat, config->mSamples); 93 } 94 } 95 else if(libGLES_CM) 96 { 97 backBuffer = libGLES_CM->createBackBuffer(width, height, config->mRenderTargetFormat, config->mSamples); 98 } 99 100 if(!backBuffer) 101 { 102 ERR("Could not create back buffer"); 103 deleteResources(); 104 return error(EGL_BAD_ALLOC, false); 105 } 106 107 if(config->mDepthStencilFormat != sw::FORMAT_NULL) 108 { 109 if(libGLESv2) 110 { 111 depthStencil = libGLESv2->createDepthStencil(width, height, config->mDepthStencilFormat, config->mSamples); 112 } 113 else if(libGLES_CM) 114 { 115 depthStencil = libGLES_CM->createDepthStencil(width, height, config->mDepthStencilFormat, config->mSamples); 116 } 117 118 if(!depthStencil) 119 { 120 ERR("Could not create depth/stencil buffer for surface"); 121 deleteResources(); 122 return error(EGL_BAD_ALLOC, false); 123 } 124 } 125 126 return true; 127 } 128 129 void Surface::deleteResources() 130 { 131 if(depthStencil) 132 { 133 depthStencil->release(); 134 depthStencil = nullptr; 135 } 136 137 if(texture) 138 { 139 texture->releaseTexImage(); 140 texture = nullptr; 141 } 142 143 if(backBuffer) 144 { 145 backBuffer->release(); 146 backBuffer = nullptr; 147 } 148 } 149 150 egl::Image *Surface::getRenderTarget() 151 { 152 if(backBuffer) 153 { 154 backBuffer->addRef(); 155 } 156 157 return backBuffer; 158 } 159 160 egl::Image *Surface::getDepthStencil() 161 { 162 if(depthStencil) 163 { 164 depthStencil->addRef(); 165 } 166 167 return depthStencil; 168 } 169 170 void Surface::setSwapBehavior(EGLenum swapBehavior) 171 { 172 this->swapBehavior = swapBehavior; 173 } 174 175 void Surface::setSwapInterval(EGLint interval) 176 { 177 if(swapInterval == interval) 178 { 179 return; 180 } 181 182 swapInterval = interval; 183 swapInterval = std::max(swapInterval, display->getMinSwapInterval()); 184 swapInterval = std::min(swapInterval, display->getMaxSwapInterval()); 185 } 186 187 EGLint Surface::getConfigID() const 188 { 189 return config->mConfigID; 190 } 191 192 EGLenum Surface::getSurfaceType() const 193 { 194 return config->mSurfaceType; 195 } 196 197 EGLint Surface::getWidth() const 198 { 199 return width; 200 } 201 202 EGLint Surface::getHeight() const 203 { 204 return height; 205 } 206 207 EGLint Surface::getPixelAspectRatio() const 208 { 209 return pixelAspectRatio; 210 } 211 212 EGLenum Surface::getRenderBuffer() const 213 { 214 return renderBuffer; 215 } 216 217 EGLenum Surface::getSwapBehavior() const 218 { 219 return swapBehavior; 220 } 221 222 EGLenum Surface::getTextureFormat() const 223 { 224 return textureFormat; 225 } 226 227 EGLenum Surface::getTextureTarget() const 228 { 229 return textureTarget; 230 } 231 232 EGLBoolean Surface::getLargestPBuffer() const 233 { 234 return largestPBuffer; 235 } 236 237 sw::Format Surface::getClientBufferFormat() const 238 { 239 switch(clientBufferType) 240 { 241 case GL_UNSIGNED_BYTE: 242 switch(clientBufferFormat) 243 { 244 case GL_RED: 245 return sw::FORMAT_R8; 246 case GL_RG: 247 return sw::FORMAT_G8R8; 248 case GL_BGRA_EXT: 249 return sw::FORMAT_A8R8G8B8; 250 default: 251 UNREACHABLE(clientBufferFormat); 252 break; 253 } 254 break; 255 case GL_UNSIGNED_SHORT: 256 switch(clientBufferFormat) 257 { 258 case GL_R16UI: 259 return sw::FORMAT_R16UI; 260 default: 261 UNREACHABLE(clientBufferFormat); 262 break; 263 } 264 break; 265 case GL_HALF_FLOAT_OES: 266 case GL_HALF_FLOAT: 267 switch(clientBufferFormat) 268 { 269 case GL_RGBA: 270 return sw::FORMAT_A16B16G16R16F; 271 default: 272 UNREACHABLE(clientBufferFormat); 273 break; 274 } 275 default: 276 UNREACHABLE(clientBufferType); 277 break; 278 } 279 280 return sw::FORMAT_NULL; 281 } 282 283 void Surface::setBoundTexture(egl::Texture *texture) 284 { 285 this->texture = texture; 286 } 287 288 egl::Texture *Surface::getBoundTexture() const 289 { 290 return texture; 291 } 292 293 WindowSurface::WindowSurface(Display *display, const Config *config, EGLNativeWindowType window) 294 : Surface(display, config), window(window) 295 { 296 frameBuffer = nullptr; 297 } 298 299 WindowSurface::~WindowSurface() 300 { 301 WindowSurface::deleteResources(); 302 } 303 304 bool WindowSurface::initialize() 305 { 306 ASSERT(!frameBuffer && !backBuffer && !depthStencil); 307 308 return checkForResize(); 309 } 310 311 void WindowSurface::swap() 312 { 313 if(backBuffer && frameBuffer) 314 { 315 frameBuffer->flip(backBuffer); 316 317 checkForResize(); 318 } 319 } 320 321 EGLNativeWindowType WindowSurface::getWindowHandle() const 322 { 323 return window; 324 } 325 326 bool WindowSurface::checkForResize() 327 { 328 #if defined(_WIN32) 329 RECT client; 330 BOOL status = GetClientRect(window, &client); 331 332 if(status == 0) 333 { 334 return error(EGL_BAD_NATIVE_WINDOW, false); 335 } 336 337 int windowWidth = client.right - client.left; 338 int windowHeight = client.bottom - client.top; 339 #elif defined(__ANDROID__) 340 int windowWidth; window->query(window, NATIVE_WINDOW_WIDTH, &windowWidth); 341 int windowHeight; window->query(window, NATIVE_WINDOW_HEIGHT, &windowHeight); 342 #elif defined(__linux__) 343 XWindowAttributes windowAttributes; 344 Status status = libX11->XGetWindowAttributes((::Display*)display->getNativeDisplay(), window, &windowAttributes); 345 346 if(status == 0) 347 { 348 return error(EGL_BAD_NATIVE_WINDOW, false); 349 } 350 351 int windowWidth = windowAttributes.width; 352 int windowHeight = windowAttributes.height; 353 #elif defined(__APPLE__) 354 int windowWidth; 355 int windowHeight; 356 sw::OSX::GetNativeWindowSize(window, windowWidth, windowHeight); 357 #elif defined(__Fuchsia__) 358 // TODO(crbug.com/800951): Integrate with Mozart. 359 int windowWidth = 100; 360 int windowHeight = 100; 361 #else 362 #error "WindowSurface::checkForResize unimplemented for this platform" 363 #endif 364 365 if((windowWidth != width) || (windowHeight != height)) 366 { 367 bool success = reset(windowWidth, windowHeight); 368 369 if(getCurrentDrawSurface() == this) 370 { 371 getCurrentContext()->makeCurrent(this); 372 } 373 374 return success; 375 } 376 377 return true; // Success 378 } 379 380 void WindowSurface::deleteResources() 381 { 382 delete frameBuffer; 383 frameBuffer = nullptr; 384 385 Surface::deleteResources(); 386 } 387 388 bool WindowSurface::reset(int backBufferWidth, int backBufferHeight) 389 { 390 width = backBufferWidth; 391 height = backBufferHeight; 392 393 deleteResources(); 394 395 if(window) 396 { 397 if(libGLESv2) 398 { 399 frameBuffer = libGLESv2->createFrameBuffer(display->getNativeDisplay(), window, width, height); 400 } 401 else if(libGLES_CM) 402 { 403 frameBuffer = libGLES_CM->createFrameBuffer(display->getNativeDisplay(), window, width, height); 404 } 405 406 if(!frameBuffer) 407 { 408 ERR("Could not create frame buffer"); 409 deleteResources(); 410 return error(EGL_BAD_ALLOC, false); 411 } 412 } 413 414 return Surface::initialize(); 415 } 416 417 PBufferSurface::PBufferSurface(Display *display, const Config *config, EGLint width, EGLint height, 418 EGLenum textureFormat, EGLenum textureTarget, EGLenum clientBufferFormat, 419 EGLenum clientBufferType, EGLBoolean largestPBuffer, EGLClientBuffer clientBuffer, 420 EGLint clientBufferPlane) 421 : Surface(display, config) 422 { 423 this->width = width; 424 this->height = height; 425 this->largestPBuffer = largestPBuffer; 426 this->textureFormat = textureFormat; 427 this->textureTarget = textureTarget; 428 this->clientBufferFormat = clientBufferFormat; 429 this->clientBufferType = clientBufferType; 430 this->clientBuffer = clientBuffer; 431 this->clientBufferPlane = clientBufferPlane; 432 } 433 434 PBufferSurface::~PBufferSurface() 435 { 436 PBufferSurface::deleteResources(); 437 } 438 439 void PBufferSurface::swap() 440 { 441 // No effect 442 } 443 444 EGLNativeWindowType PBufferSurface::getWindowHandle() const 445 { 446 UNREACHABLE(-1); // Should not be called. Only WindowSurface has a window handle. 447 448 return 0; 449 } 450 451 void PBufferSurface::deleteResources() 452 { 453 Surface::deleteResources(); 454 } 455 456 } 457