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