blob: dd912ed767ef6fa6bea30ba6cfa9a13d845c73ab [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// 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
Nicolas Capens31c07a32017-06-13 23:44:13 -040019#include "Surface.hpp"
Nicolas Capens0bac2852016-05-07 06:09:58 -040020
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
Alexis Hetu20eea3c2018-06-19 14:50:41 -040029#if defined(USE_X11)
Nicolas Capens0bac2852016-05-07 06:09:58 -040030#include "Main/libX11.hpp"
31#elif defined(_WIN32)
32#include <tchar.h>
33#elif defined(__APPLE__)
34#include "OSXUtils.hpp"
35#endif
Stephen Whitee6ab01f2019-04-04 14:31:25 -040036#if defined(__ANDROID__) && defined(ANDROID_NDK_BUILD)
37#include <android/native_window.h>
38#endif
Nicolas Capens0bac2852016-05-07 06:09:58 -040039
40#include <algorithm>
41
Nicolas Capens31c07a32017-06-13 23:44:13 -040042namespace gl
43{
44Surface::Surface()
45{
46}
47
48Surface::~Surface()
49{
50}
51}
52
Nicolas Capens0bac2852016-05-07 06:09:58 -040053namespace egl
54{
Nicolas Capens0bac2852016-05-07 06:09:58 -040055Surface::Surface(const Display *display, const Config *config) : display(display), config(config)
56{
Nicolas Capens0bac2852016-05-07 06:09:58 -040057}
58
59Surface::~Surface()
60{
61 Surface::deleteResources();
62}
63
64bool Surface::initialize()
65{
66 ASSERT(!backBuffer && !depthStencil);
67
Nicolas Capens3911efd2017-10-30 10:46:56 -040068 if(libGLESv2)
Nicolas Capens0bac2852016-05-07 06:09:58 -040069 {
Alexis Hetuc80eada2018-02-13 15:02:40 -050070 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 }
Nicolas Capens0bac2852016-05-07 06:09:58 -040079 }
Nicolas Capens3911efd2017-10-30 10:46:56 -040080 else if(libGLES_CM)
81 {
82 backBuffer = libGLES_CM->createBackBuffer(width, height, config->mRenderTargetFormat, config->mSamples);
83 }
Nicolas Capens0bac2852016-05-07 06:09:58 -040084
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 {
Nicolas Capens3911efd2017-10-30 10:46:56 -040094 if(libGLESv2)
Nicolas Capens0bac2852016-05-07 06:09:58 -040095 {
Nicolas Capens96699f12017-07-05 17:00:23 -040096 depthStencil = libGLESv2->createDepthStencil(width, height, config->mDepthStencilFormat, config->mSamples);
Nicolas Capens0bac2852016-05-07 06:09:58 -040097 }
Nicolas Capens3911efd2017-10-30 10:46:56 -040098 else if(libGLES_CM)
99 {
100 depthStencil = libGLES_CM->createDepthStencil(width, height, config->mDepthStencilFormat, config->mSamples);
101 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400102
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
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400155void Surface::setMipmapLevel(EGLint mipmapLevel)
156{
157 this->mipmapLevel = mipmapLevel;
158}
159
160void Surface::setMultisampleResolve(EGLenum multisampleResolve)
161{
162 this->multisampleResolve = multisampleResolve;
163}
164
Nicolas Capens0bac2852016-05-07 06:09:58 -0400165void 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
Nicolas Capens0bac2852016-05-07 06:09:58 -0400192EGLint Surface::getWidth() const
193{
194 return width;
195}
196
197EGLint Surface::getHeight() const
198{
199 return height;
200}
201
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400202EGLint Surface::getMipmapLevel() const
203{
204 return mipmapLevel;
205}
206
207EGLenum Surface::getMultisampleResolve() const
208{
209 return multisampleResolve;
210}
211
Nicolas Capens0bac2852016-05-07 06:09:58 -0400212EGLint 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
Alexis Hetuc80eada2018-02-13 15:02:40 -0500242sw::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_BGRA_EXT:
254 return sw::FORMAT_A8R8G8B8;
255 default:
256 UNREACHABLE(clientBufferFormat);
257 break;
258 }
259 break;
260 case GL_UNSIGNED_SHORT:
261 switch(clientBufferFormat)
262 {
263 case GL_R16UI:
264 return sw::FORMAT_R16UI;
265 default:
266 UNREACHABLE(clientBufferFormat);
267 break;
268 }
269 break;
Nicolas Capensce8eb942018-04-26 16:38:05 -0400270 case GL_HALF_FLOAT_OES:
Alexis Hetuc80eada2018-02-13 15:02:40 -0500271 case GL_HALF_FLOAT:
272 switch(clientBufferFormat)
273 {
274 case GL_RGBA:
275 return sw::FORMAT_A16B16G16R16F;
276 default:
277 UNREACHABLE(clientBufferFormat);
278 break;
279 }
280 default:
281 UNREACHABLE(clientBufferType);
282 break;
283 }
284
285 return sw::FORMAT_NULL;
286}
287
Nicolas Capens0bac2852016-05-07 06:09:58 -0400288void Surface::setBoundTexture(egl::Texture *texture)
289{
290 this->texture = texture;
291}
292
293egl::Texture *Surface::getBoundTexture() const
294{
295 return texture;
296}
297
298WindowSurface::WindowSurface(Display *display, const Config *config, EGLNativeWindowType window)
299 : Surface(display, config), window(window)
300{
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400301 pixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
Nicolas Capens0bac2852016-05-07 06:09:58 -0400302}
303
304WindowSurface::~WindowSurface()
305{
306 WindowSurface::deleteResources();
307}
308
309bool WindowSurface::initialize()
310{
311 ASSERT(!frameBuffer && !backBuffer && !depthStencil);
312
313 return checkForResize();
314}
315
316void WindowSurface::swap()
317{
318 if(backBuffer && frameBuffer)
319 {
Nicolas Capens241f7892015-12-30 23:40:45 -0500320 frameBuffer->flip(backBuffer);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400321
322 checkForResize();
323 }
324}
325
326EGLNativeWindowType WindowSurface::getWindowHandle() const
327{
328 return window;
329}
330
331bool WindowSurface::checkForResize()
332{
333 #if defined(_WIN32)
334 RECT client;
Nicolas Capensf9b80fe2018-03-13 10:54:18 -0400335 BOOL status = GetClientRect(window, &client);
336
337 if(status == 0)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400338 {
Alexis Hetu560232a2017-09-29 13:13:14 -0400339 return error(EGL_BAD_NATIVE_WINDOW, false);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400340 }
341
342 int windowWidth = client.right - client.left;
343 int windowHeight = client.bottom - client.top;
344 #elif defined(__ANDROID__)
Stephen Whitee6ab01f2019-04-04 14:31:25 -0400345 #ifdef ANDROID_NDK_BUILD
346 int windowWidth = ANativeWindow_getWidth(window);
347 int windowHeight = ANativeWindow_getHeight(window);
348 #else
Nicolas Capens0bac2852016-05-07 06:09:58 -0400349 int windowWidth; window->query(window, NATIVE_WINDOW_WIDTH, &windowWidth);
350 int windowHeight; window->query(window, NATIVE_WINDOW_HEIGHT, &windowHeight);
Stephen Whitee6ab01f2019-04-04 14:31:25 -0400351 #endif
Alexis Hetu20eea3c2018-06-19 14:50:41 -0400352 #elif defined(USE_X11)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400353 XWindowAttributes windowAttributes;
Nicolas Capensf9b80fe2018-03-13 10:54:18 -0400354 Status status = libX11->XGetWindowAttributes((::Display*)display->getNativeDisplay(), window, &windowAttributes);
355
356 if(status == 0)
357 {
358 return error(EGL_BAD_NATIVE_WINDOW, false);
359 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400360
361 int windowWidth = windowAttributes.width;
362 int windowHeight = windowAttributes.height;
Alexis Hetu20eea3c2018-06-19 14:50:41 -0400363 #elif defined(__linux__)
364 // Non X11 linux is headless only
365 int windowWidth = 100;
366 int windowHeight = 100;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400367 #elif defined(__APPLE__)
368 int windowWidth;
369 int windowHeight;
370 sw::OSX::GetNativeWindowSize(window, windowWidth, windowHeight);
Sergey Ulanov53c601e2018-01-10 15:12:42 -0800371 #elif defined(__Fuchsia__)
372 // TODO(crbug.com/800951): Integrate with Mozart.
373 int windowWidth = 100;
374 int windowHeight = 100;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400375 #else
376 #error "WindowSurface::checkForResize unimplemented for this platform"
377 #endif
378
379 if((windowWidth != width) || (windowHeight != height))
380 {
381 bool success = reset(windowWidth, windowHeight);
382
383 if(getCurrentDrawSurface() == this)
384 {
385 getCurrentContext()->makeCurrent(this);
386 }
387
388 return success;
389 }
390
391 return true; // Success
392}
393
394void WindowSurface::deleteResources()
395{
396 delete frameBuffer;
397 frameBuffer = nullptr;
398
399 Surface::deleteResources();
400}
401
402bool WindowSurface::reset(int backBufferWidth, int backBufferHeight)
403{
404 width = backBufferWidth;
405 height = backBufferHeight;
406
407 deleteResources();
408
409 if(window)
410 {
Nicolas Capens3911efd2017-10-30 10:46:56 -0400411 if(libGLESv2)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400412 {
413 frameBuffer = libGLESv2->createFrameBuffer(display->getNativeDisplay(), window, width, height);
414 }
Nicolas Capens3911efd2017-10-30 10:46:56 -0400415 else if(libGLES_CM)
416 {
417 frameBuffer = libGLES_CM->createFrameBuffer(display->getNativeDisplay(), window, width, height);
418 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400419
420 if(!frameBuffer)
421 {
422 ERR("Could not create frame buffer");
423 deleteResources();
424 return error(EGL_BAD_ALLOC, false);
425 }
426 }
427
428 return Surface::initialize();
429}
430
Alexis Hetuc80eada2018-02-13 15:02:40 -0500431PBufferSurface::PBufferSurface(Display *display, const Config *config, EGLint width, EGLint height,
432 EGLenum textureFormat, EGLenum textureTarget, EGLenum clientBufferFormat,
433 EGLenum clientBufferType, EGLBoolean largestPBuffer, EGLClientBuffer clientBuffer,
434 EGLint clientBufferPlane)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400435 : Surface(display, config)
436{
437 this->width = width;
438 this->height = height;
439 this->largestPBuffer = largestPBuffer;
Alexis Hetuc80eada2018-02-13 15:02:40 -0500440 this->textureFormat = textureFormat;
441 this->textureTarget = textureTarget;
442 this->clientBufferFormat = clientBufferFormat;
443 this->clientBufferType = clientBufferType;
444 this->clientBuffer = clientBuffer;
445 this->clientBufferPlane = clientBufferPlane;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400446}
447
448PBufferSurface::~PBufferSurface()
449{
450 PBufferSurface::deleteResources();
451}
452
453void PBufferSurface::swap()
454{
455 // No effect
456}
457
458EGLNativeWindowType PBufferSurface::getWindowHandle() const
459{
460 UNREACHABLE(-1); // Should not be called. Only WindowSurface has a window handle.
461
462 return 0;
463}
464
465void PBufferSurface::deleteResources()
466{
467 Surface::deleteResources();
468}
469
470}