update sdl to release 2.0.22

This commit is contained in:
AzaezelX 2022-04-26 09:17:21 -05:00
parent 3f796d2a06
commit d4307ea413
135 changed files with 5746 additions and 1161 deletions

View file

@ -316,6 +316,8 @@ SDL_InitSubSystem(Uint32 flags)
#endif
}
(void) flags_initialized; /* make static analysis happy, since this only gets used in error cases. */
return (0);
quit_and_error:

View file

@ -178,6 +178,11 @@ SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
return;
}
hint->name = SDL_strdup(name);
if (!hint->name) {
SDL_free(hint);
SDL_OutOfMemory();
return;
}
hint->value = NULL;
hint->priority = SDL_HINT_DEFAULT;
hint->callbacks = NULL;

View file

@ -0,0 +1,93 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "./SDL_internal.h"
#include "SDL.h"
#include "./SDL_list.h"
/* Push */
int
SDL_ListAdd(SDL_ListNode **head, void *ent)
{
SDL_ListNode *node = SDL_malloc(sizeof (*node));
if (node == NULL) {
return SDL_OutOfMemory();
}
node->entry = ent;
node->next = *head;
*head = node;
return 0;
}
/* Pop from end as a FIFO (if add with SDL_ListAdd) */
void
SDL_ListPop(SDL_ListNode **head, void **ent)
{
SDL_ListNode **ptr = head;
/* Invalid or empty */
if (head == NULL || *head == NULL) {
return;
}
while ((*ptr)->next) {
ptr = &(*ptr)->next;
}
if (ent) {
*ent = (*ptr)->entry;
}
SDL_free(*ptr);
*ptr = NULL;
}
void
SDL_ListRemove(SDL_ListNode **head, void *ent)
{
SDL_ListNode **ptr = head;
while (*ptr) {
if ((*ptr)->entry == ent) {
SDL_ListNode *tmp = *ptr;
*ptr = (*ptr)->next;
SDL_free(tmp);
return;
}
ptr = &(*ptr)->next;
}
}
void
SDL_ListClear(SDL_ListNode **head)
{
SDL_ListNode *l = *head;
*head = NULL;
while (l) {
SDL_ListNode *tmp = l;
l = l->next;
SDL_free(tmp);
}
}
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,39 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_list_h_
#define SDL_list_h_
typedef struct SDL_ListNode
{
void *entry;
struct SDL_ListNode *next;
} SDL_ListNode;
int SDL_ListAdd(SDL_ListNode **head, void *ent);
void SDL_ListPop(SDL_ListNode **head, void **ent);
void SDL_ListRemove(SDL_ListNode **head, void *ent);
void SDL_ListClear(SDL_ListNode **head);
#endif /* SDL_list_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -936,7 +936,7 @@ SDL_AudioInit(const char *driver_name)
/* Select the proper audio driver */
if (driver_name == NULL) {
driver_name = SDL_getenv("SDL_AUDIODRIVER");
driver_name = SDL_GetHint(SDL_HINT_AUDIODRIVER);
}
if (driver_name != NULL && *driver_name != 0) {

View file

@ -80,7 +80,7 @@ SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format)
Just use unaligned load/stores, if the memory at runtime is
aligned it'll be just as fast on modern processors */
while (i >= 4) { /* 4 * float32 */
_mm_storeu_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_load_ps(src), _mm_loadu_ps(src+4)), divby2));
_mm_storeu_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_loadu_ps(src), _mm_loadu_ps(src+4)), divby2));
i -= 4; src += 8; dst += 4;
}

View file

@ -685,7 +685,7 @@ MS_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
state.output.pos = 0;
state.output.size = outputsize / sizeof(Sint16);
state.output.data = (Sint16 *)SDL_malloc(outputsize);
state.output.data = (Sint16 *)SDL_calloc(1, outputsize);
if (state.output.data == NULL) {
return SDL_OutOfMemory();
}

View file

@ -32,7 +32,7 @@ static void
FeedAudioDevice(_THIS, const void *buf, const int buflen)
{
const int framelen = (SDL_AUDIO_BITSIZE(this->spec.format) / 8) * this->spec.channels;
EM_ASM_ARGS({
MAIN_THREAD_EM_ASM({
var SDL2 = Module['SDL2'];
var numChannels = SDL2.audio.currentOutputBuffer['numberOfChannels'];
for (var c = 0; c < numChannels; ++c) {
@ -101,7 +101,7 @@ HandleCaptureProcess(_THIS)
return;
}
EM_ASM_ARGS({
MAIN_THREAD_EM_ASM({
var SDL2 = Module['SDL2'];
var numChannels = SDL2.capture.currentCaptureBuffer.numberOfChannels;
for (var c = 0; c < numChannels; ++c) {
@ -147,7 +147,7 @@ HandleCaptureProcess(_THIS)
static void
EMSCRIPTENAUDIO_CloseDevice(_THIS)
{
EM_ASM_({
MAIN_THREAD_EM_ASM({
var SDL2 = Module['SDL2'];
if ($0) {
if (SDL2.capture.silenceTimer !== undefined) {
@ -201,7 +201,7 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
/* based on parts of library_sdl.js */
/* create context */
result = EM_ASM_INT({
result = MAIN_THREAD_EM_ASM_INT({
if(typeof(Module['SDL2']) === 'undefined') {
Module['SDL2'] = {};
}
@ -280,7 +280,7 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
feels like it's a pretty inefficient tapdance in similar ways,
to be honest. */
EM_ASM_({
MAIN_THREAD_EM_ASM({
var SDL2 = Module['SDL2'];
var have_microphone = function(stream) {
//console.log('SDL audio capture: we have a microphone! Replacing silence callback.');
@ -323,7 +323,7 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
}, this->spec.channels, this->spec.samples, HandleCaptureProcess, this);
} else {
/* setup a ScriptProcessorNode */
EM_ASM_ARGS({
MAIN_THREAD_EM_ASM({
var SDL2 = Module['SDL2'];
SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0);
SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) {
@ -359,7 +359,7 @@ EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->ProvidesOwnCallbackThread = SDL_TRUE;
/* check availability */
available = EM_ASM_INT_V({
available = MAIN_THREAD_EM_ASM_INT({
if (typeof(AudioContext) !== 'undefined') {
return true;
} else if (typeof(webkitAudioContext) !== 'undefined') {
@ -372,7 +372,7 @@ EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl)
SDL_SetError("No audio context available");
}
capture_available = available && EM_ASM_INT_V({
capture_available = available && MAIN_THREAD_EM_ASM_INT({
if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) {
return true;
} else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') {

View file

@ -37,18 +37,35 @@
#include <psp2/kernel/threadmgr.h>
#include <psp2/audioout.h>
#include <psp2/audioin.h>
#define SCE_AUDIO_SAMPLE_ALIGN(s) (((s) + 63) & ~63)
#define SCE_AUDIO_MAX_VOLUME 0x8000
/* The tag name used by VITA audio */
#define VITAAUD_DRIVER_NAME "vita"
static int
VITAAUD_OpenCaptureDevice(_THIS)
{
this->spec.freq = 16000;
this->spec.samples = 512;
this->spec.channels = 1;
SDL_CalculateAudioSpec(&this->spec);
this->hidden->port = sceAudioInOpenPort(SCE_AUDIO_IN_PORT_TYPE_VOICE , 512, 16000, SCE_AUDIO_IN_PARAM_FORMAT_S16_MONO);
if (this->hidden->port < 0) {
return SDL_SetError("Couldn't open audio in port: %x", this->hidden->port);
}
return 0;
}
static int
VITAAUD_OpenDevice(_THIS, const char *devname)
{
int format, mixlen, i, port = SCE_AUDIO_OUT_PORT_TYPE_MAIN;
int vols[2] = {SCE_AUDIO_MAX_VOLUME, SCE_AUDIO_MAX_VOLUME};
SDL_AudioFormat test_format;
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*this->hidden));
@ -56,13 +73,20 @@ VITAAUD_OpenDevice(_THIS, const char *devname)
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, sizeof(*this->hidden));
switch (this->spec.format & 0xff) {
case 8:
case 16:
this->spec.format = AUDIO_S16LSB;
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
if (test_format == AUDIO_S16LSB) {
this->spec.format = test_format;
break;
default:
return SDL_SetError("Unsupported audio format");
}
}
if(!test_format) {
return SDL_SetError("Unsupported audio format");
}
if (this->iscapture) {
return VITAAUD_OpenCaptureDevice(this);
}
/* The sample count must be a multiple of 64. */
@ -91,14 +115,14 @@ VITAAUD_OpenDevice(_THIS, const char *devname)
port = SCE_AUDIO_OUT_PORT_TYPE_BGM;
}
this->hidden->channel = sceAudioOutOpenPort(port, this->spec.samples, this->spec.freq, format);
if (this->hidden->channel < 0) {
this->hidden->port = sceAudioOutOpenPort(port, this->spec.samples, this->spec.freq, format);
if (this->hidden->port < 0) {
free(this->hidden->rawbuf);
this->hidden->rawbuf = NULL;
return SDL_SetError("Couldn't reserve hardware channel");
return SDL_SetError("Couldn't open audio out port: %x", this->hidden->port);
}
sceAudioOutSetVolume(this->hidden->channel, SCE_AUDIO_VOLUME_FLAG_L_CH|SCE_AUDIO_VOLUME_FLAG_R_CH, vols);
sceAudioOutSetVolume(this->hidden->port, SCE_AUDIO_VOLUME_FLAG_L_CH|SCE_AUDIO_VOLUME_FLAG_R_CH, vols);
SDL_memset(this->hidden->rawbuf, 0, mixlen);
for (i = 0; i < NUM_BUFFERS; i++) {
@ -113,7 +137,7 @@ static void VITAAUD_PlayDevice(_THIS)
{
Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
sceAudioOutOutput(this->hidden->channel, mixbuf);
sceAudioOutOutput(this->hidden->port, mixbuf);
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
}
@ -123,6 +147,7 @@ static void VITAAUD_WaitDevice(_THIS)
{
/* Because we block when sending audio, there's no need for this function to do anything. */
}
static Uint8 *VITAAUD_GetDeviceBuf(_THIS)
{
return this->hidden->mixbufs[this->hidden->next_buffer];
@ -130,17 +155,32 @@ static Uint8 *VITAAUD_GetDeviceBuf(_THIS)
static void VITAAUD_CloseDevice(_THIS)
{
if (this->hidden->channel >= 0) {
sceAudioOutReleasePort(this->hidden->channel);
this->hidden->channel = -1;
if (this->hidden->port >= 0) {
if (this->iscapture) {
sceAudioInReleasePort(this->hidden->port);
} else {
sceAudioOutReleasePort(this->hidden->port);
}
this->hidden->port = -1;
}
if (this->hidden->rawbuf != NULL) {
if (!this->iscapture && this->hidden->rawbuf != NULL) {
free(this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */
this->hidden->rawbuf = NULL;
}
}
static int VITAAUD_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
int ret;
SDL_assert(buflen == this->spec.size);
ret = sceAudioInInput(this->hidden->port, buffer);
if (ret < 0) {
return SDL_SetError("Failed to capture from device: %x", ret);
}
return this->spec.size;
}
static void VITAAUD_ThreadInit(_THIS)
{
/* Increase the priority of this audio thread by 1 to put it
@ -165,12 +205,13 @@ VITAAUD_Init(SDL_AudioDriverImpl * impl)
impl->CloseDevice = VITAAUD_CloseDevice;
impl->ThreadInit = VITAAUD_ThreadInit;
/* VITA audio device */
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
/*
impl->CaptureFromDevice = VITAAUD_CaptureFromDevice;
/* and the capabilities */
impl->HasCaptureSupport = SDL_TRUE;
impl->OnlyHasDefaultInputDevice = SDL_TRUE;
*/
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
}

View file

@ -30,8 +30,8 @@
#define NUM_BUFFERS 2
struct SDL_PrivateAudioData {
/* The hardware output channel. */
int channel;
/* The hardware input/output port. */
int port;
/* The raw allocated mixing buffer. */
Uint8 *rawbuf;
/* Individual mixing buffers. */

View file

@ -558,12 +558,16 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
return WIN_SetErrorFromHRESULT("WASAPI can't determine minimum device period", ret);
}
#if 1 /* we're getting reports that WASAPI's resampler introduces distortions, so it's disabled for now. --ryan. */
this->spec.freq = waveformat->nSamplesPerSec; /* force sampling rate so our resampler kicks in, if necessary. */
#else
/* favor WASAPI's resampler over our own */
if (this->spec.freq != waveformat->nSamplesPerSec) {
streamflags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
waveformat->nSamplesPerSec = this->spec.freq;
waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nChannels * (waveformat->wBitsPerSample / 8);
}
#endif
streamflags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
ret = IAudioClient_Initialize(client, sharemode, streamflags, 0, 0, waveformat, NULL);

View file

@ -339,11 +339,11 @@ SDL_Fcitx_Reset(void)
}
SDL_bool
SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state)
{
Uint32 state = Fcitx_ModState();
Uint32 mod_state = Fcitx_ModState();
Uint32 handled = SDL_FALSE;
Uint32 is_release = SDL_FALSE;
Uint32 is_release = (state == SDL_RELEASED);
Uint32 event_time = 0;
if (!fcitx_client.ic_path) {
@ -351,7 +351,7 @@ SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
}
if (SDL_DBus_CallMethod(FCITX_DBUS_SERVICE, fcitx_client.ic_path, FCITX_IC_DBUS_INTERFACE, "ProcessKeyEvent",
DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &state, DBUS_TYPE_BOOLEAN, &is_release, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID,
DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &mod_state, DBUS_TYPE_BOOLEAN, &is_release, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID,
DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID)) {
if (handled) {
SDL_Fcitx_UpdateTextRect(NULL);

View file

@ -31,7 +31,7 @@ extern SDL_bool SDL_Fcitx_Init(void);
extern void SDL_Fcitx_Quit(void);
extern void SDL_Fcitx_SetFocus(SDL_bool focused);
extern void SDL_Fcitx_Reset(void);
extern SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
extern SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state);
extern void SDL_Fcitx_UpdateTextRect(SDL_Rect *rect);
extern void SDL_Fcitx_PumpEvents(void);

View file

@ -503,15 +503,20 @@ SDL_IBus_Reset(void)
}
SDL_bool
SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state)
{
Uint32 result = 0;
SDL_DBusContext *dbus = SDL_DBus_GetContext();
if (IBus_CheckConnection(dbus)) {
Uint32 mods = IBus_ModState();
Uint32 ibus_keycode = keycode - 8;
if (state == SDL_RELEASED) {
mods |= (1 << 30); // IBUS_RELEASE_MASK
}
if (!SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent",
DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID,
DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &ibus_keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID,
DBUS_TYPE_BOOLEAN, &result, DBUS_TYPE_INVALID)) {
result = 0;
}

View file

@ -41,7 +41,7 @@ extern void SDL_IBus_Reset(void);
/* Sends a keypress event to IBus, returns SDL_TRUE if IBus used this event to
update its candidate list or change input methods. PumpEvents should be
called some time after this, to recieve the TextInput / TextEditing event back. */
extern SDL_bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
extern SDL_bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state);
/* Update the position of IBus' candidate list. If rect is NULL then this will
just reposition it relative to the focused window's new position. */

View file

@ -27,7 +27,7 @@ typedef SDL_bool (*_SDL_IME_Init)(void);
typedef void (*_SDL_IME_Quit)(void);
typedef void (*_SDL_IME_SetFocus)(SDL_bool);
typedef void (*_SDL_IME_Reset)(void);
typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32);
typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32, Uint8 state);
typedef void (*_SDL_IME_UpdateTextRect)(SDL_Rect *);
typedef void (*_SDL_IME_PumpEvents)(void);
@ -127,10 +127,10 @@ SDL_IME_Reset(void)
}
SDL_bool
SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state)
{
if (SDL_IME_ProcessKeyEvent_Real)
return SDL_IME_ProcessKeyEvent_Real(keysym, keycode);
return SDL_IME_ProcessKeyEvent_Real(keysym, keycode, state);
return SDL_FALSE;
}

View file

@ -31,7 +31,7 @@ extern SDL_bool SDL_IME_Init(void);
extern void SDL_IME_Quit(void);
extern void SDL_IME_SetFocus(SDL_bool focused);
extern void SDL_IME_Reset(void);
extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state);
extern void SDL_IME_UpdateTextRect(SDL_Rect *rect);
extern void SDL_IME_PumpEvents(void);

View file

@ -25,7 +25,15 @@
#include "SDL_windows.h"
#include "SDL_error.h"
#include <objbase.h> /* for CoInitialize/CoUninitialize (Win32 only) */
#include <objbase.h> /* for CoInitialize/CoUninitialize (Win32 only) */
#if defined(HAVE_ROAPI_H)
#include <roapi.h> /* For RoInitialize/RoUninitialize (Win32 only) */
#else
typedef enum RO_INIT_TYPE {
RO_INIT_SINGLETHREADED = 0,
RO_INIT_MULTITHREADED = 1
} RO_INIT_TYPE;
#endif
#ifndef _WIN32_WINNT_VISTA
#define _WIN32_WINNT_VISTA 0x0600
@ -37,6 +45,10 @@
#define _WIN32_WINNT_WIN8 0x0602
#endif
#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32
#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
#endif
/* Sets an error message based on an HRESULT */
int
@ -104,51 +116,66 @@ void
WIN_CoUninitialize(void)
{
#ifndef __WINRT__
/* Don't uninitialize COM because of what appears to be a bug in Microsoft WGI reference counting.
*
* If you plug in a non-Xbox controller and let the application run for 30 seconds, then it crashes in CoUninitialize()
* with this stack trace:
CoUninitialize();
#endif
}
Windows.Gaming.Input.dll!GameController::~GameController(void) Unknown
Windows.Gaming.Input.dll!GameController::`vector deleting destructor'(unsigned int) Unknown
Windows.Gaming.Input.dll!Microsoft::WRL::Details::RuntimeClassImpl<struct Microsoft::WRL::RuntimeClassFlags<1>,1,1,0,struct Windows::Gaming::Input::IGameController,struct Windows::Gaming::Input::IGameControllerBatteryInfo,struct Microsoft::WRL::CloakedIid<struct Windows::Gaming::Input::Internal::IGameControllerPrivate>,class Microsoft::WRL::FtmBase>::Release(void) Unknown
Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::AggregableRuntimeClass<struct Windows::Gaming::Input::IGamepad,struct Windows::Gaming::Input::IGamepad2,struct Microsoft::WRL::CloakedIid<struct Windows::Gaming::Input::Custom::IGameControllerInputSink>,struct Microsoft::WRL::CloakedIid<struct Windows::Gaming::Input::Custom::IGipGameControllerInputSink>,struct Microsoft::WRL::CloakedIid<struct Windows::Gaming::Input::Custom::IHidGameControllerInputSink>,struct Microsoft::WRL::CloakedIid<struct Windows::Gaming::Input::Custom::IXusbGameControllerInputSink>,class Microsoft::WRL::Details::Nil,class Microsoft::WRL::Details::Nil,class Microsoft::WRL::Details::Nil>::Release(void) Unknown
Windows.Gaming.Input.dll!Microsoft::WRL::ComPtr<`WaitForCompletion<Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<Windows::Storage::Streams::IBuffer *,unsigned int>,Windows::Foundation::IAsyncOperationWithProgress<Windows::Storage::Streams::IBuffer *,unsigned int>>'::`2'::FTMEventDelegate>::~ComPtr<`WaitForCompletion<Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<Windows::Storage::Streams::IBuffer *,unsigned int>,Windows::Foundation::IAsyncOperationWithProgress<Windows::Storage::Streams::IBuffer *,unsigned int>>'::`2'::FTMEventDelegate>() Unknown
Windows.Gaming.Input.dll!`eh vector destructor iterator'(void *,unsigned int,int,void (*)(void *)) Unknown
Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::GameControllerCollection<class Windows::Gaming::Input::RawGameController,struct Windows::Gaming::Input::IRawGameController>::~GameControllerCollection<class Windows::Gaming::Input::RawGameController,struct Windows::Gaming::Input::IRawGameController>(void) Unknown
Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::GameControllerCollection<class Windows::Gaming::Input::RawGameController,struct Windows::Gaming::Input::IRawGameController>::`vector deleting destructor'(unsigned int) Unknown
Windows.Gaming.Input.dll!Microsoft::WRL::Details::RuntimeClassImpl<struct Microsoft::WRL::RuntimeClassFlags<1>,1,1,0,struct Windows::Foundation::Collections::IIterable<class Windows::Gaming::Input::ArcadeStick *>,struct Windows::Foundation::Collections::IVectorView<class Windows::Gaming::Input::ArcadeStick *>,class Microsoft::WRL::FtmBase>::Release(void) Unknown
Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::CustomGameControllerFactoryBase<class Windows::Gaming::Input::FlightStick,class Windows::Gaming::Input::FlightStick,struct Windows::Gaming::Input::IFlightStick,struct Windows::Gaming::Input::IFlightStickStatics,class Microsoft::WRL::Details::Nil>::~CustomGameControllerFactoryBase<class Windows::Gaming::Input::FlightStick,class Windows::Gaming::Input::FlightStick,struct Windows::Gaming::Input::IFlightStick,struct Windows::Gaming::Input::IFlightStickStatics,class Microsoft::WRL::Details::Nil>(void) Unknown
Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::CustomGameControllerFactoryBase<class Windows::Gaming::Input::FlightStick,class Windows::Gaming::Input::FlightStick,struct Windows::Gaming::Input::IFlightStick,struct Windows::Gaming::Input::IFlightStickStatics,class Microsoft::WRL::Details::Nil>::`vector deleting destructor'(unsigned int) Unknown
Windows.Gaming.Input.dll!Microsoft::WRL::ActivationFactory<struct Microsoft::WRL::Implements<class Microsoft::WRL::FtmBase,struct Microsoft::WRL::CloakedIid<struct Windows::Gaming::Input::Custom::ICustomGameControllerFactory> >,struct Windows::Gaming::Input::IFlightStickStatics,class Microsoft::WRL::Details::Nil,0>::Release(void) Unknown
Windows.Gaming.Input.dll!Microsoft::WRL::ComPtr<`WaitForCompletion<Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<Windows::Storage::Streams::IBuffer *,unsigned int>,Windows::Foundation::IAsyncOperationWithProgress<Windows::Storage::Streams::IBuffer *,unsigned int>>'::`2'::FTMEventDelegate>::~ComPtr<`WaitForCompletion<Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<Windows::Storage::Streams::IBuffer *,unsigned int>,Windows::Foundation::IAsyncOperationWithProgress<Windows::Storage::Streams::IBuffer *,unsigned int>>'::`2'::FTMEventDelegate>() Unknown
Windows.Gaming.Input.dll!NtList<struct FactoryManager::FactoryListEntry>::~NtList<struct FactoryManager::FactoryListEntry>(void) Unknown
Windows.Gaming.Input.dll!FactoryManager::`vector deleting destructor'(unsigned int) Unknown
Windows.Gaming.Input.dll!Microsoft::WRL::ActivationFactory<struct Microsoft::WRL::Implements<class Microsoft::WRL::FtmBase,struct Windows::Gaming::Input::Custom::IGameControllerFactoryManagerStatics>,struct Windows::Gaming::Input::Custom::IGameControllerFactoryManagerStatics2,struct Microsoft::WRL::CloakedIid<struct Windows::Gaming::Input::Internal::IGameControllerFactoryManagerStaticsPrivate>,0>::Release(void) Unknown
Windows.Gaming.Input.dll!Microsoft::WRL::Details::TerminateMap(class Microsoft::WRL::Details::ModuleBase *,unsigned short const *,bool) Unknown
Windows.Gaming.Input.dll!Microsoft::WRL::Module<1,class Microsoft::WRL::Details::DefaultModule<1> >::~Module<1,class Microsoft::WRL::Details::DefaultModule<1> >(void) Unknown
Windows.Gaming.Input.dll!Microsoft::WRL::Details::DefaultModule<1>::`vector deleting destructor'(unsigned int) Unknown
Windows.Gaming.Input.dll!`dynamic atexit destructor for 'Microsoft::WRL::Details::StaticStorage<Microsoft::WRL::Details::DefaultModule<1>,0,int>::instance_''() Unknown
Windows.Gaming.Input.dll!__CRT_INIT@12() Unknown
Windows.Gaming.Input.dll!__DllMainCRTStartup() Unknown
ntdll.dll!_LdrxCallInitRoutine@16() Unknown
ntdll.dll!LdrpCallInitRoutine() Unknown
ntdll.dll!LdrpProcessDetachNode() Unknown
ntdll.dll!LdrpUnloadNode() Unknown
ntdll.dll!LdrpDecrementModuleLoadCountEx() Unknown
ntdll.dll!LdrUnloadDll() Unknown
KernelBase.dll!FreeLibrary() Unknown
combase.dll!FreeLibraryWithLogging(LoadOrFreeWhy why, HINSTANCE__ * hMod, const wchar_t * pswzOptionalFileName) Line 193 C++
combase.dll!CClassCache::CDllPathEntry::CFinishObject::Finish() Line 3311 C++
combase.dll!CClassCache::CFinishComposite::Finish() Line 3421 C++
combase.dll!CClassCache::CleanUpDllsForProcess() Line 7009 C++
[Inline Frame] combase.dll!CCCleanUpDllsForProcess() Line 8773 C++
combase.dll!ProcessUninitialize() Line 2243 C++
combase.dll!DecrementProcessInitializeCount() Line 993 C++
combase.dll!wCoUninitialize(COleTls & Tls, int fHostThread) Line 4126 C++
combase.dll!CoUninitialize() Line 3945 C++
*/
/*CoUninitialize();*/
#ifndef __WINRT__
void *
WIN_LoadComBaseFunction(const char *name)
{
static SDL_bool s_bLoaded;
static HMODULE s_hComBase;
if (!s_bLoaded) {
s_hComBase = LoadLibraryEx(TEXT("combase.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
s_bLoaded = SDL_TRUE;
}
if (s_hComBase) {
return GetProcAddress(s_hComBase, name);
} else {
return NULL;
}
}
#endif
HRESULT
WIN_RoInitialize(void)
{
#ifdef __WINRT__
return S_OK;
#else
typedef HRESULT (WINAPI *RoInitialize_t)(RO_INIT_TYPE initType);
RoInitialize_t RoInitializeFunc = (RoInitialize_t)WIN_LoadComBaseFunction("RoInitialize");
if (RoInitializeFunc) {
/* RO_INIT_SINGLETHREADED is equivalent to COINIT_APARTMENTTHREADED */
HRESULT hr = RoInitializeFunc(RO_INIT_SINGLETHREADED);
if (hr == RPC_E_CHANGED_MODE) {
hr = RoInitializeFunc(RO_INIT_MULTITHREADED);
}
/* S_FALSE means success, but someone else already initialized. */
/* You still need to call RoUninitialize in this case! */
if (hr == S_FALSE) {
return S_OK;
}
return hr;
} else {
return E_NOINTERFACE;
}
#endif
}
void
WIN_RoUninitialize(void)
{
#ifndef __WINRT__
typedef void (WINAPI *RoUninitialize_t)(void);
RoUninitialize_t RoUninitializeFunc = (RoUninitialize_t)WIN_LoadComBaseFunction("RoUninitialize");
if (RoUninitializeFunc) {
RoUninitializeFunc();
}
#endif
}

View file

@ -63,10 +63,19 @@ extern int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr);
/* Sets an error message based on GetLastError(). Always return -1. */
extern int WIN_SetError(const char *prefix);
#if !defined(__WINRT__)
/* Load a function from combase.dll */
void *WIN_LoadComBaseFunction(const char *name);
#endif
/* Wrap up the oddities of CoInitialize() into a common function. */
extern HRESULT WIN_CoInitialize(void);
extern void WIN_CoUninitialize(void);
/* Wrap up the oddities of RoInitialize() into a common function. */
extern HRESULT WIN_RoInitialize(void);
extern void WIN_RoUninitialize(void);
/* Returns SDL_TRUE if we're running on Windows Vista and newer */
extern BOOL WIN_IsWindowsVistaOrGreater(void);

View file

@ -864,3 +864,4 @@
#define SDL_UnionFRect SDL_UnionFRect_REAL
#define SDL_EncloseFPoints SDL_EncloseFPoints_REAL
#define SDL_IntersectFRectAndLine SDL_IntersectFRectAndLine_REAL
#define SDL_RenderGetWindow SDL_RenderGetWindow_REAL

View file

@ -935,3 +935,4 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_IntersectFRect,(const SDL_FRect *a, const SDL_FRect
SDL_DYNAPI_PROC(void,SDL_UnionFRect,(const SDL_FRect *a, const SDL_FRect *b, SDL_FRect *c),(a,b,c),)
SDL_DYNAPI_PROC(SDL_bool,SDL_EncloseFPoints,(const SDL_FPoint *a, int b, const SDL_FRect *c, SDL_FRect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_IntersectFRectAndLine,(const SDL_FRect *a, float *b, float *c, float *d, float *e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(SDL_Window*,SDL_RenderGetWindow,(SDL_Renderer *a),(a),return)

View file

@ -638,6 +638,7 @@ SDL_SetKeyboardFocus(SDL_Window * window)
/* old window must lose an existing mouse capture. */
if (keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE) {
SDL_CaptureMouse(SDL_FALSE); /* drop the capture. */
SDL_UpdateMouseCapture(SDL_TRUE);
SDL_assert(!(keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE));
}

View file

@ -109,6 +109,28 @@ SDL_TouchMouseEventsChanged(void *userdata, const char *name, const char *oldVal
mouse->touch_mouse_events = SDL_GetStringBoolean(hint, SDL_TRUE);
}
#if defined(__vita__)
static void SDLCALL
SDL_VitaTouchMouseDeviceChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
if (hint) {
switch(*hint) {
default:
case '0':
mouse->vita_touch_mouse_device = 0;
break;
case '1':
mouse->vita_touch_mouse_device = 1;
break;
case '2':
mouse->vita_touch_mouse_device = 2;
break;
}
}
}
#endif
static void SDLCALL
SDL_MouseTouchEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
@ -134,12 +156,8 @@ SDL_MouseAutoCaptureChanged(void *userdata, const char *name, const char *oldVal
SDL_bool auto_capture = SDL_GetStringBoolean(hint, SDL_TRUE);
if (auto_capture != mouse->auto_capture) {
/* Turn off mouse capture if it's currently active because of button presses */
if (!auto_capture && SDL_GetMouseState(NULL, NULL) != 0) {
SDL_CaptureMouse(SDL_FALSE);
}
mouse->auto_capture = auto_capture;
SDL_UpdateMouseCapture(SDL_FALSE);
}
}
@ -166,6 +184,11 @@ SDL_MouseInit(void)
SDL_AddHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS,
SDL_TouchMouseEventsChanged, mouse);
#if defined(__vita__)
SDL_AddHintCallback(SDL_HINT_VITA_TOUCH_MOUSE_DEVICE,
SDL_VitaTouchMouseDeviceChanged, mouse);
#endif
SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS,
SDL_MouseTouchEventsChanged, mouse);
@ -384,12 +407,9 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
/* Ignore relative motion when first positioning the mouse */
if (!mouse->has_position) {
xrel = 0;
yrel = 0;
mouse->x = x;
mouse->y = y;
mouse->has_position = SDL_TRUE;
return 0;
} else if (!xrel && !yrel) { /* Drop events that don't change state */
#ifdef DEBUG_MOUSE
SDL_Log("Mouse event didn't change state - dropped!\n");
@ -540,7 +560,6 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state
Uint32 type;
Uint32 buttonstate;
SDL_MouseInputSource *source;
SDL_bool had_buttons_pressed = (SDL_GetMouseState(NULL, NULL) ? SDL_TRUE : SDL_FALSE);
source = GetMouseInputSource(mouse, mouseID);
if (!source) {
@ -643,10 +662,7 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state
/* Automatically capture the mouse while buttons are pressed */
if (mouse->auto_capture) {
SDL_bool has_buttons_pressed = (SDL_GetMouseState(NULL, NULL) ? SDL_TRUE : SDL_FALSE);
if (has_buttons_pressed != had_buttons_pressed) {
SDL_CaptureMouse(has_buttons_pressed);
}
SDL_UpdateMouseCapture(SDL_FALSE);
}
return posted;
@ -743,6 +759,7 @@ SDL_MouseQuit(void)
if (mouse->CaptureMouse) {
SDL_CaptureMouse(SDL_FALSE);
SDL_UpdateMouseCapture(SDL_TRUE);
}
SDL_SetRelativeMouseMode(SDL_FALSE);
SDL_ShowCursor(1);
@ -947,6 +964,8 @@ SDL_SetRelativeMouseMode(SDL_bool enabled)
if (!enabled) {
SDL_WarpMouseInWindow(focusWindow, mouse->x, mouse->y);
}
SDL_UpdateMouseCapture(SDL_FALSE);
}
if (!enabled) {
@ -968,39 +987,59 @@ SDL_GetRelativeMouseMode()
return mouse->relative_mode;
}
int
SDL_UpdateMouseCapture(SDL_bool force_release)
{
SDL_Mouse *mouse = SDL_GetMouse();
SDL_Window *capture_window = NULL;
if (!mouse->CaptureMouse) {
return 0;
}
if (!force_release) {
if (mouse->capture_desired || (mouse->auto_capture && SDL_GetMouseState(NULL, NULL) != 0)) {
if (!mouse->relative_mode) {
capture_window = SDL_GetKeyboardFocus();
}
}
}
if (capture_window != mouse->capture_window) {
if (mouse->capture_window) {
mouse->CaptureMouse(NULL);
mouse->capture_window->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
mouse->capture_window = NULL;
}
if (capture_window) {
if (mouse->CaptureMouse(capture_window) < 0) {
/* CaptureMouse() will have set an error */
return -1;
}
capture_window->flags |= SDL_WINDOW_MOUSE_CAPTURE;
}
mouse->capture_window = capture_window;
}
return 0;
}
int
SDL_CaptureMouse(SDL_bool enabled)
{
SDL_Mouse *mouse = SDL_GetMouse();
SDL_Window *focusWindow;
SDL_bool isCaptured;
if (!mouse->CaptureMouse) {
return SDL_Unsupported();
}
focusWindow = SDL_GetKeyboardFocus();
isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE);
if (isCaptured == enabled) {
return 0; /* already done! */
if (enabled && SDL_GetKeyboardFocus() == NULL) {
return SDL_SetError("No window has focus");
}
mouse->capture_desired = enabled;
if (enabled) {
if (!focusWindow) {
return SDL_SetError("No window has focus");
} else if (mouse->CaptureMouse(focusWindow) == -1) {
return -1; /* CaptureMouse() should call SetError */
}
focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
} else {
if (mouse->CaptureMouse(NULL) == -1) {
return -1; /* CaptureMouse() should call SetError */
}
focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
}
return 0;
return SDL_UpdateMouseCapture(SDL_FALSE);
}
SDL_Cursor *

View file

@ -100,7 +100,12 @@ typedef struct
SDL_bool touch_mouse_events;
SDL_bool mouse_touch_events;
SDL_bool was_touch_mouse_events; /* Was a touch-mouse event pending? */
#if defined(__vita__)
Uint8 vita_touch_mouse_device;
#endif
SDL_bool auto_capture;
SDL_bool capture_desired;
SDL_Window *capture_window;
/* Data for input source state */
int num_sources;
@ -132,6 +137,9 @@ extern void SDL_SetDefaultCursor(SDL_Cursor * cursor);
/* Set the mouse focus window */
extern void SDL_SetMouseFocus(SDL_Window * window);
/* Update the mouse capture window */
extern int SDL_UpdateMouseCapture(SDL_bool force_release);
/* Send a mouse motion event */
extern int SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y);

View file

@ -265,8 +265,13 @@ SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window,
#if SYNTHESIZE_TOUCH_TO_MOUSE
/* SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events */
/* SDL_HINT_VITA_TOUCH_MOUSE_DEVICE: controlling which touchpad should generate synthetic mouse events, PSVita-only */
{
#if defined(__vita__)
if (mouse->touch_mouse_events && ((mouse->vita_touch_mouse_device == id) || (mouse->vita_touch_mouse_device == 2)) ) {
#else
if (mouse->touch_mouse_events) {
#endif
/* FIXME: maybe we should only restrict to a few SDL_TouchDeviceType */
if (id != SDL_MOUSE_TOUCHID) {
if (window) {

View file

@ -35,39 +35,23 @@
char *
SDL_GetBasePath(void)
{
typedef DWORD (WINAPI *GetModuleFileNameExW_t)(HANDLE, HMODULE, LPWSTR, DWORD);
GetModuleFileNameExW_t pGetModuleFileNameExW;
DWORD buflen = 128;
WCHAR *path = NULL;
HANDLE psapi = LoadLibrary(TEXT("psapi.dll"));
char *retval = NULL;
DWORD len = 0;
int i;
if (!psapi) {
WIN_SetError("Couldn't load psapi.dll");
return NULL;
}
pGetModuleFileNameExW = (GetModuleFileNameExW_t)GetProcAddress(psapi, "GetModuleFileNameExW");
if (!pGetModuleFileNameExW) {
WIN_SetError("Couldn't find GetModuleFileNameExW");
FreeLibrary(psapi);
return NULL;
}
while (SDL_TRUE) {
void *ptr = SDL_realloc(path, buflen * sizeof (WCHAR));
if (!ptr) {
SDL_free(path);
FreeLibrary(psapi);
SDL_OutOfMemory();
return NULL;
}
path = (WCHAR *) ptr;
len = pGetModuleFileNameExW(GetCurrentProcess(), NULL, path, buflen);
len = GetModuleFileNameW(NULL, path, buflen);
/* if it truncated, then len >= buflen - 1 */
/* if there was enough room (or failure), len < buflen - 1 */
if (len < buflen - 1) {
@ -78,8 +62,6 @@ SDL_GetBasePath(void)
buflen *= 2;
}
FreeLibrary(psapi);
if (len == 0) {
SDL_free(path);
WIN_SetError("Couldn't locate our .exe");

View file

@ -951,6 +951,7 @@ DeleteHIDDeviceWrapper(SDL_hid_device *device)
}
#if !SDL_HIDAPI_DISABLED
#if HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || defined(SDL_LIBUSB_DYNAMIC)
#define COPY_IF_EXISTS(var) \
if (pSrc->var != NULL) { \
@ -987,6 +988,7 @@ CopyHIDDeviceInfo(struct SDL_hid_device_info *pSrc, struct SDL_hid_device_info *
#undef COPY_IF_EXISTS
#undef WCOPY_IF_EXISTS
#endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || SDL_LIBUSB_DYNAMIC */
#endif /* !SDL_HIDAPI_DISABLED */
static int SDL_hidapi_refcount = 0;
@ -1185,9 +1187,9 @@ struct SDL_hid_device_info *SDL_hid_enumerate(unsigned short vendor_id, unsigned
#ifdef SDL_LIBUSB_DYNAMIC
if (libusb_ctx.libhandle) {
usb_devs = LIBUSB_hid_enumerate(vendor_id, product_id);
#ifdef DEBUG_HIDAPI
#ifdef DEBUG_HIDAPI
SDL_Log("libusb devices found:");
#endif
#endif
for (usb_dev = usb_devs; usb_dev; usb_dev = usb_dev->next) {
new_dev = (struct SDL_hid_device_info*) SDL_malloc(sizeof(struct SDL_hid_device_info));
if (!new_dev) {
@ -1197,11 +1199,11 @@ struct SDL_hid_device_info *SDL_hid_enumerate(unsigned short vendor_id, unsigned
return NULL;
}
CopyHIDDeviceInfo(usb_dev, new_dev);
#ifdef DEBUG_HIDAPI
#ifdef DEBUG_HIDAPI
SDL_Log(" - %ls %ls 0x%.4hx 0x%.4hx",
usb_dev->manufacturer_string, usb_dev->product_string,
usb_dev->vendor_id, usb_dev->product_id);
#endif
#endif
if (last != NULL) {
last->next = new_dev;

View file

@ -1497,6 +1497,7 @@ void HID_API_EXPORT hid_close(hid_device *dev)
/* Clean up the Transfer objects allocated in read_thread(). */
free(dev->transfer->buffer);
dev->transfer->buffer = NULL;
libusb_free_transfer(dev->transfer);
/* release the interface */

View file

@ -572,8 +572,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
if ((vendor_id == 0x0 && product_id == 0x0) ||
(vendor_id == dev_vid && product_id == dev_pid)) {
struct hid_device_info *tmp;
size_t len;
/* VID/PID match. Create the record. */
tmp = (struct hid_device_info *)calloc(1, sizeof(struct hid_device_info));
if (cur_dev) {
@ -590,7 +589,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
/* Fill out the record */
cur_dev->next = NULL;
len = make_path(dev, cbuf, sizeof(cbuf));
make_path(dev, cbuf, sizeof(cbuf));
cur_dev->path = strdup(cbuf);
/* Serial Number */
@ -817,10 +816,9 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
CFSetGetValues(device_set, (const void **) device_array);
for (i = 0; i < num_devices; i++) {
char cbuf[BUF_LEN];
size_t len;
IOHIDDeviceRef os_dev = device_array[i];
len = make_path(os_dev, cbuf, sizeof(cbuf));
make_path(os_dev, cbuf, sizeof(cbuf));
if (!strcmp(cbuf, path)) {
// Matched Paths. Open this Device.
IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone);
@ -833,6 +831,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
/* Create the buffers for receiving data */
dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev);
SDL_assert(dev->max_input_report_len > 0);
dev->input_report_buf = (uint8_t *)calloc(dev->max_input_report_len, sizeof(uint8_t));
/* Create the Run Loop Mode for this device.
@ -936,11 +935,14 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length)
/* Copy the data out of the linked list item (rpt) into the
return buffer (data), and delete the liked list item. */
struct input_report *rpt = dev->input_reports;
size_t len = (length < rpt->len)? length: rpt->len;
memcpy(data, rpt->data, len);
dev->input_reports = rpt->next;
free(rpt->data);
free(rpt);
size_t len = 0;
if (rpt != NULL) {
len = (length < rpt->len)? length: rpt->len;
memcpy(data, rpt->data, len);
dev->input_reports = rpt->next;
free(rpt->data);
free(rpt);
}
return (int)len;
}

View file

@ -501,7 +501,7 @@ static const char *s_ControllerMappings [] =
"03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,",
#endif
#if defined(__LINUX__)
#ifdef SDL_JOYSTICK_LINUX
"xinput,*,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
"03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
@ -762,6 +762,7 @@ static const char *s_ControllerMappings [] =
"0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,",
"030000004f0400000ed0000011010000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
"030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
"030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,",
"030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,",

View file

@ -1590,11 +1590,13 @@ SDL_JoystickUpdate(void)
for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
if (joystick->attached) {
/* This should always be true, but seeing a crash in the wild...? */
if (joystick->driver) {
joystick->driver->Update(joystick);
/* This driver should always be != NULL, but seeing a crash in the wild...? */
if (!joystick->driver) {
continue; /* nothing we can do, and other things use joystick->driver below here. */
}
joystick->driver->Update(joystick);
if (joystick->delayed_guide_button) {
SDL_GameControllerHandleDelayedGuideButton(joystick);
}
@ -2158,7 +2160,10 @@ static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
MAKE_VIDPID(0x044f, 0xb65d), /* Thrustmaster Wheel FFB */
MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster Wheel FFB */
MAKE_VIDPID(0x044f, 0xb677), /* Thrustmaster T150 */
MAKE_VIDPID(0x044f, 0xb66e), /* Thrustmaster T300RS */
MAKE_VIDPID(0x044f, 0xb696), /* Thrustmaster T248 */
MAKE_VIDPID(0x044f, 0xb66e), /* Thrustmaster T300RS (normal mode) */
MAKE_VIDPID(0x044f, 0xb66f), /* Thrustmaster T300RS (advanced mode) */
MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster T300RS (PS4 mode) */
MAKE_VIDPID(0x044f, 0xb65e), /* Thrustmaster T500RS */
MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */
MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */

View file

@ -747,7 +747,11 @@ HIDAPI_DriverPS5_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joy
}
}
return SDL_HIDAPI_SendRumbleAndUnlock(device, data, report_size);
if (SDL_HIDAPI_SendRumbleAndUnlock(device, data, report_size) != report_size) {
return -1;
}
return 0;
}
static int
@ -957,7 +961,10 @@ HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev,
axis = ((int)packet->ucRightJoystickY * 257) - 32768;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
if (packet->ucBatteryLevel & 0x10) {
/* A check of packet->ucBatteryLevel & 0x10 should work as a check for BT vs USB but doesn't
* seem to always work. Possibly related to being 100% charged?
*/
if (!ctx->is_bluetooth) {
/* 0x20 set means fully charged */
SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_WIRED);
} else {

View file

@ -227,7 +227,7 @@ HIDAPI_CleanupDeviceDriver(SDL_HIDAPI_Device *device)
}
/* Disconnect any joysticks */
while (device->num_joysticks) {
while (device->num_joysticks && device->joysticks) {
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}

View file

@ -330,6 +330,19 @@ IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controlle
subtype = 1;
}
if (SDL_strcmp(name, "Backbone One") == 0) {
/* The Backbone app uses the guide and share buttons */
if ((device->button_mask & (1 << SDL_CONTROLLER_BUTTON_GUIDE)) != 0) {
device->button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_GUIDE);
--nbuttons;
}
if ((device->button_mask & (1 << SDL_CONTROLLER_BUTTON_MISC1)) != 0) {
device->button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_MISC1);
--nbuttons;
device->has_xbox_share_button = SDL_FALSE;
}
}
device->naxes = 6; /* 2 thumbsticks and 2 triggers */
device->nhats = 1; /* d-pad */
device->nbuttons = nbuttons;

View file

@ -109,6 +109,7 @@ typedef struct SDL_joylist_item
/* Steam Controller support */
SDL_bool m_bSteamController;
SDL_bool checked_mapping;
SDL_GamepadMapping *mapping;
} SDL_joylist_item;
@ -605,6 +606,26 @@ LINUX_InotifyJoystickDetect(void)
}
#endif /* HAVE_INOTIFY */
static int get_event_joystick_index(int event)
{
int joystick_index = -1;
int i, count;
struct dirent **entries = NULL;
char path[PATH_MAX];
SDL_snprintf(path, SDL_arraysize(path), "/sys/class/input/event%d/device", event);
count = scandir(path, &entries, NULL, alphasort);
for (i = 0; i < count; ++i) {
if (SDL_strncmp(entries[i]->d_name, "js", 2) == 0) {
joystick_index = SDL_atoi(entries[i]->d_name+2);
}
free(entries[i]); /* This should NOT be SDL_free() */
}
free(entries); /* This should NOT be SDL_free() */
return joystick_index;
}
/* Detect devices by reading /dev/input. In the inotify code path we
* have to do this the first time, to detect devices that already existed
* before we started; in the non-inotify code path we do this repeatedly
@ -615,12 +636,39 @@ filter_entries(const struct dirent *entry)
return IsJoystickDeviceNode(entry->d_name);
}
static int
sort_entries(const struct dirent **a, const struct dirent **b)
sort_entries(const void *_a, const void *_b)
{
int numA = SDL_atoi((*a)->d_name+5);
int numB = SDL_atoi((*b)->d_name+5);
const struct dirent **a = (const struct dirent **)_a;
const struct dirent **b = (const struct dirent **)_b;
int numA, numB;
int offset;
if (SDL_classic_joysticks) {
offset = 2; /* strlen("js") */
numA = SDL_atoi((*a)->d_name+offset);
numB = SDL_atoi((*b)->d_name+offset);
} else {
offset = 5; /* strlen("event") */
numA = SDL_atoi((*a)->d_name+offset);
numB = SDL_atoi((*b)->d_name+offset);
/* See if we can get the joystick ordering */
{
int jsA = get_event_joystick_index(numA);
int jsB = get_event_joystick_index(numB);
if (jsA >= 0 && jsB >= 0) {
numA = jsA;
numB = jsB;
} else if (jsA >= 0) {
return -1;
} else if (jsB >= 0) {
return 1;
}
}
}
return (numA - numB);
}
static void
LINUX_FallbackJoystickDetect(void)
{
@ -633,10 +681,13 @@ LINUX_FallbackJoystickDetect(void)
/* Opening input devices can generate synchronous device I/O, so avoid it if we can */
if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) {
int i, count;
struct dirent **entries;
struct dirent **entries = NULL;
char path[PATH_MAX];
count = scandir("/dev/input", &entries, filter_entries, sort_entries);
count = scandir("/dev/input", &entries, filter_entries, NULL);
if (count > 1) {
qsort(entries, count, sizeof(*entries), sort_entries);
}
for (i = 0; i < count; ++i) {
SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", entries[i]->d_name);
MaybeAddDevice(path);
@ -683,29 +734,7 @@ LINUX_JoystickInit(void)
SDL_classic_joysticks = SDL_GetHintBoolean(SDL_HINT_LINUX_JOYSTICK_CLASSIC, SDL_FALSE);
#if SDL_USE_LIBUDEV
if (enumeration_method == ENUMERATION_UNSET) {
if (SDL_GetHintBoolean("SDL_JOYSTICK_DISABLE_UDEV", SDL_FALSE)) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
"udev disabled by SDL_JOYSTICK_DISABLE_UDEV");
enumeration_method = ENUMERATION_FALLBACK;
} else if (access("/.flatpak-info", F_OK) == 0
|| access("/run/host/container-manager", F_OK) == 0) {
/* Explicitly check `/.flatpak-info` because, for old versions of
* Flatpak, this was the only available way to tell if we were in
* a Flatpak container. */
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
"Container detected, disabling udev integration");
enumeration_method = ENUMERATION_FALLBACK;
} else {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
"Using udev for joystick device discovery");
enumeration_method = ENUMERATION_LIBUDEV;
}
}
#endif
enumeration_method = ENUMERATION_UNSET;
/* First see if the user specified one or more joysticks to use */
if (devices != NULL) {
@ -734,6 +763,28 @@ LINUX_JoystickInit(void)
LINUX_JoystickDetect();
#if SDL_USE_LIBUDEV
if (enumeration_method == ENUMERATION_UNSET) {
if (SDL_GetHintBoolean("SDL_JOYSTICK_DISABLE_UDEV", SDL_FALSE)) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
"udev disabled by SDL_JOYSTICK_DISABLE_UDEV");
enumeration_method = ENUMERATION_FALLBACK;
} else if (access("/.flatpak-info", F_OK) == 0
|| access("/run/host/container-manager", F_OK) == 0) {
/* Explicitly check `/.flatpak-info` because, for old versions of
* Flatpak, this was the only available way to tell if we were in
* a Flatpak container. */
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
"Container detected, disabling udev integration");
enumeration_method = ENUMERATION_FALLBACK;
} else {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
"Using udev for joystick device discovery");
enumeration_method = ENUMERATION_LIBUDEV;
}
}
if (enumeration_method == ENUMERATION_LIBUDEV) {
if (SDL_UDEV_Init() < 0) {
return SDL_SetError("Could not initialize UDEV");
@ -1573,9 +1624,13 @@ LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
SDL_Joystick *joystick;
SDL_joylist_item *item = JoystickByDevIndex(device_index);
if (item->mapping) {
SDL_memcpy(out, item->mapping, sizeof(*out));
return SDL_TRUE;
if (item->checked_mapping) {
if (item->mapping) {
SDL_memcpy(out, item->mapping, sizeof(*out));
return SDL_TRUE;
} else {
return SDL_FALSE;
}
}
/* We temporarily open the device to check how it's configured. Make
@ -1595,6 +1650,8 @@ LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
return SDL_FALSE;
}
item->checked_mapping = SDL_TRUE;
if (PrepareJoystickHwdata(joystick, item) == -1) {
SDL_free(joystick->hwdata);
SDL_free(joystick);

View file

@ -62,6 +62,7 @@ typedef struct WindowsGamingInputGamepadState WindowsGamingInputGamepadState;
#define GamepadButtons_GUIDE 0x40000000
#define COBJMACROS
#include "windows.gaming.input.h"
#include <roapi.h>
#endif
#if defined(SDL_JOYSTICK_RAWINPUT_XINPUT) || defined(SDL_JOYSTICK_RAWINPUT_WGI)
@ -565,22 +566,24 @@ RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
if (!wgi_state.initialized) {
static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
HRESULT hr;
HMODULE hModule;
/* I think this takes care of RoInitialize() in a way that is compatible with the rest of SDL */
if (FAILED(WIN_CoInitialize())) {
if (FAILED(WIN_RoInitialize())) {
return;
}
wgi_state.initialized = SDL_TRUE;
wgi_state.dirty = SDL_TRUE;
hModule = LoadLibraryA("combase.dll");
if (hModule != NULL) {
{
typedef HRESULT (WINAPI *WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING* string);
typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory);
WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)GetProcAddress(hModule, "WindowsCreateStringReference");
RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory");
#ifdef __WINRT__
WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = WindowsCreateStringReference;
RoGetActivationFactory_t RoGetActivationFactoryFunc = RoGetActivationFactory;
#else
WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference");
RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory");
#endif
if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) {
PCWSTR pNamespace = L"Windows.Gaming.Input.Gamepad";
HSTRING_HEADER hNamespaceStringHeader;
@ -591,7 +594,6 @@ RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, (void **)&wgi_state.gamepad_statics);
}
}
FreeLibrary(hModule);
}
}
}
@ -657,7 +659,7 @@ RAWINPUT_QuitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(wgi_state.gamepad_statics);
wgi_state.gamepad_statics = NULL;
}
WIN_CoUninitialize();
WIN_RoUninitialize();
wgi_state.initialized = SDL_FALSE;
}
}
@ -1320,8 +1322,10 @@ RAWINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint
if (!SUCCEEDED(hr)) {
return SDL_SetError("Setting vibration failed: 0x%lx\n", hr);
}
return 0;
} else {
return SDL_SetError("Controller isn't correlated yet, try hitting a button first");
}
return 0;
#else
return SDL_Unsupported();
#endif

View file

@ -68,6 +68,7 @@ static struct {
EventRegistrationToken controller_added_token;
EventRegistrationToken controller_removed_token;
int controller_count;
SDL_bool ro_initialized;
WindowsGamingInputControllerState *controllers;
} wgi;
@ -260,10 +261,9 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
WindowsGetStringRawBufferFunc = WindowsGetStringRawBuffer;
WindowsDeleteStringFunc = WindowsDeleteString;
#else
HMODULE hModule = LoadLibraryA("combase.dll");
if (hModule != NULL) {
WindowsGetStringRawBufferFunc = (WindowsGetStringRawBuffer_t)GetProcAddress(hModule, "WindowsGetStringRawBuffer");
WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString");
{
WindowsGetStringRawBufferFunc = (WindowsGetStringRawBuffer_t)WIN_LoadComBaseFunction("WindowsGetStringRawBuffer");
WindowsDeleteStringFunc = (WindowsDeleteString_t)WIN_LoadComBaseFunction("WindowsDeleteString");
}
#endif /* __WINRT__ */
if (WindowsGetStringRawBufferFunc && WindowsDeleteStringFunc) {
@ -277,11 +277,6 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
WindowsDeleteStringFunc(hString);
}
}
#ifndef __WINRT__
if (hModule != NULL) {
FreeLibrary(hModule);
}
#endif
__x_ABI_CWindows_CGaming_CInput_CIRawGameController2_Release(controller2);
}
if (!name) {
@ -444,23 +439,43 @@ WGI_JoystickInit(void)
WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = NULL;
RoGetActivationFactory_t RoGetActivationFactoryFunc = NULL;
#ifndef __WINRT__
HMODULE hModule;
#endif
HRESULT hr;
if (FAILED(WIN_CoInitialize())) {
return SDL_SetError("CoInitialize() failed");
if (FAILED(WIN_RoInitialize())) {
return SDL_SetError("RoInitialize() failed");
}
wgi.ro_initialized = SDL_TRUE;
#ifndef __WINRT__
{
/* There seems to be a bug in Windows where a dependency of WGI can be unloaded from memory prior to WGI itself.
* This results in Windows_Gaming_Input!GameController::~GameController() invoking an unloaded DLL and crashing.
* As a workaround, we will keep a reference to the MTA to prevent COM from unloading DLLs later.
* See https://github.com/libsdl-org/SDL/issues/5552 for more details.
*/
static PVOID cookie = NULL;
if (!cookie) {
typedef HRESULT (WINAPI *CoIncrementMTAUsage_t)(PVOID* pCookie);
CoIncrementMTAUsage_t CoIncrementMTAUsageFunc = (CoIncrementMTAUsage_t)WIN_LoadComBaseFunction("CoIncrementMTAUsage");
if (CoIncrementMTAUsageFunc) {
if (FAILED(CoIncrementMTAUsageFunc(&cookie))) {
return SDL_SetError("CoIncrementMTAUsage() failed");
}
} else {
/* CoIncrementMTAUsage() is present since Win8, so we should never make it here. */
return SDL_SetError("CoIncrementMTAUsage() not found");
}
}
}
#endif
#ifdef __WINRT__
WindowsCreateStringReferenceFunc = WindowsCreateStringReference;
RoGetActivationFactoryFunc = RoGetActivationFactory;
#else
hModule = LoadLibraryA("combase.dll");
if (hModule != NULL) {
WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)GetProcAddress(hModule, "WindowsCreateStringReference");
RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory");
{
WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference");
RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory");
}
#endif /* __WINRT__ */
if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) {
@ -519,11 +534,6 @@ WGI_JoystickInit(void)
}
}
}
#ifndef __WINRT__
if (hModule != NULL) {
FreeLibrary(hModule);
}
#endif
if (wgi.statics) {
__FIVectorView_1_Windows__CGaming__CInput__CRawGameController *controllers;
@ -863,9 +873,12 @@ WGI_JoystickQuit(void)
__x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_remove_RawGameControllerRemoved(wgi.statics, wgi.controller_removed_token);
__x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_Release(wgi.statics);
}
SDL_zero(wgi);
WIN_CoUninitialize();
if (wgi.ro_initialized) {
WIN_RoUninitialize();
}
SDL_zero(wgi);
}
static SDL_bool

View file

@ -0,0 +1,71 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#include "../SDL_syslocale.h"
#include <psp2/apputil.h>
#include <psp2/system_param.h>
void
SDL_SYS_GetPreferredLocales(char *buf, size_t buflen)
{
const char *vita_locales[] = {
"ja_JP",
"en_US",
"fr_FR",
"es_ES",
"de_DE",
"it_IT",
"nl_NL",
"pt_PT",
"ru_RU",
"ko_KR",
"zh_TW",
"zh_CN",
"fi_FI",
"sv_SE",
"da_DK",
"no_NO",
"pl_PL",
"pt_BR",
"en_GB",
"tr_TR",
};
Sint32 language = SCE_SYSTEM_PARAM_LANG_ENGLISH_US;
SceAppUtilInitParam initParam;
SceAppUtilBootParam bootParam;
SDL_zero(initParam);
SDL_zero(bootParam);
sceAppUtilInit(&initParam, &bootParam);
sceAppUtilSystemParamGetInt(SCE_SYSTEM_PARAM_ID_LANG, &language);
if (language < 0 || language > SCE_SYSTEM_PARAM_LANG_TURKISH)
language = SCE_SYSTEM_PARAM_LANG_ENGLISH_US; // default to english
SDL_strlcpy(buf, vita_locales[language], buflen);
sceAppUtilShutdown();
}
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,0,21,0
PRODUCTVERSION 2,0,21,0
FILEVERSION 2,0,22,0
PRODUCTVERSION 2,0,22,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x40004L
@ -23,12 +23,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "SDL\0"
VALUE "FileVersion", "2, 0, 21, 0\0"
VALUE "FileVersion", "2, 0, 22, 0\0"
VALUE "InternalName", "SDL\0"
VALUE "LegalCopyright", "Copyright (C) 2022 Sam Lantinga\0"
VALUE "OriginalFilename", "SDL2.dll\0"
VALUE "ProductName", "Simple DirectMedia Layer\0"
VALUE "ProductVersion", "2, 0, 21, 0\0"
VALUE "ProductVersion", "2, 0, 22, 0\0"
END
END
BLOCK "VarFileInfo"

View file

@ -356,7 +356,7 @@ QueueCmdSetViewport(SDL_Renderer *renderer)
if (cmd != NULL) {
cmd->command = SDL_RENDERCMD_SETVIEWPORT;
cmd->data.viewport.first = 0; /* render backend will fill this in. */
/* Convert SDL_FRect to SDL_Rect */
/* Convert SDL_DRect to SDL_Rect */
cmd->data.viewport.rect.x = (int)SDL_floor(renderer->viewport.x);
cmd->data.viewport.rect.y = (int)SDL_floor(renderer->viewport.y);
cmd->data.viewport.rect.w = (int)SDL_floor(renderer->viewport.w);
@ -386,7 +386,7 @@ QueueCmdSetClipRect(SDL_Renderer *renderer)
} else {
cmd->command = SDL_RENDERCMD_SETCLIPRECT;
cmd->data.cliprect.enabled = renderer->clipping_enabled;
/* Convert SDL_FRect to SDL_Rect */
/* Convert SDL_DRect to SDL_Rect */
cmd->data.cliprect.rect.x = (int)SDL_floor(renderer->clip_rect.x);
cmd->data.cliprect.rect.y = (int)SDL_floor(renderer->clip_rect.y);
cmd->data.cliprect.rect.w = (int)SDL_floor(renderer->clip_rect.w);
@ -580,10 +580,10 @@ QueueCmdFillRects(SDL_Renderer *renderer, const SDL_FRect * rects, const int cou
if (retval < 0) {
cmd->command = SDL_RENDERCMD_NO_OP;
}
SDL_small_free(xy, isstack1);
SDL_small_free(indices, isstack2);
}
SDL_small_free(xy, isstack1);
SDL_small_free(indices, isstack2);
} else {
retval = renderer->QueueFillRects(renderer, cmd, rects, count);
if (retval < 0) {
@ -676,7 +676,7 @@ SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info)
#endif
}
static void GetWindowViewportValues(SDL_Renderer *renderer, int *logical_w, int *logical_h, SDL_FRect *viewport, SDL_FPoint *scale)
static void GetWindowViewportValues(SDL_Renderer *renderer, int *logical_w, int *logical_h, SDL_DRect *viewport, SDL_FPoint *scale)
{
SDL_LockMutex(renderer->target_mutex);
*logical_w = renderer->target ? renderer->logical_w_backup : renderer->logical_w;
@ -698,7 +698,17 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
renderer->WindowEvent(renderer, &event->window);
}
if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
/* In addition to size changes, we also want to do this block for
* moves as well, for two reasons:
*
* 1. The window could be moved to a new display, which has a new
* DPI and therefore a new window/drawable ratio
* 2. For whatever reason, the viewport can get messed up during
* window movement (this has been observed on macOS), so this is
* also a good opportunity to force viewport updates
*/
if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED ||
event->window.event == SDL_WINDOWEVENT_MOVED) {
/* Make sure we're operating on the default render target */
SDL_Texture *saved_target = SDL_GetRenderTarget(renderer);
if (saved_target) {
@ -728,10 +738,10 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
SDL_GetWindowSize(renderer->window, &w, &h);
}
renderer->viewport.x = 0;
renderer->viewport.y = 0;
renderer->viewport.w = (float) w;
renderer->viewport.h = (float) h;
renderer->viewport.x = (double)0;
renderer->viewport.y = (double)0;
renderer->viewport.w = (double)w;
renderer->viewport.h = (double)h;
QueueCmdSetViewport(renderer);
FlushRenderCommandsIfNotBatching(renderer);
}
@ -758,7 +768,7 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
SDL_Window *window = SDL_GetWindowFromID(event->motion.windowID);
if (window == renderer->window) {
int logical_w, logical_h;
SDL_FRect viewport;
SDL_DRect viewport;
SDL_FPoint scale;
GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale);
if (logical_w) {
@ -785,7 +795,7 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
SDL_Window *window = SDL_GetWindowFromID(event->button.windowID);
if (window == renderer->window) {
int logical_w, logical_h;
SDL_FRect viewport;
SDL_DRect viewport;
SDL_FPoint scale;
GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale);
if (logical_w) {
@ -800,7 +810,7 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
event->type == SDL_FINGERMOTION) {
int logical_w, logical_h;
float physical_w, physical_h;
SDL_FRect viewport;
SDL_DRect viewport;
SDL_FPoint scale;
GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale);
@ -1095,6 +1105,13 @@ SDL_GetRenderer(SDL_Window * window)
return (SDL_Renderer *)SDL_GetWindowData(window, SDL_WINDOWRENDERDATA);
}
SDL_Window *
SDL_RenderGetWindow(SDL_Renderer *renderer)
{
CHECK_RENDERER_MAGIC(renderer, NULL);
return renderer->window;
}
int
SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info)
{
@ -1585,10 +1602,11 @@ SDL_SetTextureScaleMode(SDL_Texture * texture, SDL_ScaleMode scaleMode)
CHECK_TEXTURE_MAGIC(texture, -1);
renderer = texture->renderer;
renderer->SetTextureScaleMode(renderer, texture, scaleMode);
texture->scaleMode = scaleMode;
if (texture->native) {
return SDL_SetTextureScaleMode(texture->native, scaleMode);
} else {
renderer->SetTextureScaleMode(renderer, texture, scaleMode);
}
return 0;
}
@ -2210,10 +2228,10 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
}
if (texture) {
renderer->viewport.x = 0.0f;
renderer->viewport.y = 0.0f;
renderer->viewport.w = (float) texture->w;
renderer->viewport.h = (float) texture->h;
renderer->viewport.x = (double)0;
renderer->viewport.y = (double)0;
renderer->viewport.w = (double)texture->w;
renderer->viewport.h = (double)texture->h;
SDL_zero(renderer->clip_rect);
renderer->clipping_enabled = SDL_FALSE;
renderer->scale.x = 1.0f;
@ -2245,6 +2263,8 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
SDL_Texture *
SDL_GetRenderTarget(SDL_Renderer *renderer)
{
CHECK_RENDERER_MAGIC(renderer, NULL);
return renderer->target;
}
@ -2420,19 +2440,19 @@ SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
CHECK_RENDERER_MAGIC(renderer, -1);
if (rect) {
renderer->viewport.x = rect->x * renderer->scale.x;
renderer->viewport.y = rect->y * renderer->scale.y;
renderer->viewport.w = rect->w * renderer->scale.x;
renderer->viewport.h = rect->h * renderer->scale.y;
renderer->viewport.x = (double)rect->x * renderer->scale.x;
renderer->viewport.y = (double)rect->y * renderer->scale.y;
renderer->viewport.w = (double)rect->w * renderer->scale.x;
renderer->viewport.h = (double)rect->h * renderer->scale.y;
} else {
int w, h;
if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) {
return -1;
}
renderer->viewport.x = 0.0f;
renderer->viewport.y = 0.0f;
renderer->viewport.w = (float) w;
renderer->viewport.h = (float) h;
renderer->viewport.x = (double)0;
renderer->viewport.y = (double)0;
renderer->viewport.w = (double)w;
renderer->viewport.h = (double)h;
}
retval = QueueCmdSetViewport(renderer);
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
@ -2456,8 +2476,8 @@ RenderGetViewportSize(SDL_Renderer * renderer, SDL_FRect * rect)
{
rect->x = 0.0f;
rect->y = 0.0f;
rect->w = renderer->viewport.w / renderer->scale.x;
rect->h = renderer->viewport.h / renderer->scale.y;
rect->w = (float)(renderer->viewport.w / renderer->scale.x);
rect->h = (float)(renderer->viewport.h / renderer->scale.y);
}
int
@ -2468,10 +2488,10 @@ SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect)
if (rect) {
renderer->clipping_enabled = SDL_TRUE;
renderer->clip_rect.x = rect->x * renderer->scale.x;
renderer->clip_rect.y = rect->y * renderer->scale.y;
renderer->clip_rect.w = rect->w * renderer->scale.x;
renderer->clip_rect.h = rect->h * renderer->scale.y;
renderer->clip_rect.x = (double)rect->x * renderer->scale.x;
renderer->clip_rect.y = (double)rect->y * renderer->scale.y;
renderer->clip_rect.w = (double)rect->w * renderer->scale.x;
renderer->clip_rect.h = (double)rect->h * renderer->scale.y;
} else {
renderer->clipping_enabled = SDL_FALSE;
SDL_zero(renderer->clip_rect);
@ -2535,10 +2555,10 @@ SDL_RenderWindowToLogical(SDL_Renderer * renderer, int windowX, int windowY, flo
window_physical_y = ((float) windowY) / renderer->dpi_scale.y;
if (logicalX) {
*logicalX = (window_physical_x - renderer->viewport.x) / renderer->scale.x;
*logicalX = (float)((window_physical_x - renderer->viewport.x) / renderer->scale.x);
}
if (logicalY) {
*logicalY = (window_physical_y - renderer->viewport.y) / renderer->scale.y;
*logicalY = (float)((window_physical_y - renderer->viewport.y) / renderer->scale.y);
}
}
@ -2549,8 +2569,8 @@ SDL_RenderLogicalToWindow(SDL_Renderer * renderer, float logicalX, float logical
CHECK_RENDERER_MAGIC(renderer, );
window_physical_x = (logicalX * renderer->scale.x) + renderer->viewport.x;
window_physical_y = (logicalY * renderer->scale.y) + renderer->viewport.y;
window_physical_x = (float)((logicalX * renderer->scale.x) + renderer->viewport.x);
window_physical_y = (float)((logicalY * renderer->scale.y) + renderer->viewport.y);
if (windowX) {
*windowX = (int)(window_physical_x * renderer->dpi_scale.x);
@ -3138,10 +3158,11 @@ SDL_RenderDrawLinesF(SDL_Renderer * renderer,
num_vertices, indices, num_indices, size_indices,
1.0f, 1.0f);
SDL_small_free(xy, isstack1);
SDL_small_free(indices, isstack2);
}
SDL_small_free(xy, isstack1);
SDL_small_free(indices, isstack2);
} else if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
retval = RenderDrawLinesWithRectsF(renderer, points, count);
} else {

View file

@ -28,6 +28,19 @@
#include "SDL_mutex.h"
#include "SDL_yuv_sw_c.h"
/**
* A rectangle, with the origin at the upper left (double precision).
*/
typedef struct SDL_DRect
{
double x;
double y;
double w;
double h;
} SDL_DRect;
/* The SDL 2D rendering system */
typedef struct SDL_RenderDriver SDL_RenderDriver;
@ -201,12 +214,12 @@ struct SDL_Renderer
SDL_bool integer_scale;
/* The drawable area within the window */
SDL_FRect viewport;
SDL_FRect viewport_backup;
SDL_DRect viewport;
SDL_DRect viewport_backup;
/* The clip rectangle within the window */
SDL_FRect clip_rect;
SDL_FRect clip_rect_backup;
SDL_DRect clip_rect;
SDL_DRect clip_rect_backup;
/* Wether or not the clipping rectangle is used. */
SDL_bool clipping_enabled;
@ -244,8 +257,8 @@ struct SDL_Renderer
SDL_RenderCommand *render_commands_pool;
Uint32 render_command_generation;
Uint32 last_queued_color;
SDL_FRect last_queued_viewport;
SDL_FRect last_queued_cliprect;
SDL_DRect last_queued_viewport;
SDL_DRect last_queued_cliprect;
SDL_bool last_queued_cliprect_enabled;
SDL_bool color_queued;
SDL_bool viewport_queued;

View file

@ -347,7 +347,8 @@ D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
}
}
static D3DBLEND GetBlendFunc(SDL_BlendFactor factor)
static D3DBLEND
GetBlendFunc(SDL_BlendFactor factor)
{
switch (factor) {
case SDL_BLENDFACTOR_ZERO:
@ -370,9 +371,28 @@ static D3DBLEND GetBlendFunc(SDL_BlendFactor factor)
return D3DBLEND_DESTALPHA;
case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
return D3DBLEND_INVDESTALPHA;
default:
return (D3DBLEND)0;
default: break;
}
return (D3DBLEND) 0;
}
static D3DBLENDOP
GetBlendEquation(SDL_BlendOperation operation)
{
switch (operation) {
case SDL_BLENDOPERATION_ADD:
return D3DBLENDOP_ADD;
case SDL_BLENDOPERATION_SUBTRACT:
return D3DBLENDOP_SUBTRACT;
case SDL_BLENDOPERATION_REV_SUBTRACT:
return D3DBLENDOP_REVSUBTRACT;
case SDL_BLENDOPERATION_MINIMUM:
return D3DBLENDOP_MIN;
case SDL_BLENDOPERATION_MAXIMUM:
return D3DBLENDOP_MAX;
default: break;
}
return (D3DBLENDOP) 0;
}
static SDL_bool
@ -387,14 +407,16 @@ D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
if (!GetBlendFunc(srcColorFactor) || !GetBlendFunc(srcAlphaFactor) ||
!GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor)) {
!GetBlendEquation(colorOperation) ||
!GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor) ||
!GetBlendEquation(alphaOperation)) {
return SDL_FALSE;
}
if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->enableSeparateAlphaBlend) {
return SDL_FALSE;
}
if (colorOperation != SDL_BLENDOPERATION_ADD || alphaOperation != SDL_BLENDOPERATION_ADD) {
return SDL_FALSE;
if (!data->enableSeparateAlphaBlend) {
if ((srcColorFactor != srcAlphaFactor) || (dstColorFactor != dstAlphaFactor) || (colorOperation != alphaOperation)) {
return SDL_FALSE;
}
}
return SDL_TRUE;
}
@ -1040,11 +1062,15 @@ SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd)
GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)));
IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)));
IDirect3DDevice9_SetRenderState(data->device, D3DRS_BLENDOP,
GetBlendEquation(SDL_GetBlendModeColorOperation(blend)));
if (data->enableSeparateAlphaBlend) {
IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)));
IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
IDirect3DDevice9_SetRenderState(data->device, D3DRS_BLENDOPALPHA,
GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend)));
}
}

View file

@ -998,6 +998,16 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
goto done;
}
/* Set the swap chain target immediately, so that a target is always set
* even before we get to SetDrawState. Without this it's possible to hit
* null references in places like ReadPixels!
*/
ID3D11DeviceContext_OMSetRenderTargets(data->d3dContext,
1,
&data->mainRenderTargetView,
NULL
);
data->viewportDirty = SDL_TRUE;
done:

View file

@ -30,6 +30,11 @@
#include <OpenGL/OpenGL.h>
#endif
#ifdef SDL_VIDEO_VITA_PVR_OGL
#include <GL/gl.h>
#include <GL/glext.h>
#endif
/* To prevent unnecessary window recreation,
* these should match the defaults selected in SDL_GL_ResetAttributes
*/
@ -319,6 +324,20 @@ GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h)
return result;
}
static void
GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
{
/* If the window x/y/w/h changed at all, assume the viewport has been
* changed behind our backs. x/y changes might seem weird but viewport
* resets have been observed on macOS at minimum!
*/
if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
event->event == SDL_WINDOWEVENT_MOVED) {
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
data->drawstate.viewport_dirty = SDL_TRUE;
}
}
static int
GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
{
@ -1212,9 +1231,9 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
}
#ifdef __MACOSX__
// On macOS, moving the window seems to invalidate the OpenGL viewport state,
// so don't bother trying to persist it across frames; always reset it.
// Workaround for: https://github.com/libsdl-org/SDL/issues/1504
// On macOS on older systems, the OpenGL view change and resize events aren't
// necessarily synchronized, so just always reset it.
// Workaround for: https://discourse.libsdl.org/t/sdl-2-0-22-prerelease/35306/6
data->drawstate.viewport_dirty = SDL_TRUE;
#endif
@ -1733,6 +1752,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags)
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
#ifndef SDL_VIDEO_VITA_PVR_OGL
window_flags = SDL_GetWindowFlags(window);
if (!(window_flags & SDL_WINDOW_OPENGL) ||
profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
@ -1746,6 +1766,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags)
goto error;
}
}
#endif
renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
if (!renderer) {
@ -1760,6 +1781,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags)
goto error;
}
renderer->WindowEvent = GL_WindowEvent;
renderer->GetOutputSize = GL_GetOutputSize;
renderer->SupportsBlendMode = GL_SupportsBlendMode;
renderer->CreateTexture = GL_CreateTexture;

View file

@ -61,6 +61,11 @@ static int VITA_GXM_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * text
const Uint8 *Uplane, int Upitch,
const Uint8 *Vplane, int Vpitch);
static int VITA_GXM_UpdateTextureNV(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect,
const Uint8 *Yplane, int Ypitch,
const Uint8 *UVplane, int UVpitch);
static int VITA_GXM_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_Rect *rect, void **pixels, int *pitch);
@ -105,12 +110,16 @@ SDL_RenderDriver VITA_GXM_RenderDriver = {
.info = {
.name = "VITA gxm",
.flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE,
.num_texture_formats = 4,
.num_texture_formats = 8,
.texture_formats = {
[0] = SDL_PIXELFORMAT_ABGR8888,
[1] = SDL_PIXELFORMAT_ARGB8888,
[2] = SDL_PIXELFORMAT_RGB565,
[3] = SDL_PIXELFORMAT_BGR565
[3] = SDL_PIXELFORMAT_BGR565,
[4] = SDL_PIXELFORMAT_YV12,
[5] = SDL_PIXELFORMAT_IYUV,
[6] = SDL_PIXELFORMAT_NV12,
[7] = SDL_PIXELFORMAT_NV21,
},
.max_texture_width = 4096,
.max_texture_height = 4096,
@ -133,6 +142,15 @@ PixelFormatToVITAFMT(Uint32 format)
return SCE_GXM_TEXTURE_FORMAT_U5U6U5_RGB;
case SDL_PIXELFORMAT_BGR565:
return SCE_GXM_TEXTURE_FORMAT_U5U6U5_BGR;
case SDL_PIXELFORMAT_YV12:
return SCE_GXM_TEXTURE_FORMAT_YVU420P3_CSC0;
case SDL_PIXELFORMAT_IYUV:
return SCE_GXM_TEXTURE_FORMAT_YUV420P3_CSC0;
// should be the other way around. looks like SCE bug.
case SDL_PIXELFORMAT_NV12:
return SCE_GXM_TEXTURE_FORMAT_YVU420P2_CSC0;
case SDL_PIXELFORMAT_NV21:
return SCE_GXM_TEXTURE_FORMAT_YUV420P2_CSC0;
default:
return SCE_GXM_TEXTURE_FORMAT_U8U8U8U8_ABGR;
}
@ -228,6 +246,7 @@ VITA_GXM_CreateRenderer(SDL_Window *window, Uint32 flags)
renderer->UpdateTexture = VITA_GXM_UpdateTexture;
#if SDL_HAVE_YUV
renderer->UpdateTextureYUV = VITA_GXM_UpdateTextureYUV;
renderer->UpdateTextureNV = VITA_GXM_UpdateTextureNV;
#endif
renderer->LockTexture = VITA_GXM_LockTexture;
renderer->UnlockTexture = VITA_GXM_UnlockTexture;
@ -295,7 +314,17 @@ VITA_GXM_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
return SDL_OutOfMemory();
}
vita_texture->tex = create_gxm_texture(data, texture->w, texture->h, PixelFormatToVITAFMT(texture->format), (texture->access == SDL_TEXTUREACCESS_TARGET));
vita_texture->tex = create_gxm_texture(
data,
texture->w,
texture->h,
PixelFormatToVITAFMT(texture->format),
(texture->access == SDL_TEXTUREACCESS_TARGET),
&(vita_texture->w),
&(vita_texture->h),
&(vita_texture->pitch),
&(vita_texture->wscale)
);
if (!vita_texture->tex) {
SDL_free(vita_texture);
@ -306,38 +335,129 @@ VITA_GXM_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
VITA_GXM_SetTextureScaleMode(renderer, texture, texture->scaleMode);
vita_texture->w = gxm_texture_get_width(vita_texture->tex);
vita_texture->h = gxm_texture_get_height(vita_texture->tex);
vita_texture->pitch = gxm_texture_get_stride(vita_texture->tex);
#if SDL_HAVE_YUV
vita_texture->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12));
vita_texture->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21));
#endif
return 0;
}
static void VITA_GXM_SetYUVProfile(SDL_Renderer * renderer, SDL_Texture *texture)
{
VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
int ret = 0;
switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
case SDL_YUV_CONVERSION_BT601:
ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT601_STANDARD);
break;
case SDL_YUV_CONVERSION_BT709:
ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT709_STANDARD);
break;
case SDL_YUV_CONVERSION_JPEG:
default:
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Unsupported YUV profile: %d\n", SDL_GetYUVConversionModeForResolution(texture->w, texture->h));
break;
}
if (ret < 0) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Setting YUV profile failed: %x\n", ret);
}
}
static int
VITA_GXM_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_Rect *rect, const void *pixels, int pitch)
{
const Uint8 *src;
VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) texture->driverdata;
Uint8 *dst;
int row, length,dpitch;
src = pixels;
int row, length, dpitch;
#if SDL_HAVE_YUV
if (vita_texture->yuv || vita_texture->nv12) {
VITA_GXM_SetYUVProfile(renderer, texture);
}
#endif
VITA_GXM_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch);
length = rect->w * SDL_BYTESPERPIXEL(texture->format);
if (length == pitch && length == dpitch) {
SDL_memcpy(dst, src, length*rect->h);
SDL_memcpy(dst, pixels, length*rect->h);
} else {
for (row = 0; row < rect->h; ++row) {
SDL_memcpy(dst, src, length);
src += pitch;
SDL_memcpy(dst, pixels, length);
pixels += pitch;
dst += dpitch;
}
}
#if SDL_HAVE_YUV
if (vita_texture->yuv) {
void *Udst;
void *Vdst;
int uv_pitch = (dpitch+1) / 2;
int uv_src_pitch = (pitch+1) / 2;
SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2};
// skip Y plane
Uint8 *Dpixels = gxm_texture_get_datap(vita_texture->tex) + (vita_texture->pitch * vita_texture->h);
Udst = Dpixels + (UVrect.y * uv_pitch) + UVrect.x;
Vdst = Dpixels + (uv_pitch * ((vita_texture->h + 1) / 2)) + (UVrect.y * uv_pitch) + UVrect.x;
length = UVrect.w;
// U plane
if (length == uv_src_pitch && length == uv_pitch) {
SDL_memcpy(Udst, pixels, length*UVrect.h);
} else {
for (row = 0; row < UVrect.h; ++row) {
SDL_memcpy(Udst, pixels, length);
pixels += uv_src_pitch;
Udst += uv_pitch;
}
}
// V plane
if (length == uv_src_pitch && length == uv_pitch) {
SDL_memcpy(Vdst, pixels, length*UVrect.h);
} else {
for (row = 0; row < UVrect.h; ++row) {
SDL_memcpy(Vdst, pixels, length);
pixels += uv_src_pitch;
Vdst += uv_pitch;
}
}
} else if (vita_texture->nv12) {
void *UVdst;
int uv_pitch = 2 * ((dpitch+1) / 2);
int uv_src_pitch = 2 * ((pitch+1) / 2);
SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2 , (rect->h + 1) / 2};
// skip Y plane
void *Dpixels = (void *) ((Uint8 *) gxm_texture_get_datap(vita_texture->tex) + (vita_texture->pitch * vita_texture->h));
UVdst = Dpixels + (UVrect.y * uv_pitch) + UVrect.x;
length = UVrect.w*2;
// UV plane
if (length == uv_src_pitch && length == uv_pitch) {
SDL_memcpy(UVdst, pixels, length*UVrect.h);
} else {
for (row = 0; row < UVrect.h; ++row) {
SDL_memcpy(UVdst, pixels, length);
pixels += uv_src_pitch;
UVdst += uv_pitch;
}
}
}
#endif
return 0;
}
#if SDL_HAVE_YUV
static int
VITA_GXM_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect,
@ -345,9 +465,133 @@ VITA_GXM_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
const Uint8 *Uplane, int Upitch,
const Uint8 *Vplane, int Vpitch)
{
Uint8 *dst;
int row, length, dpitch;
SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2};
VITA_GXM_SetYUVProfile(renderer, texture);
// copy Y plane
// obtain pixels via locking so that texture is flushed
VITA_GXM_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch);
length = rect->w;
if (length == Ypitch && length == dpitch) {
SDL_memcpy(dst, Yplane, length*rect->h);
} else {
for (row = 0; row < rect->h; ++row) {
SDL_memcpy(dst, Yplane, length);
Yplane += Ypitch;
dst += dpitch;
}
}
// U/V planes
{
void *Udst;
void *Vdst;
VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) texture->driverdata;
int uv_pitch = (dpitch+1) / 2;
// skip Y plane
void *pixels = (void *) ((Uint8 *) gxm_texture_get_datap(vita_texture->tex) + (vita_texture->pitch * vita_texture->h));
if (texture->format == SDL_PIXELFORMAT_YV12) { // YVU
Vdst = pixels + (UVrect.y * uv_pitch) + UVrect.x;
Udst = pixels + (uv_pitch * ((vita_texture->h + 1) / 2)) + (UVrect.y * uv_pitch) + UVrect.x;
} else { // YUV
Udst = pixels + (UVrect.y * uv_pitch) + UVrect.x;
Vdst = pixels + (uv_pitch * ((vita_texture->h + 1) / 2)) + (UVrect.y * uv_pitch) + UVrect.x;
}
length = UVrect.w;
// U plane
if (length == Upitch && length == uv_pitch) {
SDL_memcpy(Udst, Uplane, length*UVrect.h);
} else {
for (row = 0; row < UVrect.h; ++row) {
SDL_memcpy(Udst, Uplane, length);
Uplane += Upitch;
Udst += uv_pitch;
}
}
// V plane
if (length == Vpitch && length == uv_pitch) {
SDL_memcpy(Vdst, Vplane, length*UVrect.h);
} else {
for (row = 0; row < UVrect.h; ++row) {
SDL_memcpy(Vdst, Vplane, length);
Vplane += Vpitch;
Vdst += uv_pitch;
}
}
}
return 0;
}
static int
VITA_GXM_UpdateTextureNV(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect,
const Uint8 *Yplane, int Ypitch,
const Uint8 *UVplane, int UVpitch)
{
Uint8 *dst;
int row, length, dpitch;
SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2};
VITA_GXM_SetYUVProfile(renderer, texture);
// copy Y plane
VITA_GXM_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch);
length = rect->w * SDL_BYTESPERPIXEL(texture->format);
if (length == Ypitch && length == dpitch) {
SDL_memcpy(dst, Yplane, length*rect->h);
} else {
for (row = 0; row < rect->h; ++row) {
SDL_memcpy(dst, Yplane, length);
Yplane += Ypitch;
dst += dpitch;
}
}
// UV plane
{
void *UVdst;
VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) texture->driverdata;
int uv_pitch = 2 * ((dpitch+1) / 2);
// skip Y plane
void *pixels = (void *) ((Uint8 *) gxm_texture_get_datap(vita_texture->tex) + (vita_texture->pitch * vita_texture->h));
UVdst = pixels + (UVrect.y * uv_pitch) + UVrect.x;
length = UVrect.w * 2;
// UV plane
if (length == UVpitch && length == uv_pitch) {
SDL_memcpy(UVdst, UVplane, length*UVrect.h);
} else {
for (row = 0; row < UVrect.h; ++row) {
SDL_memcpy(UVdst, UVplane, length);
UVplane += UVpitch;
UVdst += uv_pitch;
}
}
}
return 0;
}
#endif
static int
VITA_GXM_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
const SDL_Rect *rect, void **pixels, int *pitch)
@ -519,6 +763,7 @@ VITA_GXM_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Textu
size_indices = indices ? size_indices : 0;
if (texture) {
VITA_GXM_TextureData* vita_texture = (VITA_GXM_TextureData*) texture->driverdata;
texture_vertex *vertices;
vertices = (texture_vertex *)pool_malloc(
@ -551,7 +796,7 @@ VITA_GXM_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Textu
vertices[i].x = xy_[0] * scale_x;
vertices[i].y = xy_[1] * scale_y;
vertices[i].u = uv_[0];
vertices[i].u = uv_[0] * vita_texture->wscale;
vertices[i].v = uv_[1];
vertices[i].color = col_;
}
@ -730,14 +975,6 @@ SetDrawState(VITA_GXM_RenderData *data, const SDL_RenderCommand *cmd)
return 0;
}
static int
SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd)
{
VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata;
return SetDrawState(data, cmd);
}
static int
VITA_GXM_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
{
@ -824,11 +1061,7 @@ VITA_GXM_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *
nextcmd = nextcmd->next;
}
if (thistexture) {
ret = SetCopyState(renderer, cmd);
} else {
ret = SetDrawState(data, cmd);
}
ret = SetDrawState(data, cmd);
if (ret == 0) {
int op = SCE_GXM_PRIMITIVE_TRIANGLES;
@ -1013,7 +1246,7 @@ VITA_GXM_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
sceGxmFinish(data->gxm_context);
free_gxm_texture(vita_texture->tex);
free_gxm_texture(data, vita_texture->tex);
SDL_free(vita_texture);

View file

@ -26,7 +26,7 @@
#include "SDL_render_vita_gxm_memory.h"
void *
mem_gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid)
vita_mem_alloc(unsigned int type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid)
{
void *mem;
@ -51,7 +51,7 @@ mem_gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignm
}
void
mem_gpu_free(SceUID uid)
vita_mem_free(SceUID uid)
{
void *mem = NULL;
if (sceKernelGetMemBlockBase(uid, &mem) < 0)
@ -61,7 +61,71 @@ mem_gpu_free(SceUID uid)
}
void *
mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset)
vita_gpu_mem_alloc(VITA_GXM_RenderData *data, unsigned int size)
{
void *mem;
if (data->texturePool == NULL) {
int poolsize;
int ret;
SceKernelFreeMemorySizeInfo info;
info.size = sizeof(SceKernelFreeMemorySizeInfo);
sceKernelGetFreeMemorySize(&info);
poolsize = ALIGN(info.size_cdram, 256*1024);
if (poolsize > info.size_cdram) {
poolsize = ALIGN(info.size_cdram - 256*1024, 256*1024);
}
data->texturePoolUID = sceKernelAllocMemBlock("gpu_texture_pool", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, poolsize, NULL);
if (data->texturePoolUID < 0) {
return NULL;
}
ret = sceKernelGetMemBlockBase(data->texturePoolUID, &mem);
if ( ret < 0)
{
return NULL;
}
data->texturePool = sceClibMspaceCreate(mem, poolsize);
if (data->texturePool == NULL) {
return NULL;
}
ret = sceGxmMapMemory(mem, poolsize, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE);
if (ret < 0)
{
return NULL;
}
}
return sceClibMspaceMemalign(data->texturePool, SCE_GXM_TEXTURE_ALIGNMENT, size);
}
void
vita_gpu_mem_free(VITA_GXM_RenderData *data, void* ptr)
{
if (data->texturePool != NULL)
{
sceClibMspaceFree(data->texturePool, ptr);
}
}
void
vita_gpu_mem_destroy(VITA_GXM_RenderData *data)
{
void *mem = NULL;
if (data->texturePool != NULL)
{
sceClibMspaceDestroy(data->texturePool);
data->texturePool = NULL;
if (sceKernelGetMemBlockBase(data->texturePoolUID, &mem) < 0)
return;
sceGxmUnmapMemory(mem);
sceKernelFreeMemBlock(data->texturePoolUID);
}
}
void *
vita_mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset)
{
void *mem = NULL;
@ -77,7 +141,7 @@ mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset)
}
void
mem_vertex_usse_free(SceUID uid)
vita_mem_vertex_usse_free(SceUID uid)
{
void *mem = NULL;
if (sceKernelGetMemBlockBase(uid, &mem) < 0)
@ -87,7 +151,7 @@ mem_vertex_usse_free(SceUID uid)
}
void *
mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset)
vita_mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset)
{
void *mem = NULL;
@ -103,7 +167,7 @@ mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offse
}
void
mem_fragment_usse_free(SceUID uid)
vita_mem_fragment_usse_free(SceUID uid)
{
void *mem = NULL;
if (sceKernelGetMemBlockBase(uid, &mem) < 0)

View file

@ -25,15 +25,19 @@
#include <psp2/gxm.h>
#include <psp2/types.h>
#include <psp2/kernel/sysmem.h>
#include "SDL_render_vita_gxm_types.h"
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
void *mem_gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid);
void mem_gpu_free(SceUID uid);
void *mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset);
void mem_vertex_usse_free(SceUID uid);
void *mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset);
void mem_fragment_usse_free(SceUID uid);
void *vita_mem_alloc(unsigned int type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid);
void vita_mem_free(SceUID uid);
void *vita_gpu_mem_alloc(VITA_GXM_RenderData *data, unsigned int size);
void vita_gpu_mem_free(VITA_GXM_RenderData *data, void* ptr);
void vita_gpu_mem_destroy(VITA_GXM_RenderData *data);
void *vita_mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset);
void vita_mem_vertex_usse_free(SceUID uid);
void *vita_mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset);
void vita_mem_fragment_usse_free(SceUID uid);
#endif /* SDL_RENDER_VITA_GXM_MEMORY_H */

View file

@ -117,6 +117,8 @@ tex_format_to_bytespp(SceGxmTextureFormat format)
case SCE_GXM_TEXTURE_BASE_FORMAT_U8:
case SCE_GXM_TEXTURE_BASE_FORMAT_S8:
case SCE_GXM_TEXTURE_BASE_FORMAT_P8:
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2: // YUV actually uses 12 bits per pixel. UV planes bits/mem are handled elsewhere
case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3:
return 1;
case SCE_GXM_TEXTURE_BASE_FORMAT_U4U4U4U4:
case SCE_GXM_TEXTURE_BASE_FORMAT_U8U3U3U2:
@ -414,28 +416,28 @@ gxm_init(SDL_Renderer *renderer)
}
// allocate ring buffer memory using default sizes
vdmRingBuffer = mem_gpu_alloc(
vdmRingBuffer = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE,
4,
SCE_GXM_MEMORY_ATTRIB_READ,
&data->vdmRingBufferUid);
vertexRingBuffer = mem_gpu_alloc(
vertexRingBuffer = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE,
4,
SCE_GXM_MEMORY_ATTRIB_READ,
&data->vertexRingBufferUid);
fragmentRingBuffer = mem_gpu_alloc(
fragmentRingBuffer = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE,
4,
SCE_GXM_MEMORY_ATTRIB_READ,
&data->fragmentRingBufferUid);
fragmentUsseRingBuffer = mem_fragment_usse_alloc(
fragmentUsseRingBuffer = vita_mem_fragment_usse_alloc(
SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE,
&data->fragmentUsseRingBufferUid,
&fragmentUsseRingBufferOffset);
@ -480,7 +482,7 @@ gxm_init(SDL_Renderer *renderer)
for (i = 0; i < VITA_GXM_BUFFERS; i++) {
// allocate memory for display
data->displayBufferData[i] = mem_gpu_alloc(
data->displayBufferData[i] = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT,
SCE_GXM_COLOR_SURFACE_ALIGNMENT,
@ -525,7 +527,7 @@ gxm_init(SDL_Renderer *renderer)
// allocate the depth buffer
data->depthBufferData = mem_gpu_alloc(
data->depthBufferData = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
4 * sampleCount,
SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT,
@ -533,7 +535,7 @@ gxm_init(SDL_Renderer *renderer)
&data->depthBufferUid);
// allocate the stencil buffer
data->stencilBufferData = mem_gpu_alloc(
data->stencilBufferData = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
4 * sampleCount,
SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT,
@ -565,19 +567,19 @@ gxm_init(SDL_Renderer *renderer)
// allocate memory for buffers and USSE code
patcherBuffer = mem_gpu_alloc(
patcherBuffer = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
patcherBufferSize,
4,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&data->patcherBufferUid);
patcherVertexUsse = mem_vertex_usse_alloc(
patcherVertexUsse = vita_mem_vertex_usse_alloc(
patcherVertexUsseSize,
&data->patcherVertexUsseUid,
&patcherVertexUsseOffset);
patcherFragmentUsse = mem_fragment_usse_alloc(
patcherFragmentUsse = vita_mem_fragment_usse_alloc(
patcherFragmentUsseSize,
&data->patcherFragmentUsseUid,
&patcherFragmentUsseOffset);
@ -728,7 +730,7 @@ gxm_init(SDL_Renderer *renderer)
}
// create the clear triangle vertex/index data
data->clearVertices = (clear_vertex *)mem_gpu_alloc(
data->clearVertices = (clear_vertex *)vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
3*sizeof(clear_vertex),
4,
@ -740,7 +742,7 @@ gxm_init(SDL_Renderer *renderer)
// Allocate a 64k * 2 bytes = 128 KiB buffer and store all possible
// 16-bit indices in linear ascending order, so we can use this for
// all drawing operations where we don't want to use indexing.
data->linearIndices = (uint16_t *)mem_gpu_alloc(
data->linearIndices = (uint16_t *)vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
UINT16_MAX*sizeof(uint16_t),
sizeof(uint16_t),
@ -871,7 +873,7 @@ gxm_init(SDL_Renderer *renderer)
data->textureWvpParam = (SceGxmProgramParameter *)sceGxmProgramFindParameterByName(textureVertexProgramGxp, "wvp");
// Allocate memory for the memory pool
data->pool_addr[0] = mem_gpu_alloc(
data->pool_addr[0] = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW,
VITA_GXM_POOL_SIZE,
sizeof(void *),
@ -879,7 +881,7 @@ gxm_init(SDL_Renderer *renderer)
&data->poolUid[0]
);
data->pool_addr[1] = mem_gpu_alloc(
data->pool_addr[1] = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW,
VITA_GXM_POOL_SIZE,
sizeof(void *),
@ -918,28 +920,28 @@ void gxm_finish(SDL_Renderer *renderer)
free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mod);
free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mul);
mem_gpu_free(data->linearIndicesUid);
mem_gpu_free(data->clearVerticesUid);
vita_mem_free(data->linearIndicesUid);
vita_mem_free(data->clearVerticesUid);
// wait until display queue is finished before deallocating display buffers
sceGxmDisplayQueueFinish();
// clean up display queue
mem_gpu_free(data->depthBufferUid);
vita_mem_free(data->depthBufferUid);
for (size_t i = 0; i < VITA_GXM_BUFFERS; i++)
{
// clear the buffer then deallocate
SDL_memset(data->displayBufferData[i], 0, VITA_GXM_SCREEN_HEIGHT * VITA_GXM_SCREEN_STRIDE * 4);
mem_gpu_free(data->displayBufferUid[i]);
vita_mem_free(data->displayBufferUid[i]);
// destroy the sync object
sceGxmSyncObjectDestroy(data->displayBufferSync[i]);
}
// Free the depth and stencil buffer
mem_gpu_free(data->depthBufferUid);
mem_gpu_free(data->stencilBufferUid);
vita_mem_free(data->depthBufferUid);
vita_mem_free(data->stencilBufferUid);
// unregister programs and destroy shader patcher
sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->clearFragmentProgramId);
@ -950,23 +952,24 @@ void gxm_finish(SDL_Renderer *renderer)
sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->textureVertexProgramId);
sceGxmShaderPatcherDestroy(data->shaderPatcher);
mem_fragment_usse_free(data->patcherFragmentUsseUid);
mem_vertex_usse_free(data->patcherVertexUsseUid);
mem_gpu_free(data->patcherBufferUid);
vita_mem_fragment_usse_free(data->patcherFragmentUsseUid);
vita_mem_vertex_usse_free(data->patcherVertexUsseUid);
vita_mem_free(data->patcherBufferUid);
// destroy the render target
sceGxmDestroyRenderTarget(data->renderTarget);
// destroy the gxm context
sceGxmDestroyContext(data->gxm_context);
mem_fragment_usse_free(data->fragmentUsseRingBufferUid);
mem_gpu_free(data->fragmentRingBufferUid);
mem_gpu_free(data->vertexRingBufferUid);
mem_gpu_free(data->vdmRingBufferUid);
vita_mem_fragment_usse_free(data->fragmentUsseRingBufferUid);
vita_mem_free(data->fragmentRingBufferUid);
vita_mem_free(data->vertexRingBufferUid);
vita_mem_free(data->vdmRingBufferUid);
SDL_free(data->contextParams.hostMem);
mem_gpu_free(data->poolUid[0]);
mem_gpu_free(data->poolUid[1]);
vita_mem_free(data->poolUid[0]);
vita_mem_free(data->poolUid[1]);
vita_gpu_mem_destroy(data);
// terminate libgxm
sceGxmTerminate();
@ -975,16 +978,20 @@ void gxm_finish(SDL_Renderer *renderer)
// textures
void
free_gxm_texture(gxm_texture *texture)
free_gxm_texture(VITA_GXM_RenderData *data, gxm_texture *texture)
{
if (texture) {
if (texture->gxm_rendertarget) {
sceGxmDestroyRenderTarget(texture->gxm_rendertarget);
}
if (texture->depth_UID) {
mem_gpu_free(texture->depth_UID);
vita_mem_free(texture->depth_UID);
}
if (texture->cdram) {
vita_gpu_mem_free(data, sceGxmTextureGetData(&texture->gxm_tex));
} else {
vita_mem_free(texture->data_UID);
}
mem_gpu_free(texture->data_UID);
SDL_free(texture);
}
}
@ -995,25 +1002,6 @@ gxm_texture_get_format(const gxm_texture *texture)
return sceGxmTextureGetFormat(&texture->gxm_tex);
}
unsigned int
gxm_texture_get_width(const gxm_texture *texture)
{
return sceGxmTextureGetWidth(&texture->gxm_tex);
}
unsigned int
gxm_texture_get_height(const gxm_texture *texture)
{
return sceGxmTextureGetHeight(&texture->gxm_tex);
}
unsigned int
gxm_texture_get_stride(const gxm_texture *texture)
{
return ((gxm_texture_get_width(texture) + 7) & ~7)
* tex_format_to_bytespp(gxm_texture_get_format(texture));
}
void *
gxm_texture_get_datap(const gxm_texture *texture)
{
@ -1021,34 +1009,53 @@ gxm_texture_get_datap(const gxm_texture *texture)
}
gxm_texture *
create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget)
create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget, unsigned int *return_w, unsigned int *return_h, unsigned int *return_pitch, float *return_wscale)
{
gxm_texture *texture = SDL_calloc(1, sizeof(gxm_texture));
const int tex_size = ((w + 7) & ~ 7) * h * tex_format_to_bytespp(format);
int aligned_w = ALIGN(w, 8);
int texture_w = w;
int tex_size = aligned_w * h * tex_format_to_bytespp(format);
void *texture_data;
int ret;
*return_wscale = 1.0f;
// SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3/P2 based formats require width aligned to 16
if ( (format & 0x9f000000U) == SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3 || (format & 0x9f000000U) == SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2) {
aligned_w = ALIGN(w, 16);
texture_w = aligned_w;
tex_size = aligned_w * h * tex_format_to_bytespp(format);
*return_wscale = (float) (w) / texture_w;
// add storage for UV planes
tex_size += (((aligned_w + 1) / 2) * ((h + 1) / 2)) * 2;
}
if (!texture)
return NULL;
*return_w = w;
*return_h = h;
*return_pitch = aligned_w * tex_format_to_bytespp(format);
/* Allocate a GPU buffer for the texture */
texture_data = mem_gpu_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
tex_size,
SCE_GXM_TEXTURE_ALIGNMENT,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&texture->data_UID
texture_data = vita_gpu_mem_alloc(
data,
tex_size
);
/* Try SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE in case we're out of VRAM */
if (!texture_data) {
SDL_LogWarn(SDL_LOG_CATEGORY_RENDER, "CDRAM texture allocation failed\n");
texture_data = mem_gpu_alloc(
texture_data = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
tex_size,
SCE_GXM_TEXTURE_ALIGNMENT,
SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE,
&texture->data_UID
);
texture->cdram = 0;
} else {
texture->cdram = 1;
}
if (!texture_data) {
@ -1060,7 +1067,12 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc
SDL_memset(texture_data, 0, tex_size);
/* Create the gxm texture */
sceGxmTextureInitLinear( &texture->gxm_tex, texture_data, format, w, h, 0);
ret = sceGxmTextureInitLinear( &texture->gxm_tex, texture_data, format, texture_w, h, 0);
if (ret < 0) {
free_gxm_texture(data, texture);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "texture init failed: %x\n", ret);
return NULL;
}
if (isRenderTarget) {
void *depthBufferData;
@ -1083,13 +1095,13 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc
);
if (err < 0) {
free_gxm_texture(texture);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %d\n", err);
free_gxm_texture(data, texture);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %x\n", err);
return NULL;
}
// allocate it
depthBufferData = mem_gpu_alloc(
depthBufferData = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE,
4*sampleCount,
SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT,
@ -1106,8 +1118,8 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc
NULL);
if (err < 0) {
free_gxm_texture(texture);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "depth stencil init failed: %d\n", err);
free_gxm_texture(data, texture);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "depth stencil init failed: %x\n", err);
return NULL;
}
@ -1131,8 +1143,8 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc
texture->gxm_rendertarget = tgt;
if (err < 0) {
free_gxm_texture(texture);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create render target failed: %d\n", err);
free_gxm_texture(data, texture);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create render target failed: %x\n", err);
return NULL;
}
}
@ -1181,7 +1193,7 @@ void gxm_init_for_common_dialog(void)
for (int i = 0; i < VITA_GXM_BUFFERS; i += 1)
{
buffer_for_common_dialog[i].displayData.wait_vblank = SDL_TRUE;
buffer_for_common_dialog[i].displayData.address = mem_gpu_alloc(
buffer_for_common_dialog[i].displayData.address = vita_mem_alloc(
SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT,
SCE_GXM_COLOR_SURFACE_ALIGNMENT,
@ -1229,7 +1241,7 @@ void gxm_term_for_common_dialog(void)
sceGxmDisplayQueueFinish();
for (int i = 0; i < VITA_GXM_BUFFERS; i += 1)
{
mem_gpu_free(buffer_for_common_dialog[i].uid);
vita_mem_free(buffer_for_common_dialog[i].uid);
sceGxmSyncObjectDestroy(buffer_for_common_dialog[i].sync);
}
}

View file

@ -48,15 +48,12 @@ void unset_clip_rectangle(VITA_GXM_RenderData *data);
int gxm_init(SDL_Renderer *renderer);
void gxm_finish(SDL_Renderer *renderer);
gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget);
void free_gxm_texture(gxm_texture *texture);
gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget, unsigned int *return_w, unsigned int *return_h, unsigned int *return_pitch, float *return_wscale);
void free_gxm_texture(VITA_GXM_RenderData *data, gxm_texture *texture);
void gxm_texture_set_filters(gxm_texture *texture, SceGxmTextureFilter min_filter, SceGxmTextureFilter mag_filter);
SceGxmTextureFormat gxm_texture_get_format(const gxm_texture *texture);
unsigned int gxm_texture_get_width(const gxm_texture *texture);
unsigned int gxm_texture_get_height(const gxm_texture *texture);
unsigned int gxm_texture_get_stride(const gxm_texture *texture);
void *gxm_texture_get_datap(const gxm_texture *texture);
void gxm_minimal_init_for_common_dialog(void);

View file

@ -33,6 +33,7 @@
#include <psp2/gxm.h>
#include <psp2/types.h>
#include <psp2/kernel/sysmem.h>
#include <psp2/kernel/clib.h>
#include <string.h>
@ -79,6 +80,7 @@ typedef struct gxm_texture {
SceGxmColorSurface gxm_colorsurface;
SceGxmDepthStencilSurface gxm_depthstencil;
SceUID depth_UID;
SDL_bool cdram;
} gxm_texture;
typedef struct fragment_programs {
@ -186,14 +188,19 @@ typedef struct
blend_fragment_programs blendFragmentPrograms;
gxm_drawstate_cache drawstate;
SceClibMspace texturePool;
SceUID texturePoolUID;
} VITA_GXM_RenderData;
typedef struct
{
gxm_texture *tex;
unsigned int pitch;
unsigned int w;
unsigned int h;
unsigned int pitch;
unsigned int w;
unsigned int h;
float wscale;
SDL_bool yuv;
SDL_bool nv12;
} VITA_GXM_TextureData;
#endif /* SDL_RENDER_VITA_GXM_TYPES_H */

View file

@ -1464,10 +1464,12 @@ default: return "???";
static void
SDLTest_PrintEvent(SDL_Event * event)
{
#ifndef VERBOSE_MOTION_EVENTS
if ((event->type == SDL_MOUSEMOTION) || (event->type == SDL_FINGERMOTION)) {
/* Mouse and finger motion are really spammy */
return;
}
#endif
switch (event->type) {
case SDL_DISPLAYEVENT:

View file

@ -56,12 +56,12 @@ SDL_CreateMutex(void)
void
SDL_DestroyMutex(SDL_mutex * mutex)
{
ULONG ulRC;
HMTX hMtx = (HMTX)mutex;
ulRC = DosCloseMutexSem(hMtx);
if (ulRC != NO_ERROR) {
debug_os2("DosCloseMutexSem(), rc = %u", ulRC);
if (hMtx != NULLHANDLE) {
const ULONG ulRC = DosCloseMutexSem(hMtx);
if (ulRC != NO_ERROR) {
debug_os2("DosCloseMutexSem(), rc = %u", ulRC);
}
}
}

View file

@ -39,6 +39,7 @@
typedef unsigned long long ULLONG;
static SDL_bool ticks_started = SDL_FALSE;
static ULONG ulTmrFreq = 0;
static ULLONG ullTmrStart = 0;
@ -46,7 +47,14 @@ void
SDL_TicksInit(void)
{
ULONG ulTmrStart; /* for 32-bit fallback. */
ULONG ulRC = DosTmrQueryFreq(&ulTmrFreq);
ULONG ulRC;
if (ticks_started) {
return;
}
ticks_started = SDL_TRUE;
ulRC = DosTmrQueryFreq(&ulTmrFreq);
if (ulRC != NO_ERROR) {
debug_os2("DosTmrQueryFreq() failed, rc = %u", ulRC);
} else {
@ -65,6 +73,7 @@ SDL_TicksInit(void)
void
SDL_TicksQuit(void)
{
ticks_started = SDL_FALSE;
}
Uint64
@ -73,7 +82,7 @@ SDL_GetTicks64(void)
Uint64 ui64Result;
ULLONG ullTmrNow;
if (ulTmrFreq == 0) { /* Was not initialized. */
if (!ticks_started) {
SDL_TicksInit();
}

View file

@ -412,6 +412,12 @@ SDL_LoadBMP_RW(SDL_RWops * src, int freesrc)
goto done;
}
if (biBitCount >= 32) { /* we shift biClrUsed by this value later. */
SDL_SetError("Unsupported or incorrect biBitCount field");
was_error = SDL_TRUE;
goto done;
}
if (biClrUsed == 0) {
biClrUsed = 1 << biBitCount;
}

View file

@ -27,7 +27,6 @@
#endif
#if SDL_VIDEO_DRIVER_ANDROID
#include <android/native_window.h>
#include "../core/android/SDL_android.h"
#include "../video/android/SDL_androidvideo.h"
#endif
#if SDL_VIDEO_DRIVER_RPI
@ -99,7 +98,7 @@
#define DEFAULT_OGL_ES "libGLESv1_CM.so.1"
#endif /* SDL_VIDEO_DRIVER_RPI */
#if SDL_VIDEO_OPENGL
#if SDL_VIDEO_OPENGL && !SDL_VIDEO_VITA_PVR_OGL
#include "SDL_opengl.h"
#endif
@ -530,7 +529,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
}
#endif
/* Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails */
if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
if ((_this->egl_data->egl_display == EGL_NO_DISPLAY) && (_this->egl_data->eglGetDisplay != NULL)) {
_this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
}
if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
@ -1062,7 +1061,7 @@ SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
if (SDL_GL_ExtensionSupported("GL_OES_surfaceless_context")) {
_this->gl_allow_no_surface = SDL_TRUE;
}
#if SDL_VIDEO_OPENGL
#if SDL_VIDEO_OPENGL && !defined(SDL_VIDEO_DRIVER_VITA)
} else {
/* Desktop OpenGL supports it by default from version 3.0 on. */
void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);

View file

@ -28,6 +28,7 @@
#include "SDL_blit.h"
#include "SDL_pixels_c.h"
#include "SDL_RLEaccel_c.h"
#include "../SDL_list.h"
/* Lookup tables to expand partial bytes to the full 0..255 range */
@ -1024,12 +1025,6 @@ SDL_AllocBlitMap(void)
}
typedef struct SDL_ListNode
{
void *entry;
struct SDL_ListNode *next;
} SDL_ListNode;
void
SDL_InvalidateAllBlitMap(SDL_Surface *surface)
{
@ -1045,40 +1040,6 @@ SDL_InvalidateAllBlitMap(SDL_Surface *surface)
}
}
static void SDL_ListAdd(SDL_ListNode **head, void *ent);
static void SDL_ListRemove(SDL_ListNode **head, void *ent);
void
SDL_ListAdd(SDL_ListNode **head, void *ent)
{
SDL_ListNode *node = SDL_malloc(sizeof (*node));
if (node == NULL) {
SDL_OutOfMemory();
return;
}
node->entry = ent;
node->next = *head;
*head = node;
}
void
SDL_ListRemove(SDL_ListNode **head, void *ent)
{
SDL_ListNode **ptr = head;
while (*ptr) {
if ((*ptr)->entry == ent) {
SDL_ListNode *tmp = *ptr;
*ptr = (*ptr)->next;
SDL_free(tmp);
return;
}
ptr = &(*ptr)->next;
}
}
void
SDL_InvalidateMap(SDL_BlitMap * map)
{

View file

@ -345,6 +345,7 @@ struct SDL_VideoDevice
Uint32 next_object_id;
char *clipboard_text;
SDL_bool setting_display_mode;
SDL_bool disable_display_mode_switching;
/* * * */
/* Data used by the GL drivers */

View file

@ -61,12 +61,12 @@ static VideoBootStrap *bootstrap[] = {
#if SDL_VIDEO_DRIVER_COCOA
&COCOA_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_WAYLAND
&Wayland_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_X11
&X11_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_WAYLAND
&Wayland_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_VIVANTE
&VIVANTE_bootstrap,
#endif
@ -261,6 +261,7 @@ SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window * window, Uint32 * fo
SDL_TEXTUREACCESS_STREAMING,
window->w, window->h);
if (!data->texture) {
/* codechecker_false_positive [Malloc] Static analyzer doesn't realize allocated `data` is saved to SDL_WINDOWTEXTUREDATA and not leaked here. */
return -1;
}
@ -424,7 +425,7 @@ SDL_VideoInit(const char *driver_name)
i = index = 0;
video = NULL;
if (driver_name == NULL) {
driver_name = SDL_getenv("SDL_VIDEODRIVER");
driver_name = SDL_GetHint(SDL_HINT_VIDEODRIVER);
}
if (driver_name != NULL && *driver_name != 0) {
const char *driver_attempt = driver_name;
@ -1184,6 +1185,7 @@ SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
} else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
&fullscreen_mode,
&fullscreen_mode)) {
SDL_zerop(mode);
return SDL_SetError("Couldn't find display mode match");
}
@ -1337,14 +1339,17 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
resized = SDL_FALSE;
}
/* only do the mode change if we want exclusive fullscreen */
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
return -1;
}
} else {
if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
return -1;
/* Don't try to change the display mode if the driver doesn't want it. */
if (_this->disable_display_mode_switching == SDL_FALSE) {
/* only do the mode change if we want exclusive fullscreen */
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
return -1;
}
} else {
if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
return -1;
}
}
}
@ -3055,7 +3060,8 @@ ShouldMinimizeOnFocusLoss(SDL_Window * window)
/* Real fullscreen windows should minimize on focus loss so the desktop video mode is restored */
hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
if (!hint || !*hint || SDL_strcasecmp(hint, "auto") == 0) {
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP ||
_this->disable_display_mode_switching == SDL_TRUE) {
return SDL_FALSE;
} else {
return SDL_TRUE;
@ -3919,6 +3925,10 @@ SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
{
int retval;
if (!_this) {
return SDL_UninitializedVideo();
}
if (window == SDL_GL_GetCurrentWindow() &&
ctx == SDL_GL_GetCurrentContext()) {
/* We're already current. */
@ -4262,12 +4272,12 @@ SDL_IsScreenKeyboardShown(SDL_Window *window)
#if SDL_VIDEO_DRIVER_UIKIT
#include "uikit/SDL_uikitmessagebox.h"
#endif
#if SDL_VIDEO_DRIVER_WAYLAND
#include "wayland/SDL_waylandmessagebox.h"
#endif
#if SDL_VIDEO_DRIVER_X11
#include "x11/SDL_x11messagebox.h"
#endif
#if SDL_VIDEO_DRIVER_WAYLAND
#include "wayland/SDL_waylandmessagebox.h"
#endif
#if SDL_VIDEO_DRIVER_HAIKU
#include "haiku/SDL_bmessagebox.h"
#endif
@ -4375,13 +4385,6 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
retval = 0;
}
#endif
#if SDL_VIDEO_DRIVER_WAYLAND
if (retval == -1 &&
SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WAYLAND) &&
Wayland_ShowMessageBox(messageboxdata, buttonid) == 0) {
retval = 0;
}
#endif
#if SDL_VIDEO_DRIVER_X11
if (retval == -1 &&
SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) &&
@ -4389,6 +4392,13 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
retval = 0;
}
#endif
#if SDL_VIDEO_DRIVER_WAYLAND
if (retval == -1 &&
SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WAYLAND) &&
Wayland_ShowMessageBox(messageboxdata, buttonid) == 0) {
retval = 0;
}
#endif
#if SDL_VIDEO_DRIVER_HAIKU
if (retval == -1 &&
SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_HAIKU) &&

View file

@ -122,6 +122,7 @@ Android_CreateDevice(int devindex)
device->SetWindowTitle = Android_SetWindowTitle;
device->SetWindowFullscreen = Android_SetWindowFullscreen;
device->MinimizeWindow = Android_MinimizeWindow;
device->SetWindowResizable = Android_SetWindowResizable;
device->DestroyWindow = Android_DestroyWindow;
device->GetWindowWMInfo = Android_GetWindowWMInfo;

View file

@ -167,6 +167,12 @@ Android_MinimizeWindow(_THIS, SDL_Window *window)
Android_JNI_MinizeWindow();
}
void Android_SetWindowResizable(_THIS, SDL_Window *window, SDL_bool resizable)
{
/* Set orientation */
Android_JNI_SetOrientation(window->w, window->h, window->flags & SDL_WINDOW_RESIZABLE, SDL_GetHint(SDL_HINT_ORIENTATIONS));
}
void
Android_DestroyWindow(_THIS, SDL_Window *window)
{

View file

@ -30,6 +30,7 @@ extern int Android_CreateWindow(_THIS, SDL_Window *window);
extern void Android_SetWindowTitle(_THIS, SDL_Window *window);
extern void Android_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen);
extern void Android_MinimizeWindow(_THIS, SDL_Window *window);
extern void Android_SetWindowResizable(_THIS, SDL_Window *window, SDL_bool resizable);
extern void Android_DestroyWindow(_THIS, SDL_Window *window);
extern SDL_bool Android_GetWindowWMInfo(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info);

View file

@ -46,6 +46,7 @@
#include "SDL_nullvideo.h"
#include "SDL_nullevents_c.h"
#include "SDL_nullframebuffer_c.h"
#include "SDL_hints.h"
#define DUMMYVID_DRIVER_NAME "dummy"
@ -59,7 +60,7 @@ static void DUMMY_VideoQuit(_THIS);
static int
DUMMY_Available(void)
{
const char *envr = SDL_getenv("SDL_VIDEODRIVER");
const char *envr = SDL_GetHint(SDL_HINT_VIDEODRIVER);
if ((envr) && (SDL_strcmp(envr, DUMMYVID_DRIVER_NAME) == 0)) {
return (1);
}

View file

@ -26,6 +26,8 @@
#include "SDL_emscriptenframebuffer.h"
#include "SDL_hints.h"
#include <emscripten/threading.h>
int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
{
@ -57,18 +59,9 @@ int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * form
return 0;
}
int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects)
static void
Emscripten_UpdateWindowFramebufferWorker(SDL_Surface* surface)
{
SDL_Surface *surface;
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
surface = data->surface;
if (!surface) {
return SDL_SetError("Couldn't find framebuffer surface for window");
}
/* Send the data to the display */
EM_ASM_INT({
var w = $0;
var h = $1;
@ -156,6 +149,29 @@ int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rec
SDL2.ctx.putImageData(SDL2.image, 0, 0);
return 0;
}, surface->w, surface->h, surface->pixels);
}
int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects)
{
SDL_Surface *surface;
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
surface = data->surface;
if (!surface) {
return SDL_SetError("Couldn't find framebuffer surface for window");
}
/* Send the data to the display */
if (emscripten_is_main_runtime_thread()) {
Emscripten_UpdateWindowFramebufferWorker(surface);
} else {
emscripten_sync_run_in_main_runtime_thread(
EM_FUNC_SIG_VI,
Emscripten_UpdateWindowFramebufferWorker,
(uint32_t)surface
);
}
if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) {
/* give back control to browser for screen refresh */

View file

@ -24,6 +24,7 @@
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#include <emscripten/threading.h>
#include "SDL_emscriptenmouse.h"
#include "SDL_emscriptenvideo.h"
@ -62,19 +63,10 @@ Emscripten_CreateDefaultCursor()
return Emscripten_CreateCursorFromString("default", SDL_FALSE);
}
static SDL_Cursor*
Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y)
static const char*
Emscripten_GetCursorUrl(int w, int h, int hot_x, int hot_y, void* pixels)
{
const char *cursor_url = NULL;
SDL_Surface *conv_surf;
conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0);
if (!conv_surf) {
return NULL;
}
cursor_url = (const char *)EM_ASM_INT({
return (const char *)EM_ASM_INT({
var w = $0;
var h = $1;
var hot_x = $2;
@ -122,7 +114,40 @@ Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y)
stringToUTF8(url, urlBuf, url.length + 1);
return urlBuf;
}, surface->w, surface->h, hot_x, hot_y, conv_surf->pixels);
}, w, h, hot_x, hot_y, pixels);
}
static SDL_Cursor*
Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y)
{
const char *cursor_url = NULL;
SDL_Surface *conv_surf;
conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0);
if (!conv_surf) {
return NULL;
}
if (emscripten_is_main_runtime_thread()) {
cursor_url = Emscripten_GetCursorUrl(
surface->w,
surface->h,
hot_x,
hot_y,
conv_surf->pixels
);
} else {
cursor_url = (const char *)emscripten_sync_run_in_main_runtime_thread(
EM_FUNC_SIG_IIIIIII,
Emscripten_GetCursorUrl,
surface->w,
surface->h,
hot_x,
hot_y,
conv_surf->pixels
);
}
SDL_FreeSurface(conv_surf);
@ -206,16 +231,15 @@ Emscripten_ShowCursor(SDL_Cursor* cursor)
curdata = (Emscripten_CursorData *) cursor->driverdata;
if(curdata->system_cursor) {
EM_ASM_INT({
MAIN_THREAD_EM_ASM({
if (Module['canvas']) {
Module['canvas'].style['cursor'] = UTF8ToString($0);
}
return 0;
}, curdata->system_cursor);
}
}
else {
EM_ASM(
MAIN_THREAD_EM_ASM(
if (Module['canvas']) {
Module['canvas'].style['cursor'] = 'none';
}

View file

@ -174,10 +174,10 @@ Emscripten_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect *
if (rect) {
rect->x = 0;
rect->y = 0;
rect->w = EM_ASM_INT_V({
rect->w = MAIN_THREAD_EM_ASM_INT({
return window.innerWidth;
});
rect->h = EM_ASM_INT_V({
rect->h = MAIN_THREAD_EM_ASM_INT({
return window.innerHeight;
});
}

View file

@ -186,8 +186,8 @@ UIKit_ShowMessageBoxAlertView(const SDL_MessageBoxData *messageboxdata, int *but
#endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 */
}
int
UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
static void
UIKit_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonid, int *returnValue)
{
BOOL success = NO;
@ -199,12 +199,26 @@ UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
}
if (!success) {
return SDL_SetError("Could not show message box.");
*returnValue = SDL_SetError("Could not show message box.");
} else {
*returnValue = 0;
}
return 0;
}
int
UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
{ @autoreleasepool
{
__block int returnValue = 0;
if ([NSThread isMainThread]) {
UIKit_ShowMessageBoxImpl(messageboxdata, buttonid, &returnValue);
} else {
dispatch_sync(dispatch_get_main_queue(), ^{ UIKit_ShowMessageBoxImpl(messageboxdata, buttonid, &returnValue); });
}
return returnValue;
}}
#endif /* SDL_VIDEO_DRIVER_UIKIT */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -31,7 +31,7 @@
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
#define DISPLAY_PIXEL_FORMAT SCE_DISPLAY_PIXELFORMAT_A8B8G8R8
void *vita_gpu_alloc(SceKernelMemBlockType type, unsigned int size, SceUID *uid)
void *vita_gpu_alloc(unsigned int type, unsigned int size, SceUID *uid)
{
void *mem;

View file

@ -20,11 +20,12 @@
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR
#if SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR && SDL_VIDEO_VITA_PVR_OGL
#include <stdlib.h>
#include <string.h>
#include <psp2/kernel/modulemgr.h>
#include <gpu_es4/psp2_pvr_hint.h>
#include <gl4esinit.h>
#include "SDL_error.h"
#include "SDL_log.h"
@ -34,6 +35,16 @@
#define MAX_PATH 256 // vita limits are somehow wrong
/* Defaults */
int FB_WIDTH = 960;
int FB_HEIGHT = 544;
void getFBSize(int *width, int *height)
{
*width = FB_WIDTH;
*height = FB_HEIGHT;
}
int
VITA_GL_LoadLibrary(_THIS, const char *path)
{
@ -53,6 +64,9 @@ VITA_GL_LoadLibrary(_THIS, const char *path)
sceKernelLoadStartModule("vs0:sys/external/libfios2.suprx", 0, NULL, 0, NULL, NULL);
sceKernelLoadStartModule("vs0:sys/external/libc.suprx", 0, NULL, 0, NULL, NULL);
SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libGL.suprx");
sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL);
SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libgpu_es4_ext.suprx");
sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL);
@ -74,30 +88,45 @@ VITA_GL_LoadLibrary(_THIS, const char *path)
SDL_GLContext
VITA_GL_CreateContext(_THIS, SDL_Window * window)
{
return SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
}
char gl_version[3];
SDL_GLContext context = NULL;
int temp_major = _this->gl_config.major_version;
int temp_minor = _this->gl_config.minor_version;
int temp_profile = _this->gl_config.profile_mask;
int
VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
{
if (window && context) {
return SDL_EGL_MakeCurrent(_this, ((SDL_WindowData *) window->driverdata)->egl_surface, context);
} else {
return SDL_EGL_MakeCurrent(_this, NULL, NULL);
/* Set version to 2.0 and PROFILE to ES */
_this->gl_config.major_version = 2;
_this->gl_config.minor_version = 0;
_this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
context = SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
if (context != NULL)
{
FB_WIDTH = window->w;
FB_HEIGHT = window->h;
set_getprocaddress((void *(*)(const char *))eglGetProcAddress);
set_getmainfbsize(getFBSize);
SDL_snprintf(gl_version, 3, "%d%d", temp_major, temp_minor);
gl4es_setenv("LIBGL_NOTEXRECT", "1", 1); /* Currently broken in driver */
gl4es_setenv("LIBGL_GL", gl_version, 1);
initialize_gl4es();
}
/* Restore gl_config */
_this->gl_config.major_version = temp_major;
_this->gl_config.minor_version = temp_minor;
_this->gl_config.profile_mask = temp_profile;
return context;
}
int
VITA_GL_SwapWindow(_THIS, SDL_Window * window)
void *
VITA_GL_GetProcAddress(_THIS, const char *proc)
{
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
if (videodata->ime_active) {
sceImeUpdate();
}
return SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
return gl4es_GetProcAddress(proc);
}
#endif /* SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -19,17 +19,16 @@
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_vitagl_c_h_
#define SDL_vitagl_c_h_
#ifndef SDL_vitagl_pvr_c_h_
#define SDL_vitagl_pvr_c_h_
#include "SDL_vitavideo.h"
extern int VITA_GL_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context);
extern int VITA_GL_SwapWindow(_THIS, SDL_Window * window);
extern SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window);
extern int VITA_GL_LoadLibrary(_THIS, const char *path);
extern void *VITA_GL_GetProcAddress(_THIS, const char *proc);
#endif /* SDL_vitagl_c_h_ */
#endif /* SDL_vitagl_pvr_c_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -27,7 +27,7 @@
#include "SDL_error.h"
#include "SDL_log.h"
#include "SDL_vitavideo.h"
#include "SDL_vitagl_c.h"
#include "SDL_vitagles_c.h"
/*****************************************************************************/
/* SDL OpenGL/OpenGL ES functions */
@ -45,7 +45,7 @@
} while (0)
void
VITA_GL_KeyboardCallback(ScePigletPreSwapData *data)
VITA_GLES_KeyboardCallback(ScePigletPreSwapData *data)
{
SceCommonDialogUpdateParam commonDialogParam;
SDL_zero(commonDialogParam);
@ -62,20 +62,20 @@ VITA_GL_KeyboardCallback(ScePigletPreSwapData *data)
}
int
VITA_GL_LoadLibrary(_THIS, const char *path)
VITA_GLES_LoadLibrary(_THIS, const char *path)
{
pibInit(PIB_SHACCCG | PIB_GET_PROC_ADDR_CORE);
return 0;
}
void *
VITA_GL_GetProcAddress(_THIS, const char *proc)
VITA_GLES_GetProcAddress(_THIS, const char *proc)
{
return eglGetProcAddress(proc);
}
void
VITA_GL_UnloadLibrary(_THIS)
VITA_GLES_UnloadLibrary(_THIS)
{
eglTerminate(_this->gl_data->display);
}
@ -84,7 +84,7 @@ static EGLint width = 960;
static EGLint height = 544;
SDL_GLContext
VITA_GL_CreateContext(_THIS, SDL_Window * window)
VITA_GLES_CreateContext(_THIS, SDL_Window * window)
{
SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
@ -159,13 +159,13 @@ VITA_GL_CreateContext(_THIS, SDL_Window * window)
_this->gl_data->surface = surface;
preSwapCallback = (PFNEGLPIGLETVITASETPRESWAPCALLBACKSCEPROC) eglGetProcAddress("eglPigletVitaSetPreSwapCallbackSCE");
preSwapCallback(VITA_GL_KeyboardCallback);
preSwapCallback(VITA_GLES_KeyboardCallback);
return context;
}
int
VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
VITA_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
{
if (!eglMakeCurrent(_this->gl_data->display, _this->gl_data->surface,
_this->gl_data->surface, _this->gl_data->context))
@ -176,7 +176,7 @@ VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
}
int
VITA_GL_SetSwapInterval(_THIS, int interval)
VITA_GLES_SetSwapInterval(_THIS, int interval)
{
EGLBoolean status;
status = eglSwapInterval(_this->gl_data->display, interval);
@ -190,13 +190,13 @@ VITA_GL_SetSwapInterval(_THIS, int interval)
}
int
VITA_GL_GetSwapInterval(_THIS)
VITA_GLES_GetSwapInterval(_THIS)
{
return _this->gl_data->swapinterval;
}
int
VITA_GL_SwapWindow(_THIS, SDL_Window * window)
VITA_GLES_SwapWindow(_THIS, SDL_Window * window)
{
if (!eglSwapBuffers(_this->gl_data->display, _this->gl_data->surface)) {
return SDL_SetError("eglSwapBuffers() failed");
@ -205,7 +205,7 @@ VITA_GL_SwapWindow(_THIS, SDL_Window * window)
}
void
VITA_GL_DeleteContext(_THIS, SDL_GLContext context)
VITA_GLES_DeleteContext(_THIS, SDL_GLContext context)
{
SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
EGLBoolean status;

View file

@ -19,8 +19,8 @@
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_vitagl_c_h_
#define SDL_vitagl_c_h_
#ifndef SDL_vitagles_c_h_
#define SDL_vitagles_c_h_
#include <pib.h>
@ -39,19 +39,19 @@ typedef struct SDL_GLDriverData {
uint32_t swapinterval;
}SDL_GLDriverData;
extern void * VITA_GL_GetProcAddress(_THIS, const char *proc);
extern int VITA_GL_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context);
extern void VITA_GL_SwapBuffers(_THIS);
extern void * VITA_GLES_GetProcAddress(_THIS, const char *proc);
extern int VITA_GLES_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context);
extern void VITA_GLES_SwapBuffers(_THIS);
extern int VITA_GL_SwapWindow(_THIS, SDL_Window * window);
extern SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window);
extern int VITA_GLES_SwapWindow(_THIS, SDL_Window * window);
extern SDL_GLContext VITA_GLES_CreateContext(_THIS, SDL_Window * window);
extern int VITA_GL_LoadLibrary(_THIS, const char *path);
extern void VITA_GL_UnloadLibrary(_THIS);
extern int VITA_GL_SetSwapInterval(_THIS, int interval);
extern int VITA_GL_GetSwapInterval(_THIS);
extern int VITA_GLES_LoadLibrary(_THIS, const char *path);
extern void VITA_GLES_UnloadLibrary(_THIS);
extern int VITA_GLES_SetSwapInterval(_THIS, int interval);
extern int VITA_GLES_GetSwapInterval(_THIS);
#endif /* SDL_vitagl_c_h_ */
#endif /* SDL_vitagles_c_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,103 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR
#include <stdlib.h>
#include <string.h>
#include <psp2/kernel/modulemgr.h>
#include <gpu_es4/psp2_pvr_hint.h>
#include "SDL_error.h"
#include "SDL_log.h"
#include "SDL_vitavideo.h"
#include "../SDL_egl_c.h"
#include "SDL_vitagles_pvr_c.h"
#define MAX_PATH 256 // vita limits are somehow wrong
int
VITA_GLES_LoadLibrary(_THIS, const char *path)
{
PVRSRV_PSP2_APPHINT hint;
char* override = SDL_getenv("VITA_MODULE_PATH");
char* skip_init = SDL_getenv("VITA_PVR_SKIP_INIT");
char* default_path = "app0:module";
char target_path[MAX_PATH];
if (skip_init == NULL) // we don't care about actual value
{
if (override != NULL)
{
default_path = override;
}
sceKernelLoadStartModule("vs0:sys/external/libfios2.suprx", 0, NULL, 0, NULL, NULL);
sceKernelLoadStartModule("vs0:sys/external/libc.suprx", 0, NULL, 0, NULL, NULL);
SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libgpu_es4_ext.suprx");
sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL);
SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libIMGEGL.suprx");
sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL);
PVRSRVInitializeAppHint(&hint);
SDL_snprintf(hint.szGLES1, MAX_PATH, "%s/%s", default_path, "libGLESv1_CM.suprx");
SDL_snprintf(hint.szGLES2, MAX_PATH, "%s/%s", default_path, "libGLESv2.suprx");
SDL_snprintf(hint.szWindowSystem, MAX_PATH, "%s/%s", default_path, "libpvrPSP2_WSEGL.suprx");
PVRSRVCreateVirtualAppHint(&hint);
}
return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) 0, 0);
}
SDL_GLContext
VITA_GLES_CreateContext(_THIS, SDL_Window * window)
{
return SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
}
int
VITA_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
{
if (window && context) {
return SDL_EGL_MakeCurrent(_this, ((SDL_WindowData *) window->driverdata)->egl_surface, context);
} else {
return SDL_EGL_MakeCurrent(_this, NULL, NULL);
}
}
int
VITA_GLES_SwapWindow(_THIS, SDL_Window * window)
{
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
if (videodata->ime_active) {
sceImeUpdate();
}
return SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
}
#endif /* SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,35 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_vitagles_pvr_c_h_
#define SDL_vitagles_pvr_c_h_
#include "SDL_vitavideo.h"
extern int VITA_GLES_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context);
extern int VITA_GLES_SwapWindow(_THIS, SDL_Window * window);
extern SDL_GLContext VITA_GLES_CreateContext(_THIS, SDL_Window * window);
extern int VITA_GLES_LoadLibrary(_THIS, const char *path);
#endif /* SDL_vitagles_pvr_c_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -41,15 +41,17 @@
#include "SDL_vitaframebuffer.h"
#if defined(SDL_VIDEO_VITA_PIB)
#include "SDL_vitagl_c.h"
#include "SDL_vitagles_c.h"
#elif defined(SDL_VIDEO_VITA_PVR)
#include "SDL_vitagles_pvr_c.h"
#if defined(SDL_VIDEO_VITA_PVR_OGL)
#include "SDL_vitagl_pvr_c.h"
#include "../SDL_egl_c.h"
#define VITA_GL_GetProcAddress SDL_EGL_GetProcAddress
#define VITA_GL_UnloadLibrary SDL_EGL_UnloadLibrary
#define VITA_GL_SetSwapInterval SDL_EGL_SetSwapInterval
#define VITA_GL_GetSwapInterval SDL_EGL_GetSwapInterval
#define VITA_GL_DeleteContext SDL_EGL_DeleteContext
#endif
#define VITA_GLES_GetProcAddress SDL_EGL_GetProcAddress
#define VITA_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
#define VITA_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
#define VITA_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
#define VITA_GLES_DeleteContext SDL_EGL_DeleteContext
#endif
SDL_Window *Vita_Window;
@ -140,15 +142,26 @@ VITA_Create()
*/
#if defined(SDL_VIDEO_VITA_PIB) || defined(SDL_VIDEO_VITA_PVR)
#if defined(SDL_VIDEO_VITA_PVR_OGL)
if(SDL_getenv("VITA_PVR_OGL") != NULL) {
device->GL_LoadLibrary = VITA_GL_LoadLibrary;
device->GL_GetProcAddress = VITA_GL_GetProcAddress;
device->GL_UnloadLibrary = VITA_GL_UnloadLibrary;
device->GL_CreateContext = VITA_GL_CreateContext;
device->GL_MakeCurrent = VITA_GL_MakeCurrent;
device->GL_SetSwapInterval = VITA_GL_SetSwapInterval;
device->GL_GetSwapInterval = VITA_GL_GetSwapInterval;
device->GL_SwapWindow = VITA_GL_SwapWindow;
device->GL_DeleteContext = VITA_GL_DeleteContext;
device->GL_GetProcAddress = VITA_GL_GetProcAddress;
} else {
#endif
device->GL_LoadLibrary = VITA_GLES_LoadLibrary;
device->GL_CreateContext = VITA_GLES_CreateContext;
device->GL_GetProcAddress = VITA_GLES_GetProcAddress;
#if defined(SDL_VIDEO_VITA_PVR_OGL)
}
#endif
device->GL_UnloadLibrary = VITA_GLES_UnloadLibrary;
device->GL_MakeCurrent = VITA_GLES_MakeCurrent;
device->GL_SetSwapInterval = VITA_GLES_SetSwapInterval;
device->GL_GetSwapInterval = VITA_GLES_GetSwapInterval;
device->GL_SwapWindow = VITA_GLES_SwapWindow;
device->GL_DeleteContext = VITA_GLES_DeleteContext;
#endif
device->HasScreenKeyboardSupport = VITA_HasScreenKeyboardSupport;
@ -245,6 +258,9 @@ VITA_CreateWindow(_THIS, SDL_Window * window)
SDL_WindowData *wdata;
#if defined(SDL_VIDEO_VITA_PVR)
Psp2NativeWindow win;
int temp_major = 2;
int temp_minor = 1;
int temp_profile = 0;
#endif
/* Allocate window internal data */
@ -282,11 +298,26 @@ VITA_CreateWindow(_THIS, SDL_Window * window)
win.windowSize = PSP2_WINDOW_960X544;
}
if ((window->flags & SDL_WINDOW_OPENGL) != 0) {
wdata->egl_surface = SDL_EGL_CreateSurface(_this, &win);
if(SDL_getenv("VITA_PVR_OGL") != NULL) {
/* Set version to 2.1 and PROFILE to ES */
temp_major = _this->gl_config.major_version;
temp_minor = _this->gl_config.minor_version;
temp_profile = _this->gl_config.profile_mask;
_this->gl_config.major_version = 2;
_this->gl_config.minor_version = 1;
_this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
}
wdata->egl_surface = SDL_EGL_CreateSurface(_this, &win);
if (wdata->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("Could not create GLES window surface");
}
if(SDL_getenv("VITA_PVR_OGL") != NULL) {
/* Revert */
_this->gl_config.major_version = temp_major;
_this->gl_config.minor_version = temp_minor;
_this->gl_config.profile_mask = temp_profile;
}
}
#endif

View file

@ -90,16 +90,23 @@ SDL_bool VITA_GetWindowWMInfo(_THIS, SDL_Window * window,
struct SDL_SysWMinfo *info);
#if SDL_VIDEO_DRIVER_VITA
#if defined(SDL_VIDEO_VITA_PVR_OGL)
/* OpenGL functions */
int VITA_GL_LoadLibrary(_THIS, const char *path);
void *VITA_GL_GetProcAddress(_THIS, const char *proc);
void VITA_GL_UnloadLibrary(_THIS);
SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window);
int VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
int VITA_GL_SetSwapInterval(_THIS, int interval);
int VITA_GL_GetSwapInterval(_THIS);
int VITA_GL_SwapWindow(_THIS, SDL_Window * window);
void VITA_GL_DeleteContext(_THIS, SDL_GLContext context);
void *VITA_GL_GetProcAddress(_THIS, const char *proc);
#endif
/* OpenGLES functions */
int VITA_GLES_LoadLibrary(_THIS, const char *path);
void *VITA_GLES_GetProcAddress(_THIS, const char *proc);
void VITA_GLES_UnloadLibrary(_THIS);
SDL_GLContext VITA_GLES_CreateContext(_THIS, SDL_Window * window);
int VITA_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
int VITA_GLES_SetSwapInterval(_THIS, int interval);
int VITA_GLES_GetSwapInterval(_THIS);
int VITA_GLES_SwapWindow(_THIS, SDL_Window * window);
void VITA_GLES_DeleteContext(_THIS, SDL_GLContext context);
#endif
/* VITA on screen keyboard */

View file

@ -52,6 +52,14 @@ enum libdecor_window_state;
#include "xkbcommon/xkbcommon.h"
#include "xkbcommon/xkbcommon-compose.h"
/* Must be included before our #defines, see Bugzilla #4957 */
#include "wayland-client-core.h"
#define SDL_WAYLAND_CHECK_VERSION(x, y, z) \
(WAYLAND_VERSION_MAJOR > x || \
(WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR > y) || \
(WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR == y && WAYLAND_VERSION_MICRO >= z))
#ifdef __cplusplus
extern "C"
{
@ -71,9 +79,6 @@ void SDL_WAYLAND_UnloadSymbols(void);
}
#endif
/* Must be included before our #defines, see Bugzilla #4957 */
#include "wayland-client-core.h"
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
#if defined(_WAYLAND_CLIENT_H) || defined(WAYLAND_CLIENT_H)

View file

@ -40,6 +40,7 @@
#include "xdg-shell-client-protocol.h"
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
#include "tablet-unstable-v2-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@ -83,6 +84,7 @@ static const struct {
{ XKB_KEY_Super_R, SDLK_RGUI },
{ XKB_KEY_Hyper_L, SDLK_LGUI },
{ XKB_KEY_Hyper_R, SDLK_RGUI },
{ XKB_KEY_BackSpace, SDLK_BACKSPACE },
};
struct SDL_WaylandTouchPoint {
@ -387,8 +389,10 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer,
input->sx_w = sx_w;
input->sy_w = sy_w;
if (input->pointer_focus) {
const int sx = wl_fixed_to_int(sx_w);
const int sy = wl_fixed_to_int(sy_w);
const float sx_f = (float)wl_fixed_to_double(sx_w);
const float sy_f = (float)wl_fixed_to_double(sy_w);
const int sx = (int)SDL_floorf(sx_f * window->pointer_scale_x);
const int sy = (int)SDL_floorf(sy_f * window->pointer_scale_y);
SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
}
}
@ -472,6 +476,9 @@ ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
const uint32_t *directions_libdecor = directions;
#endif
/* Hit tests shouldn't apply to xdg_popups, right? */
SDL_assert(!WINDOW_IS_XDG_POPUP(window));
switch (rc) {
case SDL_HITTEST_DRAGGABLE:
#ifdef HAVE_LIBDECOR_H
@ -715,8 +722,8 @@ touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial,
int id, wl_fixed_t fx, wl_fixed_t fy)
{
SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
const double dblx = wl_fixed_to_double(fx);
const double dbly = wl_fixed_to_double(fy);
const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x;
const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y;
const float x = dblx / window_data->sdlwindow->w;
const float y = dbly / window_data->sdlwindow->h;
@ -748,8 +755,8 @@ touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp,
int id, wl_fixed_t fx, wl_fixed_t fy)
{
SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id));
const double dblx = wl_fixed_to_double(fx);
const double dbly = wl_fixed_to_double(fy);
const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x;
const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y;
const float x = dblx / window_data->sdlwindow->w;
const float y = dbly / window_data->sdlwindow->h;
@ -815,6 +822,16 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
return;
}
#define GET_MOD_INDEX(mod) \
WAYLAND_xkb_keymap_mod_get_index(input->xkb.keymap, XKB_MOD_NAME_##mod)
input->xkb.idx_shift = 1 << GET_MOD_INDEX(SHIFT);
input->xkb.idx_ctrl = 1 << GET_MOD_INDEX(CTRL);
input->xkb.idx_alt = 1 << GET_MOD_INDEX(ALT);
input->xkb.idx_gui = 1 << GET_MOD_INDEX(LOGO);
input->xkb.idx_num = 1 << GET_MOD_INDEX(NUM);
input->xkb.idx_caps = 1 << GET_MOD_INDEX(CAPS);
#undef GET_MOD_INDEX
input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
if (!input->xkb.state) {
fprintf(stderr, "failed to create XKB state\n");
@ -829,10 +846,14 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
*/
/* Look up the preferred locale, falling back to "C" as default */
if (!(locale = SDL_getenv("LC_ALL")))
if (!(locale = SDL_getenv("LC_CTYPE")))
if (!(locale = SDL_getenv("LANG")))
if (!(locale = SDL_getenv("LC_ALL"))) {
if (!(locale = SDL_getenv("LC_CTYPE"))) {
if (!(locale = SDL_getenv("LANG"))) {
locale = "C";
}
}
}
/* Set up XKB compose table */
input->xkb.compose_table = WAYLAND_xkb_compose_table_new_from_locale(input->display->xkb_context,
locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
@ -903,7 +924,7 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
}
static SDL_bool
keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, SDL_bool *handled_by_ime)
keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, Uint8 state, SDL_bool *handled_by_ime)
{
SDL_WindowData *window = input->keyboard_focus;
const xkb_keysym_t *syms;
@ -920,12 +941,16 @@ keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint
sym = syms[0];
#ifdef SDL_USE_IME
if (SDL_IME_ProcessKeyEvent(sym, key + 8)) {
if (SDL_IME_ProcessKeyEvent(sym, key + 8, state)) {
*handled_by_ime = SDL_TRUE;
return SDL_TRUE;
}
#endif
if (state == SDL_RELEASED) {
return SDL_FALSE;
}
if (input->xkb.compose_state && WAYLAND_xkb_compose_state_feed(input->xkb.compose_state, sym) == XKB_COMPOSE_FEED_ACCEPTED) {
switch(WAYLAND_xkb_compose_state_get_status(input->xkb.compose_state)) {
case XKB_COMPOSE_COMPOSING:
@ -959,7 +984,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
SDL_bool handled_by_ime = SDL_FALSE;
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
has_text = keyboard_input_get_text(text, input, key, &handled_by_ime);
has_text = keyboard_input_get_text(text, input, key, SDL_PRESSED, &handled_by_ime);
} else {
if (keyboard_repeat_is_set(&input->keyboard_repeat)) {
// Send any due key repeat events before stopping the repeat and generating the key up event
@ -969,6 +994,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
keyboard_repeat_handle(&input->keyboard_repeat, time - input->keyboard_repeat.wl_press_time);
keyboard_repeat_clear(&input->keyboard_repeat);
}
keyboard_input_get_text(text, input, key, SDL_RELEASED, &handled_by_ime);
}
if (!handled_by_ime && key < SDL_arraysize(xfree86_scancode_table2)) {
@ -1054,10 +1080,24 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
{
struct SDL_WaylandInput *input = data;
Wayland_Keymap keymap;
uint32_t modstate = (mods_depressed | mods_latched | mods_locked);
WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
mods_locked, 0, 0, group);
SDL_ToggleModState(KMOD_SHIFT, modstate & input->xkb.idx_shift);
SDL_ToggleModState(KMOD_CTRL, modstate & input->xkb.idx_ctrl);
SDL_ToggleModState(KMOD_ALT, modstate & input->xkb.idx_alt);
SDL_ToggleModState(KMOD_GUI, modstate & input->xkb.idx_gui);
SDL_ToggleModState(KMOD_NUM, modstate & input->xkb.idx_num);
SDL_ToggleModState(KMOD_CAPS, modstate & input->xkb.idx_caps);
if (group == input->xkb.current_group) {
return;
}
/* The layout changed, remap and fire an event */
input->xkb.current_group = group;
keymap.layout = group;
SDL_GetDefaultKeymap(keymap.keymap);
WAYLAND_xkb_keymap_key_for_each(input->xkb.keymap,
@ -1646,6 +1686,363 @@ Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
}
}
static void
tablet_tool_handle_type(void* data, struct zwp_tablet_tool_v2* tool, uint32_t type)
{
/* unimplemented */
}
static void
tablet_tool_handle_hardware_serial(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial_hi, uint32_t serial_lo)
{
/* unimplemented */
}
static void
tablet_tool_handle_hardware_id_wacom(void* data, struct zwp_tablet_tool_v2* tool, uint32_t id_hi, uint32_t id_lo)
{
/* unimplemented */
}
static void
tablet_tool_handle_capability(void* data, struct zwp_tablet_tool_v2* tool, uint32_t capability)
{
/* unimplemented */
}
static void
tablet_tool_handle_done(void* data, struct zwp_tablet_tool_v2* tool)
{
/* unimplemented */
}
static void
tablet_tool_handle_removed(void* data, struct zwp_tablet_tool_v2* tool)
{
/* unimplemented */
}
static void
tablet_tool_handle_proximity_in(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial, struct zwp_tablet_v2* tablet, struct wl_surface* surface)
{
struct SDL_WaylandTabletInput* input = data;
SDL_WindowData* window;
if (!surface) {
return;
}
if (!SDL_WAYLAND_own_surface(surface)) {
return;
}
window = (SDL_WindowData*)wl_surface_get_user_data(surface);
if (window) {
input->tool_focus = window;
input->tool_prox_serial = serial;
input->is_down = SDL_FALSE;
input->btn_stylus = SDL_FALSE;
input->btn_stylus2 = SDL_FALSE;
input->btn_stylus3 = SDL_FALSE;
SDL_SetMouseFocus(window->sdlwindow);
SDL_SetCursor(NULL);
}
}
static void
tablet_tool_handle_proximity_out(void* data, struct zwp_tablet_tool_v2* tool)
{
struct SDL_WaylandTabletInput* input = data;
if (input->tool_focus) {
SDL_SetMouseFocus(NULL);
input->tool_focus = NULL;
}
}
uint32_t
tablet_tool_btn_to_sdl_button(struct SDL_WaylandTabletInput* input)
{
unsigned int tool_btn = input->btn_stylus3 << 2 | input->btn_stylus2 << 1 | input->btn_stylus << 0;
switch (tool_btn) {
case 0b000:
return SDL_BUTTON_LEFT;
case 0b001:
return SDL_BUTTON_RIGHT;
case 0b010:
return SDL_BUTTON_MIDDLE;
case 0b100:
return SDL_BUTTON_X1;
default:
return SDL_BUTTON_LEFT;
}
}
static void
tablet_tool_handle_down(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial)
{
struct SDL_WaylandTabletInput* input = data;
SDL_WindowData* window = input->tool_focus;
input->is_down = SDL_TRUE;
if (!window) {
/* tablet_tool_handle_proximity_out gets called when moving over the libdecoration csd.
* that sets input->tool_focus (window) to NULL, but handle_{down,up} events are still
* received. To prevent SIGSEGV this returns when this is the case.
*/
return;
}
SDL_SendMouseButton(window->sdlwindow, 0, SDL_PRESSED, tablet_tool_btn_to_sdl_button(input));
}
static void
tablet_tool_handle_up(void* data, struct zwp_tablet_tool_v2* tool)
{
struct SDL_WaylandTabletInput* input = data;
SDL_WindowData* window = input->tool_focus;
input->is_down = SDL_FALSE;
if (!window) {
/* tablet_tool_handle_proximity_out gets called when moving over the libdecoration csd.
* that sets input->tool_focus (window) to NULL, but handle_{down,up} events are still
* received. To prevent SIGSEGV this returns when this is the case.
*/
return;
}
SDL_SendMouseButton(window->sdlwindow, 0, SDL_RELEASED, tablet_tool_btn_to_sdl_button(input));
}
static void
tablet_tool_handle_motion(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t sx_w, wl_fixed_t sy_w)
{
struct SDL_WaylandTabletInput* input = data;
SDL_WindowData* window = input->tool_focus;
input->sx_w = sx_w;
input->sy_w = sy_w;
if (input->tool_focus) {
const float sx_f = (float)wl_fixed_to_double(sx_w);
const float sy_f = (float)wl_fixed_to_double(sy_w);
const int sx = (int)SDL_floorf(sx_f * window->pointer_scale_x);
const int sy = (int)SDL_floorf(sy_f * window->pointer_scale_y);
SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
}
}
static void
tablet_tool_handle_pressure(void* data, struct zwp_tablet_tool_v2* tool, uint32_t pressure)
{
/* unimplemented */
}
static void
tablet_tool_handle_distance(void* data, struct zwp_tablet_tool_v2* tool, uint32_t distance)
{
/* unimplemented */
}
static void
tablet_tool_handle_tilt(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t xtilt, wl_fixed_t ytilt)
{
/* unimplemented */
}
static void
tablet_tool_handle_button(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial, uint32_t button, uint32_t state)
{
struct SDL_WaylandTabletInput* input = data;
if (input->is_down) {
tablet_tool_handle_up(data, tool);
input->is_down = SDL_TRUE;
}
switch (button) {
/* see %{_includedir}/linux/input-event-codes.h */
case 0x14b: /* BTN_STYLUS */
input->btn_stylus = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE;
break;
case 0x14c: /* BTN_STYLUS2 */
input->btn_stylus2 = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE;
break;
case 0x149: /* BTN_STYLUS3 */
input->btn_stylus3 = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE;
break;
}
if (input->is_down) {
tablet_tool_handle_down(data, tool, serial);
}
}
static void
tablet_tool_handle_rotation(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t degrees)
{
/* unimplemented */
}
static void
tablet_tool_handle_slider(void* data, struct zwp_tablet_tool_v2* tool, int32_t position)
{
/* unimplemented */
}
static void
tablet_tool_handle_wheel(void* data, struct zwp_tablet_tool_v2* tool, int32_t degrees, int32_t clicks)
{
/* unimplemented */
}
static void
tablet_tool_handle_frame(void* data, struct zwp_tablet_tool_v2* tool, uint32_t time)
{
/* unimplemented */
}
static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {
tablet_tool_handle_type,
tablet_tool_handle_hardware_serial,
tablet_tool_handle_hardware_id_wacom,
tablet_tool_handle_capability,
tablet_tool_handle_done,
tablet_tool_handle_removed,
tablet_tool_handle_proximity_in,
tablet_tool_handle_proximity_out,
tablet_tool_handle_down,
tablet_tool_handle_up,
tablet_tool_handle_motion,
tablet_tool_handle_pressure,
tablet_tool_handle_distance,
tablet_tool_handle_tilt,
tablet_tool_handle_rotation,
tablet_tool_handle_slider,
tablet_tool_handle_wheel,
tablet_tool_handle_button,
tablet_tool_handle_frame
};
struct SDL_WaylandTabletObjectListNode*
tablet_object_list_new_node(void* object)
{
struct SDL_WaylandTabletObjectListNode* node;
node = SDL_calloc(1, sizeof *node);
if (node == NULL) {
return NULL;
}
node->next = NULL;
node->object = object;
return node;
}
void tablet_object_list_append(struct SDL_WaylandTabletObjectListNode* head, void* object)
{
if (head->object == NULL) {
head->object = object;
return;
}
while (head->next) {
head = head->next;
}
head->next = tablet_object_list_new_node(object);
}
void tablet_object_list_destroy(struct SDL_WaylandTabletObjectListNode* head, void (*deleter)(void* object))
{
while (head) {
struct SDL_WaylandTabletObjectListNode* next = head->next;
if (head->object) {
(*deleter)(head->object);
}
SDL_free(head);
head = next;
}
}
static void
tablet_seat_handle_tablet_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_v2* tablet)
{
struct SDL_WaylandTabletInput* input = data;
tablet_object_list_append(input->tablets, tablet);
}
static void
tablet_seat_handle_tool_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_tool_v2* tool)
{
struct SDL_WaylandTabletInput* input = data;
zwp_tablet_tool_v2_add_listener(tool, &tablet_tool_listener, data);
zwp_tablet_tool_v2_set_user_data(tool, data);
tablet_object_list_append(input->tools, tool);
}
static void
tablet_seat_handle_pad_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_pad_v2* pad)
{
struct SDL_WaylandTabletInput* input = data;
tablet_object_list_append(input->pads, pad);
}
static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
tablet_seat_handle_tablet_added,
tablet_seat_handle_tool_added,
tablet_seat_handle_pad_added
};
void
Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_WaylandTabletManager* tablet_manager)
{
struct SDL_WaylandTabletInput* tablet_input;
if (!tablet_manager || !input || !input->seat) {
return;
}
tablet_input = SDL_calloc(1, sizeof *tablet_input);
if (tablet_input == NULL) {
return;
}
input->tablet = tablet_input;
tablet_input->seat = (struct SDL_WaylandTabletSeat*)zwp_tablet_manager_v2_get_tablet_seat((struct zwp_tablet_manager_v2*)tablet_manager, input->seat);
tablet_input->tablets = tablet_object_list_new_node(NULL);
tablet_input->tools = tablet_object_list_new_node(NULL);
tablet_input->pads = tablet_object_list_new_node(NULL);
zwp_tablet_seat_v2_add_listener((struct zwp_tablet_seat_v2*)tablet_input->seat, &tablet_seat_listener, tablet_input);
}
#define TABLET_OBJECT_LIST_DELETER(fun) (void (*)(void*))fun
void
Wayland_input_destroy_tablet(struct SDL_WaylandInput* input)
{
tablet_object_list_destroy(input->tablet->pads, TABLET_OBJECT_LIST_DELETER(zwp_tablet_pad_v2_destroy));
tablet_object_list_destroy(input->tablet->tools, TABLET_OBJECT_LIST_DELETER(zwp_tablet_tool_v2_destroy));
tablet_object_list_destroy(input->tablet->tablets, TABLET_OBJECT_LIST_DELETER(zwp_tablet_v2_destroy));
zwp_tablet_seat_v2_destroy((struct zwp_tablet_seat_v2*)input->tablet->seat);
SDL_free(input->tablet);
input->tablet = NULL;
}
void
Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
{
@ -1659,6 +2056,7 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, SDL_min(5, version));
input->sx_w = wl_fixed_from_int(0);
input->sy_w = wl_fixed_from_int(0);
input->xkb.current_group = ~0;
d->input = input;
if (d->data_device_manager != NULL) {
@ -1671,6 +2069,10 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
wl_seat_add_listener(input->seat, &seat_listener, input);
wl_seat_set_user_data(input->seat, input);
if (d->tablet_manager) {
Wayland_input_add_tablet(input, d->tablet_manager);
}
WAYLAND_wl_display_flush(d->display);
}
@ -1711,6 +2113,10 @@ void Wayland_display_destroy_input(SDL_VideoData *d)
wl_touch_destroy(input->touch);
}
if (input->tablet) {
Wayland_input_destroy_tablet(input);
}
if (input->seat)
wl_seat_destroy(input->seat);
@ -1951,12 +2357,19 @@ int Wayland_input_confine_pointer(struct SDL_WaylandInput *input, SDL_Window *wi
if (SDL_RectEmpty(&window->mouse_rect)) {
confine_rect = NULL;
} else {
SDL_Rect scaled_mouse_rect;
scaled_mouse_rect.x = (int)SDL_floorf((float)window->mouse_rect.x / w->pointer_scale_x);
scaled_mouse_rect.y = (int)SDL_floorf((float)window->mouse_rect.y / w->pointer_scale_y);
scaled_mouse_rect.w = (int)SDL_ceilf((float)window->mouse_rect.w / w->pointer_scale_x);
scaled_mouse_rect.h = (int)SDL_ceilf((float)window->mouse_rect.h / w->pointer_scale_y);
confine_rect = wl_compositor_create_region(d->compositor);
wl_region_add(confine_rect,
window->mouse_rect.x,
window->mouse_rect.y,
window->mouse_rect.w,
window->mouse_rect.h);
scaled_mouse_rect.x,
scaled_mouse_rect.y,
scaled_mouse_rect.w,
scaled_mouse_rect.h);
}
confined_pointer =

View file

@ -29,6 +29,34 @@
#include "SDL_waylanddatamanager.h"
#include "SDL_waylandkeyboard.h"
struct SDL_WaylandTabletSeat;
struct SDL_WaylandTabletObjectListNode {
void* object;
struct SDL_WaylandTabletObjectListNode* next;
};
struct SDL_WaylandTabletInput {
struct SDL_WaylandTabletSeat* seat;
struct SDL_WaylandTabletObjectListNode* tablets;
struct SDL_WaylandTabletObjectListNode* tools;
struct SDL_WaylandTabletObjectListNode* pads;
SDL_WindowData *tool_focus;
uint32_t tool_prox_serial;
/* Last motion location */
wl_fixed_t sx_w;
wl_fixed_t sy_w;
SDL_bool is_down;
SDL_bool btn_stylus;
SDL_bool btn_stylus2;
SDL_bool btn_stylus3;
};
typedef struct {
// repeat_rate in range of [1, 1000]
int32_t repeat_rate;
@ -68,6 +96,17 @@ struct SDL_WaylandInput {
struct xkb_state *state;
struct xkb_compose_table *compose_table;
struct xkb_compose_state *compose_state;
/* Keyboard layout "group" */
uint32_t current_group;
/* Modifier bitshift values */
uint32_t idx_shift;
uint32_t idx_ctrl;
uint32_t idx_alt;
uint32_t idx_gui;
uint32_t idx_num;
uint32_t idx_caps;
} xkb;
/* information about axis events on current frame */
@ -80,6 +119,8 @@ struct SDL_WaylandInput {
} pointer_curr_axis_info;
SDL_WaylandKeyboardRepeat keyboard_repeat;
struct SDL_WaylandTabletInput* tablet;
};
extern void Wayland_PumpEvents(_THIS);
@ -107,6 +148,9 @@ extern void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d);
extern int Wayland_input_grab_keyboard(SDL_Window *window, struct SDL_WaylandInput *input);
extern int Wayland_input_ungrab_keyboard(SDL_Window *window);
extern void Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_WaylandTabletManager* tablet_manager);
extern void Wayland_input_destroy_tablet(struct SDL_WaylandInput *input);
#endif /* SDL_waylandevents_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -205,11 +205,11 @@ Wayland_GLES_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
data = (SDL_WindowData *) window->driverdata;
if (w) {
*w = window->w * data->scale_factor;
*w = data->drawable_width;
}
if (h) {
*h = window->h * data->scale_factor;
*h = data->drawable_height;
}
}
}

View file

@ -72,21 +72,19 @@ SDL_WAYLAND_SYM(void, wl_list_remove, (struct wl_list *))
SDL_WAYLAND_SYM(int, wl_list_length, (const struct wl_list *))
SDL_WAYLAND_SYM(int, wl_list_empty, (const struct wl_list *))
SDL_WAYLAND_SYM(void, wl_list_insert_list, (struct wl_list *, struct wl_list *))
/* These functions are available in Wayland >= 1.4 */
SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_4)
SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor, (struct wl_proxy *, uint32_t opcode, const struct wl_interface *interface, ...))
SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_10)
SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor_versioned, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, ...))
SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_18)
SDL_WAYLAND_SYM(void, wl_proxy_set_tag, (struct wl_proxy *, const char * const *))
SDL_WAYLAND_SYM(const char * const *, wl_proxy_get_tag, (struct wl_proxy *))
SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_20)
#if SDL_WAYLAND_CHECK_VERSION(1, 20, 0)
/* wayland-scanner 1.20 generates code that will call these, so these are
* non-optional when we are compiling against Wayland 1.20. We don't
* explicitly call them ourselves, though, so if we are only compiling
* against Wayland 1.18, they're unnecessary. */
SDL_WAYLAND_SYM(struct wl_proxy*, wl_proxy_marshal_flags, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interfac, uint32_t version, uint32_t flags, ...))
SDL_WAYLAND_SYM(struct wl_proxy*, wl_proxy_marshal_array_flags, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, union wl_argument *args))
#endif
SDL_WAYLAND_INTERFACE(wl_seat_interface)
SDL_WAYLAND_INTERFACE(wl_surface_interface)
@ -149,6 +147,8 @@ SDL_WAYLAND_SYM(int, xkb_keymap_key_get_syms_by_level, (struct xkb_keymap *,
xkb_layout_index_t,
const xkb_keysym_t **) )
SDL_WAYLAND_SYM(uint32_t, xkb_keysym_to_utf32, (xkb_keysym_t) )
SDL_WAYLAND_SYM(uint32_t, xkb_keymap_mod_get_index, (struct xkb_keymap *,
const char *) )
#ifdef HAVE_LIBDECOR_H
SDL_WAYLAND_MODULE(WAYLAND_LIBDECOR)

View file

@ -52,6 +52,9 @@
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
#include "tablet-unstable-v2-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@ -59,6 +62,9 @@
#define WAYLANDVID_DRIVER_NAME "wayland"
static void
display_handle_done(void *data, struct wl_output *output);
/* Initialization/Query functions */
static int
Wayland_VideoInit(_THIS);
@ -133,32 +139,22 @@ static const char *SDL_WAYLAND_output_tag = "sdl-output";
void SDL_WAYLAND_register_surface(struct wl_surface *surface)
{
if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
wl_proxy_set_tag((struct wl_proxy *)surface, &SDL_WAYLAND_surface_tag);
}
wl_proxy_set_tag((struct wl_proxy *)surface, &SDL_WAYLAND_surface_tag);
}
void SDL_WAYLAND_register_output(struct wl_output *output)
{
if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
wl_proxy_set_tag((struct wl_proxy *)output, &SDL_WAYLAND_output_tag);
}
wl_proxy_set_tag((struct wl_proxy *)output, &SDL_WAYLAND_output_tag);
}
SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface)
{
if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
return wl_proxy_get_tag((struct wl_proxy *) surface) == &SDL_WAYLAND_surface_tag;
}
return SDL_TRUE; /* For older clients we have to assume this is us... */
return wl_proxy_get_tag((struct wl_proxy *) surface) == &SDL_WAYLAND_surface_tag;
}
SDL_bool SDL_WAYLAND_own_output(struct wl_output *output)
{
if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
return wl_proxy_get_tag((struct wl_proxy *) output) == &SDL_WAYLAND_output_tag;
}
return SDL_TRUE; /* For older clients we have to assume this is us... */
return wl_proxy_get_tag((struct wl_proxy *) output) == &SDL_WAYLAND_output_tag;
}
static void
@ -283,6 +279,8 @@ Wayland_CreateDevice(int devindex)
device->free = Wayland_DeleteDevice;
device->disable_display_mode_switching = SDL_TRUE;
return device;
}
@ -291,6 +289,155 @@ VideoBootStrap Wayland_bootstrap = {
Wayland_CreateDevice
};
static void
xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output,
int32_t x, int32_t y)
{
SDL_WaylandOutputData* driverdata = data;
driverdata->x = x;
driverdata->y = y;
driverdata->has_logical_position = SDL_TRUE;
}
static void
xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output,
int32_t width, int32_t height)
{
SDL_WaylandOutputData* driverdata = data;
if (driverdata->width != 0 && driverdata->height != 0) {
/* FIXME: GNOME has a bug where the logical size does not account for
* scale, resulting in bogus viewport sizes.
*
* Until this is fixed, validate that _some_ kind of scaling is being
* done (we can't match exactly because fractional scaling can't be
* detected otherwise), then override if necessary.
* -flibit
*/
const float scale = (float) driverdata->width / (float) width;
if ((scale == 1.0f) && (driverdata->scale_factor != 1.0f)) {
SDL_LogWarn(
SDL_LOG_CATEGORY_VIDEO,
"xdg_output scale did not match, overriding with wl_output scale"
);
return;
}
}
driverdata->width = width;
driverdata->height = height;
driverdata->has_logical_size = SDL_TRUE;
}
static void
xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
{
SDL_WaylandOutputData* driverdata = data;
/*
* xdg-output.done events are deprecated and only apply below version 3 of the protocol.
* A wl-output.done event will be emitted in version 3 or higher.
*/
if (zxdg_output_v1_get_version(driverdata->xdg_output) < 3) {
display_handle_done(data, driverdata->output);
}
}
static void
xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output,
const char *name)
{
}
static void
xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output,
const char *description)
{
}
static const struct zxdg_output_v1_listener xdg_output_listener = {
xdg_output_handle_logical_position,
xdg_output_handle_logical_size,
xdg_output_handle_done,
xdg_output_handle_name,
xdg_output_handle_description,
};
static void
AddEmulatedModes(SDL_VideoDisplay *dpy, SDL_bool rot_90)
{
struct EmulatedMode
{
int w;
int h;
};
/* Resolution lists courtesy of XWayland */
const struct EmulatedMode mode_list[] = {
/* 16:9 (1.77) */
{ 7680, 4320 },
{ 6144, 3160 },
{ 5120, 2880 },
{ 4096, 2304 },
{ 3840, 2160 },
{ 3200, 1800 },
{ 2880, 1620 },
{ 2560, 1440 },
{ 2048, 1152 },
{ 1920, 1080 },
{ 1600, 900 },
{ 1368, 768 },
{ 1280, 720 },
{ 864, 486 },
/* 16:10 (1.6) */
{ 2560, 1600 },
{ 1920, 1200 },
{ 1680, 1050 },
{ 1440, 900 },
{ 1280, 800 },
/* 3:2 (1.5) */
{ 720, 480 },
/* 4:3 (1.33) */
{ 2048, 1536 },
{ 1920, 1440 },
{ 1600, 1200 },
{ 1440, 1080 },
{ 1400, 1050 },
{ 1280, 1024 },
{ 1280, 960 },
{ 1152, 864 },
{ 1024, 768 },
{ 800, 600 },
{ 640, 480 }
};
int i;
const int native_width = dpy->display_modes->w;
const int native_height = dpy->display_modes->h;
for (i = 0; i < SDL_arraysize(mode_list); ++i) {
/* Only add modes that are smaller than the native mode */
if ((mode_list[i].w < native_width && mode_list[i].h < native_height) ||
(mode_list[i].w < native_width && mode_list[i].h == native_height)) {
SDL_DisplayMode mode = *dpy->display_modes;
if (rot_90) {
mode.w = mode_list[i].h;
mode.h = mode_list[i].w;
} else {
mode.w = mode_list[i].w;
mode.h = mode_list[i].h;
}
SDL_AddDisplayMode(dpy, &mode);
}
}
}
static void
display_handle_geometry(void *data,
struct wl_output *output,
@ -307,7 +454,7 @@ display_handle_geometry(void *data,
SDL_VideoDisplay *display;
int i;
if (driverdata->done) {
if (driverdata->wl_output_done_count) {
/* Clear the wl_output ref so Reset doesn't free it */
display = SDL_GetDisplay(driverdata->index);
for (i = 0; i < display->num_display_modes; i += 1) {
@ -318,11 +465,14 @@ display_handle_geometry(void *data,
SDL_ResetDisplayModes(driverdata->index);
/* The display has officially started over. */
driverdata->done = SDL_FALSE;
driverdata->wl_output_done_count = 0;
}
driverdata->x = x;
driverdata->y = y;
/* Apply the change from wl-output only if xdg-output is not supported */
if (!driverdata->has_logical_position) {
driverdata->x = x;
driverdata->y = y;
}
driverdata->physical_width = physical_width;
driverdata->physical_height = physical_height;
if (driverdata->index == -1) {
@ -369,36 +519,21 @@ display_handle_mode(void *data,
int refresh)
{
SDL_WaylandOutputData* driverdata = data;
SDL_DisplayMode mode;
if (flags & WL_OUTPUT_MODE_CURRENT) {
/* Don't rotate this yet, handle_done will do it later */
driverdata->width = width;
driverdata->height = height;
driverdata->refresh = refresh;
}
driverdata->native_width = width;
driverdata->native_height = height;
/* Note that the width/height are NOT multiplied by scale_factor!
* This is intentional and is designed to get the unscaled modes, which is
* important for high-DPI games intending to use the display mode as the
* target drawable size. The scaled desktop mode will be added at the end
* when display_handle_done is called (see below).
*/
SDL_zero(mode);
mode.format = SDL_PIXELFORMAT_RGB888;
if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) {
mode.w = height;
mode.h = width;
} else {
mode.w = width;
mode.h = height;
}
mode.refresh_rate = (int)SDL_round(refresh / 1000.0); /* mHz to Hz */
mode.driverdata = driverdata->output;
if (driverdata->index > -1) {
SDL_AddDisplayMode(SDL_GetDisplay(driverdata->index), &mode);
} else {
SDL_AddDisplayMode(&driverdata->placeholder, &mode);
/*
* Don't rotate this yet, wl-output coordinates are transformed in
* handle_done and xdg-output coordinates are pre-transformed.
*/
if (!driverdata->has_logical_size) {
driverdata->width = width;
driverdata->height = height;
}
driverdata->refresh = refresh;
}
}
@ -407,20 +542,73 @@ display_handle_done(void *data,
struct wl_output *output)
{
SDL_WaylandOutputData* driverdata = data;
SDL_DisplayMode mode;
SDL_VideoData* video = driverdata->videodata;
SDL_DisplayMode native_mode, desktop_mode;
SDL_VideoDisplay *dpy;
if (driverdata->done)
/*
* When using xdg-output, two wl-output.done events will be emitted:
* one at the completion of wl-display and one at the completion of xdg-output.
*
* All required events must be received before proceeding.
*/
const int event_await_count = 1 + (driverdata->xdg_output != NULL);
driverdata->wl_output_done_count = SDL_min(driverdata->wl_output_done_count + 1, event_await_count + 1);
if (driverdata->wl_output_done_count != event_await_count) {
return;
}
driverdata->done = SDL_TRUE;
/* The native display resolution */
SDL_zero(native_mode);
native_mode.format = SDL_PIXELFORMAT_RGB888;
SDL_zero(mode);
mode.format = SDL_PIXELFORMAT_RGB888;
if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) {
mode.w = driverdata->height / driverdata->scale_factor;
mode.h = driverdata->width / driverdata->scale_factor;
native_mode.w = driverdata->native_height;
native_mode.h = driverdata->native_width;
} else {
native_mode.w = driverdata->native_width;
native_mode.h = driverdata->native_height;
}
native_mode.refresh_rate = (int)SDL_round(driverdata->refresh / 1000.0); /* mHz to Hz */
native_mode.driverdata = driverdata->output;
/* The scaled desktop mode */
SDL_zero(desktop_mode);
desktop_mode.format = SDL_PIXELFORMAT_RGB888;
/* Scale the desktop coordinates, if xdg-output isn't present */
if (!driverdata->has_logical_size) {
driverdata->width /= driverdata->scale_factor;
driverdata->height /= driverdata->scale_factor;
}
/* xdg-output dimensions are already transformed, so no need to rotate. */
if (driverdata->has_logical_size || !(driverdata->transform & WL_OUTPUT_TRANSFORM_90)) {
desktop_mode.w = driverdata->width;
desktop_mode.h = driverdata->height;
} else {
desktop_mode.w = driverdata->height;
desktop_mode.h = driverdata->width;
}
desktop_mode.refresh_rate = (int)SDL_round(driverdata->refresh / 1000.0); /* mHz to Hz */
desktop_mode.driverdata = driverdata->output;
/*
* The native display mode is only exposed separately from the desktop size if:
* the desktop is scaled and the wp_viewporter protocol is supported.
*/
if (driverdata->scale_factor > 1.0f && video->viewporter != NULL) {
if (driverdata->index > -1) {
SDL_AddDisplayMode(SDL_GetDisplay(driverdata->index), &native_mode);
} else {
SDL_AddDisplayMode(&driverdata->placeholder, &native_mode);
}
}
/* Calculate the display DPI */
if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) {
driverdata->hdpi = driverdata->physical_height ?
(((float) driverdata->height) * 25.4f / driverdata->physical_height) :
0.0f;
@ -432,9 +620,6 @@ display_handle_done(void *data,
((float) driverdata->physical_height) / 25.4f,
((float) driverdata->physical_width) / 25.4f);
} else {
mode.w = driverdata->width / driverdata->scale_factor;
mode.h = driverdata->height / driverdata->scale_factor;
driverdata->hdpi = driverdata->physical_width ?
(((float) driverdata->width) * 25.4f / driverdata->physical_width) :
0.0f;
@ -446,8 +631,6 @@ display_handle_done(void *data,
((float) driverdata->physical_width) / 25.4f,
((float) driverdata->physical_height) / 25.4f);
}
mode.refresh_rate = (int)SDL_round(driverdata->refresh / 1000.0); /* mHz to Hz */
mode.driverdata = driverdata->output;
if (driverdata->index > -1) {
dpy = SDL_GetDisplay(driverdata->index);
@ -455,9 +638,14 @@ display_handle_done(void *data,
dpy = &driverdata->placeholder;
}
SDL_AddDisplayMode(dpy, &mode);
SDL_SetCurrentDisplayMode(dpy, &mode);
SDL_SetDesktopDisplayMode(dpy, &mode);
SDL_AddDisplayMode(dpy, &desktop_mode);
SDL_SetCurrentDisplayMode(dpy, &desktop_mode);
SDL_SetDesktopDisplayMode(dpy, &desktop_mode);
/* Add emulated modes if wp_viewporter is supported. */
if (video->viewporter) {
AddEmulatedModes(dpy, (driverdata->transform & WL_OUTPUT_TRANSFORM_90) != 0);
}
if (driverdata->index == -1) {
/* First time getting display info, create the VideoDisplay */
@ -504,11 +692,29 @@ Wayland_add_display(SDL_VideoData *d, uint32_t id)
data->videodata = d;
data->output = output;
data->registry_id = id;
data->scale_factor = 1.0;
data->scale_factor = 1.0f;
data->index = -1;
wl_output_add_listener(output, &output_listener, data);
SDL_WAYLAND_register_output(output);
/* Keep a list of outputs for deferred xdg-output initialization. */
if (d->output_list != NULL) {
SDL_WaylandOutputData *node = (SDL_WaylandOutputData*)d->output_list;
while (node->next != NULL) {
node = (SDL_WaylandOutputData*)node->next;
}
node->next = (struct SDL_WaylandOutputData*)data;
} else {
d->output_list = (struct SDL_WaylandOutputData*)data;
}
if (data->videodata->xdg_output_manager) {
data->xdg_output = zxdg_output_manager_v1_get_xdg_output(data->videodata->xdg_output_manager, output);
zxdg_output_v1_add_listener(data->xdg_output, &xdg_output_listener, data);
}
}
static void
@ -524,6 +730,9 @@ Wayland_free_display(uint32_t id)
data = (SDL_WaylandOutputData *) display->driverdata;
if (data->registry_id == id) {
SDL_DelVideoDisplay(i);
if (data->xdg_output) {
zxdg_output_v1_destroy(data->xdg_output);
}
wl_output_destroy(data->output);
SDL_free(data);
@ -540,6 +749,16 @@ Wayland_free_display(uint32_t id)
}
}
static void
Wayland_init_xdg_output(SDL_VideoData *d)
{
SDL_WaylandOutputData *node;
for (node = d->output_list; node != NULL; node = node->next) {
node->xdg_output = zxdg_output_manager_v1_get_xdg_output(node->videodata->xdg_output_manager, node->output);
zxdg_output_v1_add_listener(node->xdg_output, &xdg_output_listener, node);
}
}
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
static void
windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
@ -600,7 +819,7 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
} else if (SDL_strcmp(interface, "wl_seat") == 0) {
Wayland_display_add_input(d, id, version);
} else if (SDL_strcmp(interface, "xdg_wm_base") == 0) {
d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, 1);
d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, SDL_min(version, 3));
xdg_wm_base_add_listener(d->shell.xdg, &shell_listener_xdg, NULL);
} else if (SDL_strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
@ -620,6 +839,17 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
Wayland_add_data_device_manager(d, id, version);
} else if (SDL_strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
d->decoration_manager = wl_registry_bind(d->registry, id, &zxdg_decoration_manager_v1_interface, 1);
} else if (SDL_strcmp(interface, "zwp_tablet_manager_v2") == 0) {
d->tablet_manager = wl_registry_bind(d->registry, id, &zwp_tablet_manager_v2_interface, 1);
if (d->input) {
Wayland_input_add_tablet(d->input, d->tablet_manager);
}
} else if (SDL_strcmp(interface, "zxdg_output_manager_v1") == 0) {
version = SDL_min(version, 3); /* Versions 1 through 3 are supported. */
d->xdg_output_manager = wl_registry_bind(d->registry, id, &zxdg_output_manager_v1_interface, version);
Wayland_init_xdg_output(d);
} else if (SDL_strcmp(interface, "wp_viewporter") == 0) {
d->viewporter = wl_registry_bind(d->registry, id, &wp_viewporter_interface, 1);
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
} else if (SDL_strcmp(interface, "qt_touch_extension") == 0) {
@ -646,6 +876,29 @@ static const struct wl_registry_listener registry_listener = {
display_handle_global,
display_remove_global
};
#ifdef HAVE_LIBDECOR_H
static SDL_bool should_use_libdecor(SDL_VideoData *data)
{
if (!SDL_WAYLAND_HAVE_WAYLAND_LIBDECOR) {
return SDL_FALSE;
}
if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR, SDL_TRUE)) {
return SDL_FALSE;
}
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR, SDL_FALSE)) {
return SDL_TRUE;
}
if (data->decoration_manager) {
return SDL_FALSE;
}
return SDL_TRUE;
}
#endif
int
Wayland_VideoInit(_THIS)
@ -669,14 +922,8 @@ Wayland_VideoInit(_THIS)
#ifdef HAVE_LIBDECOR_H
/* Don't have server-side decorations? Try client-side instead. */
if (!data->decoration_manager && SDL_WAYLAND_HAVE_WAYLAND_LIBDECOR && SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR, SDL_TRUE)) {
if (should_use_libdecor(data)) {
data->shell.libdecor = libdecor_new(data->display, &libdecor_interface);
/* If libdecor works, we don't need xdg-shell anymore. */
if (data->shell.libdecor && data->shell.xdg) {
xdg_wm_base_destroy(data->shell.xdg);
data->shell.xdg = NULL;
}
}
#endif
@ -737,6 +984,10 @@ Wayland_VideoQuit(_THIS)
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *display = &_this->displays[i];
if (((SDL_WaylandOutputData*)display->driverdata)->xdg_output) {
zxdg_output_v1_destroy(((SDL_WaylandOutputData*)display->driverdata)->xdg_output);
}
wl_output_destroy(((SDL_WaylandOutputData*)display->driverdata)->output);
SDL_free(display->driverdata);
display->driverdata = NULL;
@ -779,6 +1030,9 @@ Wayland_VideoQuit(_THIS)
Wayland_touch_destroy(data);
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
if (data->tablet_manager)
zwp_tablet_manager_v2_destroy((struct zwp_tablet_manager_v2*)data->tablet_manager);
if (data->data_device_manager)
wl_data_device_manager_destroy(data->data_device_manager);
@ -798,6 +1052,14 @@ Wayland_VideoQuit(_THIS)
}
#endif
if (data->xdg_output_manager) {
zxdg_output_manager_v1_destroy(data->xdg_output_manager);
}
if (data->viewporter) {
wp_viewporter_destroy(data->viewporter);
}
if (data->compositor)
wl_compositor_destroy(data->compositor);

View file

@ -34,6 +34,7 @@
struct xkb_context;
struct SDL_WaylandInput;
struct SDL_WaylandTabletManager;
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct SDL_WaylandTouch;
@ -46,6 +47,8 @@ typedef struct {
int size;
} SDL_WaylandCursorTheme;
typedef struct SDL_WaylandOutputData SDL_WaylandOutputData;
typedef struct {
SDL_bool initializing;
struct wl_display *display;
@ -70,6 +73,8 @@ typedef struct {
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
struct xdg_activation_v1 *activation_manager;
struct zwp_text_input_manager_v3 *text_input_manager;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct wp_viewporter *viewporter;
EGLDisplay edpy;
EGLContext context;
@ -77,6 +82,8 @@ typedef struct {
struct xkb_context *xkb_context;
struct SDL_WaylandInput *input;
struct SDL_WaylandTabletManager *tablet_manager;
SDL_WaylandOutputData *output_list;
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct SDL_WaylandTouch *touch;
@ -89,19 +96,23 @@ typedef struct {
int relative_mouse_mode;
} SDL_VideoData;
typedef struct {
struct SDL_WaylandOutputData {
SDL_VideoData *videodata;
struct wl_output *output;
struct zxdg_output_v1 *xdg_output;
uint32_t registry_id;
float scale_factor;
int native_width, native_height;
int x, y, width, height, refresh, transform;
SDL_DisplayOrientation orientation;
int physical_width, physical_height;
float ddpi, hdpi, vdpi;
SDL_bool has_logical_position, has_logical_size;
int index;
SDL_VideoDisplay placeholder;
SDL_bool done;
} SDL_WaylandOutputData;
int wl_output_done_count;
SDL_WaylandOutputData *next;
};
/* Needed here to get wl_surface declaration, fixes GitHub#4594 */
#include "SDL_waylanddyn.h"

View file

@ -139,11 +139,11 @@ void Wayland_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h)
data = (SDL_WindowData *) window->driverdata;
if (w) {
*w = window->w * data->scale_factor;
*w = data->drawable_width;
}
if (h) {
*h = window->h * data->scale_factor;
*h = data->drawable_height;
}
}
}

View file

@ -25,22 +25,294 @@
#include "../SDL_sysvideo.h"
#include "../../events/SDL_windowevents_c.h"
#include "../../events/SDL_mouse_c.h"
#include "../SDL_egl_c.h"
#include "SDL_waylandevents_c.h"
#include "SDL_waylandwindow.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylandtouch.h"
#include "SDL_hints.h"
#include "SDL_events.h"
#include "xdg-shell-client-protocol.h"
#include "xdg-decoration-unstable-v1-client-protocol.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
#endif
static void
GetFullScreenDimensions(SDL_Window *window, int *width, int *height, int *drawable_width, int *drawable_height)
{
SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
int fs_width, fs_height;
int buf_width, buf_height;
/*
* Fullscreen desktop mandates a desktop sized window, so that's what applications will get.
* If the application is DPI aware, it will need to handle the transformations between the
* differently sized window and backbuffer spaces on its own.
*/
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
fs_width = output->width;
fs_height = output->height;
/* If the application is DPI aware, we can expose the true backbuffer size */
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
buf_width = output->native_width;
buf_height = output->native_height;
} else {
buf_width = fs_width;
buf_height = fs_height;
}
} else {
/*
* If a mode was set, use it, otherwise use the native resolution
* for DPI aware apps and the desktop size for legacy apps.
*/
if (window->fullscreen_mode.w != 0 && window->fullscreen_mode.h != 0) {
fs_width = window->fullscreen_mode.w;
fs_height = window->fullscreen_mode.h;
} else if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
fs_width = output->native_width;
fs_height = output->native_height;
} else {
fs_width = output->width;
fs_height = output->height;
}
buf_width = fs_width;
buf_height = fs_height;
}
if (width) {
*width = fs_width;
}
if (height) {
*height = fs_height;
}
if (drawable_width) {
*drawable_width = buf_width;
}
if (drawable_height) {
*drawable_height = buf_height;
}
}
static inline SDL_bool
DesktopIsScaled(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
return data->scale_factor != 1.0f;
}
static inline SDL_bool
DesktopIsFractionalScaled(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
if ((output->native_width != (int)(output->width * data->scale_factor) ||
output->native_height != (int)(output->height * data->scale_factor))) {
return SDL_TRUE;
}
return SDL_FALSE;
}
static SDL_bool
NeedFullscreenViewport(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
SDL_VideoData *video = data->waylandData;
SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
int fs_width, fs_height;
GetFullScreenDimensions(window, &fs_width, &fs_height, NULL, NULL);
/*
* Fullscreen needs a viewport:
* - If the desktop uses fractional scaling
* - Fullscreen desktop was not requested OR the window is DPI aware
*
* - The desktop uses non-fractional scaling
* - Fullscreen desktop was NOT requested
*
* - The desktop is not scaled
* - A non-native fullscreen mode was explicitly set by the client
*/
if (video->viewporter != NULL && (window->flags & SDL_WINDOW_FULLSCREEN)) {
if (DesktopIsFractionalScaled(window)) {
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP ||
(window->flags & SDL_WINDOW_ALLOW_HIGHDPI)) {
return SDL_TRUE;
}
} else if (DesktopIsScaled(window)) {
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
return SDL_TRUE;
}
} else if (fs_width != output->native_width && fs_height != output->native_height) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
static inline SDL_bool
NeedWindowedViewport(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
SDL_VideoData *video = data->waylandData;
return !(window->flags & SDL_WINDOW_FULLSCREEN) && (video->viewporter != NULL) &&
DesktopIsFractionalScaled(window) && (window->flags & SDL_WINDOW_ALLOW_HIGHDPI);
}
/* Never set a fullscreen window size larger than the desktop. */
SDL_FORCE_INLINE int
GetWindowWidth(SDL_Window *window)
{
return NeedFullscreenViewport(window) ? ((SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata)->width : window->w;
}
SDL_FORCE_INLINE int
GetWindowHeight(SDL_Window *window)
{
return NeedFullscreenViewport(window) ? ((SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata)->height : window->h;
}
static void
GetWindowBufferSize(SDL_Window *window, int *width, int *height)
{
SDL_WindowData *data = window->driverdata;
SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
int buf_width;
int buf_height;
if (NeedWindowedViewport(window)) {
const float frac_scale_x = (float)output->native_width / (float)output->width;
const float frac_scale_y = (float)output->native_height / (float)output->height;
buf_width = (int)SDL_lroundf(window->w * frac_scale_x);
buf_height = (int)SDL_lroundf(window->h * frac_scale_y);
} else { /* Windowed or fullscreen with no viewport */
buf_width = window->w * data->scale_factor;
buf_height = window->h * data->scale_factor;
}
if (width) {
*width = buf_width;
}
if (height) {
*height = buf_height;
}
}
static void
SetViewport(SDL_Window *window, int src_width, int src_height, int dst_width, int dst_height)
{
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *video = wind->waylandData;
if (video->viewporter) {
if (wind->viewport == NULL) {
wind->viewport = wp_viewporter_get_viewport(video->viewporter, wind->surface);
}
wp_viewport_set_source(wind->viewport, wl_fixed_from_int(0), wl_fixed_from_int(0), wl_fixed_from_int(src_width), wl_fixed_from_int(src_height));
wp_viewport_set_destination(wind->viewport, dst_width, dst_height);
}
}
static void
UnsetViewport(SDL_Window *window)
{
SDL_WindowData *wind = window->driverdata;
if (wind->viewport) {
wp_viewport_destroy(wind->viewport);
wind->viewport = NULL;
}
}
static void
ConfigureViewport(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
SDL_VideoData *viddata = data->waylandData;
SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
if (NeedFullscreenViewport(window)) {
int fs_width, fs_height;
int src_width, src_height;
GetFullScreenDimensions(window, &fs_width, &fs_height, &src_width, &src_height);
SetViewport(window, src_width, src_height, output->width, output->height);
data->damage_region.x = 0;
data->damage_region.y = 0;
data->damage_region.w = output->width;
data->damage_region.h = output->height;
data->pointer_scale_x = (float)fs_width / (float)output->width;
data->pointer_scale_y = (float)fs_height / (float)output->height;
} else {
if (NeedWindowedViewport(window)) {
int src_width, src_height;
GetWindowBufferSize(window, &src_width, &src_height);
SetViewport(window, src_width, src_height, window->w, window->h);
} else {
UnsetViewport(window);
}
SDL_zero(data->damage_region);
data->pointer_scale_x = 1.0f;
data->pointer_scale_y = 1.0f;
}
/*
* If mouse_rect is not empty, re-create the confinement region with the new scale value.
* If the pointer is locked to the general surface with unspecified coordinates, it will
* be confined to the viewport region, so no update is required.
*/
if (!SDL_RectEmpty(&window->mouse_rect)) {
Wayland_input_confine_pointer(viddata->input, window);
}
}
static void
SetDrawScale(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
if (NeedFullscreenViewport(window)) {
int fs_width, fs_height;
GetFullScreenDimensions(window, &fs_width, &fs_height, &data->drawable_width, &data->drawable_height);
/* Set the buffer scale to 1 since a viewport will be used. */
wl_surface_set_buffer_scale(data->surface, 1);
} else {
GetWindowBufferSize(window, &data->drawable_width, &data->drawable_height);
if (NeedWindowedViewport(window)) {
/* Set the buffer scale to 1 since a viewport will be used. */
wl_surface_set_buffer_scale(data->surface, 1);
} else {
wl_surface_set_buffer_scale(data->surface, (int32_t)data->scale_factor);
}
}
}
static void
SetMinMaxDimensions(SDL_Window *window, SDL_bool commit)
{
@ -48,6 +320,15 @@ SetMinMaxDimensions(SDL_Window *window, SDL_bool commit)
SDL_VideoData *viddata = wind->waylandData;
int min_width, min_height, max_width, max_height;
/* Pop-ups don't get to change size */
if (WINDOW_IS_XDG_POPUP(window)) {
/* ... but we still want to commit, particularly for ShowWindow */
if (commit) {
wl_surface_commit(wind->surface);
}
return;
}
if (window->flags & SDL_WINDOW_FULLSCREEN) {
min_width = 0;
min_height = 0;
@ -66,7 +347,7 @@ SetMinMaxDimensions(SDL_Window *window, SDL_bool commit)
}
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -100,13 +381,22 @@ SetFullscreen(SDL_Window *window, struct wl_output *output, SDL_bool commit)
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *viddata = wind->waylandData;
/* Pop-ups don't get to be fullscreened */
if (WINDOW_IS_XDG_POPUP(window)) {
/* ... but we still want to commit, particularly for ShowWindow */
if (commit) {
wl_surface_commit(wind->surface);
}
return;
}
/* The desktop may try to enforce min/max sizes here, so turn them off for
* fullscreen and on (if applicable) for windowed
*/
SetMinMaxDimensions(window, SDL_FALSE);
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -150,6 +440,11 @@ handle_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time)
SDL_WindowData *wind = (SDL_WindowData *) data;
SDL_AtomicSet(&wind->swap_interval_ready, 1); /* mark window as ready to present again. */
if (!SDL_RectEmpty(&wind->damage_region)) {
wl_surface_damage(wind->surface, wind->damage_region.x, wind->damage_region.y,
wind->damage_region.w, wind->damage_region.h);
}
/* reset this callback to fire again once a new frame was presented and compositor wants the next one. */
wind->frame_callback = wl_surface_frame(wind->frame_surface_wrapper);
wl_callback_destroy(cb);
@ -303,9 +598,14 @@ handle_configure_xdg_toplevel(void *data,
* UPDATE: Nope, sure enough a compositor sends 0,0. This is a known bug:
* https://bugs.kde.org/show_bug.cgi?id=444962
*/
if (width != 0 && height != 0 && (window->w != width || window->h != height)) {
window->w = width;
window->h = height;
if (!NeedFullscreenViewport(window)) {
if (width != 0 && height != 0 && (window->w != width || window->h != height)) {
window->w = width;
window->h = height;
wind->needs_resize_event = SDL_TRUE;
}
} else {
GetFullScreenDimensions(window, &window->w, &window->h, NULL, NULL);
wind->needs_resize_event = SDL_TRUE;
}
@ -329,6 +629,60 @@ static const struct xdg_toplevel_listener toplevel_listener_xdg = {
handle_close_xdg_toplevel
};
static void
handle_configure_xdg_popup(void *data,
struct xdg_popup *xdg_popup,
int32_t x,
int32_t y,
int32_t width,
int32_t height)
{
/* No-op, we don't use x/y and width/height are fixed-size */
}
static void
handle_done_xdg_popup(void *data, struct xdg_popup *xdg_popup)
{
SDL_WindowData *window = (SDL_WindowData *)data;
SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
}
static void
handle_repositioned_xdg_popup(void *data,
struct xdg_popup *xdg_popup,
uint32_t token)
{
/* No-op, configure does all the work we care about */
}
static const struct xdg_popup_listener popup_listener_xdg = {
handle_configure_xdg_popup,
handle_done_xdg_popup,
handle_repositioned_xdg_popup
};
#define TOOLTIP_CURSOR_OFFSET 8 /* FIXME: Arbitrary, eyeballed from X tooltip */
static int
Wayland_PopupWatch(void *data, SDL_Event *event)
{
if (event->type == SDL_MOUSEMOTION) {
SDL_Window *window = (SDL_Window *) data;
SDL_WindowData *wind = window->driverdata;
/* Coordinates might be relative to the popup, which we don't want */
if (event->motion.windowID == wind->shell_surface.xdg.roleobj.popup.parentID) {
xdg_positioner_set_offset(wind->shell_surface.xdg.roleobj.popup.positioner,
event->motion.x + TOOLTIP_CURSOR_OFFSET,
event->motion.y + TOOLTIP_CURSOR_OFFSET);
xdg_popup_reposition(wind->shell_surface.xdg.roleobj.popup.popup,
wind->shell_surface.xdg.roleobj.popup.positioner,
0);
}
}
return 1;
}
#ifdef HAVE_LIBDECOR_H
static void
decoration_frame_configure(struct libdecor_frame *frame,
@ -399,17 +753,23 @@ decoration_frame_configure(struct libdecor_frame *frame,
* Always assume the configure is wrong.
*/
if (fullscreen) {
/* FIXME: We have been explicitly told to respect the fullscreen size
* parameters here, even though they are known to be wrong on GNOME at
* bare minimum. If this is wrong, don't blame us, we were explicitly
* told to do this.
*/
if (!libdecor_configuration_get_content_size(configuration, frame,
&width, &height)) {
width = window->w;
height = window->h;
if (!NeedFullscreenViewport(window)) {
/* FIXME: We have been explicitly told to respect the fullscreen size
* parameters here, even though they are known to be wrong on GNOME at
* bare minimum. If this is wrong, don't blame us, we were explicitly
* told to do this.
*/
if (!libdecor_configuration_get_content_size(configuration, frame,
&width, &height)) {
width = window->w;
height = window->h;
}
} else {
GetFullScreenDimensions(window, &width, &height, NULL, NULL);
}
wind->needs_resize_event = SDL_TRUE;
/* This part is good though. */
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
scale_factor = driverdata->scale_factor;
@ -445,7 +805,7 @@ decoration_frame_configure(struct libdecor_frame *frame,
wind->shell_surface.libdecor.initial_configure_seen = SDL_TRUE;
/* ... then commit the changes on the libdecor side. */
state = libdecor_state_new(width, height);
state = libdecor_state_new(GetWindowWidth(window), GetWindowHeight(window));
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
@ -554,9 +914,28 @@ Wayland_move_window(SDL_Window *window,
int i, numdisplays = SDL_GetNumVideoDisplays();
for (i = 0; i < numdisplays; i += 1) {
if (SDL_GetDisplay(i)->driverdata == driverdata) {
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED,
SDL_WINDOWPOS_CENTERED_DISPLAY(i),
SDL_WINDOWPOS_CENTERED_DISPLAY(i));
/* We want to send a very very specific combination here:
*
* 1. A coordinate that tells the application what display we're on
* 2. Exactly (0, 0)
*
* Part 1 is useful information but is also really important for
* ensuring we end up on the right display for fullscreen, while
* part 2 is important because numerous applications use a specific
* combination of GetWindowPosition and GetGlobalMouseState, and of
* course neither are supported by Wayland. Since global mouse will
* fall back to just GetMouseState, we need the window position to
* be zero so the cursor math works without it going off in some
* random direction. See UE5 Editor for a notable example of this!
*
* This may be an issue some day if we're ever able to implement
* SDL_GetDisplayUsableBounds!
*
* -flibit
*/
SDL_Rect bounds;
SDL_GetDisplayBounds(i, &bounds);
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, bounds.x, bounds.y);
break;
}
}
@ -624,6 +1003,19 @@ static const struct wl_surface_listener surface_listener = {
handle_surface_leave
};
static void
Wayland_FillEmptyShellInfo(SDL_SysWMinfo * info, const Uint32 version)
{
info->info.wl.xdg_surface = NULL;
if (version >= SDL_VERSIONNUM(2, 0, 17)) {
info->info.wl.xdg_toplevel = NULL;
if (version >= SDL_VERSIONNUM(2, 0, 22)) {
info->info.wl.xdg_popup = NULL;
info->info.wl.xdg_positioner = NULL;
}
}
}
SDL_bool
Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
{
@ -656,23 +1048,40 @@ Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
info->info.wl.egl_window = data->egl_window;
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor && data->shell_surface.libdecor.frame != NULL) {
info->info.wl.xdg_surface = libdecor_frame_get_xdg_surface(data->shell_surface.libdecor.frame);
if (version >= SDL_VERSIONNUM(2, 0, 17)) {
info->info.wl.xdg_toplevel = libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame);
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (data->shell_surface.libdecor.frame != NULL) {
info->info.wl.xdg_surface = libdecor_frame_get_xdg_surface(data->shell_surface.libdecor.frame);
if (version >= SDL_VERSIONNUM(2, 0, 17)) {
info->info.wl.xdg_toplevel = libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame);
if (version >= SDL_VERSIONNUM(2, 0, 22)) {
info->info.wl.xdg_popup = NULL;
info->info.wl.xdg_positioner = NULL;
}
}
} else {
/* Not mapped yet */
Wayland_FillEmptyShellInfo(info, version);
}
} else
#endif
if (viddata->shell.xdg && data->shell_surface.xdg.surface != NULL) {
info->info.wl.xdg_surface = data->shell_surface.xdg.surface;
if (version >= SDL_VERSIONNUM(2, 0, 17)) {
info->info.wl.xdg_toplevel = data->shell_surface.xdg.roleobj.toplevel;
SDL_bool popup = WINDOW_IS_XDG_POPUP(window);
info->info.wl.xdg_toplevel = popup ? NULL : data->shell_surface.xdg.roleobj.toplevel;
if (version >= SDL_VERSIONNUM(2, 0, 22)) {
if (popup) {
info->info.wl.xdg_popup = data->shell_surface.xdg.roleobj.popup.popup;
info->info.wl.xdg_positioner = data->shell_surface.xdg.roleobj.popup.positioner;
} else {
info->info.wl.xdg_popup = NULL;
info->info.wl.xdg_positioner = NULL;
}
}
}
} else {
info->info.wl.xdg_surface = NULL;
if (version >= SDL_VERSIONNUM(2, 0, 17)) {
info->info.wl.xdg_toplevel = NULL;
}
/* Either it's not mapped yet or we don't have a shell protocol */
Wayland_FillEmptyShellInfo(info, version);
}
}
@ -697,6 +1106,10 @@ Wayland_SetWindowModalFor(_THIS, SDL_Window *modal_window, SDL_Window *parent_wi
SDL_WindowData *modal_data = modal_window->driverdata;
SDL_WindowData *parent_data = parent_window->driverdata;
if (WINDOW_IS_XDG_POPUP(modal_window) || WINDOW_IS_XDG_POPUP(parent_window)) {
return SDL_SetError("Modal/Parent was a popup, not a toplevel");
}
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (modal_data->shell_surface.libdecor.frame == NULL) {
@ -731,9 +1144,26 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
SDL_VideoData *c = _this->driverdata;
SDL_WindowData *data = window->driverdata;
/* Create the shell surface and map the toplevel */
/* Detach any previous buffers before resetting everything, otherwise when
* calling this a second time you'll get an annoying protocol error!
*
* FIXME: This was originally moved to HideWindow, which _should_ make
* sense, but for whatever reason UE5's popups require that this actually
* be in both places at once? Possibly from renderers making commits? I can't
* fully remember if this location caused crashes or if I was fixing a pair
* of Hide/Show calls. In any case, UE gives us a pretty good test and having
* both detach calls passes. This bug may be relevant if I'm wrong:
*
* https://bugs.kde.org/show_bug.cgi?id=448856
*
* -flibit
*/
wl_surface_attach(data->surface, NULL, 0, 0);
wl_surface_commit(data->surface);
/* Create the shell surface and map the toplevel/popup */
#ifdef HAVE_LIBDECOR_H
if (c->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(c, window)) {
data->shell_surface.libdecor.frame = libdecor_decorate(c->shell.libdecor,
data->surface,
&libdecor_frame_interface,
@ -751,10 +1181,42 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
xdg_surface_set_user_data(data->shell_surface.xdg.surface, data);
xdg_surface_add_listener(data->shell_surface.xdg.surface, &shell_surface_listener_xdg, data);
/* !!! FIXME: add popup role */
data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface);
xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname);
xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data);
if (WINDOW_IS_XDG_POPUP(window)) {
SDL_Mouse *mouse = SDL_GetMouse();
SDL_Window *focused = SDL_GetMouseFocus();
SDL_WindowData *focuseddata = focused->driverdata;
/* This popup may be a child of another popup! */
data->shell_surface.xdg.roleobj.popup.parentID = SDL_GetWindowID(focused);
data->shell_surface.xdg.roleobj.popup.child = NULL;
if (WINDOW_IS_XDG_POPUP(focused)) {
SDL_assert(focuseddata->shell_surface.xdg.roleobj.popup.child == NULL);
focuseddata->shell_surface.xdg.roleobj.popup.child = window;
}
/* Set up the positioner for the popup */
data->shell_surface.xdg.roleobj.popup.positioner = xdg_wm_base_create_positioner(c->shell.xdg);
xdg_positioner_set_offset(data->shell_surface.xdg.roleobj.popup.positioner,
mouse->x + TOOLTIP_CURSOR_OFFSET,
mouse->y + TOOLTIP_CURSOR_OFFSET);
/* Assign the popup role */
data->shell_surface.xdg.roleobj.popup.popup = xdg_surface_get_popup(data->shell_surface.xdg.surface,
focuseddata->shell_surface.xdg.surface,
data->shell_surface.xdg.roleobj.popup.positioner);
xdg_popup_add_listener(data->shell_surface.xdg.roleobj.popup.popup, &popup_listener_xdg, data);
/* For tooltips, track mouse motion so it follows the cursor */
if (window->flags & SDL_WINDOW_TOOLTIP) {
if (xdg_popup_get_version(data->shell_surface.xdg.roleobj.popup.popup) >= 3) {
SDL_AddEventWatch(Wayland_PopupWatch, window);
}
}
} else {
data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface);
xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname);
xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data);
}
}
/* Restore state that was set prior to this call */
@ -770,7 +1232,7 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
* this surface will fail. This is a new rule for xdg_shell.
*/
#ifdef HAVE_LIBDECOR_H
if (c->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(c, window)) {
if (data->shell_surface.libdecor.frame) {
while (!data->shell_surface.libdecor.initial_configure_seen) {
WAYLAND_wl_display_flush(c->display);
@ -794,7 +1256,7 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
}
/* Create the window decorations */
if (data->shell_surface.xdg.roleobj.toplevel && c->decoration_manager) {
if (!WINDOW_IS_XDG_POPUP(window) && data->shell_surface.xdg.roleobj.toplevel && c->decoration_manager) {
data->server_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(c->decoration_manager, data->shell_surface.xdg.roleobj.toplevel);
}
} else {
@ -807,11 +1269,11 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
* them immediately afterward.
*/
#ifdef HAVE_LIBDECOR_H
if (c->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(c, window)) {
/* ... but don't call it redundantly for libdecor, the decorator
* may not interpret a redundant call nicely and cause weird stuff to happen
*/
if (window->flags & SDL_WINDOW_BORDERLESS) {
if (data->shell_surface.libdecor.frame && window->flags & SDL_WINDOW_BORDERLESS) {
Wayland_SetWindowBordered(_this, window, SDL_FALSE);
}
} else
@ -837,6 +1299,42 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
}
}
static void
Wayland_ReleasePopup(_THIS, SDL_Window *popup)
{
SDL_WindowData *popupdata;
/* Basic sanity checks to weed out the weird popup closures */
if (popup == NULL || popup->magic != &_this->window_magic) {
return;
}
popupdata = popup->driverdata;
if (popupdata == NULL) {
return;
}
/* This may already be freed by a parent popup! */
if (popupdata->shell_surface.xdg.roleobj.popup.popup == NULL) {
return;
}
/* Release the child _first_, otherwise a protocol error triggers */
if (popupdata->shell_surface.xdg.roleobj.popup.child != NULL) {
Wayland_ReleasePopup(_this, popupdata->shell_surface.xdg.roleobj.popup.child);
popupdata->shell_surface.xdg.roleobj.popup.child = NULL;
}
if (popup->flags & SDL_WINDOW_TOOLTIP) {
if (xdg_popup_get_version(popupdata->shell_surface.xdg.roleobj.popup.popup) >= 3) {
SDL_DelEventWatch(Wayland_PopupWatch, popup);
}
}
xdg_popup_destroy(popupdata->shell_surface.xdg.roleobj.popup.popup);
xdg_positioner_destroy(popupdata->shell_surface.xdg.roleobj.popup.positioner);
popupdata->shell_surface.xdg.roleobj.popup.popup = NULL;
popupdata->shell_surface.xdg.roleobj.popup.positioner = NULL;
}
void Wayland_HideWindow(_THIS, SDL_Window *window)
{
SDL_VideoData *data = _this->driverdata;
@ -848,7 +1346,7 @@ void Wayland_HideWindow(_THIS, SDL_Window *window)
}
#ifdef HAVE_LIBDECOR_H
if (data->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(data, window)) {
if (wind->shell_surface.libdecor.frame) {
libdecor_frame_unref(wind->shell_surface.libdecor.frame);
wind->shell_surface.libdecor.frame = NULL;
@ -856,7 +1354,9 @@ void Wayland_HideWindow(_THIS, SDL_Window *window)
} else
#endif
if (data->shell.xdg) {
if (wind->shell_surface.xdg.roleobj.toplevel) {
if (WINDOW_IS_XDG_POPUP(window)) {
Wayland_ReleasePopup(_this, window);
} else if (wind->shell_surface.xdg.roleobj.toplevel) {
xdg_toplevel_destroy(wind->shell_surface.xdg.roleobj.toplevel);
wind->shell_surface.xdg.roleobj.toplevel = NULL;
}
@ -1073,13 +1573,17 @@ Wayland_RestoreWindow(_THIS, SDL_Window * window)
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
if (WINDOW_IS_XDG_POPUP(window)) {
return;
}
/* Set this flag now even if we never actually maximized, eventually
* ShowWindow will take care of it along with the other window state.
*/
window->flags &= ~SDL_WINDOW_MAXIMIZED;
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -1102,8 +1606,13 @@ Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
{
SDL_WindowData *wind = window->driverdata;
const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
if (WINDOW_IS_XDG_POPUP(window)) {
return;
}
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame) {
libdecor_frame_set_visibility(wind->shell_surface.libdecor.frame, bordered);
}
@ -1122,7 +1631,7 @@ Wayland_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
SDL_VideoData *data = _this->driverdata;
const SDL_WindowData *wind = window->driverdata;
if (data->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(data, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -1144,6 +1653,10 @@ Wayland_MaximizeWindow(_THIS, SDL_Window * window)
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
if (WINDOW_IS_XDG_POPUP(window)) {
return;
}
if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
return;
}
@ -1154,7 +1667,7 @@ Wayland_MaximizeWindow(_THIS, SDL_Window * window)
window->flags |= SDL_WINDOW_MAXIMIZED;
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -1177,8 +1690,12 @@ Wayland_MinimizeWindow(_THIS, SDL_Window * window)
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
if (WINDOW_IS_XDG_POPUP(window)) {
return;
}
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -1269,7 +1786,9 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
data->waylandData = c;
data->sdlwindow = window;
data->scale_factor = 1.0;
data->scale_factor = 1.0f;
data->pointer_scale_x = 1.0f;
data->pointer_scale_y = 1.0f;
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
int i;
@ -1316,16 +1835,18 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
data->drawable_width = window->w * data->scale_factor;
data->drawable_height = window->h * data->scale_factor;
if (window->flags & SDL_WINDOW_OPENGL) {
data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
window->w * data->scale_factor, window->h * data->scale_factor);
data->egl_window = WAYLAND_wl_egl_window_create(data->surface, data->drawable_width, data->drawable_height);
#if SDL_VIDEO_OPENGL_EGL
/* Create the GLES window surface */
data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
if (data->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("failed to create an EGL window surface");
return -1; /* SDL_EGL_CreateSurface should have set error */
}
#endif
}
@ -1375,12 +1896,13 @@ Wayland_HandleResize(SDL_Window *window, int width, int height, float scale)
data->needs_resize_event = SDL_FALSE;
}
wl_surface_set_buffer_scale(data->surface, data->scale_factor);
/* Configure the backbuffer size and scale factors */
SetDrawScale(window);
if (data->egl_window) {
WAYLAND_wl_egl_window_resize(data->egl_window,
window->w * data->scale_factor,
window->h * data->scale_factor,
data->drawable_width,
data->drawable_height,
0, 0);
}
@ -1394,9 +1916,18 @@ Wayland_HandleResize(SDL_Window *window, int width, int height, float scale)
* It doesn't fix the first frames after resize being glitched visually,
* but at least lets us not be terminated by the compositor.
* Can be removed once SDL's resize logic becomes compliant. */
if (viddata->shell.xdg && data->shell_surface.xdg.surface) {
xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, window->w, window->h);
if (
#ifdef HAVE_LIBDECOR_H
!WINDOW_IS_LIBDECOR(viddata, window) &&
#endif
viddata->shell.xdg &&
data->shell_surface.xdg.surface) {
xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0,
GetWindowWidth(window), GetWindowHeight(window));
}
/* Update the viewport */
ConfigureViewport(window);
}
void
@ -1422,7 +1953,7 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window)
#ifdef HAVE_LIBDECOR_H
/* we must not resize the window while we have a static (non-floating) size */
if (data->shell.libdecor &&
if (WINDOW_IS_LIBDECOR(data, window) &&
wind->shell_surface.libdecor.frame &&
!libdecor_frame_is_floating(wind->shell_surface.libdecor.frame)) {
/* Commit the resize when we re-enter floating state */
@ -1431,18 +1962,18 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window)
}
#endif
wl_surface_set_buffer_scale(wind->surface, wind->scale_factor);
SetDrawScale(window);
if (wind->egl_window) {
WAYLAND_wl_egl_window_resize(wind->egl_window,
window->w * wind->scale_factor,
window->h * wind->scale_factor,
wind->drawable_width,
wind->drawable_height,
0, 0);
}
#ifdef HAVE_LIBDECOR_H
if (data->shell.libdecor && wind->shell_surface.libdecor.frame) {
state = libdecor_state_new(window->w, window->h);
if (WINDOW_IS_LIBDECOR(data, window) && wind->shell_surface.libdecor.frame) {
state = libdecor_state_new(GetWindowWidth(window), GetWindowHeight(window));
libdecor_frame_commit(wind->shell_surface.libdecor.frame, state, NULL);
libdecor_state_free(state);
}
@ -1458,8 +1989,14 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window)
wl_region_destroy(region);
/* Update the geometry which may have been set by a hack in Wayland_HandleResize */
if (data->shell.xdg && wind->shell_surface.xdg.surface) {
xdg_surface_set_window_geometry(wind->shell_surface.xdg.surface, 0, 0, window->w, window->h);
if (
#ifdef HAVE_LIBDECOR_H
!WINDOW_IS_LIBDECOR(data, window) &&
#endif
data->shell.xdg &&
wind->shell_surface.xdg.surface) {
xdg_surface_set_window_geometry(wind->shell_surface.xdg.surface, 0, 0,
GetWindowWidth(window), GetWindowHeight(window));
}
}
@ -1468,9 +2005,13 @@ void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *viddata = _this->driverdata;
if (WINDOW_IS_XDG_POPUP(window)) {
return;
}
if (window->title != NULL) {
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -1549,6 +2090,10 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window)
xdg_activation_token_v1_destroy(wind->activation_token);
}
if (wind->viewport) {
wp_viewport_destroy(wind->viewport);
}
SDL_free(wind->outputs);
if (wind->frame_callback) {

View file

@ -36,16 +36,27 @@ typedef struct {
struct xdg_surface *surface;
union {
struct xdg_toplevel *toplevel;
struct xdg_popup *popup;
struct {
struct xdg_popup *popup;
struct xdg_positioner *positioner;
Uint32 parentID;
SDL_Window *child;
} popup;
} roleobj;
SDL_bool initial_configure_seen;
} SDL_xdg_shell_surface;
#define WINDOW_IS_XDG_POPUP(window) \
(window->flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU))
#ifdef HAVE_LIBDECOR_H
typedef struct {
struct libdecor_frame *frame;
SDL_bool initial_configure_seen;
} SDL_libdecor_surface;
#define WINDOW_IS_LIBDECOR(viddata, window) \
(viddata->shell.libdecor && !WINDOW_IS_XDG_POPUP(window))
#endif
typedef struct {
@ -72,6 +83,7 @@ typedef struct {
struct zwp_keyboard_shortcuts_inhibitor_v1 *key_inhibitor;
struct zwp_idle_inhibitor_v1 *idle_inhibitor;
struct xdg_activation_token_v1 *activation_token;
struct wp_viewport *viewport;
/* floating dimensions for restoring from maximized and fullscreen */
int floating_width, floating_height;
@ -86,6 +98,10 @@ typedef struct {
int num_outputs;
float scale_factor;
float pointer_scale_x;
float pointer_scale_y;
int drawable_width, drawable_height;
SDL_Rect damage_region;
SDL_bool needs_resize_event;
SDL_bool floating_resize_pending;
} SDL_WindowData;

View file

@ -378,14 +378,14 @@ WIN_CheckAsyncMouseRelease(SDL_WindowData *data)
}
static void
WIN_UpdateFocus(SDL_Window *window)
WIN_UpdateFocus(SDL_Window *window, SDL_bool expect_focus)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
HWND hwnd = data->hwnd;
SDL_bool had_focus = (SDL_GetKeyboardFocus() == window) ? SDL_TRUE : SDL_FALSE;
SDL_bool has_focus = (GetForegroundWindow() == hwnd) ? SDL_TRUE : SDL_FALSE;
if (had_focus == has_focus) {
if (had_focus == has_focus || has_focus != expect_focus) {
return;
}
@ -686,7 +686,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
/* Update the focus here, since it's possible to get WM_ACTIVATE and WM_SETFOCUS without
actually being the foreground window, but this appears to get called in all cases where
the global foreground window changes to and from this window. */
WIN_UpdateFocus(data->window);
WIN_UpdateFocus(data->window, !!wParam);
WIN_CheckICMProfileChanged(data->window);
}
break;
@ -694,16 +694,22 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_ACTIVATE:
{
/* Update the focus in case we changed focus to a child window and then away from the application */
WIN_UpdateFocus(data->window);
WIN_UpdateFocus(data->window, !!LOWORD(wParam));
}
break;
case WM_SETFOCUS:
{
/* Update the focus in case it's changing between top-level windows in the same application */
WIN_UpdateFocus(data->window, SDL_TRUE);
}
break;
case WM_KILLFOCUS:
case WM_ENTERIDLE:
{
/* Update the focus in case it's changing between top-level windows in the same application */
WIN_UpdateFocus(data->window);
WIN_UpdateFocus(data->window, SDL_FALSE);
}
break;

View file

@ -158,7 +158,7 @@ WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags)
int w, h;
/* Figure out what the window area will be */
if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || (window->flags & SDL_WINDOW_ALWAYS_ON_TOP))) {
if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) {
top = HWND_TOPMOST;
} else {
top = HWND_NOTOPMOST;
@ -734,7 +734,14 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
int x, y;
int w, h;
if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) {
if (!fullscreen && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0) {
/* Resizing the window on hide causes problems restoring it in Wine, and it's unnecessary.
* Also, Windows would preview the minimized window with the wrong size.
*/
return;
}
if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) {
top = HWND_TOPMOST;
} else {
top = HWND_NOTOPMOST;

View file

@ -380,7 +380,7 @@ X11_GetScrollLockModifierMask(_THIS)
return num_mask;
}
static void
void
X11_ReconcileKeyboardState(_THIS)
{
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
@ -408,7 +408,22 @@ X11_ReconcileKeyboardState(_THIS)
SDL_bool sdlKeyPressed = keyboardState[scancode] == SDL_PRESSED;
if (x11KeyPressed && !sdlKeyPressed) {
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
/* Only update modifier state for keys that are pressed in another application */
switch (SDL_GetKeyFromScancode(scancode)) {
case SDLK_LCTRL:
case SDLK_RCTRL:
case SDLK_LSHIFT:
case SDLK_RSHIFT:
case SDLK_LALT:
case SDLK_RALT:
case SDLK_LGUI:
case SDLK_RGUI:
case SDLK_MODE:
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
break;
default:
break;
}
} else if (!x11KeyPressed && sdlKeyPressed) {
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
}
@ -718,7 +733,6 @@ static void
X11_DispatchEvent(_THIS, XEvent *xevent)
{
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
XkbEvent* xkbEvent = (XkbEvent*) xevent;
Display *display;
SDL_WindowData *data;
int orig_event_type;
@ -805,11 +819,13 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
if (!data) {
/* The window for KeymapNotify, etc events is 0 */
if (xevent->type == KeymapNotify) {
#ifdef DEBUG_XEVENTS
printf("window %p: KeymapNotify!\n", data);
#endif
if (SDL_GetKeyboardFocus() != NULL) {
X11_ReconcileKeyboardState(_this);
}
} else if (xevent->type == MappingNotify ||
(xevent->type == videodata->xkb_event && xkbEvent->any.xkb_type == XkbStateNotify)) {
} else if (xevent->type == MappingNotify) {
/* Has the keyboard layout changed? */
const int request = xevent->xmapping.request;
@ -996,8 +1012,9 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
}
break;
/* Key press? */
case KeyPress:{
/* Key press/release? */
case KeyPress:
case KeyRelease: {
KeyCode keycode = xevent->xkey.keycode;
KeySym keysym = NoSymbol;
char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
@ -1005,7 +1022,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
SDL_bool handled_by_ime = SDL_FALSE;
#ifdef DEBUG_XEVENTS
printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent->xkey.keycode);
printf("window %p: %s (X11 keycode = 0x%X)\n", data, (xevent->type == KeyPress ? "KeyPress" : "KeyRelease"), xevent->xkey.keycode);
#endif
#if 1
if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) {
@ -1021,7 +1038,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
/* */
SDL_zeroa(text);
#ifdef X_HAVE_UTF8_STRING
if (data->ic) {
if (data->ic && xevent->type == KeyPress) {
X11_Xutf8LookupString(data->ic, &xevent->xkey, text, sizeof(text),
&keysym, &status);
} else {
@ -1033,35 +1050,30 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
#ifdef SDL_USE_IME
if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode);
handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode, (xevent->type == KeyPress ? SDL_PRESSED : SDL_RELEASED));
}
#endif
if (!handled_by_ime) {
/* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */
if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) {
SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
}
if(*text) {
SDL_SendKeyboardText(text);
if (xevent->type == KeyPress) {
/* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */
if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) {
SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
}
if(*text) {
SDL_SendKeyboardText(text);
}
} else {
if (X11_KeyRepeat(display, xevent)) {
/* We're about to get a repeated key down, ignore the key up */
break;
}
SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
}
}
X11_UpdateUserTime(data, xevent->xkey.time);
}
break;
/* Key release? */
case KeyRelease:{
KeyCode keycode = xevent->xkey.keycode;
#ifdef DEBUG_XEVENTS
printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent->xkey.keycode);
#endif
if (X11_KeyRepeat(display, xevent)) {
/* We're about to get a repeated key down, ignore the key up */
break;
if (xevent->type == KeyPress) {
X11_UpdateUserTime(data, xevent->xkey.time);
}
SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
}
break;

View file

@ -27,6 +27,7 @@ extern void X11_PumpEvents(_THIS);
extern int X11_WaitEventTimeout(_THIS, int timeout);
extern void X11_SendWakeupEvent(_THIS, SDL_Window *window);
extern void X11_SuspendScreenSaver(_THIS);
extern void X11_ReconcileKeyboardState(_THIS);
#endif /* SDL_x11events_h_ */

View file

@ -409,6 +409,8 @@ X11_InitKeyboard(_THIS)
SDL_IME_Init();
#endif
X11_ReconcileKeyboardState(_this);
return 0;
}

View file

@ -830,10 +830,11 @@ X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
int exitcode = 0;
close(fds[0]);
status = X11_ShowMessageBoxImpl(messageboxdata, buttonid);
if (write(fds[1], &status, sizeof (int)) != sizeof (int))
if (write(fds[1], &status, sizeof (int)) != sizeof (int)) {
exitcode = 1;
else if (write(fds[1], buttonid, sizeof (int)) != sizeof (int))
} else if (write(fds[1], buttonid, sizeof (int)) != sizeof (int)) {
exitcode = 1;
}
close(fds[1]);
_exit(exitcode); /* don't run atexit() stuff, static destructors, etc. */
} else { /* we're the parent */
@ -846,13 +847,12 @@ X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
SDL_assert(rc == pid); /* not sure what to do if this fails. */
if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) {
return SDL_SetError("msgbox child process failed");
status = SDL_SetError("msgbox child process failed");
} else if ( (read(fds[0], &status, sizeof (int)) != sizeof (int)) ||
(read(fds[0], buttonid, sizeof (int)) != sizeof (int)) ) {
status = SDL_SetError("read from msgbox child process failed");
*buttonid = 0;
}
if (read(fds[0], &status, sizeof (int)) != sizeof (int))
status = -1;
else if (read(fds[0], buttonid, sizeof (int)) != sizeof (int))
status = -1;
close(fds[0]);
return status;

View file

@ -1011,7 +1011,13 @@ static int (*PreXRRSetScreenSizeErrorHandler)(Display *, XErrorEvent *) = NULL;
static int
SDL_XRRSetScreenSizeErrHandler(Display *d, XErrorEvent *e)
{
return (e->error_code == BadMatch) ? 0 : PreXRRSetScreenSizeErrorHandler(d, e);
/* BadMatch: https://github.com/libsdl-org/SDL/issues/4561 */
/* BadValue: https://github.com/libsdl-org/SDL/issues/4840 */
if ((e->error_code == BadMatch) || (e->error_code == BadValue)) {
return 0;
}
return PreXRRSetScreenSizeErrorHandler(d, e);
}
int

View file

@ -247,11 +247,6 @@ X11_GL_LoadLibrary(_THIS, const char *path)
X11_GL_UseEGL(_this) ) {
#if SDL_VIDEO_OPENGL_EGL
X11_GL_UnloadLibrary(_this);
/* Better avoid conflicts! */
if (_this->gl_config.dll_handle != NULL ) {
GL_UnloadObject(_this->gl_config.dll_handle);
_this->gl_config.dll_handle = NULL;
}
_this->GL_LoadLibrary = X11_GLES_LoadLibrary;
_this->GL_GetProcAddress = X11_GLES_GetProcAddress;
_this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;

View file

@ -185,7 +185,6 @@ SDL_X11_SYM(XkbDescPtr,XkbGetMap,(Display* a,unsigned int b,unsigned int c),(a,b
SDL_X11_SYM(void,XkbFreeClientMap,(XkbDescPtr a,unsigned int b, Bool c),(a,b,c),)
SDL_X11_SYM(void,XkbFreeKeyboard,(XkbDescPtr a,unsigned int b, Bool c),(a,b,c),)
SDL_X11_SYM(Bool,XkbSetDetectableAutoRepeat,(Display* a, Bool b, Bool* c),(a,b,c),return)
SDL_X11_SYM(Bool,XkbSelectEvents,(Display* a, unsigned int b, unsigned int c, unsigned int d),(a,b,c,d),return)
#endif
#if NeedWidePrototypes

View file

@ -678,8 +678,6 @@ X11_CreateWindow(_THIS, SDL_Window * window)
/* For _ICC_PROFILE. */
X11_XSelectInput(display, RootWindow(display, screen), PropertyChangeMask);
X11_XkbSelectEvents(display, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask);
X11_XFlush(display);
return 0;
@ -782,11 +780,22 @@ X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
X11_XFlush(display);
}
static SDL_bool caught_x11_error = SDL_FALSE;
static int
X11_CatchAnyError(Display * d, XErrorEvent * e)
{
/* this may happen during tumultuous times when we are polling anyhow,
so just note we had an error and return control. */
caught_x11_error = SDL_TRUE;
return 0;
}
void
X11_SetWindowPosition(_THIS, SDL_Window * window)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
Display *display = data->videodata->display;
int (*prev_handler) (Display *, XErrorEvent *) = NULL;
unsigned int childCount;
Window childReturn, root, parent;
Window* children;
@ -805,20 +814,27 @@ X11_SetWindowPosition(_THIS, SDL_Window * window)
/* Wait a brief time to see if the window manager decided to let this move happen.
If the window changes at all, even to an unexpected value, we break out. */
X11_XSync(display, False);
prev_handler = X11_XSetErrorHandler(X11_CatchAnyError);
timeout = SDL_GetTicks() + 100;
while (SDL_TRUE) {
int x, y;
caught_x11_error = SDL_FALSE;
X11_XSync(display, False);
X11_XGetWindowAttributes(display, data->xwindow, &attrs);
X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display),
attrs.x, attrs.y, &x, &y, &childReturn);
if ((x != orig_x) || (y != orig_y)) {
window->x = x;
window->y = y;
break; /* window moved, time to go. */
} else if ((x == window->x) && (y == window->y)) {
break; /* we're at the place we wanted to be anyhow, drop out. */
if (!caught_x11_error) {
if ((x != orig_x) || (y != orig_y)) {
window->x = x;
window->y = y;
break; /* window moved, time to go. */
} else if ((x == window->x) && (y == window->y)) {
break; /* we're at the place we wanted to be anyhow, drop out. */
}
}
if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
@ -827,6 +843,9 @@ X11_SetWindowPosition(_THIS, SDL_Window * window)
SDL_Delay(10);
}
X11_XSetErrorHandler(prev_handler);
caught_x11_error = SDL_FALSE;
}
void
@ -892,6 +911,7 @@ X11_SetWindowSize(_THIS, SDL_Window * window)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
Display *display = data->videodata->display;
int (*prev_handler) (Display *, XErrorEvent *) = NULL;
XWindowAttributes attrs;
int orig_w, orig_h;
Uint32 timeout;
@ -943,19 +963,25 @@ X11_SetWindowSize(_THIS, SDL_Window * window)
X11_XResizeWindow(display, data->xwindow, window->w, window->h);
}
X11_XSync(display, False);
prev_handler = X11_XSetErrorHandler(X11_CatchAnyError);
/* Wait a brief time to see if the window manager decided to let this resize happen.
If the window changes at all, even to an unexpected value, we break out. */
timeout = SDL_GetTicks() + 100;
while (SDL_TRUE) {
caught_x11_error = SDL_FALSE;
X11_XSync(display, False);
X11_XGetWindowAttributes(display, data->xwindow, &attrs);
if ((attrs.width != orig_w) || (attrs.height != orig_h)) {
window->w = attrs.width;
window->h = attrs.height;
break; /* window changed, time to go. */
} else if ((attrs.width == window->w) && (attrs.height == window->h)) {
break; /* we're at the place we wanted to be anyhow, drop out. */
if (!caught_x11_error) {
if ((attrs.width != orig_w) || (attrs.height != orig_h)) {
window->w = attrs.width;
window->h = attrs.height;
break; /* window changed, time to go. */
} else if ((attrs.width == window->w) && (attrs.height == window->h)) {
break; /* we're at the place we wanted to be anyhow, drop out. */
}
}
if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
@ -964,6 +990,9 @@ X11_SetWindowSize(_THIS, SDL_Window * window)
SDL_Delay(10);
}
X11_XSetErrorHandler(prev_handler);
caught_x11_error = SDL_FALSE;
}
int
@ -1281,6 +1310,22 @@ X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _dis
if (X11_IsWindowMapped(_this, window)) {
XEvent e;
/* !!! FIXME: most of this waiting code is copy/pasted from elsewhere. */
int (*prev_handler) (Display *, XErrorEvent *) = NULL;
unsigned int childCount;
Window childReturn, root, parent;
Window* children;
XWindowAttributes attrs;
int orig_w, orig_h, orig_x, orig_y;
Uint64 timeout;
X11_XSync(display, False);
X11_XQueryTree(display, data->xwindow, &root, &parent, &children, &childCount);
X11_XGetWindowAttributes(display, data->xwindow, &attrs);
X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display),
attrs.x, attrs.y, &orig_x, &orig_y, &childReturn);
orig_w = attrs.width;
orig_h = attrs.height;
if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
/* Compiz refuses fullscreen toggle if we're not resizable, so update the hints so we
@ -1330,6 +1375,41 @@ X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _dis
X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
SubstructureNotifyMask | SubstructureRedirectMask, &e);
}
/* Wait a brief time to see if the window manager decided to let this happen.
If the window changes at all, even to an unexpected value, we break out. */
X11_XSync(display, False);
prev_handler = X11_XSetErrorHandler(X11_CatchAnyError);
timeout = SDL_GetTicks64() + 100;
while (SDL_TRUE) {
int x, y;
caught_x11_error = SDL_FALSE;
X11_XSync(display, False);
X11_XGetWindowAttributes(display, data->xwindow, &attrs);
X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display),
attrs.x, attrs.y, &x, &y, &childReturn);
if (!caught_x11_error) {
if ((x != orig_x) || (y != orig_y) || (attrs.width != orig_w) || (attrs.height != orig_h)) {
window->x = x;
window->y = y;
window->w = attrs.width;
window->h = attrs.height;
break; /* window moved, time to go. */
}
}
if (SDL_GetTicks64() >= timeout) {
break;
}
SDL_Delay(10);
}
X11_XSetErrorHandler(prev_handler);
caught_x11_error = SDL_FALSE;
} else {
Uint32 flags;

View file

@ -426,9 +426,17 @@ void SSE_FUNCTION_NAME(uint32_t width, uint32_t height,
const int fix_read_nv12 = 0;
#endif
#if YUV_FORMAT == YUV_FORMAT_422
/* Avoid invalid read on last line */
const int fix_read_422 = 1;
#else
const int fix_read_422 = 0;
#endif
if (width >= 32) {
uint32_t xpos, ypos;
for(ypos=0; ypos<(height-(uv_y_sample_interval-1)); ypos+=uv_y_sample_interval)
for(ypos=0; ypos<(height-(uv_y_sample_interval-1)) - fix_read_422; ypos+=uv_y_sample_interval)
{
const uint8_t *y_ptr1=Y+ypos*Y_stride,
*y_ptr2=Y+(ypos+1)*Y_stride,
@ -459,6 +467,15 @@ void SSE_FUNCTION_NAME(uint32_t width, uint32_t height,
}
}
if (fix_read_422) {
const uint8_t *y_ptr=Y+ypos*Y_stride,
*u_ptr=U+(ypos/uv_y_sample_interval)*UV_stride,
*v_ptr=V+(ypos/uv_y_sample_interval)*UV_stride;
uint8_t *rgb_ptr=RGB+ypos*RGB_stride;
STD_FUNCTION_NAME(width, 1, y_ptr, u_ptr, v_ptr, Y_stride, UV_stride, rgb_ptr, RGB_stride, yuv_type);
ypos += uv_y_sample_interval;
}
/* Catch the last line, if needed */
if (uv_y_sample_interval == 2 && ypos == (height-1))
{