blob: 17fc2346005dcffa6604f5115e316d625a0ddf2a [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;
Geoff Langdbb6f3f2019-08-21 15:09:44 -0400253 case GL_RGB:
254 return sw::FORMAT_X8R8G8B8;
Alexis Hetuc80eada2018-02-13 15:02:40 -0500255 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;
Nicolas Capensce8eb942018-04-26 16:38:05 -0400272 case GL_HALF_FLOAT_OES:
Alexis Hetuc80eada2018-02-13 15:02:40 -0500273 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
Nicolas Capens0bac2852016-05-07 06:09:58 -0400290void 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{
Nicolas Capensc8eedeb2018-04-12 12:50:21 -0400303 pixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
Nicolas Capens0bac2852016-05-07 06:09:58 -0400304}
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 {
Nicolas Capens241f7892015-12-30 23:40:45 -0500322 frameBuffer->flip(backBuffer);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400323
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;
Nicolas Capensf9b80fe2018-03-13 10:54:18 -0400337 BOOL status = GetClientRect(window, &client);
338
339 if(status == 0)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400340 {
Alexis Hetu560232a2017-09-29 13:13:14 -0400341 return error(EGL_BAD_NATIVE_WINDOW, false);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400342 }
343
344 int windowWidth = client.right - client.left;
345 int windowHeight = client.bottom - client.top;
346 #elif defined(__ANDROID__)
Stephen Whitee6ab01f2019-04-04 14:31:25 -0400347 #ifdef ANDROID_NDK_BUILD
348 int windowWidth = ANativeWindow_getWidth(window);
349 int windowHeight = ANativeWindow_getHeight(window);
350 #else
Nicolas Capens0bac2852016-05-07 06:09:58 -0400351 int windowWidth; window->query(window, NATIVE_WINDOW_WIDTH, &windowWidth);
352 int windowHeight; window->query(window, NATIVE_WINDOW_HEIGHT, &windowHeight);
Stephen Whitee6ab01f2019-04-04 14:31:25 -0400353 #endif
Alexis Hetu20eea3c2018-06-19 14:50:41 -0400354 #elif defined(USE_X11)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400355 XWindowAttributes windowAttributes;
Nicolas Capensf9b80fe2018-03-13 10:54:18 -0400356 Status status = libX11->XGetWindowAttributes((::Display*)display->getNativeDisplay(), window, &windowAttributes);
357
358 if(status == 0)
359 {
360 return error(EGL_BAD_NATIVE_WINDOW, false);
361 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400362
363 int windowWidth = windowAttributes.width;
364 int windowHeight = windowAttributes.height;
Alexis Hetu20eea3c2018-06-19 14:50:41 -0400365 #elif defined(__linux__)
366 // Non X11 linux is headless only
367 int windowWidth = 100;
368 int windowHeight = 100;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400369 #elif defined(__APPLE__)
370 int windowWidth;
371 int windowHeight;
372 sw::OSX::GetNativeWindowSize(window, windowWidth, windowHeight);
Sergey Ulanov53c601e2018-01-10 15:12:42 -0800373 #elif defined(__Fuchsia__)
374 // TODO(crbug.com/800951): Integrate with Mozart.
375 int windowWidth = 100;
376 int windowHeight = 100;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400377 #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 {
Nicolas Capens3911efd2017-10-30 10:46:56 -0400413 if(libGLESv2)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400414 {
415 frameBuffer = libGLESv2->createFrameBuffer(display->getNativeDisplay(), window, width, height);
416 }
Nicolas Capens3911efd2017-10-30 10:46:56 -0400417 else if(libGLES_CM)
418 {
419 frameBuffer = libGLES_CM->createFrameBuffer(display->getNativeDisplay(), window, width, height);
420 }
Nicolas Capens0bac2852016-05-07 06:09:58 -0400421
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
Alexis Hetuc80eada2018-02-13 15:02:40 -0500433PBufferSurface::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)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400437 : Surface(display, config)
438{
439 this->width = width;
440 this->height = height;
441 this->largestPBuffer = largestPBuffer;
Alexis Hetuc80eada2018-02-13 15:02:40 -0500442 this->textureFormat = textureFormat;
443 this->textureTarget = textureTarget;
444 this->clientBufferFormat = clientBufferFormat;
445 this->clientBufferType = clientBufferType;
446 this->clientBuffer = clientBuffer;
447 this->clientBufferPlane = clientBufferPlane;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400448}
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}