• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
Surface()41 Surface::Surface()
42 {
43 }
44 
~Surface()45 Surface::~Surface()
46 {
47 }
48 }
49 
50 namespace egl
51 {
Surface(const Display * display,const Config * config)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 
~Surface()74 Surface::~Surface()
75 {
76 	Surface::deleteResources();
77 }
78 
initialize()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 
deleteResources()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 
getRenderTarget()150 egl::Image *Surface::getRenderTarget()
151 {
152 	if(backBuffer)
153 	{
154 		backBuffer->addRef();
155 	}
156 
157 	return backBuffer;
158 }
159 
getDepthStencil()160 egl::Image *Surface::getDepthStencil()
161 {
162 	if(depthStencil)
163 	{
164 		depthStencil->addRef();
165 	}
166 
167 	return depthStencil;
168 }
169 
setSwapBehavior(EGLenum swapBehavior)170 void Surface::setSwapBehavior(EGLenum swapBehavior)
171 {
172 	this->swapBehavior = swapBehavior;
173 }
174 
setSwapInterval(EGLint interval)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 
getConfigID() const187 EGLint Surface::getConfigID() const
188 {
189 	return config->mConfigID;
190 }
191 
getSurfaceType() const192 EGLenum Surface::getSurfaceType() const
193 {
194 	return config->mSurfaceType;
195 }
196 
getWidth() const197 EGLint Surface::getWidth() const
198 {
199 	return width;
200 }
201 
getHeight() const202 EGLint Surface::getHeight() const
203 {
204 	return height;
205 }
206 
getPixelAspectRatio() const207 EGLint Surface::getPixelAspectRatio() const
208 {
209 	return pixelAspectRatio;
210 }
211 
getRenderBuffer() const212 EGLenum Surface::getRenderBuffer() const
213 {
214 	return renderBuffer;
215 }
216 
getSwapBehavior() const217 EGLenum Surface::getSwapBehavior() const
218 {
219 	return swapBehavior;
220 }
221 
getTextureFormat() const222 EGLenum Surface::getTextureFormat() const
223 {
224 	return textureFormat;
225 }
226 
getTextureTarget() const227 EGLenum Surface::getTextureTarget() const
228 {
229 	return textureTarget;
230 }
231 
getLargestPBuffer() const232 EGLBoolean Surface::getLargestPBuffer() const
233 {
234 	return largestPBuffer;
235 }
236 
getClientBufferFormat() const237 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 
setBoundTexture(egl::Texture * texture)283 void Surface::setBoundTexture(egl::Texture *texture)
284 {
285 	this->texture = texture;
286 }
287 
getBoundTexture() const288 egl::Texture *Surface::getBoundTexture() const
289 {
290 	return texture;
291 }
292 
WindowSurface(Display * display,const Config * config,EGLNativeWindowType window)293 WindowSurface::WindowSurface(Display *display, const Config *config, EGLNativeWindowType window)
294 	: Surface(display, config), window(window)
295 {
296 	frameBuffer = nullptr;
297 }
298 
~WindowSurface()299 WindowSurface::~WindowSurface()
300 {
301 	WindowSurface::deleteResources();
302 }
303 
initialize()304 bool WindowSurface::initialize()
305 {
306 	ASSERT(!frameBuffer && !backBuffer && !depthStencil);
307 
308 	return checkForResize();
309 }
310 
swap()311 void WindowSurface::swap()
312 {
313 	if(backBuffer && frameBuffer)
314 	{
315 		frameBuffer->flip(backBuffer);
316 
317 		checkForResize();
318 	}
319 }
320 
getWindowHandle() const321 EGLNativeWindowType WindowSurface::getWindowHandle() const
322 {
323 	return window;
324 }
325 
checkForResize()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 
deleteResources()380 void WindowSurface::deleteResources()
381 {
382 	delete frameBuffer;
383 	frameBuffer = nullptr;
384 
385 	Surface::deleteResources();
386 }
387 
reset(int backBufferWidth,int backBufferHeight)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 
PBufferSurface(Display * display,const Config * config,EGLint width,EGLint height,EGLenum textureFormat,EGLenum textureTarget,EGLenum clientBufferFormat,EGLenum clientBufferType,EGLBoolean largestPBuffer,EGLClientBuffer clientBuffer,EGLint clientBufferPlane)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 
~PBufferSurface()434 PBufferSurface::~PBufferSurface()
435 {
436 	PBufferSurface::deleteResources();
437 }
438 
swap()439 void PBufferSurface::swap()
440 {
441 	// No effect
442 }
443 
getWindowHandle() const444 EGLNativeWindowType PBufferSurface::getWindowHandle() const
445 {
446 	UNREACHABLE(-1);   // Should not be called. Only WindowSurface has a window handle.
447 
448 	return 0;
449 }
450 
deleteResources()451 void PBufferSurface::deleteResources()
452 {
453 	Surface::deleteResources();
454 }
455 
456 }
457