Home | History | Annotate | Download | only in libEGL
      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