1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2010 VMware, Inc. 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 16bf215546Sopenharmony_ci * of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci **************************************************************************/ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include <windows.h> 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#define WGL_WGLEXT_PROTOTYPES 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include <GL/gl.h> 33bf215546Sopenharmony_ci#include <GL/wglext.h> 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci#include "pipe/p_defines.h" 36bf215546Sopenharmony_ci#include "pipe/p_screen.h" 37bf215546Sopenharmony_ci 38bf215546Sopenharmony_ci#include "util/u_debug.h" 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci#include "stw_device.h" 41bf215546Sopenharmony_ci#include "stw_pixelformat.h" 42bf215546Sopenharmony_ci#include "stw_framebuffer.h" 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci#define LARGE_WINDOW_SIZE 60000 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_cistatic LRESULT CALLBACK 49bf215546Sopenharmony_ciWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 50bf215546Sopenharmony_ci{ 51bf215546Sopenharmony_ci MINMAXINFO *pMMI; 52bf215546Sopenharmony_ci switch (uMsg) { 53bf215546Sopenharmony_ci case WM_GETMINMAXINFO: 54bf215546Sopenharmony_ci // Allow to create a window bigger than the desktop 55bf215546Sopenharmony_ci pMMI = (MINMAXINFO *)lParam; 56bf215546Sopenharmony_ci pMMI->ptMaxSize.x = LARGE_WINDOW_SIZE; 57bf215546Sopenharmony_ci pMMI->ptMaxSize.y = LARGE_WINDOW_SIZE; 58bf215546Sopenharmony_ci pMMI->ptMaxTrackSize.x = LARGE_WINDOW_SIZE; 59bf215546Sopenharmony_ci pMMI->ptMaxTrackSize.y = LARGE_WINDOW_SIZE; 60bf215546Sopenharmony_ci break; 61bf215546Sopenharmony_ci default: 62bf215546Sopenharmony_ci break; 63bf215546Sopenharmony_ci } 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci return DefWindowProc(hWnd, uMsg, wParam, lParam); 66bf215546Sopenharmony_ci} 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ciHPBUFFERARB WINAPI 70bf215546Sopenharmony_ciwglCreatePbufferARB(HDC hCurrentDC, 71bf215546Sopenharmony_ci int iPixelFormat, 72bf215546Sopenharmony_ci int iWidth, 73bf215546Sopenharmony_ci int iHeight, 74bf215546Sopenharmony_ci const int *piAttribList) 75bf215546Sopenharmony_ci{ 76bf215546Sopenharmony_ci static boolean first = TRUE; 77bf215546Sopenharmony_ci const int *piAttrib; 78bf215546Sopenharmony_ci int useLargest = 0; 79bf215546Sopenharmony_ci const struct stw_pixelformat_info *info; 80bf215546Sopenharmony_ci struct stw_framebuffer *fb; 81bf215546Sopenharmony_ci DWORD dwExStyle; 82bf215546Sopenharmony_ci DWORD dwStyle; 83bf215546Sopenharmony_ci RECT rect; 84bf215546Sopenharmony_ci HWND hWnd; 85bf215546Sopenharmony_ci int iDisplayablePixelFormat; 86bf215546Sopenharmony_ci PIXELFORMATDESCRIPTOR pfd; 87bf215546Sopenharmony_ci BOOL bRet; 88bf215546Sopenharmony_ci int textureFormat = WGL_NO_TEXTURE_ARB; 89bf215546Sopenharmony_ci int textureTarget = WGL_NO_TEXTURE_ARB; 90bf215546Sopenharmony_ci BOOL textureMipmap = FALSE; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci info = stw_pixelformat_get_info(iPixelFormat); 93bf215546Sopenharmony_ci if (!info) { 94bf215546Sopenharmony_ci SetLastError(ERROR_INVALID_PIXEL_FORMAT); 95bf215546Sopenharmony_ci return 0; 96bf215546Sopenharmony_ci } 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci if (iWidth <= 0 || iHeight <= 0) { 99bf215546Sopenharmony_ci SetLastError(ERROR_INVALID_DATA); 100bf215546Sopenharmony_ci return 0; 101bf215546Sopenharmony_ci } 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci if (piAttribList) { 104bf215546Sopenharmony_ci for (piAttrib = piAttribList; *piAttrib; piAttrib++) { 105bf215546Sopenharmony_ci switch (*piAttrib) { 106bf215546Sopenharmony_ci case WGL_PBUFFER_LARGEST_ARB: 107bf215546Sopenharmony_ci piAttrib++; 108bf215546Sopenharmony_ci useLargest = *piAttrib; 109bf215546Sopenharmony_ci break; 110bf215546Sopenharmony_ci case WGL_TEXTURE_FORMAT_ARB: 111bf215546Sopenharmony_ci /* WGL_ARB_render_texture */ 112bf215546Sopenharmony_ci piAttrib++; 113bf215546Sopenharmony_ci textureFormat = *piAttrib; 114bf215546Sopenharmony_ci if (textureFormat != WGL_TEXTURE_RGB_ARB && 115bf215546Sopenharmony_ci textureFormat != WGL_TEXTURE_RGBA_ARB && 116bf215546Sopenharmony_ci textureFormat != WGL_NO_TEXTURE_ARB) { 117bf215546Sopenharmony_ci SetLastError(ERROR_INVALID_DATA); 118bf215546Sopenharmony_ci return 0; 119bf215546Sopenharmony_ci } 120bf215546Sopenharmony_ci break; 121bf215546Sopenharmony_ci case WGL_TEXTURE_TARGET_ARB: 122bf215546Sopenharmony_ci /* WGL_ARB_render_texture */ 123bf215546Sopenharmony_ci piAttrib++; 124bf215546Sopenharmony_ci textureTarget = *piAttrib; 125bf215546Sopenharmony_ci if (textureTarget != WGL_TEXTURE_CUBE_MAP_ARB && 126bf215546Sopenharmony_ci textureTarget != WGL_TEXTURE_1D_ARB && 127bf215546Sopenharmony_ci textureTarget != WGL_TEXTURE_2D_ARB && 128bf215546Sopenharmony_ci textureTarget != WGL_NO_TEXTURE_ARB) { 129bf215546Sopenharmony_ci SetLastError(ERROR_INVALID_DATA); 130bf215546Sopenharmony_ci return 0; 131bf215546Sopenharmony_ci } 132bf215546Sopenharmony_ci break; 133bf215546Sopenharmony_ci case WGL_MIPMAP_TEXTURE_ARB: 134bf215546Sopenharmony_ci /* WGL_ARB_render_texture */ 135bf215546Sopenharmony_ci piAttrib++; 136bf215546Sopenharmony_ci textureMipmap = !!*piAttrib; 137bf215546Sopenharmony_ci break; 138bf215546Sopenharmony_ci default: 139bf215546Sopenharmony_ci SetLastError(ERROR_INVALID_DATA); 140bf215546Sopenharmony_ci debug_printf("wgl: Unsupported attribute 0x%x in %s\n", 141bf215546Sopenharmony_ci *piAttrib, __func__); 142bf215546Sopenharmony_ci return 0; 143bf215546Sopenharmony_ci } 144bf215546Sopenharmony_ci } 145bf215546Sopenharmony_ci } 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci if (iWidth > stw_dev->max_2d_length) { 148bf215546Sopenharmony_ci if (useLargest) { 149bf215546Sopenharmony_ci iWidth = stw_dev->max_2d_length; 150bf215546Sopenharmony_ci } else { 151bf215546Sopenharmony_ci SetLastError(ERROR_NO_SYSTEM_RESOURCES); 152bf215546Sopenharmony_ci return 0; 153bf215546Sopenharmony_ci } 154bf215546Sopenharmony_ci } 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci if (iHeight > stw_dev->max_2d_length) { 157bf215546Sopenharmony_ci if (useLargest) { 158bf215546Sopenharmony_ci iHeight = stw_dev->max_2d_length; 159bf215546Sopenharmony_ci } else { 160bf215546Sopenharmony_ci SetLastError(ERROR_NO_SYSTEM_RESOURCES); 161bf215546Sopenharmony_ci return 0; 162bf215546Sopenharmony_ci } 163bf215546Sopenharmony_ci } 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci /* 166bf215546Sopenharmony_ci * Implement pbuffers through invisible windows 167bf215546Sopenharmony_ci */ 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci if (first) { 170bf215546Sopenharmony_ci WNDCLASS wc; 171bf215546Sopenharmony_ci memset(&wc, 0, sizeof wc); 172bf215546Sopenharmony_ci wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); 173bf215546Sopenharmony_ci wc.hCursor = LoadCursor(NULL, IDC_ARROW); 174bf215546Sopenharmony_ci wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 175bf215546Sopenharmony_ci wc.lpfnWndProc = WndProc; 176bf215546Sopenharmony_ci wc.lpszClassName = "wglpbuffer"; 177bf215546Sopenharmony_ci wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; 178bf215546Sopenharmony_ci RegisterClass(&wc); 179bf215546Sopenharmony_ci first = FALSE; 180bf215546Sopenharmony_ci } 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci dwExStyle = 0; 183bf215546Sopenharmony_ci dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci if (0) { 186bf215546Sopenharmony_ci /* 187bf215546Sopenharmony_ci * Don't hide the window -- useful for debugging what the application is 188bf215546Sopenharmony_ci * drawing 189bf215546Sopenharmony_ci */ 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci dwStyle |= WS_VISIBLE | WS_OVERLAPPEDWINDOW; 192bf215546Sopenharmony_ci } else { 193bf215546Sopenharmony_ci dwStyle |= WS_POPUPWINDOW; 194bf215546Sopenharmony_ci } 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci rect.left = 0; 197bf215546Sopenharmony_ci rect.top = 0; 198bf215546Sopenharmony_ci rect.right = rect.left + iWidth; 199bf215546Sopenharmony_ci rect.bottom = rect.top + iHeight; 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci /* 202bf215546Sopenharmony_ci * The CreateWindowEx parameters are the total (outside) dimensions of the 203bf215546Sopenharmony_ci * window, which can vary with Windows version and user settings. Use 204bf215546Sopenharmony_ci * AdjustWindowRect to get the required total area for the given client area. 205bf215546Sopenharmony_ci * 206bf215546Sopenharmony_ci * AdjustWindowRectEx does not accept WS_OVERLAPPED style (which is defined 207bf215546Sopenharmony_ci * as 0), which means we need to use some other style instead, e.g., 208bf215546Sopenharmony_ci * WS_OVERLAPPEDWINDOW or WS_POPUPWINDOW as above. 209bf215546Sopenharmony_ci */ 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle); 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci hWnd = CreateWindowEx(dwExStyle, 214bf215546Sopenharmony_ci "wglpbuffer", /* wc.lpszClassName */ 215bf215546Sopenharmony_ci NULL, 216bf215546Sopenharmony_ci dwStyle, 217bf215546Sopenharmony_ci CW_USEDEFAULT, /* x */ 218bf215546Sopenharmony_ci CW_USEDEFAULT, /* y */ 219bf215546Sopenharmony_ci rect.right - rect.left, /* width */ 220bf215546Sopenharmony_ci rect.bottom - rect.top, /* height */ 221bf215546Sopenharmony_ci NULL, 222bf215546Sopenharmony_ci NULL, 223bf215546Sopenharmony_ci NULL, 224bf215546Sopenharmony_ci NULL); 225bf215546Sopenharmony_ci if (!hWnd) { 226bf215546Sopenharmony_ci return 0; 227bf215546Sopenharmony_ci } 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci#ifdef DEBUG 230bf215546Sopenharmony_ci /* 231bf215546Sopenharmony_ci * Verify the client area size matches the specified size. 232bf215546Sopenharmony_ci */ 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci GetClientRect(hWnd, &rect); 235bf215546Sopenharmony_ci assert(rect.left == 0); 236bf215546Sopenharmony_ci assert(rect.top == 0); 237bf215546Sopenharmony_ci assert(rect.right - rect.left == iWidth); 238bf215546Sopenharmony_ci assert(rect.bottom - rect.top == iHeight); 239bf215546Sopenharmony_ci#endif 240bf215546Sopenharmony_ci 241bf215546Sopenharmony_ci /* 242bf215546Sopenharmony_ci * We can't pass non-displayable pixel formats to GDI, which is why we 243bf215546Sopenharmony_ci * create the framebuffer object before calling SetPixelFormat(). 244bf215546Sopenharmony_ci */ 245bf215546Sopenharmony_ci fb = stw_framebuffer_create(hWnd, iPixelFormat, STW_FRAMEBUFFER_PBUFFER); 246bf215546Sopenharmony_ci if (!fb) { 247bf215546Sopenharmony_ci SetLastError(ERROR_NO_SYSTEM_RESOURCES); 248bf215546Sopenharmony_ci return NULL; 249bf215546Sopenharmony_ci } 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci /* WGL_ARB_render_texture fields */ 252bf215546Sopenharmony_ci fb->textureTarget = textureTarget; 253bf215546Sopenharmony_ci fb->textureFormat = textureFormat; 254bf215546Sopenharmony_ci fb->textureMipmap = textureMipmap; 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci iDisplayablePixelFormat = fb->iDisplayablePixelFormat; 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci stw_framebuffer_unlock(fb); 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci /* 261bf215546Sopenharmony_ci * We need to set a displayable pixel format on the hidden window DC 262bf215546Sopenharmony_ci * so that wglCreateContext and wglMakeCurrent are not overruled by GDI. 263bf215546Sopenharmony_ci */ 264bf215546Sopenharmony_ci bRet = SetPixelFormat(GetDC(hWnd), iDisplayablePixelFormat, &pfd); 265bf215546Sopenharmony_ci assert(bRet); 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ci return (HPBUFFERARB)fb; 268bf215546Sopenharmony_ci} 269bf215546Sopenharmony_ci 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ciHDC WINAPI 272bf215546Sopenharmony_ciwglGetPbufferDCARB(HPBUFFERARB hPbuffer) 273bf215546Sopenharmony_ci{ 274bf215546Sopenharmony_ci struct stw_framebuffer *fb; 275bf215546Sopenharmony_ci HDC hDC; 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci if (!hPbuffer) { 278bf215546Sopenharmony_ci SetLastError(ERROR_INVALID_HANDLE); 279bf215546Sopenharmony_ci return NULL; 280bf215546Sopenharmony_ci } 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer); 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci hDC = GetDC(fb->hWnd); 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci return hDC; 287bf215546Sopenharmony_ci} 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ciint WINAPI 291bf215546Sopenharmony_ciwglReleasePbufferDCARB(HPBUFFERARB hPbuffer, 292bf215546Sopenharmony_ci HDC hDC) 293bf215546Sopenharmony_ci{ 294bf215546Sopenharmony_ci struct stw_framebuffer *fb; 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_ci if (!hPbuffer) { 297bf215546Sopenharmony_ci SetLastError(ERROR_INVALID_HANDLE); 298bf215546Sopenharmony_ci return 0; 299bf215546Sopenharmony_ci } 300bf215546Sopenharmony_ci 301bf215546Sopenharmony_ci fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer); 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci return ReleaseDC(fb->hWnd, hDC); 304bf215546Sopenharmony_ci} 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_ci 307bf215546Sopenharmony_ciBOOL WINAPI 308bf215546Sopenharmony_ciwglDestroyPbufferARB(HPBUFFERARB hPbuffer) 309bf215546Sopenharmony_ci{ 310bf215546Sopenharmony_ci struct stw_framebuffer *fb; 311bf215546Sopenharmony_ci 312bf215546Sopenharmony_ci if (!hPbuffer) { 313bf215546Sopenharmony_ci SetLastError(ERROR_INVALID_HANDLE); 314bf215546Sopenharmony_ci return FALSE; 315bf215546Sopenharmony_ci } 316bf215546Sopenharmony_ci 317bf215546Sopenharmony_ci fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer); 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_ci /* This will destroy all our data */ 320bf215546Sopenharmony_ci return DestroyWindow(fb->hWnd); 321bf215546Sopenharmony_ci} 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_ciBOOL WINAPI 325bf215546Sopenharmony_ciwglQueryPbufferARB(HPBUFFERARB hPbuffer, 326bf215546Sopenharmony_ci int iAttribute, 327bf215546Sopenharmony_ci int *piValue) 328bf215546Sopenharmony_ci{ 329bf215546Sopenharmony_ci struct stw_framebuffer *fb; 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci if (!hPbuffer) { 332bf215546Sopenharmony_ci SetLastError(ERROR_INVALID_HANDLE); 333bf215546Sopenharmony_ci return FALSE; 334bf215546Sopenharmony_ci } 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer); 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci switch (iAttribute) { 339bf215546Sopenharmony_ci case WGL_PBUFFER_WIDTH_ARB: 340bf215546Sopenharmony_ci *piValue = fb->width; 341bf215546Sopenharmony_ci return TRUE; 342bf215546Sopenharmony_ci case WGL_PBUFFER_HEIGHT_ARB: 343bf215546Sopenharmony_ci *piValue = fb->height; 344bf215546Sopenharmony_ci return TRUE; 345bf215546Sopenharmony_ci case WGL_PBUFFER_LOST_ARB: 346bf215546Sopenharmony_ci /* We assume that no content is ever lost due to display mode change */ 347bf215546Sopenharmony_ci *piValue = FALSE; 348bf215546Sopenharmony_ci return TRUE; 349bf215546Sopenharmony_ci /* WGL_ARB_render_texture */ 350bf215546Sopenharmony_ci case WGL_TEXTURE_TARGET_ARB: 351bf215546Sopenharmony_ci *piValue = fb->textureTarget; 352bf215546Sopenharmony_ci return TRUE; 353bf215546Sopenharmony_ci case WGL_TEXTURE_FORMAT_ARB: 354bf215546Sopenharmony_ci *piValue = fb->textureFormat; 355bf215546Sopenharmony_ci return TRUE; 356bf215546Sopenharmony_ci case WGL_MIPMAP_TEXTURE_ARB: 357bf215546Sopenharmony_ci *piValue = fb->textureMipmap; 358bf215546Sopenharmony_ci return TRUE; 359bf215546Sopenharmony_ci case WGL_MIPMAP_LEVEL_ARB: 360bf215546Sopenharmony_ci *piValue = fb->textureLevel; 361bf215546Sopenharmony_ci return TRUE; 362bf215546Sopenharmony_ci case WGL_CUBE_MAP_FACE_ARB: 363bf215546Sopenharmony_ci *piValue = fb->textureFace + WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; 364bf215546Sopenharmony_ci return TRUE; 365bf215546Sopenharmony_ci default: 366bf215546Sopenharmony_ci SetLastError(ERROR_INVALID_DATA); 367bf215546Sopenharmony_ci return FALSE; 368bf215546Sopenharmony_ci } 369bf215546Sopenharmony_ci} 370