mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-06 03:25:36 +00:00
OpenGLDevice: Support SDL window type
This commit is contained in:
parent
ee1a3b904e
commit
df9f15eb68
@ -190,6 +190,12 @@ if(NOT ANDROID)
|
|||||||
sdl_input_source.cpp
|
sdl_input_source.cpp
|
||||||
sdl_input_source.h
|
sdl_input_source.h
|
||||||
)
|
)
|
||||||
|
if(ENABLE_OPENGL)
|
||||||
|
target_sources(util PRIVATE
|
||||||
|
opengl_context_sdl.cpp
|
||||||
|
opengl_context_sdl.h
|
||||||
|
)
|
||||||
|
endif()
|
||||||
target_compile_definitions(util PUBLIC
|
target_compile_definitions(util PUBLIC
|
||||||
ENABLE_SDL
|
ENABLE_SDL
|
||||||
)
|
)
|
||||||
|
@ -33,6 +33,10 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_SDL
|
||||||
|
#include "opengl_context_sdl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
LOG_CHANNEL(GPUDevice);
|
LOG_CHANNEL(GPUDevice);
|
||||||
|
|
||||||
static bool ShouldPreferESContext()
|
static bool ShouldPreferESContext()
|
||||||
@ -175,6 +179,10 @@ std::unique_ptr<OpenGLContext> OpenGLContext::Create(WindowInfo& wi, SurfaceHand
|
|||||||
if (wi.type == WindowInfo::Type::Surfaceless)
|
if (wi.type == WindowInfo::Type::Surfaceless)
|
||||||
context = OpenGLContextEGL::Create(wi, surface, versions_to_try, error);
|
context = OpenGLContextEGL::Create(wi, surface, versions_to_try, error);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ENABLE_SDL
|
||||||
|
if (wi.type == WindowInfo::Type::SDL)
|
||||||
|
context = OpenGLContextSDL::Create(wi, surface, versions_to_try, error);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!context)
|
if (!context)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
256
src/util/opengl_context_sdl.cpp
Normal file
256
src/util/opengl_context_sdl.cpp
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||||
|
|
||||||
|
#include "opengl_context_sdl.h"
|
||||||
|
#include "opengl_loader.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 != WindowInfo::Type::SDL)
|
||||||
|
{
|
||||||
|
Error::SetStringView(error, "Incompatible window type.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wi.surface_format == GPUTexture::Format::Unknown)
|
||||||
|
wi.surface_format = GPUTexture::Format::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 != WindowInfo::Type::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?
|
||||||
|
}
|
||||||
|
|
||||||
|
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) != 0)
|
||||||
|
{
|
||||||
|
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) != 0)
|
||||||
|
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,
|
||||||
|
GPUTexture::Format surface_format, bool share_context, bool make_current)
|
||||||
|
{
|
||||||
|
SDL_GL_ResetAttributes();
|
||||||
|
|
||||||
|
switch (surface_format)
|
||||||
|
{
|
||||||
|
case GPUTexture::Format::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 GPUTexture::Format::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;
|
||||||
|
}
|
46
src/util/opengl_context_sdl.h
Normal file
46
src/util/opengl_context_sdl.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// 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);
|
||||||
|
|
||||||
|
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, GPUTexture::Format 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;
|
||||||
|
};
|
@ -59,6 +59,9 @@
|
|||||||
<ClInclude Include="opengl_context_egl_xlib.h">
|
<ClInclude Include="opengl_context_egl_xlib.h">
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="opengl_context_sdl.h">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'=='ARM64'">true</ExcludedFromBuild>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="opengl_context_wgl.h">
|
<ClInclude Include="opengl_context_wgl.h">
|
||||||
<ExcludedFromBuild Condition="'$(Platform)'=='ARM64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Platform)'=='ARM64'">true</ExcludedFromBuild>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@ -166,6 +169,9 @@
|
|||||||
<ClCompile Include="opengl_context_egl_xlib.cpp">
|
<ClCompile Include="opengl_context_egl_xlib.cpp">
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="opengl_context_sdl.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Platform)'=='ARM64'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="opengl_context_wgl.cpp">
|
<ClCompile Include="opengl_context_wgl.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Platform)'=='ARM64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Platform)'=='ARM64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -74,6 +74,7 @@
|
|||||||
<ClInclude Include="x11_tools.h" />
|
<ClInclude Include="x11_tools.h" />
|
||||||
<ClInclude Include="opengl_context_egl_xlib.h" />
|
<ClInclude Include="opengl_context_egl_xlib.h" />
|
||||||
<ClInclude Include="texture_decompress.h" />
|
<ClInclude Include="texture_decompress.h" />
|
||||||
|
<ClInclude Include="opengl_context_sdl.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="state_wrapper.cpp" />
|
<ClCompile Include="state_wrapper.cpp" />
|
||||||
@ -156,6 +157,7 @@
|
|||||||
<ClCompile Include="x11_tools.cpp" />
|
<ClCompile Include="x11_tools.cpp" />
|
||||||
<ClCompile Include="opengl_context_egl_xlib.cpp" />
|
<ClCompile Include="opengl_context_egl_xlib.cpp" />
|
||||||
<ClCompile Include="texture_decompress.cpp" />
|
<ClCompile Include="texture_decompress.cpp" />
|
||||||
|
<ClCompile Include="opengl_context_sdl.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="metal_shaders.metal" />
|
<None Include="metal_shaders.metal" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user