2024-01-20 13:21:35 +00:00
|
|
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
2022-12-04 11:03:45 +00:00
|
|
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
|
|
|
|
2020-05-07 12:48:13 +00:00
|
|
|
#include "context.h"
|
2023-08-13 03:42:02 +00:00
|
|
|
#include "../opengl_loader.h"
|
|
|
|
|
2024-01-20 13:21:35 +00:00
|
|
|
#include "common/error.h"
|
2023-08-13 03:42:02 +00:00
|
|
|
#include "common/log.h"
|
|
|
|
|
2023-04-29 10:45:19 +00:00
|
|
|
#include <cstdio>
|
2020-05-07 12:48:13 +00:00
|
|
|
#include <cstdlib>
|
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <stdlib.h>
|
|
|
|
#else
|
|
|
|
#include <malloc.h>
|
|
|
|
#endif
|
|
|
|
|
2021-06-28 10:16:48 +00:00
|
|
|
#if defined(_WIN32) && !defined(_M_ARM64)
|
2020-05-07 12:48:13 +00:00
|
|
|
#include "context_wgl.h"
|
2022-07-30 15:06:40 +00:00
|
|
|
#elif defined(__APPLE__)
|
2020-05-07 12:48:13 +00:00
|
|
|
#include "context_agl.h"
|
2023-10-31 15:32:29 +00:00
|
|
|
#elif defined(__ANDROID__)
|
|
|
|
#include "context_egl_android.h"
|
2023-08-13 03:42:02 +00:00
|
|
|
#else
|
2023-09-17 02:28:11 +00:00
|
|
|
#ifdef ENABLE_EGL
|
|
|
|
#ifdef ENABLE_WAYLAND
|
2020-07-07 11:40:55 +00:00
|
|
|
#include "context_egl_wayland.h"
|
2020-09-23 09:46:39 +00:00
|
|
|
#endif
|
2023-09-17 02:28:11 +00:00
|
|
|
#ifdef ENABLE_X11
|
2021-01-31 15:45:30 +00:00
|
|
|
#include "context_egl_x11.h"
|
|
|
|
#endif
|
2020-05-07 12:48:13 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2023-08-13 03:42:02 +00:00
|
|
|
Log_SetChannel(GL::Context);
|
2020-05-07 12:48:13 +00:00
|
|
|
|
|
|
|
namespace GL {
|
|
|
|
|
|
|
|
static bool ShouldPreferESContext()
|
|
|
|
{
|
2022-10-20 14:29:24 +00:00
|
|
|
#if defined(__ANDROID__)
|
|
|
|
return true;
|
|
|
|
#elif !defined(_MSC_VER)
|
2020-05-07 12:48:13 +00:00
|
|
|
const char* value = std::getenv("PREFER_GLES_CONTEXT");
|
|
|
|
return (value && std::strcmp(value, "1") == 0);
|
|
|
|
#else
|
|
|
|
char buffer[2] = {};
|
|
|
|
size_t buffer_size = sizeof(buffer);
|
|
|
|
getenv_s(&buffer_size, buffer, "PREFER_GLES_CONTEXT");
|
|
|
|
return (std::strcmp(buffer, "1") == 0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-09-03 04:15:15 +00:00
|
|
|
static void DisableBrokenExtensions(const char* gl_vendor, const char* gl_renderer, const char* gl_version)
|
2021-02-06 09:10:25 +00:00
|
|
|
{
|
2021-02-06 10:25:26 +00:00
|
|
|
if (std::strstr(gl_vendor, "ARM"))
|
2021-02-06 09:10:25 +00:00
|
|
|
{
|
|
|
|
// GL_{EXT,OES}_copy_image seem to be implemented on the CPU in the Mali drivers...
|
2022-09-03 04:15:15 +00:00
|
|
|
// Older drivers don't implement timer queries correctly either.
|
|
|
|
int gl_major_version, gl_minor_version, unused_version, major_version, patch_version;
|
2022-11-15 11:33:06 +00:00
|
|
|
if ((std::sscanf(gl_version, "OpenGL ES %d.%d v%d.r%dp%d", &gl_major_version, &gl_minor_version, &unused_version,
|
|
|
|
&major_version, &patch_version) == 5 &&
|
|
|
|
gl_major_version >= 3 && gl_minor_version >= 2 && major_version >= 32) ||
|
|
|
|
(std::sscanf(gl_version, "OpenGL ES %d.%d v%d.g%dp%d", &gl_major_version, &gl_minor_version, &unused_version,
|
|
|
|
&major_version, &patch_version) == 5 &&
|
|
|
|
gl_major_version >= 3 && gl_minor_version >= 2 && major_version > 0))
|
2022-09-03 04:15:15 +00:00
|
|
|
{
|
|
|
|
// r32p0 and beyond seem okay.
|
2024-01-20 13:21:35 +00:00
|
|
|
// Log_VerbosePrintf("Keeping copy_image for driver version '%s'", gl_version);
|
2023-12-16 11:04:40 +00:00
|
|
|
|
|
|
|
// Framebuffer blits still end up faster.
|
|
|
|
Log_VerbosePrintf("Newer Mali driver detected, disabling GL_{EXT,OES}_copy_image.");
|
|
|
|
GLAD_GL_EXT_copy_image = 0;
|
|
|
|
GLAD_GL_OES_copy_image = 0;
|
2022-09-03 04:15:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Log_VerbosePrintf("Older Mali driver detected, disabling GL_{EXT,OES}_copy_image, disjoint_timer_query.");
|
|
|
|
GLAD_GL_EXT_copy_image = 0;
|
|
|
|
GLAD_GL_OES_copy_image = 0;
|
|
|
|
GLAD_GL_EXT_disjoint_timer_query = 0;
|
|
|
|
}
|
2021-02-06 09:10:25 +00:00
|
|
|
}
|
2023-12-03 11:43:57 +00:00
|
|
|
else if (std::strstr(gl_vendor, "Qualcomm") && std::strstr(gl_renderer, "Adreno"))
|
|
|
|
{
|
|
|
|
// Framebuffer fetch appears to be broken in drivers ?? >= 464 < 502.
|
|
|
|
int gl_major_version = 0, gl_minor_version = 0, major_version = 0;
|
|
|
|
if ((std::sscanf(gl_version, "OpenGL ES %d.%d V@%d", &gl_major_version, &gl_minor_version, &major_version) == 3 &&
|
|
|
|
gl_major_version >= 3 && gl_minor_version >= 2 && major_version < 502))
|
|
|
|
{
|
|
|
|
Log_VerboseFmt("Disabling GL_EXT_shader_framebuffer_fetch on Adreno version {}", major_version);
|
|
|
|
GLAD_GL_EXT_shader_framebuffer_fetch = 0;
|
|
|
|
GLAD_GL_ARM_shader_framebuffer_fetch = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Log_VerboseFmt("Keeping GL_EXT_shader_framebuffer_fetch on Adreno version {}", major_version);
|
|
|
|
}
|
|
|
|
}
|
2022-10-03 15:40:13 +00:00
|
|
|
|
|
|
|
// If we're missing GLES 3.2, but have OES_draw_elements_base_vertex, redirect the function pointers.
|
|
|
|
if (!glad_glDrawElementsBaseVertex && GLAD_GL_OES_draw_elements_base_vertex && !GLAD_GL_ES_VERSION_3_2)
|
|
|
|
{
|
|
|
|
glad_glDrawElementsBaseVertex = glad_glDrawElementsBaseVertexOES;
|
|
|
|
glad_glDrawRangeElementsBaseVertex = glad_glDrawRangeElementsBaseVertexOES;
|
|
|
|
glad_glDrawElementsInstancedBaseVertex = glad_glDrawElementsInstancedBaseVertexOES;
|
|
|
|
}
|
2021-02-06 09:10:25 +00:00
|
|
|
}
|
|
|
|
|
2023-08-13 03:42:02 +00:00
|
|
|
Context::Context(const WindowInfo& wi) : m_wi(wi)
|
|
|
|
{
|
|
|
|
}
|
2020-05-07 12:48:13 +00:00
|
|
|
|
|
|
|
Context::~Context() = default;
|
|
|
|
|
2021-02-13 14:52:34 +00:00
|
|
|
std::vector<Context::FullscreenModeInfo> Context::EnumerateFullscreenModes()
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2024-01-20 13:21:35 +00:00
|
|
|
std::unique_ptr<GL::Context> Context::Create(const WindowInfo& wi, Error* error)
|
2020-05-07 12:48:13 +00:00
|
|
|
{
|
2024-01-20 13:21:35 +00:00
|
|
|
static constexpr std::array<Version, 14> vlist = {{{Profile::Core, 4, 6},
|
|
|
|
{Profile::Core, 4, 5},
|
|
|
|
{Profile::Core, 4, 4},
|
|
|
|
{Profile::Core, 4, 3},
|
|
|
|
{Profile::Core, 4, 2},
|
|
|
|
{Profile::Core, 4, 1},
|
|
|
|
{Profile::Core, 4, 0},
|
|
|
|
{Profile::Core, 3, 3},
|
|
|
|
{Profile::Core, 3, 2},
|
|
|
|
{Profile::Core, 3, 1},
|
|
|
|
{Profile::Core, 3, 0},
|
|
|
|
{Profile::ES, 3, 2},
|
|
|
|
{Profile::ES, 3, 1},
|
|
|
|
{Profile::ES, 3, 0}}};
|
|
|
|
|
|
|
|
std::span<const Version> versions_to_try = vlist;
|
2020-05-07 12:48:13 +00:00
|
|
|
if (ShouldPreferESContext())
|
|
|
|
{
|
|
|
|
// move ES versions to the front
|
2024-01-20 13:21:35 +00:00
|
|
|
Version* new_versions_to_try = static_cast<Version*>(alloca(sizeof(Version) * versions_to_try.size()));
|
2020-05-07 12:48:13 +00:00
|
|
|
size_t count = 0;
|
2024-01-20 13:21:35 +00:00
|
|
|
for (const Version& cv : versions_to_try)
|
2020-05-07 12:48:13 +00:00
|
|
|
{
|
2024-01-20 13:21:35 +00:00
|
|
|
if (cv.profile == Profile::ES)
|
|
|
|
new_versions_to_try[count++] = cv;
|
2020-05-07 12:48:13 +00:00
|
|
|
}
|
2024-01-20 13:21:35 +00:00
|
|
|
for (const Version& cv : versions_to_try)
|
2020-05-07 12:48:13 +00:00
|
|
|
{
|
2024-01-20 13:21:35 +00:00
|
|
|
if (cv.profile != Profile::ES)
|
|
|
|
new_versions_to_try[count++] = cv;
|
2020-05-07 12:48:13 +00:00
|
|
|
}
|
2024-01-20 13:21:35 +00:00
|
|
|
versions_to_try = std::span<const Version>(new_versions_to_try, versions_to_try.size());
|
2020-05-07 12:48:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<Context> context;
|
2024-02-18 08:16:46 +00:00
|
|
|
Error local_error;
|
2021-06-28 10:16:48 +00:00
|
|
|
#if defined(_WIN32) && !defined(_M_ARM64)
|
2024-02-18 08:16:46 +00:00
|
|
|
context = ContextWGL::Create(wi, versions_to_try, error ? error : &local_error);
|
2021-03-08 07:28:34 +00:00
|
|
|
#elif defined(__APPLE__)
|
2024-01-20 13:21:35 +00:00
|
|
|
context = ContextAGL::Create(wi, versions_to_try);
|
2023-10-31 15:32:29 +00:00
|
|
|
#elif defined(__ANDROID__)
|
2024-02-18 08:16:46 +00:00
|
|
|
context = ContextEGLAndroid::Create(wi, versions_to_try, error ? error : &local_error);
|
2023-08-13 03:42:02 +00:00
|
|
|
#else
|
2023-09-17 02:28:11 +00:00
|
|
|
#if defined(ENABLE_X11)
|
2020-05-07 12:48:13 +00:00
|
|
|
if (wi.type == WindowInfo::Type::X11)
|
2024-02-18 08:16:46 +00:00
|
|
|
context = ContextEGLX11::Create(wi, versions_to_try, error ? error : &local_error);
|
2020-05-07 12:48:13 +00:00
|
|
|
#endif
|
2023-09-17 02:28:11 +00:00
|
|
|
#if defined(ENABLE_WAYLAND)
|
2020-07-07 11:40:55 +00:00
|
|
|
if (wi.type == WindowInfo::Type::Wayland)
|
2024-02-18 08:16:46 +00:00
|
|
|
context = ContextEGLWayland::Create(wi, versions_to_try, error ? error : &local_error);
|
2020-07-07 11:40:55 +00:00
|
|
|
#endif
|
2023-11-21 07:04:45 +00:00
|
|
|
if (wi.type == WindowInfo::Type::Surfaceless)
|
2024-02-18 08:16:46 +00:00
|
|
|
context = ContextEGL::Create(wi, versions_to_try, error ? error : &local_error);
|
2021-02-13 16:51:26 +00:00
|
|
|
#endif
|
|
|
|
|
2020-05-07 12:48:13 +00:00
|
|
|
if (!context)
|
2024-02-18 08:16:46 +00:00
|
|
|
{
|
|
|
|
Log_ErrorFmt("Failed to create GL context: {}", (error ? error : &local_error)->GetDescription());
|
2020-05-07 12:48:13 +00:00
|
|
|
return nullptr;
|
2024-02-18 08:16:46 +00:00
|
|
|
}
|
2020-05-07 12:48:13 +00:00
|
|
|
|
2024-02-18 08:16:46 +00:00
|
|
|
Log_InfoPrint(context->IsGLES() ? "Created an OpenGL ES context" : "Created an OpenGL context");
|
2020-05-07 12:48:13 +00:00
|
|
|
|
|
|
|
// TODO: Not thread-safe.
|
|
|
|
static Context* context_being_created;
|
|
|
|
context_being_created = context.get();
|
|
|
|
|
|
|
|
// load up glad
|
|
|
|
if (!context->IsGLES())
|
|
|
|
{
|
2024-02-25 05:32:26 +00:00
|
|
|
if (!gladLoadGL([](const char* name) { return (GLADapiproc)context_being_created->GetProcAddress(name); }))
|
2020-05-07 12:48:13 +00:00
|
|
|
{
|
2024-01-20 13:21:35 +00:00
|
|
|
Error::SetStringView(error, "Failed to load GL functions for GLAD");
|
2020-05-07 12:48:13 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-02-25 05:32:26 +00:00
|
|
|
if (!gladLoadGLES2([](const char* name) { return (GLADapiproc)context_being_created->GetProcAddress(name); }))
|
2020-05-07 12:48:13 +00:00
|
|
|
{
|
2024-01-20 13:21:35 +00:00
|
|
|
Error::SetStringView(error, "Failed to load GLES functions for GLAD");
|
2020-05-07 12:48:13 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
|
|
|
const char* gl_renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
|
|
|
|
const char* gl_version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
|
2020-05-25 08:36:52 +00:00
|
|
|
const char* gl_shading_language_version = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
|
2020-05-07 12:48:13 +00:00
|
|
|
Log_InfoPrintf("GL_VENDOR: %s", gl_vendor);
|
|
|
|
Log_InfoPrintf("GL_RENDERER: %s", gl_renderer);
|
|
|
|
Log_InfoPrintf("GL_VERSION: %s", gl_version);
|
2020-05-25 08:36:52 +00:00
|
|
|
Log_InfoPrintf("GL_SHADING_LANGUAGE_VERSION: %s", gl_shading_language_version);
|
2020-05-07 12:48:13 +00:00
|
|
|
|
2022-09-03 04:15:15 +00:00
|
|
|
DisableBrokenExtensions(gl_vendor, gl_renderer, gl_version);
|
2021-02-06 09:10:25 +00:00
|
|
|
|
2020-05-07 12:48:13 +00:00
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace GL
|