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