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 | { |
44 | Surface::Surface() |
45 | { |
46 | } |
47 | |
48 | Surface::~Surface() |
49 | { |
50 | } |
51 | } |
52 | |
53 | namespace egl |
54 | { |
55 | Surface::Surface(const Display *display, const Config *config) : display(display), config(config) |
56 | { |
57 | } |
58 | |
59 | Surface::~Surface() |
60 | { |
61 | Surface::deleteResources(); |
62 | } |
63 | |
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 | |
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 | |
135 | egl::Image *Surface::getRenderTarget() |
136 | { |
137 | if(backBuffer) |
138 | { |
139 | backBuffer->addRef(); |
140 | } |
141 | |
142 | return backBuffer; |
143 | } |
144 | |
145 | egl::Image *Surface::getDepthStencil() |
146 | { |
147 | if(depthStencil) |
148 | { |
149 | depthStencil->addRef(); |
150 | } |
151 | |
152 | return depthStencil; |
153 | } |
154 | |
155 | void Surface::setMipmapLevel(EGLint mipmapLevel) |
156 | { |
157 | this->mipmapLevel = mipmapLevel; |
158 | } |
159 | |
160 | void Surface::setMultisampleResolve(EGLenum multisampleResolve) |
161 | { |
162 | this->multisampleResolve = multisampleResolve; |
163 | } |
164 | |
165 | void Surface::setSwapBehavior(EGLenum swapBehavior) |
166 | { |
167 | this->swapBehavior = swapBehavior; |
168 | } |
169 | |
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 | |
182 | EGLint Surface::getConfigID() const |
183 | { |
184 | return config->mConfigID; |
185 | } |
186 | |
187 | EGLenum Surface::getSurfaceType() const |
188 | { |
189 | return config->mSurfaceType; |
190 | } |
191 | |
192 | EGLint Surface::getWidth() const |
193 | { |
194 | return width; |
195 | } |
196 | |
197 | EGLint Surface::getHeight() const |
198 | { |
199 | return height; |
200 | } |
201 | |
202 | EGLint Surface::getMipmapLevel() const |
203 | { |
204 | return mipmapLevel; |
205 | } |
206 | |
207 | EGLenum Surface::getMultisampleResolve() const |
208 | { |
209 | return multisampleResolve; |
210 | } |
211 | |
212 | EGLint Surface::getPixelAspectRatio() const |
213 | { |
214 | return pixelAspectRatio; |
215 | } |
216 | |
217 | EGLenum Surface::getRenderBuffer() const |
218 | { |
219 | return renderBuffer; |
220 | } |
221 | |
222 | EGLenum Surface::getSwapBehavior() const |
223 | { |
224 | return swapBehavior; |
225 | } |
226 | |
227 | EGLenum Surface::getTextureFormat() const |
228 | { |
229 | return textureFormat; |
230 | } |
231 | |
232 | EGLenum Surface::getTextureTarget() const |
233 | { |
234 | return textureTarget; |
235 | } |
236 | |
237 | EGLBoolean Surface::getLargestPBuffer() const |
238 | { |
239 | return largestPBuffer; |
240 | } |
241 | |
242 | 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 | |
290 | void Surface::setBoundTexture(egl::Texture *texture) |
291 | { |
292 | this->texture = texture; |
293 | } |
294 | |
295 | egl::Texture *Surface::getBoundTexture() const |
296 | { |
297 | return texture; |
298 | } |
299 | |
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 | |
306 | WindowSurface::~WindowSurface() |
307 | { |
308 | WindowSurface::deleteResources(); |
309 | } |
310 | |
311 | bool WindowSurface::initialize() |
312 | { |
313 | ASSERT(!frameBuffer && !backBuffer && !depthStencil); |
314 | |
315 | return checkForResize(); |
316 | } |
317 | |
318 | void WindowSurface::swap() |
319 | { |
320 | if(backBuffer && frameBuffer) |
321 | { |
322 | frameBuffer->flip(backBuffer); |
323 | |
324 | checkForResize(); |
325 | } |
326 | } |
327 | |
328 | EGLNativeWindowType WindowSurface::getWindowHandle() const |
329 | { |
330 | return window; |
331 | } |
332 | |
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 | #ifdef ANDROID_NDK_BUILD |
348 | int windowWidth = ANativeWindow_getWidth(window); |
349 | int windowHeight = ANativeWindow_getHeight(window); |
350 | #else |
351 | int windowWidth; window->query(window, NATIVE_WINDOW_WIDTH, &windowWidth); |
352 | int windowHeight; window->query(window, NATIVE_WINDOW_HEIGHT, &windowHeight); |
353 | #endif |
354 | #elif defined(USE_X11) |
355 | XWindowAttributes windowAttributes; |
356 | Status status = libX11->XGetWindowAttributes((::Display*)display->getNativeDisplay(), window, &windowAttributes); |
357 | |
358 | if(status == 0) |
359 | { |
360 | return error(EGL_BAD_NATIVE_WINDOW, false); |
361 | } |
362 | |
363 | int windowWidth = windowAttributes.width; |
364 | int windowHeight = windowAttributes.height; |
365 | #elif defined(__linux__) |
366 | // Non X11 linux is headless only |
367 | int windowWidth = 100; |
368 | int windowHeight = 100; |
369 | #elif defined(__APPLE__) |
370 | int windowWidth; |
371 | int windowHeight; |
372 | sw::OSX::GetNativeWindowSize(window, windowWidth, windowHeight); |
373 | #elif defined(__Fuchsia__) |
374 | // TODO(crbug.com/800951): Integrate with Mozart. |
375 | int windowWidth = 100; |
376 | int windowHeight = 100; |
377 | #else |
378 | #error "WindowSurface::checkForResize unimplemented for this platform" |
379 | #endif |
380 | |
381 | if((windowWidth != width) || (windowHeight != height)) |
382 | { |
383 | bool success = reset(windowWidth, windowHeight); |
384 | |
385 | if(getCurrentDrawSurface() == this) |
386 | { |
387 | getCurrentContext()->makeCurrent(this); |
388 | } |
389 | |
390 | return success; |
391 | } |
392 | |
393 | return true; // Success |
394 | } |
395 | |
396 | void WindowSurface::deleteResources() |
397 | { |
398 | delete frameBuffer; |
399 | frameBuffer = nullptr; |
400 | |
401 | Surface::deleteResources(); |
402 | } |
403 | |
404 | bool WindowSurface::reset(int backBufferWidth, int backBufferHeight) |
405 | { |
406 | width = backBufferWidth; |
407 | height = backBufferHeight; |
408 | |
409 | deleteResources(); |
410 | |
411 | if(window) |
412 | { |
413 | if(libGLESv2) |
414 | { |
415 | frameBuffer = libGLESv2->createFrameBuffer(display->getNativeDisplay(), window, width, height); |
416 | } |
417 | else if(libGLES_CM) |
418 | { |
419 | frameBuffer = libGLES_CM->createFrameBuffer(display->getNativeDisplay(), window, width, height); |
420 | } |
421 | |
422 | if(!frameBuffer) |
423 | { |
424 | ERR("Could not create frame buffer" ); |
425 | deleteResources(); |
426 | return error(EGL_BAD_ALLOC, false); |
427 | } |
428 | } |
429 | |
430 | return Surface::initialize(); |
431 | } |
432 | |
433 | PBufferSurface::PBufferSurface(Display *display, const Config *config, EGLint width, EGLint height, |
434 | EGLenum textureFormat, EGLenum textureTarget, EGLenum clientBufferFormat, |
435 | EGLenum clientBufferType, EGLBoolean largestPBuffer, EGLClientBuffer clientBuffer, |
436 | EGLint clientBufferPlane) |
437 | : Surface(display, config) |
438 | { |
439 | this->width = width; |
440 | this->height = height; |
441 | this->largestPBuffer = largestPBuffer; |
442 | this->textureFormat = textureFormat; |
443 | this->textureTarget = textureTarget; |
444 | this->clientBufferFormat = clientBufferFormat; |
445 | this->clientBufferType = clientBufferType; |
446 | this->clientBuffer = clientBuffer; |
447 | this->clientBufferPlane = clientBufferPlane; |
448 | } |
449 | |
450 | PBufferSurface::~PBufferSurface() |
451 | { |
452 | PBufferSurface::deleteResources(); |
453 | } |
454 | |
455 | void PBufferSurface::swap() |
456 | { |
457 | // No effect |
458 | } |
459 | |
460 | EGLNativeWindowType PBufferSurface::getWindowHandle() const |
461 | { |
462 | UNREACHABLE(-1); // Should not be called. Only WindowSurface has a window handle. |
463 | |
464 | return 0; |
465 | } |
466 | |
467 | void PBufferSurface::deleteResources() |
468 | { |
469 | Surface::deleteResources(); |
470 | } |
471 | |
472 | } |
473 | |