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 	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