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