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