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 
39 namespace egl
40 {
41 
Surface(const Display * display,const Config * config)42 Surface::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 
~Surface()60 Surface::~Surface()
61 {
62 	Surface::deleteResources();
63 }
64 
initialize()65 bool 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 
deleteResources()107 void 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 
getRenderTarget()128 egl::Image *Surface::getRenderTarget()
129 {
130 	if(backBuffer)
131 	{
132 		backBuffer->addRef();
133 	}
134 
135 	return backBuffer;
136 }
137 
getDepthStencil()138 egl::Image *Surface::getDepthStencil()
139 {
140 	if(depthStencil)
141 	{
142 		depthStencil->addRef();
143 	}
144 
145 	return depthStencil;
146 }
147 
setSwapBehavior(EGLenum swapBehavior)148 void Surface::setSwapBehavior(EGLenum swapBehavior)
149 {
150 	this->swapBehavior = swapBehavior;
151 }
152 
setSwapInterval(EGLint interval)153 void 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 
getConfigID() const165 EGLint Surface::getConfigID() const
166 {
167 	return config->mConfigID;
168 }
169 
getSurfaceType() const170 EGLenum Surface::getSurfaceType() const
171 {
172 	return config->mSurfaceType;
173 }
174 
getInternalFormat() const175 sw::Format Surface::getInternalFormat() const
176 {
177 	return config->mRenderTargetFormat;
178 }
179 
getWidth() const180 EGLint Surface::getWidth() const
181 {
182 	return width;
183 }
184 
getHeight() const185 EGLint Surface::getHeight() const
186 {
187 	return height;
188 }
189 
getPixelAspectRatio() const190 EGLint Surface::getPixelAspectRatio() const
191 {
192 	return pixelAspectRatio;
193 }
194 
getRenderBuffer() const195 EGLenum Surface::getRenderBuffer() const
196 {
197 	return renderBuffer;
198 }
199 
getSwapBehavior() const200 EGLenum Surface::getSwapBehavior() const
201 {
202 	return swapBehavior;
203 }
204 
getTextureFormat() const205 EGLenum Surface::getTextureFormat() const
206 {
207 	return textureFormat;
208 }
209 
getTextureTarget() const210 EGLenum Surface::getTextureTarget() const
211 {
212 	return textureTarget;
213 }
214 
getLargestPBuffer() const215 EGLBoolean Surface::getLargestPBuffer() const
216 {
217 	return largestPBuffer;
218 }
219 
setBoundTexture(egl::Texture * texture)220 void Surface::setBoundTexture(egl::Texture *texture)
221 {
222 	this->texture = texture;
223 }
224 
getBoundTexture() const225 egl::Texture *Surface::getBoundTexture() const
226 {
227 	return texture;
228 }
229 
WindowSurface(Display * display,const Config * config,EGLNativeWindowType window)230 WindowSurface::WindowSurface(Display *display, const Config *config, EGLNativeWindowType window)
231 	: Surface(display, config), window(window)
232 {
233 	frameBuffer = nullptr;
234 }
235 
~WindowSurface()236 WindowSurface::~WindowSurface()
237 {
238 	WindowSurface::deleteResources();
239 }
240 
initialize()241 bool WindowSurface::initialize()
242 {
243 	ASSERT(!frameBuffer && !backBuffer && !depthStencil);
244 
245 	return checkForResize();
246 }
247 
swap()248 void 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 
getWindowHandle() const260 EGLNativeWindowType WindowSurface::getWindowHandle() const
261 {
262 	return window;
263 }
264 
checkForResize()265 bool 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 
deleteResources()309 void WindowSurface::deleteResources()
310 {
311 	delete frameBuffer;
312 	frameBuffer = nullptr;
313 
314 	Surface::deleteResources();
315 }
316 
reset(int backBufferWidth,int backBufferHeight)317 bool 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 
PBufferSurface(Display * display,const Config * config,EGLint width,EGLint height,EGLenum textureFormat,EGLenum textureType,EGLBoolean largestPBuffer)346 PBufferSurface::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 
~PBufferSurface()354 PBufferSurface::~PBufferSurface()
355 {
356 	PBufferSurface::deleteResources();
357 }
358 
swap()359 void PBufferSurface::swap()
360 {
361 	// No effect
362 }
363 
getWindowHandle() const364 EGLNativeWindowType PBufferSurface::getWindowHandle() const
365 {
366 	UNREACHABLE(-1);   // Should not be called. Only WindowSurface has a window handle.
367 
368 	return 0;
369 }
370 
deleteResources()371 void PBufferSurface::deleteResources()
372 {
373 	Surface::deleteResources();
374 }
375 
376 }
377