• 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 "Context.hpp"
22 #include "Display.h"
23 #include "Main/FrameBuffer.hpp"
24 #include "Texture.hpp"
25 #include "common/Image.hpp"
26 #include "common/debug.h"
27 #include "main.h"
28 
29 #if defined(SWIFTSHADER_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 
81 	if(!backBuffer)
82 	{
83 		ERR("Could not create back buffer");
84 		deleteResources();
85 		return error(EGL_BAD_ALLOC, false);
86 	}
87 
88 	if(config->mDepthStencilFormat != sw::FORMAT_NULL)
89 	{
90 		if(libGLESv2)
91 		{
92 			depthStencil = libGLESv2->createDepthStencil(width, height, config->mDepthStencilFormat, config->mSamples);
93 		}
94 
95 		if(!depthStencil)
96 		{
97 			ERR("Could not create depth/stencil buffer for surface");
98 			deleteResources();
99 			return error(EGL_BAD_ALLOC, false);
100 		}
101 	}
102 
103 	return true;
104 }
105 
deleteResources()106 void Surface::deleteResources()
107 {
108 	if(depthStencil)
109 	{
110 		depthStencil->release();
111 		depthStencil = nullptr;
112 	}
113 
114 	if(texture)
115 	{
116 		texture->releaseTexImage();
117 		texture = nullptr;
118 	}
119 
120 	if(backBuffer)
121 	{
122 		backBuffer->release();
123 		backBuffer = nullptr;
124 	}
125 }
126 
getRenderTarget()127 egl::Image *Surface::getRenderTarget()
128 {
129 	if(backBuffer)
130 	{
131 		backBuffer->addRef();
132 	}
133 
134 	return backBuffer;
135 }
136 
getDepthStencil()137 egl::Image *Surface::getDepthStencil()
138 {
139 	if(depthStencil)
140 	{
141 		depthStencil->addRef();
142 	}
143 
144 	return depthStencil;
145 }
146 
setMipmapLevel(EGLint mipmapLevel)147 void Surface::setMipmapLevel(EGLint mipmapLevel)
148 {
149 	this->mipmapLevel = mipmapLevel;
150 }
151 
setMultisampleResolve(EGLenum multisampleResolve)152 void Surface::setMultisampleResolve(EGLenum multisampleResolve)
153 {
154 	this->multisampleResolve = multisampleResolve;
155 }
156 
setSwapBehavior(EGLenum swapBehavior)157 void Surface::setSwapBehavior(EGLenum swapBehavior)
158 {
159 	this->swapBehavior = swapBehavior;
160 }
161 
setSwapInterval(EGLint interval)162 void Surface::setSwapInterval(EGLint interval)
163 {
164 	if(swapInterval == interval)
165 	{
166 		return;
167 	}
168 
169 	swapInterval = interval;
170 	swapInterval = std::max(swapInterval, display->getMinSwapInterval());
171 	swapInterval = std::min(swapInterval, display->getMaxSwapInterval());
172 }
173 
getConfigID() const174 EGLint Surface::getConfigID() const
175 {
176 	return config->mConfigID;
177 }
178 
getSurfaceType() const179 EGLenum Surface::getSurfaceType() const
180 {
181 	return config->mSurfaceType;
182 }
183 
getWidth() const184 EGLint Surface::getWidth() const
185 {
186 	return width;
187 }
188 
getHeight() const189 EGLint Surface::getHeight() const
190 {
191 	return height;
192 }
193 
getMipmapLevel() const194 EGLint Surface::getMipmapLevel() const
195 {
196 	return mipmapLevel;
197 }
198 
getMultisampleResolve() const199 EGLenum Surface::getMultisampleResolve() const
200 {
201 	return multisampleResolve;
202 }
203 
getPixelAspectRatio() const204 EGLint Surface::getPixelAspectRatio() const
205 {
206 	return pixelAspectRatio;
207 }
208 
getRenderBuffer() const209 EGLenum Surface::getRenderBuffer() const
210 {
211 	return renderBuffer;
212 }
213 
getSwapBehavior() const214 EGLenum Surface::getSwapBehavior() const
215 {
216 	return swapBehavior;
217 }
218 
getTextureFormat() const219 EGLenum Surface::getTextureFormat() const
220 {
221 	return textureFormat;
222 }
223 
getTextureTarget() const224 EGLenum Surface::getTextureTarget() const
225 {
226 	return textureTarget;
227 }
228 
getLargestPBuffer() const229 EGLBoolean Surface::getLargestPBuffer() const
230 {
231 	return largestPBuffer;
232 }
233 
getClientBufferFormat() const234 sw::Format Surface::getClientBufferFormat() const
235 {
236 	switch(clientBufferType)
237 	{
238 	case GL_UNSIGNED_BYTE:
239 		switch(clientBufferFormat)
240 		{
241 		case GL_RED:
242 			return sw::FORMAT_R8;
243 		case GL_RG:
244 			return sw::FORMAT_G8R8;
245 		case GL_RGB:
246 			return sw::FORMAT_X8R8G8B8;
247 		case GL_BGRA_EXT:
248 			return sw::FORMAT_A8R8G8B8;
249 		default:
250 			UNREACHABLE(clientBufferFormat);
251 			break;
252 		}
253 		break;
254 	case GL_UNSIGNED_SHORT:
255 		switch(clientBufferFormat)
256 		{
257 		case GL_R16UI:
258 			return sw::FORMAT_R16UI;
259 		default:
260 			UNREACHABLE(clientBufferFormat);
261 			break;
262 		}
263 		break;
264 	case GL_HALF_FLOAT_OES:
265 	case GL_HALF_FLOAT:
266 		switch(clientBufferFormat)
267 		{
268 		case GL_RGBA:
269 			return sw::FORMAT_A16B16G16R16F;
270 		default:
271 			UNREACHABLE(clientBufferFormat);
272 			break;
273 		}
274 	default:
275 		UNREACHABLE(clientBufferType);
276 		break;
277 	}
278 
279 	return sw::FORMAT_NULL;
280 }
281 
setBoundTexture(egl::Texture * texture)282 void Surface::setBoundTexture(egl::Texture *texture)
283 {
284 	this->texture = texture;
285 }
286 
getBoundTexture() const287 egl::Texture *Surface::getBoundTexture() const
288 {
289 	return texture;
290 }
291 
WindowSurface(Display * display,const Config * config,EGLNativeWindowType window)292 WindowSurface::WindowSurface(Display *display, const Config *config, EGLNativeWindowType window)
293 	: Surface(display, config), window(window)
294 {
295 	pixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING);   // FIXME: Determine actual pixel aspect ratio
296 }
297 
~WindowSurface()298 WindowSurface::~WindowSurface()
299 {
300 	WindowSurface::deleteResources();
301 }
302 
initialize()303 bool WindowSurface::initialize()
304 {
305 	ASSERT(!frameBuffer && !backBuffer && !depthStencil);
306 
307 	return checkForResize();
308 }
309 
swap()310 void WindowSurface::swap()
311 {
312 	if(backBuffer && frameBuffer)
313 	{
314 		frameBuffer->flip(backBuffer);
315 
316 		checkForResize();
317 	}
318 }
319 
getWindowHandle() const320 EGLNativeWindowType WindowSurface::getWindowHandle() const
321 {
322 	return window;
323 }
324 
checkForResize()325 bool WindowSurface::checkForResize()
326 {
327 	#if defined(_WIN32)
328 		RECT client;
329 		BOOL status = GetClientRect(window, &client);
330 
331 		if(status == 0)
332 		{
333 			return error(EGL_BAD_NATIVE_WINDOW, false);
334 		}
335 
336 		int windowWidth = client.right - client.left;
337 		int windowHeight = client.bottom - client.top;
338 	#elif defined(__ANDROID__)
339 		int windowWidth = ANativeWindow_getWidth(window);
340 		int windowHeight = ANativeWindow_getHeight(window);
341 	#elif defined(SWIFTSHADER_USE_X11)
342 		XWindowAttributes windowAttributes;
343 		Status status = libX11->XGetWindowAttributes((::Display*)display->getNativeDisplay(), window, &windowAttributes);
344 
345 		if(status == 0)
346 		{
347 			return error(EGL_BAD_NATIVE_WINDOW, false);
348 		}
349 
350 		int windowWidth = windowAttributes.width;
351 		int windowHeight = windowAttributes.height;
352 	#elif defined(__linux__)
353 		// Non X11 linux is headless only
354 		int windowWidth = 100;
355 		int windowHeight = 100;
356 	#elif defined(__APPLE__)
357 		int windowWidth;
358 		int windowHeight;
359 		sw::OSX::GetNativeWindowSize(window, windowWidth, windowHeight);
360 	#elif defined(__Fuchsia__)
361 		// TODO(crbug.com/800951): Integrate with Mozart.
362 		int windowWidth = 100;
363 		int windowHeight = 100;
364 	#else
365 		#error "WindowSurface::checkForResize unimplemented for this platform"
366 	#endif
367 
368 	if((windowWidth != width) || (windowHeight != height))
369 	{
370 		bool success = reset(windowWidth, windowHeight);
371 
372 		if(getCurrentDrawSurface() == this)
373 		{
374 			getCurrentContext()->makeCurrent(this);
375 		}
376 
377 		return success;
378 	}
379 
380 	return true;   // Success
381 }
382 
deleteResources()383 void WindowSurface::deleteResources()
384 {
385 	delete frameBuffer;
386 	frameBuffer = nullptr;
387 
388 	Surface::deleteResources();
389 }
390 
reset(int backBufferWidth,int backBufferHeight)391 bool WindowSurface::reset(int backBufferWidth, int backBufferHeight)
392 {
393 	width = backBufferWidth;
394 	height = backBufferHeight;
395 
396 	deleteResources();
397 
398 	if(window)
399 	{
400 		if(libGLESv2)
401 		{
402 			frameBuffer = libGLESv2->createFrameBuffer(display->getNativeDisplay(), window, width, height);
403 		}
404 
405 		if(!frameBuffer)
406 		{
407 			ERR("Could not create frame buffer");
408 			deleteResources();
409 			return error(EGL_BAD_ALLOC, false);
410 		}
411 	}
412 
413 	return Surface::initialize();
414 }
415 
PBufferSurface(Display * display,const Config * config,EGLint width,EGLint height,EGLenum textureFormat,EGLenum textureTarget,EGLenum clientBufferFormat,EGLenum clientBufferType,EGLBoolean largestPBuffer,EGLClientBuffer clientBuffer,EGLint clientBufferPlane)416 PBufferSurface::PBufferSurface(Display *display, const Config *config, EGLint width, EGLint height,
417                                EGLenum textureFormat, EGLenum textureTarget, EGLenum clientBufferFormat,
418                                EGLenum clientBufferType, EGLBoolean largestPBuffer, EGLClientBuffer clientBuffer,
419                                EGLint clientBufferPlane)
420 	: Surface(display, config)
421 {
422 	this->width = width;
423 	this->height = height;
424 	this->largestPBuffer = largestPBuffer;
425 	this->textureFormat = textureFormat;
426 	this->textureTarget = textureTarget;
427 	this->clientBufferFormat = clientBufferFormat;
428 	this->clientBufferType = clientBufferType;
429 	this->clientBuffer = clientBuffer;
430 	this->clientBufferPlane = clientBufferPlane;
431 }
432 
~PBufferSurface()433 PBufferSurface::~PBufferSurface()
434 {
435 	PBufferSurface::deleteResources();
436 }
437 
swap()438 void PBufferSurface::swap()
439 {
440 	// No effect
441 }
442 
getWindowHandle() const443 EGLNativeWindowType PBufferSurface::getWindowHandle() const
444 {
445 	UNREACHABLE(-1);   // Should not be called. Only WindowSurface has a window handle.
446 
447 	return 0;
448 }
449 
deleteResources()450 void PBufferSurface::deleteResources()
451 {
452 	Surface::deleteResources();
453 }
454 
455 }
456