mirror of https://github.com/stenzek/duckstation
GPUDevice: Drop SDL window type
Never worked properly anyway. Couldn't change modes, since releasing the window destroyed the context, didn't support multi-window, etc.pull/3706/head
parent
7b50681fa7
commit
98e9db7fbb
@ -1,281 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#include "opengl_context_sdl.h"
|
||||
#include "gpu_texture.h"
|
||||
#include "opengl_loader.h"
|
||||
#include "sdl_video_helpers.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
#include "common/scoped_guard.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
LOG_CHANNEL(GPUDevice);
|
||||
|
||||
OpenGLContextSDL::OpenGLContextSDL() = default;
|
||||
|
||||
OpenGLContextSDL::~OpenGLContextSDL()
|
||||
{
|
||||
if (SDL_GL_GetCurrentContext() == m_context)
|
||||
SDL_GL_MakeCurrent(nullptr, nullptr);
|
||||
|
||||
if (m_context)
|
||||
SDL_GL_DestroyContext(m_context);
|
||||
}
|
||||
|
||||
std::unique_ptr<OpenGLContext> OpenGLContextSDL::Create(WindowInfo& wi, SurfaceHandle* surface,
|
||||
std::span<const Version> versions_to_try, Error* error)
|
||||
{
|
||||
std::unique_ptr<OpenGLContextSDL> context = std::make_unique<OpenGLContextSDL>();
|
||||
if (!context->Initialize(wi, surface, versions_to_try, false, error))
|
||||
context.reset();
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
GPUDevice::AdapterInfoList OpenGLContextSDL::GetAdapterList(WindowInfoType window_type, Error* error)
|
||||
{
|
||||
std::vector<GPUDevice::ExclusiveFullscreenMode> fullscreen_modes = SDLVideoHelpers::GetFullscreenModeList();
|
||||
if (fullscreen_modes.empty())
|
||||
{
|
||||
// no point adding anything if no modes
|
||||
return {};
|
||||
}
|
||||
|
||||
// Set some reasonable defaults, since we don't know this until we actually create the context.
|
||||
GPUDevice::AdapterInfoList ret;
|
||||
GPUDevice::AdapterInfo& ai = ret.emplace_back();
|
||||
ai.driver_type = GPUDriverType::Unknown;
|
||||
ai.max_multisamples = 8;
|
||||
ai.supports_sample_shading = true;
|
||||
ai.max_texture_size = 16384;
|
||||
ai.fullscreen_modes = std::move(fullscreen_modes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool OpenGLContextSDL::Initialize(WindowInfo& wi, SurfaceHandle* surface, std::span<const Version> versions_to_try,
|
||||
bool share_context, Error* error)
|
||||
{
|
||||
static bool opengl_loaded = false;
|
||||
if (!opengl_loaded)
|
||||
{
|
||||
if (!SDL_GL_LoadLibrary(nullptr))
|
||||
{
|
||||
Error::SetStringFmt(error, "SDL_GL_LoadLibrary() failed: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
opengl_loaded = true;
|
||||
}
|
||||
|
||||
if (wi.IsSurfaceless())
|
||||
{
|
||||
Error::SetStringView(error, "Surfaceless is not supported with OpenGLContextSDL.");
|
||||
return false;
|
||||
}
|
||||
else if (wi.type != WindowInfoType::SDL)
|
||||
{
|
||||
Error::SetStringView(error, "Incompatible window type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wi.surface_format == GPUTextureFormat::Unknown)
|
||||
wi.surface_format = GPUTextureFormat::RGBA8;
|
||||
|
||||
SDL_Window* const window = static_cast<SDL_Window*>(wi.window_handle);
|
||||
for (const Version& cv : versions_to_try)
|
||||
{
|
||||
if (CreateVersionContext(cv, window, wi.surface_format, share_context, !share_context))
|
||||
{
|
||||
m_version = cv;
|
||||
*surface = window;
|
||||
UpdateWindowInfoSize(wi, window);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Error::SetStringView(error, "Failed to create any contexts.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void* OpenGLContextSDL::GetProcAddress(const char* name)
|
||||
{
|
||||
return (void*)SDL_GL_GetProcAddress(name);
|
||||
}
|
||||
|
||||
OpenGLContext::SurfaceHandle OpenGLContextSDL::CreateSurface(WindowInfo& wi, Error* error /*= nullptr*/)
|
||||
{
|
||||
if (wi.IsSurfaceless()) [[unlikely]]
|
||||
{
|
||||
Error::SetStringView(error, "Trying to create a surfaceless surface.");
|
||||
return nullptr;
|
||||
}
|
||||
else if (wi.type != WindowInfoType::SDL)
|
||||
{
|
||||
Error::SetStringView(error, "Incompatible window type.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return static_cast<SDL_Window*>(wi.window_handle);
|
||||
}
|
||||
|
||||
void OpenGLContextSDL::DestroySurface(SurfaceHandle handle)
|
||||
{
|
||||
// cleaned up on window destruction? but we still need to clear current
|
||||
SDL_Window* const window = static_cast<SDL_Window*>(handle);
|
||||
if (m_current_window == window)
|
||||
DoneCurrent();
|
||||
}
|
||||
|
||||
void OpenGLContextSDL::ResizeSurface(WindowInfo& wi, SurfaceHandle handle)
|
||||
{
|
||||
UpdateWindowInfoSize(wi, static_cast<SDL_Window*>(handle));
|
||||
}
|
||||
|
||||
void OpenGLContextSDL::UpdateWindowInfoSize(WindowInfo& wi, SDL_Window* window) const
|
||||
{
|
||||
int drawable_width, drawable_height;
|
||||
SDL_GetWindowSizeInPixels(window, &drawable_width, &drawable_height);
|
||||
wi.surface_width = static_cast<u16>(drawable_width);
|
||||
wi.surface_height = static_cast<u16>(drawable_height);
|
||||
if (WindowInfo::ShouldSwapDimensionsForPreRotation(wi.surface_prerotation))
|
||||
std::swap(wi.surface_width, wi.surface_height);
|
||||
}
|
||||
|
||||
bool OpenGLContextSDL::SwapBuffers()
|
||||
{
|
||||
SDL_GL_SwapWindow(m_current_window);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLContextSDL::IsCurrent() const
|
||||
{
|
||||
return (m_context && SDL_GL_GetCurrentContext() == m_context);
|
||||
}
|
||||
|
||||
bool OpenGLContextSDL::MakeCurrent(SurfaceHandle surface, Error* error /* = nullptr */)
|
||||
{
|
||||
SDL_Window* const window = static_cast<SDL_Window*>(surface);
|
||||
if (m_current_window == window)
|
||||
return true;
|
||||
|
||||
if (!SDL_GL_MakeCurrent(window, m_context))
|
||||
{
|
||||
ERROR_LOG("SDL_GL_MakeCurrent() failed: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_current_window = window;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLContextSDL::DoneCurrent()
|
||||
{
|
||||
if (!SDL_GL_MakeCurrent(nullptr, nullptr))
|
||||
return false;
|
||||
|
||||
m_current_window = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLContextSDL::SupportsNegativeSwapInterval() const
|
||||
{
|
||||
int current_interval = 0;
|
||||
if (!SDL_GL_GetSwapInterval(¤t_interval))
|
||||
{
|
||||
ERROR_LOG("SDL_GL_GetSwapInterval() failed: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool supported = SDL_GL_SetSwapInterval(-1);
|
||||
SDL_GL_SetSwapInterval(current_interval);
|
||||
return supported;
|
||||
}
|
||||
|
||||
bool OpenGLContextSDL::SetSwapInterval(s32 interval, Error* error)
|
||||
{
|
||||
if (SDL_GL_SetSwapInterval(interval) != 0)
|
||||
{
|
||||
Error::SetStringFmt(error, "SDL_GL_SetSwapInterval() failed: ", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<OpenGLContext> OpenGLContextSDL::CreateSharedContext(WindowInfo& wi, SurfaceHandle* surface,
|
||||
Error* error)
|
||||
{
|
||||
std::unique_ptr<OpenGLContextSDL> context = std::make_unique<OpenGLContextSDL>();
|
||||
if (!context->Initialize(wi, surface, std::span<const Version>(&m_version, 1), true, error))
|
||||
context.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
bool OpenGLContextSDL::CreateVersionContext(const Version& version, SDL_Window* window, GPUTextureFormat surface_format,
|
||||
bool share_context, bool make_current)
|
||||
{
|
||||
SDL_GL_ResetAttributes();
|
||||
|
||||
switch (surface_format)
|
||||
{
|
||||
case GPUTextureFormat::RGBA8:
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
|
||||
break;
|
||||
|
||||
case GPUTextureFormat::RGB565:
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_LOG("Unsupported texture format {}", GPUTexture::GetFormatName(surface_format));
|
||||
break;
|
||||
}
|
||||
|
||||
if (share_context)
|
||||
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, true);
|
||||
|
||||
if (version.profile != Profile::NoProfile)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
|
||||
(version.profile == Profile::ES) ? SDL_GL_CONTEXT_PROFILE_ES : SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, version.major_version);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, version.minor_version);
|
||||
if (version.profile == Profile::Core)
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
|
||||
}
|
||||
|
||||
SDL_GLContext context = SDL_GL_CreateContext(window);
|
||||
if (!context)
|
||||
{
|
||||
DEV_LOG("SDL_GL_CreateContext({}.{}{}) failed: {}", version.major_version, version.minor_version,
|
||||
((version.profile == Profile::ES) ? " ES" : ((version.profile == Profile::Core) ? " Core" : "")),
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (make_current)
|
||||
{
|
||||
if (!SDL_GL_MakeCurrent(window, context))
|
||||
{
|
||||
DEV_LOG("SDL_GL_MakeCurrent({}.{}{}) failed: {}", version.major_version, version.minor_version,
|
||||
((version.profile == Profile::ES) ? " ES" : ((version.profile == Profile::Core) ? " Core" : "")),
|
||||
SDL_GetError());
|
||||
SDL_GL_DestroyContext(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_current_window = window;
|
||||
}
|
||||
|
||||
m_context = context;
|
||||
return true;
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "opengl_context.h"
|
||||
#include "opengl_loader.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
typedef struct SDL_GLContextState* SDL_GLContext;
|
||||
struct SDL_Window;
|
||||
|
||||
class OpenGLContextSDL final : public OpenGLContext
|
||||
{
|
||||
public:
|
||||
OpenGLContextSDL();
|
||||
~OpenGLContextSDL() override;
|
||||
|
||||
static std::unique_ptr<OpenGLContext> Create(WindowInfo& wi, SurfaceHandle* surface,
|
||||
std::span<const Version> versions_to_try, Error* error);
|
||||
static GPUDevice::AdapterInfoList GetAdapterList(WindowInfoType window_type, Error* error);
|
||||
|
||||
void* GetProcAddress(const char* name) override;
|
||||
SurfaceHandle CreateSurface(WindowInfo& wi, Error* error = nullptr) override;
|
||||
void DestroySurface(SurfaceHandle handle) override;
|
||||
void ResizeSurface(WindowInfo& wi, SurfaceHandle handle) override;
|
||||
bool SwapBuffers() override;
|
||||
bool IsCurrent() const override;
|
||||
bool MakeCurrent(SurfaceHandle surface, Error* error = nullptr) override;
|
||||
bool DoneCurrent() override;
|
||||
bool SupportsNegativeSwapInterval() const override;
|
||||
bool SetSwapInterval(s32 interval, Error* error = nullptr) override;
|
||||
std::unique_ptr<OpenGLContext> CreateSharedContext(WindowInfo& wi, SurfaceHandle* surface, Error* error) override;
|
||||
|
||||
private:
|
||||
bool Initialize(WindowInfo& wi, SurfaceHandle* surface, std::span<const Version> versions_to_try, bool share_context,
|
||||
Error* error);
|
||||
|
||||
bool CreateVersionContext(const Version& version, SDL_Window* window, GPUTextureFormat surface_format,
|
||||
bool share_context, bool make_current);
|
||||
|
||||
void UpdateWindowInfoSize(WindowInfo& wi, SDL_Window* window) const;
|
||||
|
||||
SDL_GLContext m_context = nullptr;
|
||||
SDL_Window* m_current_window = nullptr;
|
||||
};
|
||||
@ -1,54 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_device.h"
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace SDLVideoHelpers {
|
||||
|
||||
inline std::vector<GPUDevice::ExclusiveFullscreenMode> GetFullscreenModeList()
|
||||
{
|
||||
int display_count = 0;
|
||||
const SDL_DisplayID* const displays = SDL_GetDisplays(&display_count);
|
||||
if (display_count <= 0)
|
||||
{
|
||||
GENERIC_LOG(Log::Channel::SDL, Log::Level::Error, Log::Color::Default, "SDL_GetDisplays() returned no displays: {}",
|
||||
SDL_GetError());
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<GPUDevice::ExclusiveFullscreenMode> modes;
|
||||
for (int i = 0; i < display_count; i++)
|
||||
{
|
||||
int dm_count = 0;
|
||||
const SDL_DisplayMode* const* const dms = SDL_GetFullscreenDisplayModes(displays[i], &dm_count);
|
||||
if (dm_count <= 0)
|
||||
{
|
||||
GENERIC_LOG(Log::Channel::SDL, Log::Level::Error, Log::Color::Default,
|
||||
"SDL_GetFullscreenDisplayModes() returned no modes for display {}: {}", displays[i], SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
modes.reserve(modes.size() + static_cast<size_t>(dm_count));
|
||||
|
||||
for (int j = 0; j < dm_count; j++)
|
||||
{
|
||||
const SDL_DisplayMode* const dm = dms[j];
|
||||
const GPUDevice::ExclusiveFullscreenMode mode{static_cast<u32>(dm->w), static_cast<u32>(dm->h), dm->refresh_rate};
|
||||
if (std::ranges::find(modes, mode) == modes.end())
|
||||
modes.push_back(mode);
|
||||
}
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
||||
} // namespace SDLVideoHelpers
|
||||
Loading…
Reference in New Issue