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
42namespace gl
43{
44Surface::Surface()
45{
46}
47
48Surface::~Surface()
49{
50}
51}
52
53namespace egl
54{
55Surface::Surface(const Display *display, const Config *config) : display(display), config(config)
56{
57}
58
59Surface::~Surface()
60{
61 Surface::deleteResources();
62}
63
64bool 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
114void 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
135egl::Image *Surface::getRenderTarget()
136{
137 if(backBuffer)
138 {
139 backBuffer->addRef();
140 }
141
142 return backBuffer;
143}
144
145egl::Image *Surface::getDepthStencil()
146{
147 if(depthStencil)
148 {
149 depthStencil->addRef();
150 }
151
152 return depthStencil;
153}
154
155void Surface::setMipmapLevel(EGLint mipmapLevel)
156{
157 this->mipmapLevel = mipmapLevel;
158}
159
160void Surface::setMultisampleResolve(EGLenum multisampleResolve)
161{
162 this->multisampleResolve = multisampleResolve;
163}
164
165void Surface::setSwapBehavior(EGLenum swapBehavior)
166{
167 this->swapBehavior = swapBehavior;
168}
169
170void 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
182EGLint Surface::getConfigID() const
183{
184 return config->mConfigID;
185}
186
187EGLenum Surface::getSurfaceType() const
188{
189 return config->mSurfaceType;
190}
191
192EGLint Surface::getWidth() const
193{
194 return width;
195}
196
197EGLint Surface::getHeight() const
198{
199 return height;
200}
201
202EGLint Surface::getMipmapLevel() const
203{
204 return mipmapLevel;
205}
206
207EGLenum Surface::getMultisampleResolve() const
208{
209 return multisampleResolve;
210}
211
212EGLint Surface::getPixelAspectRatio() const
213{
214 return pixelAspectRatio;
215}
216
217EGLenum Surface::getRenderBuffer() const
218{
219 return renderBuffer;
220}
221
222EGLenum Surface::getSwapBehavior() const
223{
224 return swapBehavior;
225}
226
227EGLenum Surface::getTextureFormat() const
228{
229 return textureFormat;
230}
231
232EGLenum Surface::getTextureTarget() const
233{
234 return textureTarget;
235}
236
237EGLBoolean Surface::getLargestPBuffer() const
238{
239 return largestPBuffer;
240}
241
242sw::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
290void Surface::setBoundTexture(egl::Texture *texture)
291{
292 this->texture = texture;
293}
294
295egl::Texture *Surface::getBoundTexture() const
296{
297 return texture;
298}
299
300WindowSurface::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
306WindowSurface::~WindowSurface()
307{
308 WindowSurface::deleteResources();
309}
310
311bool WindowSurface::initialize()
312{
313 ASSERT(!frameBuffer && !backBuffer && !depthStencil);
314
315 return checkForResize();
316}
317
318void WindowSurface::swap()
319{
320 if(backBuffer && frameBuffer)
321 {
322 frameBuffer->flip(backBuffer);
323
324 checkForResize();
325 }
326}
327
328EGLNativeWindowType WindowSurface::getWindowHandle() const
329{
330 return window;
331}
332
333bool 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
396void WindowSurface::deleteResources()
397{
398 delete frameBuffer;
399 frameBuffer = nullptr;
400
401 Surface::deleteResources();
402}
403
404bool 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
433PBufferSurface::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
450PBufferSurface::~PBufferSurface()
451{
452 PBufferSurface::deleteResources();
453}
454
455void PBufferSurface::swap()
456{
457 // No effect
458}
459
460EGLNativeWindowType PBufferSurface::getWindowHandle() const
461{
462 UNREACHABLE(-1); // Should not be called. Only WindowSurface has a window handle.
463
464 return 0;
465}
466
467void PBufferSurface::deleteResources()
468{
469 Surface::deleteResources();
470}
471
472}
473