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.h"
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 egl
40 {
41
Surface(const Display * display,const Config * config)42 Surface::Surface(const Display *display, const Config *config) : display(display), config(config)
43 {
44 backBuffer = nullptr;
45 depthStencil = nullptr;
46 texture = nullptr;
47
48 width = 0;
49 height = 0;
50 largestPBuffer = EGL_FALSE;
51 pixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
52 renderBuffer = EGL_BACK_BUFFER;
53 swapBehavior = EGL_BUFFER_PRESERVED;
54 textureFormat = EGL_NO_TEXTURE;
55 textureTarget = EGL_NO_TEXTURE;
56 swapInterval = -1;
57 setSwapInterval(1);
58 }
59
~Surface()60 Surface::~Surface()
61 {
62 Surface::deleteResources();
63 }
64
initialize()65 bool Surface::initialize()
66 {
67 ASSERT(!backBuffer && !depthStencil);
68
69 if(libGLES_CM)
70 {
71 backBuffer = libGLES_CM->createBackBuffer(width, height, config);
72 }
73 else if(libGLESv2)
74 {
75 backBuffer = libGLESv2->createBackBuffer(width, height, config);
76 }
77
78 if(!backBuffer)
79 {
80 ERR("Could not create back buffer");
81 deleteResources();
82 return error(EGL_BAD_ALLOC, false);
83 }
84
85 if(config->mDepthStencilFormat != sw::FORMAT_NULL)
86 {
87 if(libGLES_CM)
88 {
89 depthStencil = libGLES_CM->createDepthStencil(width, height, config->mDepthStencilFormat, config->mSamples, false);
90 }
91 else if(libGLESv2)
92 {
93 depthStencil = libGLESv2->createDepthStencil(width, height, config->mDepthStencilFormat, config->mSamples, false);
94 }
95
96 if(!depthStencil)
97 {
98 ERR("Could not create depth/stencil buffer for surface");
99 deleteResources();
100 return error(EGL_BAD_ALLOC, false);
101 }
102 }
103
104 return true;
105 }
106
deleteResources()107 void Surface::deleteResources()
108 {
109 if(depthStencil)
110 {
111 depthStencil->release();
112 depthStencil = nullptr;
113 }
114
115 if(texture)
116 {
117 texture->releaseTexImage();
118 texture = nullptr;
119 }
120
121 if(backBuffer)
122 {
123 backBuffer->release();
124 backBuffer = nullptr;
125 }
126 }
127
getRenderTarget()128 egl::Image *Surface::getRenderTarget()
129 {
130 if(backBuffer)
131 {
132 backBuffer->addRef();
133 }
134
135 return backBuffer;
136 }
137
getDepthStencil()138 egl::Image *Surface::getDepthStencil()
139 {
140 if(depthStencil)
141 {
142 depthStencil->addRef();
143 }
144
145 return depthStencil;
146 }
147
setSwapBehavior(EGLenum swapBehavior)148 void Surface::setSwapBehavior(EGLenum swapBehavior)
149 {
150 this->swapBehavior = swapBehavior;
151 }
152
setSwapInterval(EGLint interval)153 void Surface::setSwapInterval(EGLint interval)
154 {
155 if(swapInterval == interval)
156 {
157 return;
158 }
159
160 swapInterval = interval;
161 swapInterval = std::max(swapInterval, display->getMinSwapInterval());
162 swapInterval = std::min(swapInterval, display->getMaxSwapInterval());
163 }
164
getConfigID() const165 EGLint Surface::getConfigID() const
166 {
167 return config->mConfigID;
168 }
169
getSurfaceType() const170 EGLenum Surface::getSurfaceType() const
171 {
172 return config->mSurfaceType;
173 }
174
getInternalFormat() const175 sw::Format Surface::getInternalFormat() const
176 {
177 return config->mRenderTargetFormat;
178 }
179
getWidth() const180 EGLint Surface::getWidth() const
181 {
182 return width;
183 }
184
getHeight() const185 EGLint Surface::getHeight() const
186 {
187 return height;
188 }
189
getPixelAspectRatio() const190 EGLint Surface::getPixelAspectRatio() const
191 {
192 return pixelAspectRatio;
193 }
194
getRenderBuffer() const195 EGLenum Surface::getRenderBuffer() const
196 {
197 return renderBuffer;
198 }
199
getSwapBehavior() const200 EGLenum Surface::getSwapBehavior() const
201 {
202 return swapBehavior;
203 }
204
getTextureFormat() const205 EGLenum Surface::getTextureFormat() const
206 {
207 return textureFormat;
208 }
209
getTextureTarget() const210 EGLenum Surface::getTextureTarget() const
211 {
212 return textureTarget;
213 }
214
getLargestPBuffer() const215 EGLBoolean Surface::getLargestPBuffer() const
216 {
217 return largestPBuffer;
218 }
219
setBoundTexture(egl::Texture * texture)220 void Surface::setBoundTexture(egl::Texture *texture)
221 {
222 this->texture = texture;
223 }
224
getBoundTexture() const225 egl::Texture *Surface::getBoundTexture() const
226 {
227 return texture;
228 }
229
WindowSurface(Display * display,const Config * config,EGLNativeWindowType window)230 WindowSurface::WindowSurface(Display *display, const Config *config, EGLNativeWindowType window)
231 : Surface(display, config), window(window)
232 {
233 frameBuffer = nullptr;
234 }
235
~WindowSurface()236 WindowSurface::~WindowSurface()
237 {
238 WindowSurface::deleteResources();
239 }
240
initialize()241 bool WindowSurface::initialize()
242 {
243 ASSERT(!frameBuffer && !backBuffer && !depthStencil);
244
245 return checkForResize();
246 }
247
swap()248 void WindowSurface::swap()
249 {
250 if(backBuffer && frameBuffer)
251 {
252 void *source = backBuffer->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
253 frameBuffer->flip(source, backBuffer->sw::Surface::getInternalFormat(), backBuffer->getInternalPitchB());
254 backBuffer->unlockInternal();
255
256 checkForResize();
257 }
258 }
259
getWindowHandle() const260 EGLNativeWindowType WindowSurface::getWindowHandle() const
261 {
262 return window;
263 }
264
checkForResize()265 bool WindowSurface::checkForResize()
266 {
267 #if defined(_WIN32)
268 RECT client;
269 if(!GetClientRect(window, &client))
270 {
271 ASSERT(false);
272 return false;
273 }
274
275 int windowWidth = client.right - client.left;
276 int windowHeight = client.bottom - client.top;
277 #elif defined(__ANDROID__)
278 int windowWidth; window->query(window, NATIVE_WINDOW_WIDTH, &windowWidth);
279 int windowHeight; window->query(window, NATIVE_WINDOW_HEIGHT, &windowHeight);
280 #elif defined(__linux__)
281 XWindowAttributes windowAttributes;
282 libX11->XGetWindowAttributes((::Display*)display->getNativeDisplay(), window, &windowAttributes);
283
284 int windowWidth = windowAttributes.width;
285 int windowHeight = windowAttributes.height;
286 #elif defined(__APPLE__)
287 int windowWidth;
288 int windowHeight;
289 sw::OSX::GetNativeWindowSize(window, windowWidth, windowHeight);
290 #else
291 #error "WindowSurface::checkForResize unimplemented for this platform"
292 #endif
293
294 if((windowWidth != width) || (windowHeight != height))
295 {
296 bool success = reset(windowWidth, windowHeight);
297
298 if(getCurrentDrawSurface() == this)
299 {
300 getCurrentContext()->makeCurrent(this);
301 }
302
303 return success;
304 }
305
306 return true; // Success
307 }
308
deleteResources()309 void WindowSurface::deleteResources()
310 {
311 delete frameBuffer;
312 frameBuffer = nullptr;
313
314 Surface::deleteResources();
315 }
316
reset(int backBufferWidth,int backBufferHeight)317 bool WindowSurface::reset(int backBufferWidth, int backBufferHeight)
318 {
319 width = backBufferWidth;
320 height = backBufferHeight;
321
322 deleteResources();
323
324 if(window)
325 {
326 if(libGLES_CM)
327 {
328 frameBuffer = libGLES_CM->createFrameBuffer(display->getNativeDisplay(), window, width, height);
329 }
330 else if(libGLESv2)
331 {
332 frameBuffer = libGLESv2->createFrameBuffer(display->getNativeDisplay(), window, width, height);
333 }
334
335 if(!frameBuffer)
336 {
337 ERR("Could not create frame buffer");
338 deleteResources();
339 return error(EGL_BAD_ALLOC, false);
340 }
341 }
342
343 return Surface::initialize();
344 }
345
PBufferSurface(Display * display,const Config * config,EGLint width,EGLint height,EGLenum textureFormat,EGLenum textureType,EGLBoolean largestPBuffer)346 PBufferSurface::PBufferSurface(Display *display, const Config *config, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType, EGLBoolean largestPBuffer)
347 : Surface(display, config)
348 {
349 this->width = width;
350 this->height = height;
351 this->largestPBuffer = largestPBuffer;
352 }
353
~PBufferSurface()354 PBufferSurface::~PBufferSurface()
355 {
356 PBufferSurface::deleteResources();
357 }
358
swap()359 void PBufferSurface::swap()
360 {
361 // No effect
362 }
363
getWindowHandle() const364 EGLNativeWindowType PBufferSurface::getWindowHandle() const
365 {
366 UNREACHABLE(-1); // Should not be called. Only WindowSurface has a window handle.
367
368 return 0;
369 }
370
deleteResources()371 void PBufferSurface::deleteResources()
372 {
373 Surface::deleteResources();
374 }
375
376 }
377