/*
* Copyright 2019-2021 Diligent Graphics LLC
* Copyright 2015-2019 Egor Yusov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* In no event and under no legal theory, whether in tort (including negligence),
* contract, or otherwise, unless required by applicable law (such as deliberate
* and grossly negligent acts) or agreed to in writing, shall any Contributor be
* liable for any damages, including any direct, indirect, special, incidental,
* or consequential damages of any character arising as a result of this License or
* out of the use or inability to use the software (including but not limited to damages
* for loss of goodwill, work stoppage, computer failure or malfunction, or any and
* all other commercial damages or losses), even if such Contributor has been advised
* of the possibility of such damages.
*/
#include "TestingEnvironment.hpp"
#include <GL/glx.h>
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, int, const int*);
namespace Diligent
{
namespace Testing
{
NativeWindow TestingEnvironment::CreateNativeWindow()
{
auto* display = XOpenDisplay(0);
// clang-format off
static int visual_attribs[] =
{
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_DOUBLEBUFFER, true,
// The largest available total RGBA color buffer size (sum of GLX_RED_SIZE,
// GLX_GREEN_SIZE, GLX_BLUE_SIZE, and GLX_ALPHA_SIZE) of at least the minimum
// size specified for each color component is preferred.
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
// The largest available depth buffer of at least GLX_DEPTH_SIZE size is preferred
GLX_DEPTH_SIZE, 24,
//GLX_SAMPLE_BUFFERS, 1,
GLX_SAMPLES, 1,
None
};
// clang-format on
int fbcount = 0;
GLXFBConfig* fbc = glXChooseFBConfig(display, DefaultScreen(display), visual_attribs, &fbcount);
if (!fbc)
{
LOG_ERROR_AND_THROW("Failed to retrieve a framebuffer config");
}
XVisualInfo* vi = glXGetVisualFromFBConfig(display, fbc[0]);
XSetWindowAttributes swa;
swa.colormap = XCreateColormap(display, RootWindow(display, vi->screen), vi->visual, AllocNone);
swa.border_pixel = 0;
swa.event_mask =
StructureNotifyMask |
ExposureMask |
KeyPressMask |
KeyReleaseMask |
ButtonPressMask |
ButtonReleaseMask |
PointerMotionMask;
auto win = XCreateWindow(display, RootWindow(display, vi->screen), 0, 0, 1024, 768, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &swa);
if (!win)
{
LOG_ERROR_AND_THROW("Failed to create window.");
}
{
auto SizeHints = XAllocSizeHints();
SizeHints->flags = PMinSize;
SizeHints->min_width = 320;
SizeHints->min_height = 240;
XSetWMNormalHints(display, win, SizeHints);
XFree(SizeHints);
}
XMapWindow(display, win);
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = nullptr;
{
// Create an oldstyle context first, to get the correct function pointer for glXCreateContextAttribsARB
GLXContext ctx_old = glXCreateContext(display, vi, 0, GL_TRUE);
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
glXMakeCurrent(display, None, NULL);
glXDestroyContext(display, ctx_old);
}
if (glXCreateContextAttribsARB == nullptr)
{
LOG_ERROR_AND_THROW("glXCreateContextAttribsARB entry point not found. Aborting.");
}
int Flags = GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
#ifdef _DEBUG
Flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
#endif
int major_version = 4;
int minor_version = 3;
// clang-format off
static int context_attribs[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, major_version,
GLX_CONTEXT_MINOR_VERSION_ARB, minor_version,
GLX_CONTEXT_FLAGS_ARB, Flags,
None
};
// clang-format on
GLXContext ctx = glXCreateContextAttribsARB(display, fbc[0], NULL, 1, context_attribs);
if (!ctx)
{
LOG_ERROR_AND_THROW("Failed to create GL context.");
}
XFree(fbc);
glXMakeCurrent(display, win, ctx);
struct TestingEnvironmentLinuxData : PlatformData
{
explicit TestingEnvironmentLinuxData(NativeWindow _LinuxWnd) :
LinuxWnd{_LinuxWnd}
{
}
virtual ~TestingEnvironmentLinuxData()
{
auto ctx = glXGetCurrentContext();
auto* display = reinterpret_cast<Display*>(LinuxWnd.pDisplay);
glXMakeCurrent(display, None, NULL);
glXDestroyContext(display, ctx);
XDestroyWindow(display, LinuxWnd.WindowId);
XCloseDisplay(display);
}
NativeWindow LinuxWnd;
};
NativeWindow LinuxWnd;
LinuxWnd.pDisplay = display;
LinuxWnd.WindowId = win;
m_pPlatformData.reset(new TestingEnvironmentLinuxData{LinuxWnd});
return LinuxWnd;
}
} // namespace Testing
} // namespace Diligent