update sdl Merge commit '644725478f4de0f074a6834e8423ac36dce3974f'
This commit is contained in:
14
external/sdl/SDL/src/SDL_assert.c
vendored
14
external/sdl/SDL/src/SDL_assert.c
vendored
@ -34,7 +34,15 @@
|
||||
#endif
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#include <emscripten.h>
|
||||
/* older Emscriptens don't have this, but we need to for wasm64 compatibility. */
|
||||
#ifndef MAIN_THREAD_EM_ASM_PTR
|
||||
#ifdef __wasm64__
|
||||
#error You need to upgrade your Emscripten compiler to support wasm64
|
||||
#else
|
||||
#define MAIN_THREAD_EM_ASM_PTR MAIN_THREAD_EM_ASM_INT
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The size of the stack buffer to use for rendering assert messages. */
|
||||
@ -211,7 +219,7 @@ static SDL_AssertState SDLCALL SDL_PromptAssertion(const SDL_AssertData *data, v
|
||||
}
|
||||
|
||||
/* Leave fullscreen mode, if possible (scary!) */
|
||||
window = SDL_GetFocusWindow();
|
||||
window = SDL_GetToplevelForKeyboardFocus();
|
||||
if (window) {
|
||||
if (window->fullscreen_exclusive) {
|
||||
SDL_MinimizeWindow(window);
|
||||
@ -243,7 +251,7 @@ static SDL_AssertState SDLCALL SDL_PromptAssertion(const SDL_AssertData *data, v
|
||||
for (;;) {
|
||||
SDL_bool okay = SDL_TRUE;
|
||||
/* *INDENT-OFF* */ /* clang-format off */
|
||||
char *buf = (char *) EM_ASM_INT({
|
||||
char *buf = (char *) MAIN_THREAD_EM_ASM_PTR({
|
||||
var str =
|
||||
UTF8ToString($0) + '\n\n' +
|
||||
'Abort/Retry/Ignore/AlwaysIgnore? [ariA] :';
|
||||
|
318
external/sdl/SDL/src/SDL_dataqueue.c
vendored
318
external/sdl/SDL/src/SDL_dataqueue.c
vendored
@ -1,318 +0,0 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 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_dataqueue.h"
|
||||
|
||||
typedef struct SDL_DataQueuePacket
|
||||
{
|
||||
size_t datalen; /* bytes currently in use in this packet. */
|
||||
size_t startpos; /* bytes currently consumed in this packet. */
|
||||
struct SDL_DataQueuePacket *next; /* next item in linked list. */
|
||||
Uint8 data[SDL_VARIABLE_LENGTH_ARRAY]; /* packet data */
|
||||
} SDL_DataQueuePacket;
|
||||
|
||||
struct SDL_DataQueue
|
||||
{
|
||||
SDL_Mutex *lock;
|
||||
SDL_DataQueuePacket *head; /* device fed from here. */
|
||||
SDL_DataQueuePacket *tail; /* queue fills to here. */
|
||||
SDL_DataQueuePacket *pool; /* these are unused packets. */
|
||||
size_t packet_size; /* size of new packets */
|
||||
size_t queued_bytes; /* number of bytes of data in the queue. */
|
||||
};
|
||||
|
||||
static void SDL_FreeDataQueueList(SDL_DataQueuePacket *packet)
|
||||
{
|
||||
while (packet) {
|
||||
SDL_DataQueuePacket *next = packet->next;
|
||||
SDL_free(packet);
|
||||
packet = next;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_DataQueue *SDL_CreateDataQueue(const size_t _packetlen, const size_t initialslack)
|
||||
{
|
||||
SDL_DataQueue *queue = (SDL_DataQueue *)SDL_calloc(1, sizeof(SDL_DataQueue));
|
||||
|
||||
if (queue == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
} else {
|
||||
const size_t packetlen = _packetlen ? _packetlen : 1024;
|
||||
const size_t wantpackets = (initialslack + (packetlen - 1)) / packetlen;
|
||||
size_t i;
|
||||
|
||||
queue->packet_size = packetlen;
|
||||
|
||||
queue->lock = SDL_CreateMutex();
|
||||
if (!queue->lock) {
|
||||
SDL_free(queue);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < wantpackets; i++) {
|
||||
SDL_DataQueuePacket *packet = (SDL_DataQueuePacket *)SDL_malloc(sizeof(SDL_DataQueuePacket) + packetlen);
|
||||
if (packet) { /* don't care if this fails, we'll deal later. */
|
||||
packet->datalen = 0;
|
||||
packet->startpos = 0;
|
||||
packet->next = queue->pool;
|
||||
queue->pool = packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
void SDL_DestroyDataQueue(SDL_DataQueue *queue)
|
||||
{
|
||||
if (queue) {
|
||||
SDL_FreeDataQueueList(queue->head);
|
||||
SDL_FreeDataQueueList(queue->pool);
|
||||
SDL_DestroyMutex(queue->lock);
|
||||
SDL_free(queue);
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack)
|
||||
{
|
||||
const size_t packet_size = queue ? queue->packet_size : 1;
|
||||
const size_t slackpackets = (slack + (packet_size - 1)) / packet_size;
|
||||
SDL_DataQueuePacket *packet;
|
||||
SDL_DataQueuePacket *prev = NULL;
|
||||
size_t i;
|
||||
|
||||
if (queue == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_LockMutex(queue->lock);
|
||||
|
||||
packet = queue->head;
|
||||
|
||||
/* merge the available pool and the current queue into one list. */
|
||||
if (packet) {
|
||||
queue->tail->next = queue->pool;
|
||||
} else {
|
||||
packet = queue->pool;
|
||||
}
|
||||
|
||||
/* Remove the queued packets from the device. */
|
||||
queue->tail = NULL;
|
||||
queue->head = NULL;
|
||||
queue->queued_bytes = 0;
|
||||
queue->pool = packet;
|
||||
|
||||
/* Optionally keep some slack in the pool to reduce memory allocation pressure. */
|
||||
for (i = 0; packet && (i < slackpackets); i++) {
|
||||
prev = packet;
|
||||
packet = packet->next;
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
prev->next = NULL;
|
||||
} else {
|
||||
queue->pool = NULL;
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(queue->lock);
|
||||
|
||||
SDL_FreeDataQueueList(packet); /* free extra packets */
|
||||
}
|
||||
|
||||
/* You must hold queue->lock before calling this! */
|
||||
static SDL_DataQueuePacket *AllocateDataQueuePacket(SDL_DataQueue *queue)
|
||||
{
|
||||
SDL_DataQueuePacket *packet;
|
||||
|
||||
SDL_assert(queue != NULL);
|
||||
|
||||
packet = queue->pool;
|
||||
if (packet != NULL) {
|
||||
/* we have one available in the pool. */
|
||||
queue->pool = packet->next;
|
||||
} else {
|
||||
/* Have to allocate a new one! */
|
||||
packet = (SDL_DataQueuePacket *)SDL_malloc(sizeof(SDL_DataQueuePacket) + queue->packet_size);
|
||||
if (packet == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
packet->datalen = 0;
|
||||
packet->startpos = 0;
|
||||
packet->next = NULL;
|
||||
|
||||
SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
|
||||
if (queue->tail == NULL) {
|
||||
queue->head = packet;
|
||||
} else {
|
||||
queue->tail->next = packet;
|
||||
}
|
||||
queue->tail = packet;
|
||||
return packet;
|
||||
}
|
||||
|
||||
int SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
|
||||
{
|
||||
size_t len = _len;
|
||||
const Uint8 *data = (const Uint8 *)_data;
|
||||
const size_t packet_size = queue ? queue->packet_size : 0;
|
||||
SDL_DataQueuePacket *orighead;
|
||||
SDL_DataQueuePacket *origtail;
|
||||
size_t origlen;
|
||||
size_t datalen;
|
||||
|
||||
if (queue == NULL) {
|
||||
return SDL_InvalidParamError("queue");
|
||||
}
|
||||
|
||||
SDL_LockMutex(queue->lock);
|
||||
|
||||
orighead = queue->head;
|
||||
origtail = queue->tail;
|
||||
origlen = origtail ? origtail->datalen : 0;
|
||||
|
||||
while (len > 0) {
|
||||
SDL_DataQueuePacket *packet = queue->tail;
|
||||
SDL_assert(packet == NULL || (packet->datalen <= packet_size));
|
||||
if (packet == NULL || (packet->datalen >= packet_size)) {
|
||||
/* tail packet missing or completely full; we need a new packet. */
|
||||
packet = AllocateDataQueuePacket(queue);
|
||||
if (packet == NULL) {
|
||||
/* uhoh, reset so we've queued nothing new, free what we can. */
|
||||
if (origtail == NULL) {
|
||||
packet = queue->head; /* whole queue. */
|
||||
} else {
|
||||
packet = origtail->next; /* what we added to existing queue. */
|
||||
origtail->next = NULL;
|
||||
origtail->datalen = origlen;
|
||||
}
|
||||
queue->head = orighead;
|
||||
queue->tail = origtail;
|
||||
queue->pool = NULL;
|
||||
|
||||
SDL_UnlockMutex(queue->lock);
|
||||
SDL_FreeDataQueueList(packet); /* give back what we can. */
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
}
|
||||
|
||||
datalen = SDL_min(len, packet_size - packet->datalen);
|
||||
SDL_memcpy(packet->data + packet->datalen, data, datalen);
|
||||
data += datalen;
|
||||
len -= datalen;
|
||||
packet->datalen += datalen;
|
||||
queue->queued_bytes += datalen;
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(queue->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t SDL_PeekIntoDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
|
||||
{
|
||||
size_t len = _len;
|
||||
Uint8 *buf = (Uint8 *)_buf;
|
||||
Uint8 *ptr = buf;
|
||||
SDL_DataQueuePacket *packet;
|
||||
|
||||
if (queue == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_LockMutex(queue->lock);
|
||||
|
||||
for (packet = queue->head; len && packet; packet = packet->next) {
|
||||
const size_t avail = packet->datalen - packet->startpos;
|
||||
const size_t cpy = SDL_min(len, avail);
|
||||
SDL_assert(queue->queued_bytes >= avail);
|
||||
|
||||
SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
|
||||
ptr += cpy;
|
||||
len -= cpy;
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(queue->lock);
|
||||
|
||||
return (size_t)(ptr - buf);
|
||||
}
|
||||
|
||||
size_t SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
|
||||
{
|
||||
size_t len = _len;
|
||||
Uint8 *buf = (Uint8 *)_buf;
|
||||
Uint8 *ptr = buf;
|
||||
SDL_DataQueuePacket *packet;
|
||||
|
||||
if (queue == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_LockMutex(queue->lock);
|
||||
|
||||
while ((len > 0) && ((packet = queue->head) != NULL)) {
|
||||
const size_t avail = packet->datalen - packet->startpos;
|
||||
const size_t cpy = SDL_min(len, avail);
|
||||
SDL_assert(queue->queued_bytes >= avail);
|
||||
|
||||
SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
|
||||
packet->startpos += cpy;
|
||||
ptr += cpy;
|
||||
queue->queued_bytes -= cpy;
|
||||
len -= cpy;
|
||||
|
||||
if (packet->startpos == packet->datalen) { /* packet is done, put it in the pool. */
|
||||
queue->head = packet->next;
|
||||
SDL_assert((packet->next != NULL) || (packet == queue->tail));
|
||||
packet->next = queue->pool;
|
||||
queue->pool = packet;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
|
||||
|
||||
if (queue->head == NULL) {
|
||||
queue->tail = NULL; /* in case we drained the queue entirely. */
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(queue->lock);
|
||||
|
||||
return (size_t)(ptr - buf);
|
||||
}
|
||||
|
||||
size_t SDL_GetDataQueueSize(SDL_DataQueue *queue)
|
||||
{
|
||||
size_t retval = 0;
|
||||
if (queue) {
|
||||
SDL_LockMutex(queue->lock);
|
||||
retval = queue->queued_bytes;
|
||||
SDL_UnlockMutex(queue->lock);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDL_Mutex *SDL_GetDataQueueMutex(SDL_DataQueue *queue)
|
||||
{
|
||||
return queue ? queue->lock : NULL;
|
||||
}
|
||||
|
38
external/sdl/SDL/src/SDL_dataqueue.h
vendored
38
external/sdl/SDL/src/SDL_dataqueue.h
vendored
@ -1,38 +0,0 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 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_dataqueue_h_
|
||||
#define SDL_dataqueue_h_
|
||||
|
||||
/* this is not (currently) a public API. But maybe it should be! */
|
||||
|
||||
struct SDL_DataQueue;
|
||||
typedef struct SDL_DataQueue SDL_DataQueue;
|
||||
|
||||
SDL_DataQueue *SDL_CreateDataQueue(const size_t packetlen, const size_t initialslack);
|
||||
void SDL_DestroyDataQueue(SDL_DataQueue *queue);
|
||||
void SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack);
|
||||
int SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *data, const size_t len);
|
||||
size_t SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *buf, const size_t len);
|
||||
size_t SDL_PeekIntoDataQueue(SDL_DataQueue *queue, void *buf, const size_t len);
|
||||
size_t SDL_GetDataQueueSize(SDL_DataQueue *queue);
|
||||
SDL_Mutex *SDL_GetDataQueueMutex(SDL_DataQueue *queue); /* don't destroy this, obviously. */
|
||||
|
||||
#endif /* SDL_dataqueue_h_ */
|
579
external/sdl/SDL/src/audio/SDL_audio.c
vendored
579
external/sdl/SDL/src/audio/SDL_audio.c
vendored
@ -116,6 +116,106 @@ const char *SDL_GetCurrentAudioDriver(void)
|
||||
return current_audio.name;
|
||||
}
|
||||
|
||||
static int GetDefaultSampleFramesFromFreq(const int freq)
|
||||
{
|
||||
const char *hint = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES);
|
||||
if (hint) {
|
||||
const int val = SDL_atoi(hint);
|
||||
if (val > 0) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
if (freq <= 22050) {
|
||||
return 512;
|
||||
} else if (freq <= 48000) {
|
||||
return 1024;
|
||||
} else if (freq <= 96000) {
|
||||
return 2048;
|
||||
} else {
|
||||
return 4096;
|
||||
}
|
||||
}
|
||||
|
||||
void OnAudioStreamCreated(SDL_AudioStream *stream)
|
||||
{
|
||||
SDL_assert(SDL_GetCurrentAudioDriver() != NULL);
|
||||
SDL_assert(stream != NULL);
|
||||
|
||||
// this isn't really part of the "device list" but it's a convenient lock to use here.
|
||||
SDL_LockRWLockForWriting(current_audio.device_list_lock);
|
||||
if (current_audio.existing_streams) {
|
||||
current_audio.existing_streams->prev = stream;
|
||||
}
|
||||
stream->prev = NULL;
|
||||
stream->next = current_audio.existing_streams;
|
||||
current_audio.existing_streams = stream;
|
||||
SDL_UnlockRWLock(current_audio.device_list_lock);
|
||||
}
|
||||
|
||||
void OnAudioStreamDestroy(SDL_AudioStream *stream)
|
||||
{
|
||||
SDL_assert(SDL_GetCurrentAudioDriver() != NULL);
|
||||
SDL_assert(stream != NULL);
|
||||
|
||||
// this isn't really part of the "device list" but it's a convenient lock to use here.
|
||||
SDL_LockRWLockForWriting(current_audio.device_list_lock);
|
||||
if (stream->prev) {
|
||||
stream->prev->next = stream->next;
|
||||
}
|
||||
if (stream->next) {
|
||||
stream->next->prev = stream->prev;
|
||||
}
|
||||
if (stream == current_audio.existing_streams) {
|
||||
current_audio.existing_streams = stream->next;
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_list_lock);
|
||||
}
|
||||
|
||||
|
||||
// should hold logdev's physical device's lock before calling.
|
||||
static void UpdateAudioStreamFormatsLogical(SDL_LogicalAudioDevice *logdev)
|
||||
{
|
||||
const SDL_bool iscapture = logdev->physical_device->iscapture;
|
||||
SDL_AudioSpec spec;
|
||||
SDL_copyp(&spec, &logdev->physical_device->spec);
|
||||
if (logdev->postmix != NULL) {
|
||||
spec.format = SDL_AUDIO_F32;
|
||||
}
|
||||
|
||||
for (SDL_AudioStream *stream = logdev->bound_streams; stream != NULL; stream = stream->next_binding) {
|
||||
// set the proper end of the stream to the device's format.
|
||||
// SDL_SetAudioStreamFormat does a ton of validation just to memcpy an audiospec.
|
||||
SDL_LockMutex(stream->lock);
|
||||
SDL_copyp(iscapture ? &stream->src_spec : &stream->dst_spec, &spec);
|
||||
SDL_UnlockMutex(stream->lock);
|
||||
}
|
||||
}
|
||||
|
||||
// should hold device->lock before calling.
|
||||
static void UpdateAudioStreamFormatsPhysical(SDL_AudioDevice *device)
|
||||
{
|
||||
for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev != NULL; logdev = logdev->next) {
|
||||
UpdateAudioStreamFormatsLogical(logdev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// device should be locked when calling this.
|
||||
static SDL_bool AudioDeviceCanUseSimpleCopy(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_assert(device != NULL);
|
||||
return (
|
||||
device->logical_devices && // there's a logical device
|
||||
!device->logical_devices->next && // there's only _ONE_ logical device
|
||||
!device->logical_devices->postmix && // there isn't a postmix callback
|
||||
!SDL_AtomicGet(&device->logical_devices->paused) && // it isn't paused
|
||||
device->logical_devices->bound_streams && // there's a bound stream
|
||||
!device->logical_devices->bound_streams->next_binding // there's only _ONE_ bound stream.
|
||||
) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// device management and hotplug...
|
||||
|
||||
|
||||
@ -176,6 +276,8 @@ static void DestroyLogicalAudioDevice(SDL_LogicalAudioDevice *logdev)
|
||||
SDL_UnlockMutex(stream->lock);
|
||||
}
|
||||
|
||||
logdev->physical_device->simple_copy = AudioDeviceCanUseSimpleCopy(logdev->physical_device);
|
||||
|
||||
SDL_free(logdev);
|
||||
}
|
||||
|
||||
@ -208,7 +310,10 @@ static SDL_AudioDevice *CreatePhysicalAudioDevice(const char *name, SDL_bool isc
|
||||
{
|
||||
SDL_assert(name != NULL);
|
||||
|
||||
if (SDL_AtomicGet(¤t_audio.shutting_down)) {
|
||||
SDL_LockRWLockForReading(current_audio.device_list_lock);
|
||||
const int shutting_down = SDL_AtomicGet(¤t_audio.shutting_down);
|
||||
SDL_UnlockRWLock(current_audio.device_list_lock);
|
||||
if (shutting_down) {
|
||||
return NULL; // we're shutting down, don't add any devices that are hotplugged at the last possible moment.
|
||||
}
|
||||
|
||||
@ -236,8 +341,9 @@ static SDL_AudioDevice *CreatePhysicalAudioDevice(const char *name, SDL_bool isc
|
||||
SDL_AtomicSet(&device->condemned, 0);
|
||||
SDL_AtomicSet(&device->zombie, 0);
|
||||
device->iscapture = iscapture;
|
||||
SDL_memcpy(&device->spec, spec, sizeof (SDL_AudioSpec));
|
||||
SDL_memcpy(&device->default_spec, spec, sizeof (SDL_AudioSpec));
|
||||
SDL_copyp(&device->spec, spec);
|
||||
SDL_copyp(&device->default_spec, spec);
|
||||
device->sample_frames = GetDefaultSampleFramesFromFreq(device->spec.freq);
|
||||
device->silence_value = SDL_GetSilenceValueForFormat(device->spec.format);
|
||||
device->handle = handle;
|
||||
device->prev = NULL;
|
||||
@ -336,7 +442,7 @@ void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device)
|
||||
SDL_LogicalAudioDevice *next = NULL;
|
||||
for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev != NULL; logdev = next) {
|
||||
next = logdev->next;
|
||||
if (!logdev->is_default) { // if opened as a default, leave it on the zombie device for later migration.
|
||||
if (!logdev->opened_as_default) { // if opened as a default, leave it on the zombie device for later migration.
|
||||
DisconnectLogicalAudioDevice(logdev);
|
||||
}
|
||||
}
|
||||
@ -412,7 +518,7 @@ void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device)
|
||||
|
||||
static void SDL_AudioThreadDeinit_Default(SDL_AudioDevice *device) { /* no-op. */ }
|
||||
static void SDL_AudioWaitDevice_Default(SDL_AudioDevice *device) { /* no-op. */ }
|
||||
static void SDL_AudioPlayDevice_Default(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size) { /* no-op. */ }
|
||||
static int SDL_AudioPlayDevice_Default(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size) { return 0; /* no-op. */ }
|
||||
static void SDL_AudioWaitCaptureDevice_Default(SDL_AudioDevice *device) { /* no-op. */ }
|
||||
static void SDL_AudioFlushCapture_Default(SDL_AudioDevice *device) { /* no-op. */ }
|
||||
static void SDL_AudioCloseDevice_Default(SDL_AudioDevice *device) { /* no-op. */ }
|
||||
@ -493,6 +599,7 @@ int SDL_InitAudio(const char *driver_name)
|
||||
}
|
||||
|
||||
SDL_ChooseAudioConverters();
|
||||
SDL_SetupAudioResampler();
|
||||
|
||||
SDL_RWLock *device_list_lock = SDL_CreateRWLock(); // create this early, so if it fails we don't have to tear down the whole audio subsystem.
|
||||
if (!device_list_lock) {
|
||||
@ -614,6 +721,11 @@ void SDL_QuitAudio(void)
|
||||
return;
|
||||
}
|
||||
|
||||
// Destroy any audio streams that still exist...
|
||||
while (current_audio.existing_streams != NULL) {
|
||||
SDL_DestroyAudioStream(current_audio.existing_streams);
|
||||
}
|
||||
|
||||
// merge device lists so we don't have to duplicate work below.
|
||||
SDL_LockRWLockForWriting(current_audio.device_list_lock);
|
||||
SDL_AtomicSet(¤t_audio.shutting_down, 1);
|
||||
@ -633,7 +745,7 @@ void SDL_QuitAudio(void)
|
||||
SDL_AtomicSet(¤t_audio.output_device_count, 0);
|
||||
SDL_AtomicSet(¤t_audio.capture_device_count, 0);
|
||||
SDL_UnlockRWLock(current_audio.device_list_lock);
|
||||
|
||||
|
||||
// mark all devices for shutdown so all threads can begin to terminate.
|
||||
for (SDL_AudioDevice *i = devices; i != NULL; i = i->next) {
|
||||
SDL_AtomicSet(&i->shutdown, 1);
|
||||
@ -676,6 +788,14 @@ void SDL_AudioThreadFinalize(SDL_AudioDevice *device)
|
||||
SDL_AtomicSet(&device->thread_alive, 0);
|
||||
}
|
||||
|
||||
static void MixFloat32Audio(float *dst, const float *src, const int buffer_size)
|
||||
{
|
||||
if (SDL_MixAudioFormat((Uint8 *) dst, (const Uint8 *) src, SDL_AUDIO_F32, buffer_size, SDL_MIX_MAXVOLUME) < 0) {
|
||||
SDL_assert(!"This shouldn't happen.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Output device thread. This is split into chunks, so backends that need to control this directly can use the pieces they need without duplicating effort.
|
||||
|
||||
void SDL_OutputAudioThreadSetup(SDL_AudioDevice *device)
|
||||
@ -697,41 +817,90 @@ SDL_bool SDL_OutputAudioThreadIterate(SDL_AudioDevice *device)
|
||||
|
||||
SDL_bool retval = SDL_TRUE;
|
||||
int buffer_size = device->buffer_size;
|
||||
Uint8 *mix_buffer = current_audio.impl.GetDeviceBuf(device, &buffer_size);
|
||||
if (!mix_buffer) {
|
||||
Uint8 *device_buffer = current_audio.impl.GetDeviceBuf(device, &buffer_size);
|
||||
if (!device_buffer) {
|
||||
retval = SDL_FALSE;
|
||||
} else {
|
||||
SDL_assert(buffer_size <= device->buffer_size); // you can ask for less, but not more.
|
||||
SDL_memset(mix_buffer, device->silence_value, buffer_size); // start with silence.
|
||||
SDL_assert(AudioDeviceCanUseSimpleCopy(device) == device->simple_copy); // make sure this hasn't gotten out of sync.
|
||||
|
||||
for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev != NULL; logdev = logdev->next) {
|
||||
if (SDL_AtomicGet(&logdev->paused)) {
|
||||
continue; // paused? Skip this logical device.
|
||||
// can we do a basic copy without silencing/mixing the buffer? This is an extremely likely scenario, so we special-case it.
|
||||
if (device->simple_copy) {
|
||||
SDL_LogicalAudioDevice *logdev = device->logical_devices;
|
||||
SDL_AudioStream *stream = logdev->bound_streams;
|
||||
|
||||
// We should have updated this elsewhere if the format changed!
|
||||
SDL_assert(AUDIO_SPECS_EQUAL(stream->dst_spec, device->spec));
|
||||
|
||||
const int br = SDL_GetAudioStreamData(stream, device_buffer, buffer_size);
|
||||
if (br < 0) { // Probably OOM. Kill the audio device; the whole thing is likely dying soon anyhow.
|
||||
retval = SDL_FALSE;
|
||||
SDL_memset(device_buffer, device->silence_value, buffer_size); // just supply silence to the device before we die.
|
||||
} else if (br < buffer_size) {
|
||||
SDL_memset(device_buffer + br, device->silence_value, buffer_size - br); // silence whatever we didn't write to.
|
||||
}
|
||||
} else { // need to actually mix (or silence the buffer)
|
||||
float *final_mix_buffer = (float *) ((device->spec.format == SDL_AUDIO_F32) ? device_buffer : device->mix_buffer);
|
||||
const int needed_samples = buffer_size / SDL_AUDIO_BYTESIZE(device->spec.format);
|
||||
const int work_buffer_size = needed_samples * sizeof (float);
|
||||
SDL_AudioSpec outspec;
|
||||
|
||||
for (SDL_AudioStream *stream = logdev->bound_streams; stream != NULL; stream = stream->next_binding) {
|
||||
/* this will hold a lock on `stream` while getting. We don't explicitly lock the streams
|
||||
for iterating here because the binding linked list can only change while the device lock is held.
|
||||
(we _do_ lock the stream during binding/unbinding to make sure that two threads can't try to bind
|
||||
the same stream to different devices at the same time, though.) */
|
||||
const int br = SDL_GetAudioStreamData(stream, device->work_buffer, buffer_size);
|
||||
if (br < 0) {
|
||||
// oh crud, we probably ran out of memory. This is possibly an overreaction to kill the audio device, but it's likely the whole thing is going down in a moment anyhow.
|
||||
retval = SDL_FALSE;
|
||||
break;
|
||||
} else if (br > 0) { // it's okay if we get less than requested, we mix what we have.
|
||||
// !!! FIXME: this needs to mix to float32 or int32, so we don't clip.
|
||||
if (SDL_MixAudioFormat(mix_buffer, device->work_buffer, device->spec.format, br, SDL_MIX_MAXVOLUME) < 0) { // !!! FIXME: allow streams to specify gain?
|
||||
SDL_assert(!"We probably ended up with some totally unexpected audio format here");
|
||||
retval = SDL_FALSE; // uh...?
|
||||
SDL_assert(work_buffer_size <= device->work_buffer_size);
|
||||
|
||||
outspec.format = SDL_AUDIO_F32;
|
||||
outspec.channels = device->spec.channels;
|
||||
outspec.freq = device->spec.freq;
|
||||
|
||||
SDL_memset(final_mix_buffer, '\0', work_buffer_size); // start with silence.
|
||||
|
||||
for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev != NULL; logdev = logdev->next) {
|
||||
if (SDL_AtomicGet(&logdev->paused)) {
|
||||
continue; // paused? Skip this logical device.
|
||||
}
|
||||
|
||||
const SDL_AudioPostmixCallback postmix = logdev->postmix;
|
||||
float *mix_buffer = final_mix_buffer;
|
||||
if (postmix) {
|
||||
mix_buffer = device->postmix_buffer;
|
||||
SDL_memset(mix_buffer, '\0', work_buffer_size); // start with silence.
|
||||
}
|
||||
|
||||
for (SDL_AudioStream *stream = logdev->bound_streams; stream != NULL; stream = stream->next_binding) {
|
||||
// We should have updated this elsewhere if the format changed!
|
||||
SDL_assert(AUDIO_SPECS_EQUAL(stream->dst_spec, outspec));
|
||||
|
||||
/* this will hold a lock on `stream` while getting. We don't explicitly lock the streams
|
||||
for iterating here because the binding linked list can only change while the device lock is held.
|
||||
(we _do_ lock the stream during binding/unbinding to make sure that two threads can't try to bind
|
||||
the same stream to different devices at the same time, though.) */
|
||||
const int br = SDL_GetAudioStreamData(stream, device->work_buffer, work_buffer_size);
|
||||
if (br < 0) { // Probably OOM. Kill the audio device; the whole thing is likely dying soon anyhow.
|
||||
retval = SDL_FALSE;
|
||||
break;
|
||||
} else if (br > 0) { // it's okay if we get less than requested, we mix what we have.
|
||||
MixFloat32Audio(mix_buffer, (float *) device->work_buffer, br);
|
||||
}
|
||||
}
|
||||
|
||||
if (postmix) {
|
||||
SDL_assert(mix_buffer == device->postmix_buffer);
|
||||
postmix(logdev->postmix_userdata, &outspec, mix_buffer, work_buffer_size);
|
||||
MixFloat32Audio(final_mix_buffer, mix_buffer, work_buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
if (((Uint8 *) final_mix_buffer) != device_buffer) {
|
||||
// !!! FIXME: we can't promise the device buf is aligned/padded for SIMD.
|
||||
//ConvertAudio(needed_samples * device->spec.channels, final_mix_buffer, SDL_AUDIO_F32, device->spec.channels, device_buffer, device->spec.format, device->spec.channels, device->work_buffer);
|
||||
ConvertAudio(needed_samples / device->spec.channels, final_mix_buffer, SDL_AUDIO_F32, device->spec.channels, device->work_buffer, device->spec.format, device->spec.channels, NULL);
|
||||
SDL_memcpy(device_buffer, device->work_buffer, buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
// !!! FIXME: have PlayDevice return a value and do disconnects in here with it.
|
||||
current_audio.impl.PlayDevice(device, mix_buffer, buffer_size); // this SHOULD NOT BLOCK, as we are holding a lock right now. Block in WaitDevice!
|
||||
// PlayDevice SHOULD NOT BLOCK, as we are holding a lock right now. Block in WaitDevice instead!
|
||||
if (current_audio.impl.PlayDevice(device, device_buffer, buffer_size) < 0) {
|
||||
retval = SDL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(device->lock);
|
||||
@ -746,9 +915,9 @@ SDL_bool SDL_OutputAudioThreadIterate(SDL_AudioDevice *device)
|
||||
void SDL_OutputAudioThreadShutdown(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_assert(!device->iscapture);
|
||||
const int samples = (device->buffer_size / (SDL_AUDIO_BITSIZE(device->spec.format) / 8)) / device->spec.channels;
|
||||
const int frames = device->buffer_size / SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
// Wait for the audio to drain. !!! FIXME: don't bother waiting if device is lost.
|
||||
SDL_Delay(((samples * 1000) / device->spec.freq) * 2);
|
||||
SDL_Delay(((frames * 1000) / device->spec.freq) * 2);
|
||||
current_audio.impl.ThreadDeinit(device);
|
||||
SDL_AudioThreadFinalize(device);
|
||||
}
|
||||
@ -791,21 +960,42 @@ SDL_bool SDL_CaptureAudioThreadIterate(SDL_AudioDevice *device)
|
||||
current_audio.impl.FlushCapture(device); // nothing wants data, dump anything pending.
|
||||
} else {
|
||||
// this SHOULD NOT BLOCK, as we are holding a lock right now. Block in WaitCaptureDevice!
|
||||
const int rc = current_audio.impl.CaptureFromDevice(device, device->work_buffer, device->buffer_size);
|
||||
if (rc < 0) { // uhoh, device failed for some reason!
|
||||
int br = current_audio.impl.CaptureFromDevice(device, device->work_buffer, device->buffer_size);
|
||||
if (br < 0) { // uhoh, device failed for some reason!
|
||||
retval = SDL_FALSE;
|
||||
} else if (rc > 0) { // queue the new data to each bound stream.
|
||||
} else if (br > 0) { // queue the new data to each bound stream.
|
||||
for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev != NULL; logdev = logdev->next) {
|
||||
if (SDL_AtomicGet(&logdev->paused)) {
|
||||
continue; // paused? Skip this logical device.
|
||||
}
|
||||
|
||||
void *output_buffer = device->work_buffer;
|
||||
|
||||
// I don't know why someone would want a postmix on a capture device, but we offer it for API consistency.
|
||||
if (logdev->postmix) {
|
||||
// move to float format.
|
||||
SDL_AudioSpec outspec;
|
||||
outspec.format = SDL_AUDIO_F32;
|
||||
outspec.channels = device->spec.channels;
|
||||
outspec.freq = device->spec.freq;
|
||||
output_buffer = device->postmix_buffer;
|
||||
const int frames = br / SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
br = frames * SDL_AUDIO_FRAMESIZE(outspec);
|
||||
ConvertAudio(frames, device->work_buffer, device->spec.format, outspec.channels, device->postmix_buffer, SDL_AUDIO_F32, outspec.channels, NULL);
|
||||
logdev->postmix(logdev->postmix_userdata, &outspec, device->postmix_buffer, br);
|
||||
}
|
||||
|
||||
for (SDL_AudioStream *stream = logdev->bound_streams; stream != NULL; stream = stream->next_binding) {
|
||||
// We should have updated this elsewhere if the format changed!
|
||||
SDL_assert(stream->src_spec.format == (logdev->postmix ? SDL_AUDIO_F32 : device->spec.format));
|
||||
SDL_assert(stream->src_spec.channels == device->spec.channels);
|
||||
SDL_assert(stream->src_spec.freq == device->spec.freq);
|
||||
|
||||
/* this will hold a lock on `stream` while putting. We don't explicitly lock the streams
|
||||
for iterating here because the binding linked list can only change while the device lock is held.
|
||||
(we _do_ lock the stream during binding/unbinding to make sure that two threads can't try to bind
|
||||
the same stream to different devices at the same time, though.) */
|
||||
if (SDL_PutAudioStreamData(stream, device->work_buffer, rc) < 0) {
|
||||
if (SDL_PutAudioStreamData(stream, output_buffer, br) < 0) {
|
||||
// oh crud, we probably ran out of memory. This is possibly an overreaction to kill the audio device, but it's likely the whole thing is going down in a moment anyhow.
|
||||
retval = SDL_FALSE;
|
||||
break;
|
||||
@ -1036,22 +1226,22 @@ char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int SDL_GetAudioDeviceFormat(SDL_AudioDeviceID devid, SDL_AudioSpec *spec)
|
||||
int SDL_GetAudioDeviceFormat(SDL_AudioDeviceID devid, SDL_AudioSpec *spec, int *sample_frames)
|
||||
{
|
||||
if (!spec) {
|
||||
return SDL_InvalidParamError("spec");
|
||||
}
|
||||
|
||||
SDL_bool is_default = SDL_FALSE;
|
||||
SDL_bool wants_default = SDL_FALSE;
|
||||
if (devid == SDL_AUDIO_DEVICE_DEFAULT_OUTPUT) {
|
||||
devid = current_audio.default_output_device_id;
|
||||
is_default = SDL_TRUE;
|
||||
wants_default = SDL_TRUE;
|
||||
} else if (devid == SDL_AUDIO_DEVICE_DEFAULT_CAPTURE) {
|
||||
devid = current_audio.default_capture_device_id;
|
||||
is_default = SDL_TRUE;
|
||||
wants_default = SDL_TRUE;
|
||||
}
|
||||
|
||||
if ((devid == 0) && is_default) {
|
||||
if ((devid == 0) && wants_default) {
|
||||
return SDL_SetError("No default audio device available");
|
||||
}
|
||||
|
||||
@ -1060,7 +1250,10 @@ int SDL_GetAudioDeviceFormat(SDL_AudioDeviceID devid, SDL_AudioSpec *spec)
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_memcpy(spec, &device->spec, sizeof (SDL_AudioSpec));
|
||||
SDL_copyp(spec, &device->spec);
|
||||
if (sample_frames) {
|
||||
*sample_frames = device->sample_frames;
|
||||
}
|
||||
SDL_UnlockMutex(device->lock);
|
||||
|
||||
return 0;
|
||||
@ -1080,18 +1273,22 @@ static void ClosePhysicalAudioDevice(SDL_AudioDevice *device)
|
||||
SDL_AtomicSet(&device->thread_alive, 0);
|
||||
}
|
||||
|
||||
if (device->is_opened) {
|
||||
if (device->currently_opened) {
|
||||
current_audio.impl.CloseDevice(device); // if ProvidesOwnCallbackThread, this must join on any existing device thread before returning!
|
||||
device->is_opened = SDL_FALSE;
|
||||
device->currently_opened = SDL_FALSE;
|
||||
device->hidden = NULL; // just in case.
|
||||
}
|
||||
|
||||
if (device->work_buffer) {
|
||||
SDL_aligned_free(device->work_buffer);
|
||||
device->work_buffer = NULL;
|
||||
}
|
||||
SDL_aligned_free(device->work_buffer);
|
||||
device->work_buffer = NULL;
|
||||
|
||||
SDL_memcpy(&device->spec, &device->default_spec, sizeof (SDL_AudioSpec));
|
||||
SDL_aligned_free(device->mix_buffer);
|
||||
device->mix_buffer = NULL;
|
||||
|
||||
SDL_aligned_free(device->postmix_buffer);
|
||||
device->postmix_buffer = NULL;
|
||||
|
||||
SDL_copyp(&device->spec, &device->default_spec);
|
||||
device->sample_frames = 0;
|
||||
device->silence_value = SDL_GetSilenceValueForFormat(device->spec.format);
|
||||
SDL_AtomicSet(&device->shutdown, 0); // ready to go again.
|
||||
@ -1121,16 +1318,14 @@ static SDL_AudioFormat ParseAudioFormatString(const char *string)
|
||||
#define CHECK_FMT_STRING(x) if (SDL_strcmp(string, #x) == 0) { return SDL_AUDIO_##x; }
|
||||
CHECK_FMT_STRING(U8);
|
||||
CHECK_FMT_STRING(S8);
|
||||
CHECK_FMT_STRING(S16LSB);
|
||||
CHECK_FMT_STRING(S16MSB);
|
||||
CHECK_FMT_STRING(S16LE);
|
||||
CHECK_FMT_STRING(S16BE);
|
||||
CHECK_FMT_STRING(S16);
|
||||
CHECK_FMT_STRING(S32LSB);
|
||||
CHECK_FMT_STRING(S32MSB);
|
||||
CHECK_FMT_STRING(S32SYS);
|
||||
CHECK_FMT_STRING(S32LE);
|
||||
CHECK_FMT_STRING(S32BE);
|
||||
CHECK_FMT_STRING(S32);
|
||||
CHECK_FMT_STRING(F32LSB);
|
||||
CHECK_FMT_STRING(F32MSB);
|
||||
CHECK_FMT_STRING(F32SYS);
|
||||
CHECK_FMT_STRING(F32LE);
|
||||
CHECK_FMT_STRING(F32BE);
|
||||
CHECK_FMT_STRING(F32);
|
||||
#undef CHECK_FMT_STRING
|
||||
}
|
||||
@ -1168,15 +1363,12 @@ static void PrepareAudioFormat(SDL_bool iscapture, SDL_AudioSpec *spec)
|
||||
}
|
||||
}
|
||||
|
||||
static int GetDefaultSampleFramesFromFreq(int freq)
|
||||
{
|
||||
return SDL_powerof2((freq / 1000) * 46); // Pick the closest power-of-two to ~46 ms at desired frequency
|
||||
}
|
||||
|
||||
void SDL_UpdatedAudioDeviceFormat(SDL_AudioDevice *device)
|
||||
{
|
||||
device->silence_value = SDL_GetSilenceValueForFormat(device->spec.format);
|
||||
device->buffer_size = device->sample_frames * (SDL_AUDIO_BITSIZE(device->spec.format) / 8) * device->spec.channels;
|
||||
device->buffer_size = device->sample_frames * SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
device->work_buffer_size = device->sample_frames * sizeof (float) * device->spec.channels;
|
||||
device->work_buffer_size = SDL_max(device->buffer_size, device->work_buffer_size); // just in case we end up with a 64-bit audio format at some point.
|
||||
}
|
||||
|
||||
char *SDL_GetAudioThreadName(SDL_AudioDevice *device, char *buf, size_t buflen)
|
||||
@ -1189,7 +1381,7 @@ char *SDL_GetAudioThreadName(SDL_AudioDevice *device, char *buf, size_t buflen)
|
||||
// this expects the device lock to be held.
|
||||
static int OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec *inspec)
|
||||
{
|
||||
SDL_assert(!device->is_opened);
|
||||
SDL_assert(!device->currently_opened);
|
||||
SDL_assert(device->logical_devices == NULL);
|
||||
|
||||
// Just pretend to open a zombie device. It can still collect logical devices on the assumption they will all migrate when the default device is officially changed.
|
||||
@ -1198,7 +1390,7 @@ static int OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
|
||||
}
|
||||
|
||||
SDL_AudioSpec spec;
|
||||
SDL_memcpy(&spec, inspec ? inspec : &device->default_spec, sizeof (SDL_AudioSpec));
|
||||
SDL_copyp(&spec, inspec ? inspec : &device->default_spec);
|
||||
PrepareAudioFormat(device->iscapture, &spec);
|
||||
|
||||
/* We allow the device format to change if it's better than the current settings (by various definitions of "better"). This prevents
|
||||
@ -1211,7 +1403,7 @@ static int OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
|
||||
device->sample_frames = GetDefaultSampleFramesFromFreq(device->spec.freq);
|
||||
SDL_UpdatedAudioDeviceFormat(device); // start this off sane.
|
||||
|
||||
device->is_opened = SDL_TRUE; // mark this true even if impl.OpenDevice fails, so we know to clean up.
|
||||
device->currently_opened = SDL_TRUE; // mark this true even if impl.OpenDevice fails, so we know to clean up.
|
||||
if (current_audio.impl.OpenDevice(device) < 0) {
|
||||
ClosePhysicalAudioDevice(device); // clean up anything the backend left half-initialized.
|
||||
return -1;
|
||||
@ -1220,12 +1412,20 @@ static int OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
|
||||
SDL_UpdatedAudioDeviceFormat(device); // in case the backend changed things and forgot to call this.
|
||||
|
||||
// Allocate a scratch audio buffer
|
||||
device->work_buffer = (Uint8 *)SDL_aligned_alloc(SDL_SIMDGetAlignment(), device->buffer_size);
|
||||
device->work_buffer = (Uint8 *)SDL_aligned_alloc(SDL_SIMDGetAlignment(), device->work_buffer_size);
|
||||
if (device->work_buffer == NULL) {
|
||||
ClosePhysicalAudioDevice(device);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
if (device->spec.format != SDL_AUDIO_F32) {
|
||||
device->mix_buffer = (Uint8 *)SDL_aligned_alloc(SDL_SIMDGetAlignment(), device->work_buffer_size);
|
||||
if (device->mix_buffer == NULL) {
|
||||
ClosePhysicalAudioDevice(device);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
}
|
||||
|
||||
// Start the audio thread if necessary
|
||||
SDL_AtomicSet(&device->thread_alive, 1);
|
||||
if (!current_audio.impl.ProvidesOwnCallbackThread) {
|
||||
@ -1251,16 +1451,16 @@ SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, const SDL_AudioSp
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_bool is_default = SDL_FALSE;
|
||||
SDL_bool wants_default = SDL_FALSE;
|
||||
if (devid == SDL_AUDIO_DEVICE_DEFAULT_OUTPUT) {
|
||||
devid = current_audio.default_output_device_id;
|
||||
is_default = SDL_TRUE;
|
||||
wants_default = SDL_TRUE;
|
||||
} else if (devid == SDL_AUDIO_DEVICE_DEFAULT_CAPTURE) {
|
||||
devid = current_audio.default_capture_device_id;
|
||||
is_default = SDL_TRUE;
|
||||
wants_default = SDL_TRUE;
|
||||
}
|
||||
|
||||
if ((devid == 0) && is_default) {
|
||||
if ((devid == 0) && wants_default) {
|
||||
SDL_SetError("No default audio device available");
|
||||
return 0;
|
||||
}
|
||||
@ -1273,7 +1473,7 @@ SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, const SDL_AudioSp
|
||||
} else {
|
||||
SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid); // this locks the physical device, too.
|
||||
if (logdev) {
|
||||
is_default = logdev->is_default; // was the original logical device meant to be a default? Make this one, too.
|
||||
wants_default = logdev->opened_as_default; // was the original logical device meant to be a default? Make this one, too.
|
||||
device = logdev->physical_device;
|
||||
}
|
||||
}
|
||||
@ -1282,23 +1482,24 @@ SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, const SDL_AudioSp
|
||||
|
||||
if (device) {
|
||||
SDL_LogicalAudioDevice *logdev = NULL;
|
||||
if (!is_default && SDL_AtomicGet(&device->zombie)) {
|
||||
if (!wants_default && SDL_AtomicGet(&device->zombie)) {
|
||||
// uhoh, this device is undead, and just waiting for a new default device to be declared so it can hand off to it. Refuse explicit opens.
|
||||
SDL_SetError("Device was already lost and can't accept new opens");
|
||||
} else if ((logdev = (SDL_LogicalAudioDevice *) SDL_calloc(1, sizeof (SDL_LogicalAudioDevice))) == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
} else if (!device->is_opened && OpenPhysicalAudioDevice(device, spec) == -1) { // first thing using this physical device? Open at the OS level...
|
||||
} else if (!device->currently_opened && OpenPhysicalAudioDevice(device, spec) == -1) { // first thing using this physical device? Open at the OS level...
|
||||
SDL_free(logdev);
|
||||
} else {
|
||||
SDL_AtomicSet(&logdev->paused, 0);
|
||||
retval = logdev->instance_id = assign_audio_device_instance_id(device->iscapture, /*islogical=*/SDL_TRUE);
|
||||
logdev->physical_device = device;
|
||||
logdev->is_default = is_default;
|
||||
logdev->opened_as_default = wants_default;
|
||||
logdev->next = device->logical_devices;
|
||||
if (device->logical_devices) {
|
||||
device->logical_devices->prev = logdev;
|
||||
}
|
||||
device->logical_devices = logdev;
|
||||
device->simple_copy = AudioDeviceCanUseSimpleCopy(device);
|
||||
}
|
||||
SDL_UnlockMutex(device->lock);
|
||||
}
|
||||
@ -1313,6 +1514,7 @@ static int SetLogicalAudioDevicePauseState(SDL_AudioDeviceID devid, int value)
|
||||
return -1; // ObtainLogicalAudioDevice will have set an error.
|
||||
}
|
||||
SDL_AtomicSet(&logdev->paused, value);
|
||||
logdev->physical_device->simple_copy = AudioDeviceCanUseSimpleCopy(logdev->physical_device);
|
||||
SDL_UnlockMutex(logdev->physical_device->lock);
|
||||
return 0;
|
||||
}
|
||||
@ -1327,7 +1529,7 @@ int SDLCALL SDL_ResumeAudioDevice(SDL_AudioDeviceID devid)
|
||||
return SetLogicalAudioDevicePauseState(devid, 0);
|
||||
}
|
||||
|
||||
SDL_bool SDL_IsAudioDevicePaused(SDL_AudioDeviceID devid)
|
||||
SDL_bool SDL_AudioDevicePaused(SDL_AudioDeviceID devid)
|
||||
{
|
||||
SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid);
|
||||
SDL_bool retval = SDL_FALSE;
|
||||
@ -1340,6 +1542,31 @@ SDL_bool SDL_IsAudioDevicePaused(SDL_AudioDeviceID devid)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int SDL_SetAudioPostmixCallback(SDL_AudioDeviceID devid, SDL_AudioPostmixCallback callback, void *userdata)
|
||||
{
|
||||
SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid);
|
||||
int retval = 0;
|
||||
if (logdev) {
|
||||
SDL_AudioDevice *device = logdev->physical_device;
|
||||
if (callback && !device->postmix_buffer) {
|
||||
device->postmix_buffer = (float *)SDL_aligned_alloc(SDL_SIMDGetAlignment(), device->work_buffer_size);
|
||||
if (device->mix_buffer == NULL) {
|
||||
retval = SDL_OutOfMemory();
|
||||
}
|
||||
}
|
||||
|
||||
if (retval == 0) {
|
||||
logdev->postmix = callback;
|
||||
logdev->postmix_userdata = userdata;
|
||||
}
|
||||
|
||||
UpdateAudioStreamFormatsLogical(logdev);
|
||||
device->simple_copy = AudioDeviceCanUseSimpleCopy(device);
|
||||
|
||||
SDL_UnlockMutex(device->lock);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream **streams, int num_streams)
|
||||
{
|
||||
@ -1356,8 +1583,14 @@ int SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream **streams, int
|
||||
return SDL_SetError("Audio streams are bound to device ids from SDL_OpenAudioDevice, not raw physical devices");
|
||||
} else if ((logdev = ObtainLogicalAudioDevice(devid)) == NULL) {
|
||||
return -1; // ObtainLogicalAudioDevice set the error message.
|
||||
} else if (logdev->simplified) {
|
||||
SDL_UnlockMutex(logdev->physical_device->lock);
|
||||
return SDL_SetError("Cannot change stream bindings on device opened with SDL_OpenAudioDeviceStream");
|
||||
}
|
||||
|
||||
// !!! FIXME: We'll set the device's side's format below, but maybe we should refuse to bind a stream if the app's side doesn't have a format set yet.
|
||||
// !!! FIXME: Actually, why do we allow there to be an invalid format, again?
|
||||
|
||||
// make sure start of list is sane.
|
||||
SDL_assert(!logdev->bound_streams || (logdev->bound_streams->prev_binding == NULL));
|
||||
|
||||
@ -1388,18 +1621,8 @@ int SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream **streams, int
|
||||
|
||||
if (retval == 0) {
|
||||
// Now that everything is verified, chain everything together.
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
for (int i = 0; i < num_streams; i++) {
|
||||
SDL_AudioStream *stream = streams[i];
|
||||
SDL_AudioSpec src_spec, dst_spec;
|
||||
|
||||
// set the proper end of the stream to the device's format.
|
||||
SDL_GetAudioStreamFormat(stream, &src_spec, &dst_spec);
|
||||
if (iscapture) {
|
||||
SDL_SetAudioStreamFormat(stream, &device->spec, &dst_spec);
|
||||
} else {
|
||||
SDL_SetAudioStreamFormat(stream, &src_spec, &device->spec);
|
||||
}
|
||||
|
||||
stream->bound_device = logdev;
|
||||
stream->prev_binding = NULL;
|
||||
@ -1411,8 +1634,12 @@ int SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream **streams, int
|
||||
|
||||
SDL_UnlockMutex(stream->lock);
|
||||
}
|
||||
|
||||
UpdateAudioStreamFormatsLogical(logdev);
|
||||
}
|
||||
|
||||
device->simple_copy = AudioDeviceCanUseSimpleCopy(device);
|
||||
|
||||
SDL_UnlockMutex(device->lock);
|
||||
|
||||
return retval;
|
||||
@ -1459,7 +1686,8 @@ void SDL_UnbindAudioStreams(SDL_AudioStream **streams, int num_streams)
|
||||
// everything is locked, start unbinding streams.
|
||||
for (int i = 0; i < num_streams; i++) {
|
||||
SDL_AudioStream *stream = streams[i];
|
||||
if (stream && stream->bound_device) {
|
||||
// don't allow unbinding from "simplified" devices (opened with SDL_OpenAudioDeviceStream). Just ignore them.
|
||||
if (stream && stream->bound_device && !stream->bound_device->simplified) {
|
||||
if (stream->bound_device->bound_streams == stream) {
|
||||
SDL_assert(stream->prev_binding == NULL);
|
||||
stream->bound_device->bound_streams = stream->next_binding;
|
||||
@ -1482,6 +1710,7 @@ void SDL_UnbindAudioStreams(SDL_AudioStream **streams, int num_streams)
|
||||
stream->bound_device = NULL;
|
||||
SDL_UnlockMutex(stream->lock);
|
||||
if (logdev) {
|
||||
logdev->physical_device->simple_copy = AudioDeviceCanUseSimpleCopy(logdev->physical_device);
|
||||
SDL_UnlockMutex(logdev->physical_device->lock);
|
||||
}
|
||||
}
|
||||
@ -1493,7 +1722,7 @@ void SDL_UnbindAudioStream(SDL_AudioStream *stream)
|
||||
SDL_UnbindAudioStreams(&stream, 1);
|
||||
}
|
||||
|
||||
SDL_AudioDeviceID SDL_GetAudioStreamBinding(SDL_AudioStream *stream)
|
||||
SDL_AudioDeviceID SDL_GetAudioStreamDevice(SDL_AudioStream *stream)
|
||||
{
|
||||
SDL_AudioDeviceID retval = 0;
|
||||
if (stream) {
|
||||
@ -1506,45 +1735,71 @@ SDL_AudioDeviceID SDL_GetAudioStreamBinding(SDL_AudioStream *stream)
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDL_AudioStream *SDL_CreateAndBindAudioStream(SDL_AudioDeviceID devid, const SDL_AudioSpec *spec)
|
||||
SDL_AudioStream *SDL_OpenAudioDeviceStream(SDL_AudioDeviceID devid, const SDL_AudioSpec *spec, SDL_AudioStreamCallback callback, void *userdata)
|
||||
{
|
||||
const SDL_bool islogical = (devid & (1<<1)) ? SDL_FALSE : SDL_TRUE;
|
||||
if (!islogical) {
|
||||
SDL_SetError("Audio streams are bound to device ids from SDL_OpenAudioDevice, not raw physical devices");
|
||||
return NULL;
|
||||
SDL_AudioDeviceID logdevid = SDL_OpenAudioDevice(devid, spec);
|
||||
if (!logdevid) {
|
||||
return NULL; // error string should already be set.
|
||||
}
|
||||
|
||||
SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(logdevid);
|
||||
if (logdev == NULL) { // this shouldn't happen, but just in case.
|
||||
SDL_CloseAudioDevice(logdevid);
|
||||
return NULL; // error string should already be set.
|
||||
}
|
||||
|
||||
SDL_AudioDevice *physdevice = logdev->physical_device;
|
||||
SDL_assert(physdevice != NULL);
|
||||
|
||||
SDL_AtomicSet(&logdev->paused, 1); // start the device paused, to match SDL2.
|
||||
physdevice->simple_copy = AudioDeviceCanUseSimpleCopy(physdevice);
|
||||
|
||||
SDL_UnlockMutex(physdevice->lock); // we don't need to hold the lock for any of this.
|
||||
const SDL_bool iscapture = physdevice->iscapture;
|
||||
|
||||
SDL_AudioStream *stream = NULL;
|
||||
SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid);
|
||||
if (logdev) {
|
||||
SDL_AudioDevice *device = logdev->physical_device;
|
||||
if (device->iscapture) {
|
||||
stream = SDL_CreateAudioStream(&device->spec, spec);
|
||||
} else {
|
||||
stream = SDL_CreateAudioStream(spec, &device->spec);
|
||||
}
|
||||
|
||||
if (stream) {
|
||||
if (SDL_BindAudioStream(devid, stream) == -1) {
|
||||
SDL_DestroyAudioStream(stream);
|
||||
stream = NULL;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(device->lock);
|
||||
if (iscapture) {
|
||||
stream = SDL_CreateAudioStream(&physdevice->spec, spec);
|
||||
} else {
|
||||
stream = SDL_CreateAudioStream(spec, &physdevice->spec);
|
||||
}
|
||||
return stream;
|
||||
|
||||
if (!stream) {
|
||||
SDL_CloseAudioDevice(logdevid);
|
||||
return NULL; // error string should already be set.
|
||||
}
|
||||
if (SDL_BindAudioStream(logdevid, stream) == -1) {
|
||||
SDL_DestroyAudioStream(stream);
|
||||
SDL_CloseAudioDevice(logdevid);
|
||||
return NULL; // error string should already be set.
|
||||
}
|
||||
|
||||
logdev->simplified = SDL_TRUE; // forbid further binding changes on this logical device.
|
||||
stream->simplified = SDL_TRUE; // so we know to close the audio device when this is destroyed.
|
||||
|
||||
if (callback) {
|
||||
int rc;
|
||||
if (iscapture) {
|
||||
rc = SDL_SetAudioStreamPutCallback(stream, callback, userdata);
|
||||
} else {
|
||||
rc = SDL_SetAudioStreamGetCallback(stream, callback, userdata);
|
||||
}
|
||||
SDL_assert(rc == 0); // should only fail if stream==NULL atm.
|
||||
}
|
||||
|
||||
return stream; // ready to rock.
|
||||
}
|
||||
|
||||
#define NUM_FORMATS 8
|
||||
static const SDL_AudioFormat format_list[NUM_FORMATS][NUM_FORMATS + 1] = {
|
||||
{ SDL_AUDIO_U8, SDL_AUDIO_S8, SDL_AUDIO_S16LSB, SDL_AUDIO_S16MSB, SDL_AUDIO_S32LSB, SDL_AUDIO_S32MSB, SDL_AUDIO_F32LSB, SDL_AUDIO_F32MSB, 0 },
|
||||
{ SDL_AUDIO_S8, SDL_AUDIO_U8, SDL_AUDIO_S16LSB, SDL_AUDIO_S16MSB, SDL_AUDIO_S32LSB, SDL_AUDIO_S32MSB, SDL_AUDIO_F32LSB, SDL_AUDIO_F32MSB, 0 },
|
||||
{ SDL_AUDIO_S16LSB, SDL_AUDIO_S16MSB, SDL_AUDIO_S32LSB, SDL_AUDIO_S32MSB, SDL_AUDIO_F32LSB, SDL_AUDIO_F32MSB, SDL_AUDIO_U8, SDL_AUDIO_S8, 0 },
|
||||
{ SDL_AUDIO_S16MSB, SDL_AUDIO_S16LSB, SDL_AUDIO_S32MSB, SDL_AUDIO_S32LSB, SDL_AUDIO_F32MSB, SDL_AUDIO_F32LSB, SDL_AUDIO_U8, SDL_AUDIO_S8, 0 },
|
||||
{ SDL_AUDIO_S32LSB, SDL_AUDIO_S32MSB, SDL_AUDIO_F32LSB, SDL_AUDIO_F32MSB, SDL_AUDIO_S16LSB, SDL_AUDIO_S16MSB, SDL_AUDIO_U8, SDL_AUDIO_S8, 0 },
|
||||
{ SDL_AUDIO_S32MSB, SDL_AUDIO_S32LSB, SDL_AUDIO_F32MSB, SDL_AUDIO_F32LSB, SDL_AUDIO_S16MSB, SDL_AUDIO_S16LSB, SDL_AUDIO_U8, SDL_AUDIO_S8, 0 },
|
||||
{ SDL_AUDIO_F32LSB, SDL_AUDIO_F32MSB, SDL_AUDIO_S32LSB, SDL_AUDIO_S32MSB, SDL_AUDIO_S16LSB, SDL_AUDIO_S16MSB, SDL_AUDIO_U8, SDL_AUDIO_S8, 0 },
|
||||
{ SDL_AUDIO_F32MSB, SDL_AUDIO_F32LSB, SDL_AUDIO_S32MSB, SDL_AUDIO_S32LSB, SDL_AUDIO_S16MSB, SDL_AUDIO_S16LSB, SDL_AUDIO_U8, SDL_AUDIO_S8, 0 },
|
||||
{ SDL_AUDIO_U8, SDL_AUDIO_S8, SDL_AUDIO_S16LE, SDL_AUDIO_S16BE, SDL_AUDIO_S32LE, SDL_AUDIO_S32BE, SDL_AUDIO_F32LE, SDL_AUDIO_F32BE, 0 },
|
||||
{ SDL_AUDIO_S8, SDL_AUDIO_U8, SDL_AUDIO_S16LE, SDL_AUDIO_S16BE, SDL_AUDIO_S32LE, SDL_AUDIO_S32BE, SDL_AUDIO_F32LE, SDL_AUDIO_F32BE, 0 },
|
||||
{ SDL_AUDIO_S16LE, SDL_AUDIO_S16BE, SDL_AUDIO_S32LE, SDL_AUDIO_S32BE, SDL_AUDIO_F32LE, SDL_AUDIO_F32BE, SDL_AUDIO_U8, SDL_AUDIO_S8, 0 },
|
||||
{ SDL_AUDIO_S16BE, SDL_AUDIO_S16LE, SDL_AUDIO_S32BE, SDL_AUDIO_S32LE, SDL_AUDIO_F32BE, SDL_AUDIO_F32LE, SDL_AUDIO_U8, SDL_AUDIO_S8, 0 },
|
||||
{ SDL_AUDIO_S32LE, SDL_AUDIO_S32BE, SDL_AUDIO_F32LE, SDL_AUDIO_F32BE, SDL_AUDIO_S16LE, SDL_AUDIO_S16BE, SDL_AUDIO_U8, SDL_AUDIO_S8, 0 },
|
||||
{ SDL_AUDIO_S32BE, SDL_AUDIO_S32LE, SDL_AUDIO_F32BE, SDL_AUDIO_F32LE, SDL_AUDIO_S16BE, SDL_AUDIO_S16LE, SDL_AUDIO_U8, SDL_AUDIO_S8, 0 },
|
||||
{ SDL_AUDIO_F32LE, SDL_AUDIO_F32BE, SDL_AUDIO_S32LE, SDL_AUDIO_S32BE, SDL_AUDIO_S16LE, SDL_AUDIO_S16BE, SDL_AUDIO_U8, SDL_AUDIO_S8, 0 },
|
||||
{ SDL_AUDIO_F32BE, SDL_AUDIO_F32LE, SDL_AUDIO_S32BE, SDL_AUDIO_S32LE, SDL_AUDIO_S16BE, SDL_AUDIO_S16LE, SDL_AUDIO_U8, SDL_AUDIO_S8, 0 },
|
||||
};
|
||||
|
||||
const SDL_AudioFormat *SDL_ClosestAudioFormats(SDL_AudioFormat format)
|
||||
@ -1597,8 +1852,9 @@ void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device)
|
||||
SDL_AudioSpec spec;
|
||||
SDL_bool needs_migration = SDL_FALSE;
|
||||
SDL_zero(spec);
|
||||
|
||||
for (SDL_LogicalAudioDevice *logdev = current_default_device->logical_devices; logdev != NULL; logdev = logdev->next) {
|
||||
if (logdev->is_default) {
|
||||
if (logdev->opened_as_default) {
|
||||
needs_migration = SDL_TRUE;
|
||||
for (SDL_AudioStream *stream = logdev->bound_streams; stream != NULL; stream = stream->next_binding) {
|
||||
const SDL_AudioSpec *streamspec = iscapture ? &stream->dst_spec : &stream->src_spec;
|
||||
@ -1624,19 +1880,16 @@ void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device)
|
||||
}
|
||||
|
||||
if (needs_migration) {
|
||||
const SDL_bool spec_changed = !AUDIO_SPECS_EQUAL(current_default_device->spec, new_default_device->spec);
|
||||
const SDL_bool post_fmt_event = (spec_changed && SDL_EventEnabled(SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED)) ? SDL_TRUE : SDL_FALSE;
|
||||
SDL_LogicalAudioDevice *next = NULL;
|
||||
for (SDL_LogicalAudioDevice *logdev = current_default_device->logical_devices; logdev != NULL; logdev = next) {
|
||||
next = logdev->next;
|
||||
|
||||
if (!logdev->is_default) {
|
||||
if (!logdev->opened_as_default) {
|
||||
continue; // not opened as a default, leave it on the current physical device.
|
||||
}
|
||||
|
||||
// make sure all our streams are targeting the new device's format.
|
||||
for (SDL_AudioStream *stream = logdev->bound_streams; stream != NULL; stream = stream->next_binding) {
|
||||
SDL_SetAudioStreamFormat(stream, iscapture ? &new_default_device->spec : NULL, iscapture ? NULL : &new_default_device->spec);
|
||||
}
|
||||
|
||||
// now migrate the logical device.
|
||||
if (logdev->next) {
|
||||
logdev->next->prev = logdev->prev;
|
||||
@ -1652,8 +1905,25 @@ void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device)
|
||||
logdev->prev = NULL;
|
||||
logdev->next = new_default_device->logical_devices;
|
||||
new_default_device->logical_devices = logdev;
|
||||
|
||||
// make sure all our streams are targeting the new device's format.
|
||||
UpdateAudioStreamFormatsLogical(logdev);
|
||||
|
||||
// Post an event for each logical device we moved.
|
||||
if (post_fmt_event) {
|
||||
SDL_Event event;
|
||||
SDL_zero(event);
|
||||
event.type = SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED;
|
||||
event.common.timestamp = 0;
|
||||
event.adevice.iscapture = iscapture ? 1 : 0;
|
||||
event.adevice.which = logdev->instance_id;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
}
|
||||
|
||||
current_default_device->simple_copy = AudioDeviceCanUseSimpleCopy(current_default_device);
|
||||
new_default_device->simple_copy = AudioDeviceCanUseSimpleCopy(new_default_device);
|
||||
|
||||
if (current_default_device->logical_devices == NULL) { // nothing left on the current physical device, close it.
|
||||
// !!! FIXME: we _need_ to release this lock, but doing so can cause a race condition if someone opens a device while we're closing it.
|
||||
SDL_UnlockMutex(current_default_device->lock); // can't hold the lock or the audio thread will deadlock while we WaitThread it.
|
||||
@ -1675,31 +1945,56 @@ void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device)
|
||||
|
||||
int SDL_AudioDeviceFormatChangedAlreadyLocked(SDL_AudioDevice *device, const SDL_AudioSpec *newspec, int new_sample_frames)
|
||||
{
|
||||
const int orig_work_buffer_size = device->work_buffer_size;
|
||||
|
||||
if (AUDIO_SPECS_EQUAL(device->spec, *newspec) && new_sample_frames == device->sample_frames) {
|
||||
return 0; // we're already in that format.
|
||||
}
|
||||
|
||||
SDL_copyp(&device->spec, newspec);
|
||||
UpdateAudioStreamFormatsPhysical(device);
|
||||
|
||||
SDL_bool kill_device = SDL_FALSE;
|
||||
|
||||
const int orig_buffer_size = device->buffer_size;
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
device->sample_frames = new_sample_frames;
|
||||
SDL_UpdatedAudioDeviceFormat(device);
|
||||
if (device->work_buffer && (device->work_buffer_size > orig_work_buffer_size)) {
|
||||
SDL_aligned_free(device->work_buffer);
|
||||
device->work_buffer = (Uint8 *)SDL_aligned_alloc(SDL_SIMDGetAlignment(), device->work_buffer_size);
|
||||
if (!device->work_buffer) {
|
||||
kill_device = SDL_TRUE;
|
||||
}
|
||||
|
||||
if ((device->spec.format != newspec->format) || (device->spec.channels != newspec->channels) || (device->spec.freq != newspec->freq)) {
|
||||
SDL_memcpy(&device->spec, newspec, sizeof (*newspec));
|
||||
for (SDL_LogicalAudioDevice *logdev = device->logical_devices; !kill_device && (logdev != NULL); logdev = logdev->next) {
|
||||
for (SDL_AudioStream *stream = logdev->bound_streams; !kill_device && (stream != NULL); stream = stream->next_binding) {
|
||||
if (SDL_SetAudioStreamFormat(stream, iscapture ? &device->spec : NULL, iscapture ? NULL : &device->spec) == -1) {
|
||||
kill_device = SDL_TRUE;
|
||||
}
|
||||
if (device->postmix_buffer) {
|
||||
SDL_aligned_free(device->postmix_buffer);
|
||||
device->postmix_buffer = (float *)SDL_aligned_alloc(SDL_SIMDGetAlignment(), device->work_buffer_size);
|
||||
if (!device->postmix_buffer) {
|
||||
kill_device = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_aligned_free(device->mix_buffer);
|
||||
device->mix_buffer = NULL;
|
||||
if (device->spec.format != SDL_AUDIO_F32) {
|
||||
device->mix_buffer = (Uint8 *)SDL_aligned_alloc(SDL_SIMDGetAlignment(), device->work_buffer_size);
|
||||
if (!device->mix_buffer) {
|
||||
kill_device = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!kill_device) {
|
||||
device->sample_frames = new_sample_frames;
|
||||
SDL_UpdatedAudioDeviceFormat(device);
|
||||
if (device->work_buffer && (device->buffer_size > orig_buffer_size)) {
|
||||
SDL_aligned_free(device->work_buffer);
|
||||
device->work_buffer = (Uint8 *)SDL_aligned_alloc(SDL_SIMDGetAlignment(), device->buffer_size);
|
||||
if (!device->work_buffer) {
|
||||
kill_device = SDL_TRUE;
|
||||
}
|
||||
// Post an event for the physical device, and each logical device on this physical device.
|
||||
if (!kill_device && SDL_EventEnabled(SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED)) {
|
||||
SDL_Event event;
|
||||
SDL_zero(event);
|
||||
event.type = SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED;
|
||||
event.common.timestamp = 0;
|
||||
event.adevice.iscapture = device->iscapture ? 1 : 0;
|
||||
event.adevice.which = device->instance_id;
|
||||
SDL_PushEvent(&event);
|
||||
for (SDL_LogicalAudioDevice *logdev = device->logical_devices; logdev != NULL; logdev = logdev->next) {
|
||||
event.adevice.which = logdev->instance_id;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
}
|
||||
|
||||
|
1549
external/sdl/SDL/src/audio/SDL_audio_resampler_filter.h
vendored
1549
external/sdl/SDL/src/audio/SDL_audio_resampler_filter.h
vendored
File diff suppressed because it is too large
Load Diff
1176
external/sdl/SDL/src/audio/SDL_audiocvt.c
vendored
1176
external/sdl/SDL/src/audio/SDL_audiocvt.c
vendored
File diff suppressed because it is too large
Load Diff
516
external/sdl/SDL/src/audio/SDL_audioqueue.c
vendored
Normal file
516
external/sdl/SDL/src/audio/SDL_audioqueue.c
vendored
Normal file
@ -0,0 +1,516 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 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_audioqueue.h"
|
||||
|
||||
#define AUDIO_SPECS_EQUAL(x, y) (((x).format == (y).format) && ((x).channels == (y).channels) && ((x).freq == (y).freq))
|
||||
|
||||
struct SDL_AudioTrack
|
||||
{
|
||||
SDL_AudioSpec spec;
|
||||
SDL_bool flushed;
|
||||
SDL_AudioTrack *next;
|
||||
|
||||
size_t (*avail)(void *ctx);
|
||||
int (*write)(void *ctx, const Uint8 *buf, size_t len);
|
||||
size_t (*read)(void *ctx, Uint8 *buf, size_t len, SDL_bool advance);
|
||||
void (*destroy)(void *ctx);
|
||||
};
|
||||
|
||||
struct SDL_AudioQueue
|
||||
{
|
||||
SDL_AudioTrack *head;
|
||||
SDL_AudioTrack *tail;
|
||||
size_t chunk_size;
|
||||
};
|
||||
|
||||
typedef struct SDL_AudioChunk SDL_AudioChunk;
|
||||
|
||||
struct SDL_AudioChunk
|
||||
{
|
||||
SDL_AudioChunk *next;
|
||||
size_t head;
|
||||
size_t tail;
|
||||
Uint8 data[SDL_VARIABLE_LENGTH_ARRAY];
|
||||
};
|
||||
|
||||
typedef struct SDL_ChunkedAudioTrack
|
||||
{
|
||||
SDL_AudioTrack track;
|
||||
|
||||
size_t chunk_size;
|
||||
|
||||
SDL_AudioChunk *head;
|
||||
SDL_AudioChunk *tail;
|
||||
size_t queued_bytes;
|
||||
|
||||
SDL_AudioChunk *free_chunks;
|
||||
size_t num_free_chunks;
|
||||
} SDL_ChunkedAudioTrack;
|
||||
|
||||
static void DestroyAudioChunk(SDL_AudioChunk *chunk)
|
||||
{
|
||||
SDL_free(chunk);
|
||||
}
|
||||
|
||||
static void DestroyAudioChunks(SDL_AudioChunk *chunk)
|
||||
{
|
||||
while (chunk) {
|
||||
SDL_AudioChunk *next = chunk->next;
|
||||
DestroyAudioChunk(chunk);
|
||||
chunk = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void ResetAudioChunk(SDL_AudioChunk *chunk)
|
||||
{
|
||||
chunk->next = NULL;
|
||||
chunk->head = 0;
|
||||
chunk->tail = 0;
|
||||
}
|
||||
|
||||
static SDL_AudioChunk *CreateAudioChunk(size_t chunk_size)
|
||||
{
|
||||
SDL_AudioChunk *chunk = (SDL_AudioChunk *)SDL_malloc(sizeof(*chunk) + chunk_size);
|
||||
|
||||
if (chunk == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ResetAudioChunk(chunk);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
static void DestroyAudioTrackChunk(SDL_ChunkedAudioTrack *track, SDL_AudioChunk *chunk)
|
||||
{
|
||||
// Keeping a list of free chunks reduces memory allocations,
|
||||
// But also increases the amount of work to perform when freeing the track.
|
||||
const size_t max_free_bytes = 64 * 1024;
|
||||
|
||||
if (track->chunk_size * track->num_free_chunks < max_free_bytes) {
|
||||
chunk->next = track->free_chunks;
|
||||
track->free_chunks = chunk;
|
||||
++track->num_free_chunks;
|
||||
} else {
|
||||
DestroyAudioChunk(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_AudioChunk *CreateAudioTrackChunk(SDL_ChunkedAudioTrack *track)
|
||||
{
|
||||
if (track->num_free_chunks > 0) {
|
||||
SDL_AudioChunk *chunk = track->free_chunks;
|
||||
|
||||
track->free_chunks = chunk->next;
|
||||
--track->num_free_chunks;
|
||||
|
||||
ResetAudioChunk(chunk);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
return CreateAudioChunk(track->chunk_size);
|
||||
}
|
||||
|
||||
static size_t AvailChunkedAudioTrack(void *ctx)
|
||||
{
|
||||
SDL_ChunkedAudioTrack *track = ctx;
|
||||
|
||||
return track->queued_bytes;
|
||||
}
|
||||
|
||||
static int WriteToChunkedAudioTrack(void *ctx, const Uint8 *data, size_t len)
|
||||
{
|
||||
SDL_ChunkedAudioTrack *track = ctx;
|
||||
|
||||
SDL_AudioChunk *chunk = track->tail;
|
||||
|
||||
// Handle the first chunk
|
||||
if (chunk == NULL) {
|
||||
chunk = CreateAudioTrackChunk(track);
|
||||
|
||||
if (chunk == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
SDL_assert((track->head == NULL) && (track->tail == NULL) && (track->queued_bytes == 0));
|
||||
track->head = chunk;
|
||||
track->tail = chunk;
|
||||
}
|
||||
|
||||
size_t total = 0;
|
||||
size_t old_tail = chunk->tail;
|
||||
size_t chunk_size = track->chunk_size;
|
||||
|
||||
while (chunk) {
|
||||
size_t to_write = chunk_size - chunk->tail;
|
||||
to_write = SDL_min(to_write, len - total);
|
||||
SDL_memcpy(&chunk->data[chunk->tail], &data[total], to_write);
|
||||
total += to_write;
|
||||
|
||||
chunk->tail += to_write;
|
||||
|
||||
if (total == len) {
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_AudioChunk *next = CreateAudioTrackChunk(track);
|
||||
chunk->next = next;
|
||||
chunk = next;
|
||||
}
|
||||
|
||||
// Roll back the changes if we couldn't write all the data
|
||||
if (chunk == NULL) {
|
||||
chunk = track->tail;
|
||||
|
||||
SDL_AudioChunk *next = chunk->next;
|
||||
chunk->next = NULL;
|
||||
chunk->tail = old_tail;
|
||||
|
||||
DestroyAudioChunks(next);
|
||||
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
track->tail = chunk;
|
||||
track->queued_bytes += total;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t ReadFromChunkedAudioTrack(void *ctx, Uint8 *data, size_t len, SDL_bool advance)
|
||||
{
|
||||
SDL_ChunkedAudioTrack *track = ctx;
|
||||
SDL_AudioChunk *chunk = track->head;
|
||||
|
||||
size_t total = 0;
|
||||
size_t head = 0;
|
||||
|
||||
while (chunk) {
|
||||
head = chunk->head;
|
||||
|
||||
size_t to_read = chunk->tail - head;
|
||||
to_read = SDL_min(to_read, len - total);
|
||||
SDL_memcpy(&data[total], &chunk->data[head], to_read);
|
||||
total += to_read;
|
||||
|
||||
SDL_AudioChunk *next = chunk->next;
|
||||
|
||||
if (total == len) {
|
||||
head += to_read;
|
||||
break;
|
||||
}
|
||||
|
||||
if (advance) {
|
||||
DestroyAudioTrackChunk(track, chunk);
|
||||
}
|
||||
|
||||
chunk = next;
|
||||
}
|
||||
|
||||
if (advance) {
|
||||
if (chunk) {
|
||||
chunk->head = head;
|
||||
track->head = chunk;
|
||||
} else {
|
||||
track->head = NULL;
|
||||
track->tail = NULL;
|
||||
}
|
||||
|
||||
track->queued_bytes -= total;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static void DestroyChunkedAudioTrack(void *ctx)
|
||||
{
|
||||
SDL_ChunkedAudioTrack *track = ctx;
|
||||
DestroyAudioChunks(track->head);
|
||||
DestroyAudioChunks(track->free_chunks);
|
||||
SDL_free(track);
|
||||
}
|
||||
|
||||
static SDL_AudioTrack *CreateChunkedAudioTrack(const SDL_AudioSpec *spec, size_t chunk_size)
|
||||
{
|
||||
SDL_ChunkedAudioTrack *track = (SDL_ChunkedAudioTrack *)SDL_calloc(1, sizeof(*track));
|
||||
|
||||
if (track == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_copyp(&track->track.spec, spec);
|
||||
track->track.avail = AvailChunkedAudioTrack;
|
||||
track->track.write = WriteToChunkedAudioTrack;
|
||||
track->track.read = ReadFromChunkedAudioTrack;
|
||||
track->track.destroy = DestroyChunkedAudioTrack;
|
||||
|
||||
track->chunk_size = chunk_size;
|
||||
|
||||
return &track->track;
|
||||
}
|
||||
|
||||
SDL_AudioQueue *SDL_CreateAudioQueue(size_t chunk_size)
|
||||
{
|
||||
SDL_AudioQueue *queue = (SDL_AudioQueue *)SDL_calloc(1, sizeof(*queue));
|
||||
|
||||
if (queue == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
queue->chunk_size = chunk_size;
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
void SDL_DestroyAudioQueue(SDL_AudioQueue *queue)
|
||||
{
|
||||
SDL_ClearAudioQueue(queue);
|
||||
|
||||
SDL_free(queue);
|
||||
}
|
||||
|
||||
void SDL_ClearAudioQueue(SDL_AudioQueue *queue)
|
||||
{
|
||||
SDL_AudioTrack *track = queue->head;
|
||||
queue->head = NULL;
|
||||
queue->tail = NULL;
|
||||
|
||||
while (track) {
|
||||
SDL_AudioTrack *next = track->next;
|
||||
track->destroy(track);
|
||||
track = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_FlushAudioTrack(SDL_AudioTrack *track)
|
||||
{
|
||||
track->flushed = SDL_TRUE;
|
||||
track->write = NULL;
|
||||
}
|
||||
|
||||
void SDL_FlushAudioQueue(SDL_AudioQueue *queue)
|
||||
{
|
||||
SDL_AudioTrack *track = queue->tail;
|
||||
|
||||
if (track) {
|
||||
SDL_FlushAudioTrack(track);
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_PopAudioQueueHead(SDL_AudioQueue *queue)
|
||||
{
|
||||
SDL_AudioTrack *track = queue->head;
|
||||
|
||||
for (;;) {
|
||||
SDL_bool flushed = track->flushed;
|
||||
|
||||
SDL_AudioTrack *next = track->next;
|
||||
track->destroy(track);
|
||||
track = next;
|
||||
|
||||
if (flushed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
queue->head = track;
|
||||
|
||||
if (track == NULL) {
|
||||
queue->tail = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t SDL_GetAudioQueueChunkSize(SDL_AudioQueue *queue)
|
||||
{
|
||||
return queue->chunk_size;
|
||||
}
|
||||
|
||||
SDL_AudioTrack *SDL_CreateChunkedAudioTrack(const SDL_AudioSpec *spec, const Uint8 *data, size_t len, size_t chunk_size)
|
||||
{
|
||||
SDL_AudioTrack *track = CreateChunkedAudioTrack(spec, chunk_size);
|
||||
|
||||
if (track == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (track->write(track, data, len) != 0) {
|
||||
track->destroy(track);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return track;
|
||||
}
|
||||
|
||||
void SDL_AddTrackToAudioQueue(SDL_AudioQueue *queue, SDL_AudioTrack *track)
|
||||
{
|
||||
SDL_AudioTrack *tail = queue->tail;
|
||||
|
||||
if (tail) {
|
||||
// If the spec has changed, make sure to flush the previous track
|
||||
if (!AUDIO_SPECS_EQUAL(tail->spec, track->spec)) {
|
||||
SDL_FlushAudioTrack(tail);
|
||||
}
|
||||
|
||||
tail->next = track;
|
||||
} else {
|
||||
queue->head = track;
|
||||
}
|
||||
|
||||
queue->tail = track;
|
||||
}
|
||||
|
||||
int SDL_WriteToAudioQueue(SDL_AudioQueue *queue, const SDL_AudioSpec *spec, const Uint8 *data, size_t len)
|
||||
{
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_AudioTrack *track = queue->tail;
|
||||
|
||||
if ((track != NULL) && !AUDIO_SPECS_EQUAL(track->spec, *spec)) {
|
||||
SDL_FlushAudioTrack(track);
|
||||
}
|
||||
|
||||
if ((track == NULL) || (track->write == NULL)) {
|
||||
SDL_AudioTrack *new_track = CreateChunkedAudioTrack(spec, queue->chunk_size);
|
||||
|
||||
if (new_track == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
if (track) {
|
||||
track->next = new_track;
|
||||
} else {
|
||||
queue->head = new_track;
|
||||
}
|
||||
|
||||
queue->tail = new_track;
|
||||
|
||||
track = new_track;
|
||||
}
|
||||
|
||||
return track->write(track, data, len);
|
||||
}
|
||||
|
||||
void *SDL_BeginAudioQueueIter(SDL_AudioQueue *queue)
|
||||
{
|
||||
return queue->head;
|
||||
}
|
||||
|
||||
size_t SDL_NextAudioQueueIter(SDL_AudioQueue *queue, void **inout_iter, SDL_AudioSpec *out_spec, SDL_bool *out_flushed)
|
||||
{
|
||||
SDL_AudioTrack *iter = *inout_iter;
|
||||
SDL_assert(iter != NULL);
|
||||
|
||||
SDL_copyp(out_spec, &iter->spec);
|
||||
|
||||
SDL_bool flushed = SDL_FALSE;
|
||||
size_t queued_bytes = 0;
|
||||
|
||||
while (iter) {
|
||||
SDL_AudioTrack *track = iter;
|
||||
iter = iter->next;
|
||||
|
||||
size_t avail = track->avail(track);
|
||||
|
||||
if (avail >= SDL_SIZE_MAX - queued_bytes) {
|
||||
queued_bytes = SDL_SIZE_MAX;
|
||||
flushed = SDL_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
queued_bytes += avail;
|
||||
flushed = track->flushed;
|
||||
|
||||
if (flushed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*inout_iter = iter;
|
||||
*out_flushed = flushed;
|
||||
|
||||
return queued_bytes;
|
||||
}
|
||||
|
||||
int SDL_ReadFromAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len)
|
||||
{
|
||||
size_t total = 0;
|
||||
SDL_AudioTrack *track = queue->head;
|
||||
|
||||
for (;;) {
|
||||
if (track == NULL) {
|
||||
return SDL_SetError("Reading past end of queue");
|
||||
}
|
||||
|
||||
total += track->read(track, &data[total], len - total, SDL_TRUE);
|
||||
|
||||
if (total == len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (track->flushed) {
|
||||
return SDL_SetError("Reading past end of flushed track");
|
||||
}
|
||||
|
||||
SDL_AudioTrack *next = track->next;
|
||||
|
||||
if (next == NULL) {
|
||||
return SDL_SetError("Reading past end of incomplete track");
|
||||
}
|
||||
|
||||
queue->head = next;
|
||||
|
||||
track->destroy(track);
|
||||
track = next;
|
||||
}
|
||||
}
|
||||
|
||||
int SDL_PeekIntoAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len)
|
||||
{
|
||||
size_t total = 0;
|
||||
SDL_AudioTrack *track = queue->head;
|
||||
|
||||
for (;;) {
|
||||
if (track == NULL) {
|
||||
return SDL_SetError("Peeking past end of queue");
|
||||
}
|
||||
|
||||
total += track->read(track, &data[total], len - total, SDL_FALSE);
|
||||
|
||||
if (total == len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (track->flushed) {
|
||||
// If we have run out of data, fill the rest with silence.
|
||||
SDL_memset(&data[total], SDL_GetSilenceValueForFormat(track->spec.format), len - total);
|
||||
return 0;
|
||||
}
|
||||
|
||||
track = track->next;
|
||||
}
|
||||
}
|
77
external/sdl/SDL/src/audio/SDL_audioqueue.h
vendored
Normal file
77
external/sdl/SDL/src/audio/SDL_audioqueue.h
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 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"
|
||||
|
||||
#ifndef SDL_audioqueue_h_
|
||||
#define SDL_audioqueue_h_
|
||||
|
||||
// Internal functions used by SDL_AudioStream for queueing audio.
|
||||
|
||||
typedef struct SDL_AudioQueue SDL_AudioQueue;
|
||||
typedef struct SDL_AudioTrack SDL_AudioTrack;
|
||||
|
||||
// Create a new audio queue
|
||||
SDL_AudioQueue *SDL_CreateAudioQueue(size_t chunk_size);
|
||||
|
||||
// Destroy an audio queue
|
||||
void SDL_DestroyAudioQueue(SDL_AudioQueue *queue);
|
||||
|
||||
// Completely clear the queue
|
||||
void SDL_ClearAudioQueue(SDL_AudioQueue *queue);
|
||||
|
||||
// Mark the last track as flushed
|
||||
void SDL_FlushAudioQueue(SDL_AudioQueue *queue);
|
||||
|
||||
// Pop the current head track
|
||||
// REQUIRES: The head track must exist, and must have been flushed
|
||||
void SDL_PopAudioQueueHead(SDL_AudioQueue *queue);
|
||||
|
||||
// Get the chunk size, mostly for use with SDL_CreateChunkedAudioTrack
|
||||
// This can be called from any thread
|
||||
size_t SDL_GetAudioQueueChunkSize(SDL_AudioQueue *queue);
|
||||
|
||||
// Write data to the end of queue
|
||||
// REQUIRES: If the spec has changed, the last track must have been flushed
|
||||
int SDL_WriteToAudioQueue(SDL_AudioQueue *queue, const SDL_AudioSpec *spec, const Uint8 *data, size_t len);
|
||||
|
||||
// Create a track without needing to hold any locks
|
||||
SDL_AudioTrack *SDL_CreateChunkedAudioTrack(const SDL_AudioSpec *spec, const Uint8 *data, size_t len, size_t chunk_size);
|
||||
|
||||
// Add a track to the end of the queue
|
||||
// REQUIRES: `track != NULL`
|
||||
void SDL_AddTrackToAudioQueue(SDL_AudioQueue *queue, SDL_AudioTrack *track);
|
||||
|
||||
// Iterate over the tracks in the queue
|
||||
void *SDL_BeginAudioQueueIter(SDL_AudioQueue *queue);
|
||||
|
||||
// Query and update the track iterator
|
||||
// REQUIRES: `*inout_iter != NULL` (a valid iterator)
|
||||
size_t SDL_NextAudioQueueIter(SDL_AudioQueue *queue, void **inout_iter, SDL_AudioSpec *out_spec, SDL_bool *out_flushed);
|
||||
|
||||
// Read data from the start of the queue
|
||||
// REQUIRES: There must be enough data in the queue
|
||||
int SDL_ReadFromAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len);
|
||||
|
||||
// Peek into the start of the queue
|
||||
// REQUIRES: There must be enough data in the queue, unless it has been flushed, in which case missing data is filled with silence.
|
||||
int SDL_PeekIntoAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len);
|
||||
|
||||
#endif // SDL_audioqueue_h_
|
335
external/sdl/SDL/src/audio/SDL_audioresample.c
vendored
Normal file
335
external/sdl/SDL/src/audio/SDL_audioresample.c
vendored
Normal file
@ -0,0 +1,335 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 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_sysaudio.h"
|
||||
#include "SDL_audioresample.h"
|
||||
|
||||
/* SDL's resampler uses a "bandlimited interpolation" algorithm:
|
||||
https://ccrma.stanford.edu/~jos/resample/ */
|
||||
|
||||
#include "SDL_audio_resampler_filter.h"
|
||||
|
||||
/* For a given srcpos, `srcpos + frame` are sampled, where `-RESAMPLER_ZERO_CROSSINGS < frame <= RESAMPLER_ZERO_CROSSINGS`.
|
||||
* Note, when upsampling, it is also possible to start sampling from `srcpos = -1`. */
|
||||
#define RESAMPLER_MAX_PADDING_FRAMES (RESAMPLER_ZERO_CROSSINGS + 1)
|
||||
|
||||
#define RESAMPLER_FILTER_INTERP_BITS (32 - RESAMPLER_BITS_PER_ZERO_CROSSING)
|
||||
#define RESAMPLER_FILTER_INTERP_RANGE (1 << RESAMPLER_FILTER_INTERP_BITS)
|
||||
|
||||
#define RESAMPLER_SAMPLES_PER_FRAME (RESAMPLER_ZERO_CROSSINGS * 2)
|
||||
|
||||
#define RESAMPLER_FULL_FILTER_SIZE (RESAMPLER_SAMPLES_PER_FRAME * (RESAMPLER_SAMPLES_PER_ZERO_CROSSING + 1))
|
||||
|
||||
static void ResampleFrame_Scalar(const float *src, float *dst, const float *raw_filter, float interp, int chans)
|
||||
{
|
||||
int i, chan;
|
||||
|
||||
float filter[RESAMPLER_SAMPLES_PER_FRAME];
|
||||
|
||||
// Interpolate between the nearest two filters
|
||||
for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
|
||||
filter[i] = (raw_filter[i] * (1.0f - interp)) + (raw_filter[i + RESAMPLER_SAMPLES_PER_FRAME] * interp);
|
||||
}
|
||||
|
||||
if (chans == 2) {
|
||||
float out[2];
|
||||
out[0] = 0.0f;
|
||||
out[1] = 0.0f;
|
||||
|
||||
for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
|
||||
const float scale = filter[i];
|
||||
out[0] += src[i * 2 + 0] * scale;
|
||||
out[1] += src[i * 2 + 1] * scale;
|
||||
}
|
||||
|
||||
dst[0] = out[0];
|
||||
dst[1] = out[1];
|
||||
return;
|
||||
}
|
||||
|
||||
if (chans == 1) {
|
||||
float out = 0.0f;
|
||||
|
||||
for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
|
||||
out += src[i] * filter[i];
|
||||
}
|
||||
|
||||
dst[0] = out;
|
||||
return;
|
||||
}
|
||||
|
||||
for (chan = 0; chan < chans; chan++) {
|
||||
float f = 0.0f;
|
||||
|
||||
for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
|
||||
f += src[i * chans + chan] * filter[i];
|
||||
}
|
||||
|
||||
dst[chan] = f;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SDL_SSE_INTRINSICS
|
||||
static void SDL_TARGETING("sse") ResampleFrame_SSE(const float *src, float *dst, const float *raw_filter, float interp, int chans)
|
||||
{
|
||||
#if RESAMPLER_SAMPLES_PER_FRAME != 10
|
||||
#error Invalid samples per frame
|
||||
#endif
|
||||
|
||||
// Load the filter
|
||||
__m128 f0 = _mm_loadu_ps(raw_filter + 0);
|
||||
__m128 f1 = _mm_loadu_ps(raw_filter + 4);
|
||||
__m128 f2 = _mm_loadl_pi(_mm_setzero_ps(), (const __m64 *)(raw_filter + 8));
|
||||
|
||||
__m128 g0 = _mm_loadu_ps(raw_filter + 10);
|
||||
__m128 g1 = _mm_loadu_ps(raw_filter + 14);
|
||||
__m128 g2 = _mm_loadl_pi(_mm_setzero_ps(), (const __m64 *)(raw_filter + 18));
|
||||
|
||||
__m128 interp1 = _mm_set1_ps(interp);
|
||||
__m128 interp2 = _mm_sub_ps(_mm_set1_ps(1.0f), _mm_set1_ps(interp));
|
||||
|
||||
// Linear interpolate the filter
|
||||
f0 = _mm_add_ps(_mm_mul_ps(f0, interp2), _mm_mul_ps(g0, interp1));
|
||||
f1 = _mm_add_ps(_mm_mul_ps(f1, interp2), _mm_mul_ps(g1, interp1));
|
||||
f2 = _mm_add_ps(_mm_mul_ps(f2, interp2), _mm_mul_ps(g2, interp1));
|
||||
|
||||
if (chans == 2) {
|
||||
// Duplicate each of the filter elements
|
||||
g0 = _mm_unpackhi_ps(f0, f0);
|
||||
f0 = _mm_unpacklo_ps(f0, f0);
|
||||
g1 = _mm_unpackhi_ps(f1, f1);
|
||||
f1 = _mm_unpacklo_ps(f1, f1);
|
||||
f2 = _mm_unpacklo_ps(f2, f2);
|
||||
|
||||
// Multiply the filter by the input
|
||||
f0 = _mm_mul_ps(f0, _mm_loadu_ps(src + 0));
|
||||
g0 = _mm_mul_ps(g0, _mm_loadu_ps(src + 4));
|
||||
f1 = _mm_mul_ps(f1, _mm_loadu_ps(src + 8));
|
||||
g1 = _mm_mul_ps(g1, _mm_loadu_ps(src + 12));
|
||||
f2 = _mm_mul_ps(f2, _mm_loadu_ps(src + 16));
|
||||
|
||||
// Calculate the sum
|
||||
f0 = _mm_add_ps(_mm_add_ps(_mm_add_ps(f0, g0), _mm_add_ps(f1, g1)), f2);
|
||||
f0 = _mm_add_ps(f0, _mm_movehl_ps(f0, f0));
|
||||
|
||||
// Store the result
|
||||
_mm_storel_pi((__m64 *)dst, f0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (chans == 1) {
|
||||
// Multiply the filter by the input
|
||||
f0 = _mm_mul_ps(f0, _mm_loadu_ps(src + 0));
|
||||
f1 = _mm_mul_ps(f1, _mm_loadu_ps(src + 4));
|
||||
f2 = _mm_mul_ps(f2, _mm_loadl_pi(_mm_setzero_ps(), (const __m64 *)(src + 8)));
|
||||
|
||||
// Calculate the sum
|
||||
f0 = _mm_add_ps(f0, f1);
|
||||
f0 = _mm_add_ps(_mm_add_ps(f0, f2), _mm_movehl_ps(f0, f0));
|
||||
f0 = _mm_add_ss(f0, _mm_shuffle_ps(f0, f0, _MM_SHUFFLE(1, 1, 1, 1)));
|
||||
|
||||
// Store the result
|
||||
_mm_store_ss(dst, f0);
|
||||
return;
|
||||
}
|
||||
|
||||
float filter[RESAMPLER_SAMPLES_PER_FRAME];
|
||||
_mm_storeu_ps(filter + 0, f0);
|
||||
_mm_storeu_ps(filter + 4, f1);
|
||||
_mm_storel_pi((__m64 *)(filter + 8), f2);
|
||||
|
||||
int i, chan = 0;
|
||||
|
||||
for (; chan + 4 <= chans; chan += 4) {
|
||||
f0 = _mm_setzero_ps();
|
||||
|
||||
for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
|
||||
f0 = _mm_add_ps(f0, _mm_mul_ps(_mm_loadu_ps(&src[i * chans + chan]), _mm_load1_ps(&filter[i])));
|
||||
}
|
||||
|
||||
_mm_storeu_ps(&dst[chan], f0);
|
||||
}
|
||||
|
||||
for (; chan < chans; chan++) {
|
||||
f0 = _mm_setzero_ps();
|
||||
|
||||
for (i = 0; i < RESAMPLER_SAMPLES_PER_FRAME; i++) {
|
||||
f0 = _mm_add_ss(f0, _mm_mul_ss(_mm_load_ss(&src[i * chans + chan]), _mm_load_ss(&filter[i])));
|
||||
}
|
||||
|
||||
_mm_store_ss(&dst[chan], f0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void (*ResampleFrame)(const float *src, float *dst, const float *raw_filter, float interp, int chans);
|
||||
|
||||
static float FullResamplerFilter[RESAMPLER_FULL_FILTER_SIZE];
|
||||
|
||||
void SDL_SetupAudioResampler(void)
|
||||
{
|
||||
static SDL_bool setup = SDL_FALSE;
|
||||
if (setup) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build a table combining the left and right wings, for faster access
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < RESAMPLER_SAMPLES_PER_ZERO_CROSSING; ++i) {
|
||||
for (j = 0; j < RESAMPLER_ZERO_CROSSINGS; j++) {
|
||||
int lwing = (i * RESAMPLER_SAMPLES_PER_FRAME) + (RESAMPLER_ZERO_CROSSINGS - 1) - j;
|
||||
int rwing = (RESAMPLER_FULL_FILTER_SIZE - 1) - lwing;
|
||||
|
||||
float value = ResamplerFilter[(i * RESAMPLER_ZERO_CROSSINGS) + j];
|
||||
FullResamplerFilter[lwing] = value;
|
||||
FullResamplerFilter[rwing] = value;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < RESAMPLER_ZERO_CROSSINGS; ++i) {
|
||||
int rwing = i + RESAMPLER_ZERO_CROSSINGS;
|
||||
int lwing = (RESAMPLER_FULL_FILTER_SIZE - 1) - rwing;
|
||||
|
||||
FullResamplerFilter[lwing] = 0.0f;
|
||||
FullResamplerFilter[rwing] = 0.0f;
|
||||
}
|
||||
|
||||
ResampleFrame = ResampleFrame_Scalar;
|
||||
|
||||
#ifdef SDL_SSE_INTRINSICS
|
||||
if (SDL_HasSSE()) {
|
||||
ResampleFrame = ResampleFrame_SSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
setup = SDL_TRUE;
|
||||
}
|
||||
|
||||
Sint64 SDL_GetResampleRate(int src_rate, int dst_rate)
|
||||
{
|
||||
SDL_assert(src_rate > 0);
|
||||
SDL_assert(dst_rate > 0);
|
||||
|
||||
Sint64 sample_rate = ((Sint64)src_rate << 32) / (Sint64)dst_rate;
|
||||
SDL_assert(sample_rate > 0);
|
||||
|
||||
return sample_rate;
|
||||
}
|
||||
|
||||
int SDL_GetResamplerHistoryFrames(void)
|
||||
{
|
||||
// Even if we aren't currently resampling, make sure to keep enough history in case we need to later.
|
||||
|
||||
return RESAMPLER_MAX_PADDING_FRAMES;
|
||||
}
|
||||
|
||||
int SDL_GetResamplerPaddingFrames(Sint64 resample_rate)
|
||||
{
|
||||
// This must always be <= SDL_GetResamplerHistoryFrames()
|
||||
|
||||
return resample_rate ? RESAMPLER_MAX_PADDING_FRAMES : 0;
|
||||
}
|
||||
|
||||
// These are not general purpose. They do not check for all possible underflow/overflow
|
||||
SDL_FORCE_INLINE Sint64 ResamplerAdd(Sint64 a, Sint64 b, Sint64 *ret)
|
||||
{
|
||||
if ((b > 0) && (a > SDL_MAX_SINT64 - b)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ret = a + b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE Sint64 ResamplerMul(Sint64 a, Sint64 b, Sint64 *ret)
|
||||
{
|
||||
if ((b > 0) && (a > SDL_MAX_SINT64 / b)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ret = a * b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Sint64 SDL_GetResamplerInputFrames(Sint64 output_frames, Sint64 resample_rate, Sint64 resample_offset)
|
||||
{
|
||||
// Calculate the index of the last input frame, then add 1.
|
||||
// ((((output_frames - 1) * resample_rate) + resample_offset) >> 32) + 1
|
||||
|
||||
Sint64 output_offset;
|
||||
if (ResamplerMul(output_frames, resample_rate, &output_offset) ||
|
||||
ResamplerAdd(output_offset, -resample_rate + resample_offset + 0x100000000, &output_offset)) {
|
||||
output_offset = SDL_MAX_SINT64;
|
||||
}
|
||||
|
||||
Sint64 input_frames = (Sint64)(Sint32)(output_offset >> 32);
|
||||
input_frames = SDL_max(input_frames, 0);
|
||||
|
||||
return input_frames;
|
||||
}
|
||||
|
||||
Sint64 SDL_GetResamplerOutputFrames(Sint64 input_frames, Sint64 resample_rate, Sint64 *inout_resample_offset)
|
||||
{
|
||||
Sint64 resample_offset = *inout_resample_offset;
|
||||
|
||||
// input_offset = (input_frames << 32) - resample_offset;
|
||||
Sint64 input_offset;
|
||||
if (ResamplerMul(input_frames, 0x100000000, &input_offset) ||
|
||||
ResamplerAdd(input_offset, -resample_offset, &input_offset)) {
|
||||
input_offset = SDL_MAX_SINT64;
|
||||
}
|
||||
|
||||
// output_frames = div_ceil(input_offset, resample_rate)
|
||||
Sint64 output_frames = (input_offset > 0) ? (((input_offset - 1) / resample_rate) + 1) : 0;
|
||||
|
||||
*inout_resample_offset = (output_frames * resample_rate) - input_offset;
|
||||
|
||||
return output_frames;
|
||||
}
|
||||
|
||||
void SDL_ResampleAudio(int chans, const float *src, int inframes, float *dst, int outframes,
|
||||
Sint64 resample_rate, Sint64 *inout_resample_offset)
|
||||
{
|
||||
int i;
|
||||
Sint64 srcpos = *inout_resample_offset;
|
||||
|
||||
SDL_assert(resample_rate > 0);
|
||||
|
||||
for (i = 0; i < outframes; i++) {
|
||||
int srcindex = (int)(Sint32)(srcpos >> 32);
|
||||
Uint32 srcfraction = (Uint32)(srcpos & 0xFFFFFFFF);
|
||||
srcpos += resample_rate;
|
||||
|
||||
SDL_assert(srcindex >= -1 && srcindex < inframes);
|
||||
|
||||
const float *filter = &FullResamplerFilter[(srcfraction >> RESAMPLER_FILTER_INTERP_BITS) * RESAMPLER_SAMPLES_PER_FRAME];
|
||||
const float interp = (float)(srcfraction & (RESAMPLER_FILTER_INTERP_RANGE - 1)) * (1.0f / RESAMPLER_FILTER_INTERP_RANGE);
|
||||
|
||||
const float *frame = &src[(srcindex - (RESAMPLER_ZERO_CROSSINGS - 1)) * chans];
|
||||
ResampleFrame(frame, dst, filter, interp, chans);
|
||||
|
||||
dst += chans;
|
||||
}
|
||||
|
||||
*inout_resample_offset = srcpos - ((Sint64)inframes << 32);
|
||||
}
|
43
external/sdl/SDL/src/audio/SDL_audioresample.h
vendored
Normal file
43
external/sdl/SDL/src/audio/SDL_audioresample.h
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 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"
|
||||
|
||||
#ifndef SDL_audioresample_h_
|
||||
#define SDL_audioresample_h_
|
||||
|
||||
// Internal functions used by SDL_AudioStream for resampling audio.
|
||||
// The resampler uses 32:32 fixed-point arithmetic to track its position.
|
||||
|
||||
Sint64 SDL_GetResampleRate(const int src_rate, const int dst_rate);
|
||||
|
||||
int SDL_GetResamplerHistoryFrames(void);
|
||||
int SDL_GetResamplerPaddingFrames(Sint64 resample_rate);
|
||||
|
||||
Sint64 SDL_GetResamplerInputFrames(Sint64 output_frames, Sint64 resample_rate, Sint64 resample_offset);
|
||||
Sint64 SDL_GetResamplerOutputFrames(Sint64 input_frames, Sint64 resample_rate, Sint64 *inout_resample_offset);
|
||||
|
||||
// Resample some audio.
|
||||
// REQUIRES: `inframes >= SDL_GetResamplerInputFrames(outframes)`
|
||||
// REQUIRES: At least `SDL_GetResamplerPaddingFrames(...)` extra frames to the left of src, and right of src+inframes
|
||||
void SDL_ResampleAudio(int chans, const float *src, int inframes, float *dst, int outframes,
|
||||
Sint64 resample_rate, Sint64 *inout_resample_offset);
|
||||
|
||||
#endif // SDL_audioresample_h_
|
770
external/sdl/SDL/src/audio/SDL_audiotypecvt.c
vendored
770
external/sdl/SDL/src/audio/SDL_audiotypecvt.c
vendored
@ -39,482 +39,510 @@
|
||||
#define NEED_SCALAR_CONVERTER_FALLBACKS 1
|
||||
#endif
|
||||
|
||||
#define DIVBY128 0.0078125f
|
||||
#define DIVBY32768 0.000030517578125f
|
||||
#define DIVBY8388607 0.00000011920930376163766f
|
||||
#define DIVBY2147483648 0.0000000004656612873077392578125f /* 0x1p-31f */
|
||||
|
||||
#if NEED_SCALAR_CONVERTER_FALLBACKS
|
||||
|
||||
/* these all convert backwards because (currently) float32 is >= to the size of anything it converts to, so it lets us safely convert in-place. */
|
||||
#define AUDIOCVT_TOFLOAT_SCALAR(from, fromtype, equation) \
|
||||
static void SDL_Convert_##from##_to_F32_Scalar(float *dst, const fromtype *src, int num_samples) { \
|
||||
int i; \
|
||||
LOG_DEBUG_AUDIO_CONVERT(#from, "F32"); \
|
||||
for (i = num_samples - 1; i >= 0; --i) { \
|
||||
dst[i] = equation; \
|
||||
} \
|
||||
/* This code requires that floats are in the IEEE-754 binary32 format */
|
||||
SDL_COMPILE_TIME_ASSERT(float_bits, sizeof(float) == sizeof(Uint32));
|
||||
|
||||
union float_bits {
|
||||
Uint32 u32;
|
||||
float f32;
|
||||
};
|
||||
|
||||
static void SDL_Convert_S8_to_F32_Scalar(float *dst, const Sint8 *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("S8", "F32");
|
||||
|
||||
for (i = num_samples - 1; i >= 0; --i) {
|
||||
/* 1) Construct a float in the range [65536.0, 65538.0)
|
||||
* 2) Shift the float range to [-1.0, 1.0) */
|
||||
union float_bits x;
|
||||
x.u32 = (Uint8)src[i] ^ 0x47800080u;
|
||||
dst[i] = x.f32 - 65537.0f;
|
||||
}
|
||||
}
|
||||
|
||||
AUDIOCVT_TOFLOAT_SCALAR(S8, Sint8, ((float)src[i]) * DIVBY128)
|
||||
AUDIOCVT_TOFLOAT_SCALAR(U8, Uint8, (((float)src[i]) * DIVBY128) - 1.0f)
|
||||
AUDIOCVT_TOFLOAT_SCALAR(S16, Sint16, ((float)src[i]) * DIVBY32768)
|
||||
AUDIOCVT_TOFLOAT_SCALAR(S32, Sint32, ((float)(src[i] >> 8)) * DIVBY8388607)
|
||||
#undef AUDIOCVT_FROMFLOAT_SCALAR
|
||||
static void SDL_Convert_U8_to_F32_Scalar(float *dst, const Uint8 *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* these all convert forwards because (currently) float32 is >= to the size of anything it converts from, so it lets us safely convert in-place. */
|
||||
#define AUDIOCVT_FROMFLOAT_SCALAR(to, totype, clampmin, clampmax, equation) \
|
||||
static void SDL_Convert_F32_to_##to##_Scalar(totype *dst, const float *src, int num_samples) { \
|
||||
int i; \
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", #to); \
|
||||
for (i = 0; i < num_samples; i++) { \
|
||||
const float sample = src[i]; \
|
||||
if (sample >= 1.0f) { \
|
||||
dst[i] = (totype) (clampmax); \
|
||||
} else if (sample <= -1.0f) { \
|
||||
dst[i] = (totype) (clampmin); \
|
||||
} else { \
|
||||
dst[i] = (totype) (equation); \
|
||||
} \
|
||||
} \
|
||||
LOG_DEBUG_AUDIO_CONVERT("U8", "F32");
|
||||
|
||||
for (i = num_samples - 1; i >= 0; --i) {
|
||||
/* 1) Construct a float in the range [65536.0, 65538.0)
|
||||
* 2) Shift the float range to [-1.0, 1.0) */
|
||||
union float_bits x;
|
||||
x.u32 = src[i] ^ 0x47800000u;
|
||||
dst[i] = x.f32 - 65537.0f;
|
||||
}
|
||||
}
|
||||
|
||||
AUDIOCVT_FROMFLOAT_SCALAR(S8, Sint8, -128, 127, sample * 127.0f);
|
||||
AUDIOCVT_FROMFLOAT_SCALAR(U8, Uint8, 0, 255, (sample + 1.0f) * 127.0f);
|
||||
AUDIOCVT_FROMFLOAT_SCALAR(S16, Sint16, -32768, 32767, sample * 32767.0f);
|
||||
AUDIOCVT_FROMFLOAT_SCALAR(S32, Sint32, -2147483648LL, 2147483647, ((Sint32)(sample * 8388607.0f)) << 8);
|
||||
#undef AUDIOCVT_FROMFLOAT_SCALAR
|
||||
static void SDL_Convert_S16_to_F32_Scalar(float *dst, const Sint16 *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("S16", "F32");
|
||||
|
||||
for (i = num_samples - 1; i >= 0; --i) {
|
||||
/* 1) Construct a float in the range [256.0, 258.0)
|
||||
* 2) Shift the float range to [-1.0, 1.0) */
|
||||
union float_bits x;
|
||||
x.u32 = (Uint16)src[i] ^ 0x43808000u;
|
||||
dst[i] = x.f32 - 257.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_Convert_S32_to_F32_Scalar(float *dst, const Sint32 *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("S32", "F32");
|
||||
|
||||
for (i = num_samples - 1; i >= 0; --i) {
|
||||
dst[i] = (float)src[i] * DIVBY2147483648;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a bit-mask based on the sign-bit. Should optimize to a single arithmetic-shift-right */
|
||||
#define SIGNMASK(x) (Uint32)(0u - ((Uint32)(x) >> 31))
|
||||
|
||||
static void SDL_Convert_F32_to_S8_Scalar(Sint8 *dst, const float *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S8");
|
||||
|
||||
for (i = 0; i < num_samples; ++i) {
|
||||
/* 1) Shift the float range from [-1.0, 1.0] to [98303.0, 98305.0]
|
||||
* 2) Shift the integer range from [0x47BFFF80, 0x47C00080] to [-128, 128]
|
||||
* 3) Clamp the value to [-128, 127] */
|
||||
union float_bits x;
|
||||
x.f32 = src[i] + 98304.0f;
|
||||
|
||||
Uint32 y = x.u32 - 0x47C00000u;
|
||||
Uint32 z = 0x7Fu - (y ^ SIGNMASK(y));
|
||||
y = y ^ (z & SIGNMASK(z));
|
||||
|
||||
dst[i] = (Sint8)(y & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_U8_Scalar(Uint8 *dst, const float *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "U8");
|
||||
|
||||
for (i = 0; i < num_samples; ++i) {
|
||||
/* 1) Shift the float range from [-1.0, 1.0] to [98303.0, 98305.0]
|
||||
* 2) Shift the integer range from [0x47BFFF80, 0x47C00080] to [-128, 128]
|
||||
* 3) Clamp the value to [-128, 127]
|
||||
* 4) Shift the integer range from [-128, 127] to [0, 255] */
|
||||
union float_bits x;
|
||||
x.f32 = src[i] + 98304.0f;
|
||||
|
||||
Uint32 y = x.u32 - 0x47C00000u;
|
||||
Uint32 z = 0x7Fu - (y ^ SIGNMASK(y));
|
||||
y = (y ^ 0x80u) ^ (z & SIGNMASK(z));
|
||||
|
||||
dst[i] = (Uint8)(y & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_S16_Scalar(Sint16 *dst, const float *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S16");
|
||||
|
||||
for (i = 0; i < num_samples; ++i) {
|
||||
/* 1) Shift the float range from [-1.0, 1.0] to [383.0, 385.0]
|
||||
* 2) Shift the integer range from [0x43BF8000, 0x43C08000] to [-32768, 32768]
|
||||
* 3) Clamp values outside the [-32768, 32767] range */
|
||||
union float_bits x;
|
||||
x.f32 = src[i] + 384.0f;
|
||||
|
||||
Uint32 y = x.u32 - 0x43C00000u;
|
||||
Uint32 z = 0x7FFFu - (y ^ SIGNMASK(y));
|
||||
y = y ^ (z & SIGNMASK(z));
|
||||
|
||||
dst[i] = (Sint16)(y & 0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_S32_Scalar(Sint32 *dst, const float *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S32");
|
||||
|
||||
for (i = 0; i < num_samples; ++i) {
|
||||
/* 1) Shift the float range from [-1.0, 1.0] to [-2147483648.0, 2147483648.0]
|
||||
* 2) Set values outside the [-2147483648.0, 2147483647.0] range to -2147483648.0
|
||||
* 3) Convert the float to an integer, and fixup values outside the valid range */
|
||||
union float_bits x;
|
||||
x.f32 = src[i];
|
||||
|
||||
Uint32 y = x.u32 + 0x0F800000u;
|
||||
Uint32 z = y - 0xCF000000u;
|
||||
z &= SIGNMASK(y ^ z);
|
||||
x.u32 = y - z;
|
||||
|
||||
dst[i] = (Sint32)x.f32 ^ (Sint32)SIGNMASK(z);
|
||||
}
|
||||
}
|
||||
|
||||
#undef SIGNMASK
|
||||
|
||||
#endif /* NEED_SCALAR_CONVERTER_FALLBACKS */
|
||||
|
||||
#ifdef SDL_SSE2_INTRINSICS
|
||||
static void SDL_TARGETING("sse2") SDL_Convert_S8_to_F32_SSE2(float *dst, const Sint8 *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
int i = num_samples;
|
||||
|
||||
/* 1) Flip the sign bit to convert from S8 to U8 format
|
||||
* 2) Construct a float in the range [65536.0, 65538.0)
|
||||
* 3) Shift the float range to [-1.0, 1.0)
|
||||
* dst[i] = i2f((src[i] ^ 0x80) | 0x47800000) - 65537.0 */
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
const __m128i flipper = _mm_set1_epi8(-0x80);
|
||||
const __m128i caster = _mm_set1_epi16(0x4780 /* 0x47800000 = f2i(65536.0) */);
|
||||
const __m128 offset = _mm_set1_ps(-65537.0);
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("S8", "F32 (using SSE2)");
|
||||
|
||||
src += num_samples - 1;
|
||||
dst += num_samples - 1;
|
||||
while (i >= 16) {
|
||||
i -= 16;
|
||||
|
||||
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
||||
for (i = num_samples; i && (((size_t)(dst - 15)) & 15); --i, --src, --dst) {
|
||||
*dst = ((float)*src) * DIVBY128;
|
||||
const __m128i bytes = _mm_xor_si128(_mm_loadu_si128((const __m128i *)&src[i]), flipper);
|
||||
|
||||
const __m128i shorts1 = _mm_unpacklo_epi8(bytes, zero);
|
||||
const __m128i shorts2 = _mm_unpackhi_epi8(bytes, zero);
|
||||
|
||||
const __m128 floats1 = _mm_add_ps(_mm_castsi128_ps(_mm_unpacklo_epi16(shorts1, caster)), offset);
|
||||
const __m128 floats2 = _mm_add_ps(_mm_castsi128_ps(_mm_unpackhi_epi16(shorts1, caster)), offset);
|
||||
const __m128 floats3 = _mm_add_ps(_mm_castsi128_ps(_mm_unpacklo_epi16(shorts2, caster)), offset);
|
||||
const __m128 floats4 = _mm_add_ps(_mm_castsi128_ps(_mm_unpackhi_epi16(shorts2, caster)), offset);
|
||||
|
||||
_mm_storeu_ps(&dst[i], floats1);
|
||||
_mm_storeu_ps(&dst[i + 4], floats2);
|
||||
_mm_storeu_ps(&dst[i + 8], floats3);
|
||||
_mm_storeu_ps(&dst[i + 12], floats4);
|
||||
}
|
||||
|
||||
src -= 15;
|
||||
dst -= 15; /* adjust to read SSE blocks from the start. */
|
||||
SDL_assert(!i || !(((size_t)dst) & 15));
|
||||
|
||||
/* Make sure src is aligned too. */
|
||||
if (!(((size_t)src) & 15)) {
|
||||
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
|
||||
const __m128i *mmsrc = (const __m128i *)src;
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
const __m128 divby128 = _mm_set1_ps(DIVBY128);
|
||||
while (i >= 16) { /* 16 * 8-bit */
|
||||
const __m128i bytes = _mm_load_si128(mmsrc); /* get 16 sint8 into an XMM register. */
|
||||
/* treat as int16, shift left to clear every other sint16, then back right with sign-extend. Now sint16. */
|
||||
const __m128i shorts1 = _mm_srai_epi16(_mm_slli_epi16(bytes, 8), 8);
|
||||
/* right-shift-sign-extend gets us sint16 with the other set of values. */
|
||||
const __m128i shorts2 = _mm_srai_epi16(bytes, 8);
|
||||
/* unpack against zero to make these int32, shift to make them sign-extend, convert to float, multiply. Whew! */
|
||||
const __m128 floats1 = _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_slli_epi32(_mm_unpacklo_epi16(shorts1, zero), 16), 16)), divby128);
|
||||
const __m128 floats2 = _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_slli_epi32(_mm_unpacklo_epi16(shorts2, zero), 16), 16)), divby128);
|
||||
const __m128 floats3 = _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_slli_epi32(_mm_unpackhi_epi16(shorts1, zero), 16), 16)), divby128);
|
||||
const __m128 floats4 = _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_slli_epi32(_mm_unpackhi_epi16(shorts2, zero), 16), 16)), divby128);
|
||||
/* Interleave back into correct order, store. */
|
||||
_mm_store_ps(dst, _mm_unpacklo_ps(floats1, floats2));
|
||||
_mm_store_ps(dst + 4, _mm_unpackhi_ps(floats1, floats2));
|
||||
_mm_store_ps(dst + 8, _mm_unpacklo_ps(floats3, floats4));
|
||||
_mm_store_ps(dst + 12, _mm_unpackhi_ps(floats3, floats4));
|
||||
i -= 16;
|
||||
mmsrc--;
|
||||
dst -= 16;
|
||||
}
|
||||
|
||||
src = (const Sint8 *)mmsrc;
|
||||
}
|
||||
|
||||
src += 15;
|
||||
dst += 15; /* adjust for any scalar finishing. */
|
||||
|
||||
/* Finish off any leftovers with scalar operations. */
|
||||
while (i) {
|
||||
*dst = ((float)*src) * DIVBY128;
|
||||
i--;
|
||||
src--;
|
||||
dst--;
|
||||
--i;
|
||||
_mm_store_ss(&dst[i], _mm_add_ss(_mm_castsi128_ps(_mm_cvtsi32_si128((Uint8)src[i] ^ 0x47800080u)), offset));
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_TARGETING("sse2") SDL_Convert_U8_to_F32_SSE2(float *dst, const Uint8 *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
int i = num_samples;
|
||||
|
||||
/* 1) Construct a float in the range [65536.0, 65538.0)
|
||||
* 2) Shift the float range to [-1.0, 1.0)
|
||||
* dst[i] = i2f(src[i] | 0x47800000) - 65537.0 */
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
const __m128i caster = _mm_set1_epi16(0x4780 /* 0x47800000 = f2i(65536.0) */);
|
||||
const __m128 offset = _mm_set1_ps(-65537.0);
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("U8", "F32 (using SSE2)");
|
||||
|
||||
src += num_samples - 1;
|
||||
dst += num_samples - 1;
|
||||
while (i >= 16) {
|
||||
i -= 16;
|
||||
|
||||
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
||||
for (i = num_samples; i && (((size_t)(dst - 15)) & 15); --i, --src, --dst) {
|
||||
*dst = (((float)*src) * DIVBY128) - 1.0f;
|
||||
const __m128i bytes = _mm_loadu_si128((const __m128i *)&src[i]);
|
||||
|
||||
const __m128i shorts1 = _mm_unpacklo_epi8(bytes, zero);
|
||||
const __m128i shorts2 = _mm_unpackhi_epi8(bytes, zero);
|
||||
|
||||
const __m128 floats1 = _mm_add_ps(_mm_castsi128_ps(_mm_unpacklo_epi16(shorts1, caster)), offset);
|
||||
const __m128 floats2 = _mm_add_ps(_mm_castsi128_ps(_mm_unpackhi_epi16(shorts1, caster)), offset);
|
||||
const __m128 floats3 = _mm_add_ps(_mm_castsi128_ps(_mm_unpacklo_epi16(shorts2, caster)), offset);
|
||||
const __m128 floats4 = _mm_add_ps(_mm_castsi128_ps(_mm_unpackhi_epi16(shorts2, caster)), offset);
|
||||
|
||||
_mm_storeu_ps(&dst[i], floats1);
|
||||
_mm_storeu_ps(&dst[i + 4], floats2);
|
||||
_mm_storeu_ps(&dst[i + 8], floats3);
|
||||
_mm_storeu_ps(&dst[i + 12], floats4);
|
||||
}
|
||||
|
||||
src -= 15;
|
||||
dst -= 15; /* adjust to read SSE blocks from the start. */
|
||||
SDL_assert(!i || !(((size_t)dst) & 15));
|
||||
|
||||
/* Make sure src is aligned too. */
|
||||
if (!(((size_t)src) & 15)) {
|
||||
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
|
||||
const __m128i *mmsrc = (const __m128i *)src;
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
const __m128 divby128 = _mm_set1_ps(DIVBY128);
|
||||
const __m128 minus1 = _mm_set1_ps(-1.0f);
|
||||
while (i >= 16) { /* 16 * 8-bit */
|
||||
const __m128i bytes = _mm_load_si128(mmsrc); /* get 16 uint8 into an XMM register. */
|
||||
/* treat as int16, shift left to clear every other sint16, then back right with zero-extend. Now uint16. */
|
||||
const __m128i shorts1 = _mm_srli_epi16(_mm_slli_epi16(bytes, 8), 8);
|
||||
/* right-shift-zero-extend gets us uint16 with the other set of values. */
|
||||
const __m128i shorts2 = _mm_srli_epi16(bytes, 8);
|
||||
/* unpack against zero to make these int32, convert to float, multiply, add. Whew! */
|
||||
/* Note that AVX2 can do floating point multiply+add in one instruction, fwiw. SSE2 cannot. */
|
||||
const __m128 floats1 = _mm_add_ps(_mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(shorts1, zero)), divby128), minus1);
|
||||
const __m128 floats2 = _mm_add_ps(_mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(shorts2, zero)), divby128), minus1);
|
||||
const __m128 floats3 = _mm_add_ps(_mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi16(shorts1, zero)), divby128), minus1);
|
||||
const __m128 floats4 = _mm_add_ps(_mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi16(shorts2, zero)), divby128), minus1);
|
||||
/* Interleave back into correct order, store. */
|
||||
_mm_store_ps(dst, _mm_unpacklo_ps(floats1, floats2));
|
||||
_mm_store_ps(dst + 4, _mm_unpackhi_ps(floats1, floats2));
|
||||
_mm_store_ps(dst + 8, _mm_unpacklo_ps(floats3, floats4));
|
||||
_mm_store_ps(dst + 12, _mm_unpackhi_ps(floats3, floats4));
|
||||
i -= 16;
|
||||
mmsrc--;
|
||||
dst -= 16;
|
||||
}
|
||||
|
||||
src = (const Uint8 *)mmsrc;
|
||||
}
|
||||
|
||||
src += 15;
|
||||
dst += 15; /* adjust for any scalar finishing. */
|
||||
|
||||
/* Finish off any leftovers with scalar operations. */
|
||||
while (i) {
|
||||
*dst = (((float)*src) * DIVBY128) - 1.0f;
|
||||
i--;
|
||||
src--;
|
||||
dst--;
|
||||
--i;
|
||||
_mm_store_ss(&dst[i], _mm_add_ss(_mm_castsi128_ps(_mm_cvtsi32_si128((Uint8)src[i] ^ 0x47800000u)), offset));
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_TARGETING("sse2") SDL_Convert_S16_to_F32_SSE2(float *dst, const Sint16 *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
int i = num_samples;
|
||||
|
||||
/* 1) Flip the sign bit to convert from S16 to U16 format
|
||||
* 2) Construct a float in the range [256.0, 258.0)
|
||||
* 3) Shift the float range to [-1.0, 1.0)
|
||||
* dst[i] = i2f((src[i] ^ 0x8000) | 0x43800000) - 257.0 */
|
||||
const __m128i flipper = _mm_set1_epi16(-0x8000);
|
||||
const __m128i caster = _mm_set1_epi16(0x4380 /* 0x43800000 = f2i(256.0) */);
|
||||
const __m128 offset = _mm_set1_ps(-257.0f);
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("S16", "F32 (using SSE2)");
|
||||
|
||||
src += num_samples - 1;
|
||||
dst += num_samples - 1;
|
||||
while (i >= 16) {
|
||||
i -= 16;
|
||||
|
||||
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
||||
for (i = num_samples; i && (((size_t)(dst - 7)) & 15); --i, --src, --dst) {
|
||||
*dst = ((float)*src) * DIVBY32768;
|
||||
const __m128i shorts1 = _mm_xor_si128(_mm_loadu_si128((const __m128i *)&src[i]), flipper);
|
||||
const __m128i shorts2 = _mm_xor_si128(_mm_loadu_si128((const __m128i *)&src[i + 8]), flipper);
|
||||
|
||||
const __m128 floats1 = _mm_add_ps(_mm_castsi128_ps(_mm_unpacklo_epi16(shorts1, caster)), offset);
|
||||
const __m128 floats2 = _mm_add_ps(_mm_castsi128_ps(_mm_unpackhi_epi16(shorts1, caster)), offset);
|
||||
const __m128 floats3 = _mm_add_ps(_mm_castsi128_ps(_mm_unpacklo_epi16(shorts2, caster)), offset);
|
||||
const __m128 floats4 = _mm_add_ps(_mm_castsi128_ps(_mm_unpackhi_epi16(shorts2, caster)), offset);
|
||||
|
||||
_mm_storeu_ps(&dst[i], floats1);
|
||||
_mm_storeu_ps(&dst[i + 4], floats2);
|
||||
_mm_storeu_ps(&dst[i + 8], floats3);
|
||||
_mm_storeu_ps(&dst[i + 12], floats4);
|
||||
}
|
||||
|
||||
src -= 7;
|
||||
dst -= 7; /* adjust to read SSE blocks from the start. */
|
||||
SDL_assert(!i || !(((size_t)dst) & 15));
|
||||
|
||||
/* Make sure src is aligned too. */
|
||||
if (!(((size_t)src) & 15)) {
|
||||
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
|
||||
const __m128 divby32768 = _mm_set1_ps(DIVBY32768);
|
||||
while (i >= 8) { /* 8 * 16-bit */
|
||||
const __m128i ints = _mm_load_si128((__m128i const *)src); /* get 8 sint16 into an XMM register. */
|
||||
/* treat as int32, shift left to clear every other sint16, then back right with sign-extend. Now sint32. */
|
||||
const __m128i a = _mm_srai_epi32(_mm_slli_epi32(ints, 16), 16);
|
||||
/* right-shift-sign-extend gets us sint32 with the other set of values. */
|
||||
const __m128i b = _mm_srai_epi32(ints, 16);
|
||||
/* Interleave these back into the right order, convert to float, multiply, store. */
|
||||
_mm_store_ps(dst, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi32(a, b)), divby32768));
|
||||
_mm_store_ps(dst + 4, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi32(a, b)), divby32768));
|
||||
i -= 8;
|
||||
src -= 8;
|
||||
dst -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
src += 7;
|
||||
dst += 7; /* adjust for any scalar finishing. */
|
||||
|
||||
/* Finish off any leftovers with scalar operations. */
|
||||
while (i) {
|
||||
*dst = ((float)*src) * DIVBY32768;
|
||||
i--;
|
||||
src--;
|
||||
dst--;
|
||||
--i;
|
||||
_mm_store_ss(&dst[i], _mm_add_ss(_mm_castsi128_ps(_mm_cvtsi32_si128((Uint16)src[i] ^ 0x43808000u)), offset));
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_TARGETING("sse2") SDL_Convert_S32_to_F32_SSE2(float *dst, const Sint32 *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
int i = num_samples;
|
||||
|
||||
/* dst[i] = f32(src[i]) / f32(0x80000000) */
|
||||
const __m128 scaler = _mm_set1_ps(DIVBY2147483648);
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("S32", "F32 (using SSE2)");
|
||||
|
||||
/* Get dst aligned to 16 bytes */
|
||||
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||
*dst = ((float)(*src >> 8)) * DIVBY8388607;
|
||||
while (i >= 16) {
|
||||
i -= 16;
|
||||
|
||||
const __m128i ints1 = _mm_loadu_si128((const __m128i *)&src[i]);
|
||||
const __m128i ints2 = _mm_loadu_si128((const __m128i *)&src[i + 4]);
|
||||
const __m128i ints3 = _mm_loadu_si128((const __m128i *)&src[i + 8]);
|
||||
const __m128i ints4 = _mm_loadu_si128((const __m128i *)&src[i + 12]);
|
||||
|
||||
const __m128 floats1 = _mm_mul_ps(_mm_cvtepi32_ps(ints1), scaler);
|
||||
const __m128 floats2 = _mm_mul_ps(_mm_cvtepi32_ps(ints2), scaler);
|
||||
const __m128 floats3 = _mm_mul_ps(_mm_cvtepi32_ps(ints3), scaler);
|
||||
const __m128 floats4 = _mm_mul_ps(_mm_cvtepi32_ps(ints4), scaler);
|
||||
|
||||
_mm_storeu_ps(&dst[i], floats1);
|
||||
_mm_storeu_ps(&dst[i + 4], floats2);
|
||||
_mm_storeu_ps(&dst[i + 8], floats3);
|
||||
_mm_storeu_ps(&dst[i + 12], floats4);
|
||||
}
|
||||
|
||||
SDL_assert(!i || !(((size_t)dst) & 15));
|
||||
|
||||
/* Make sure src is aligned too. */
|
||||
if (!(((size_t)src) & 15)) {
|
||||
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
|
||||
const __m128 divby8388607 = _mm_set1_ps(DIVBY8388607);
|
||||
const __m128i *mmsrc = (const __m128i *)src;
|
||||
while (i >= 4) { /* 4 * sint32 */
|
||||
/* shift out lowest bits so int fits in a float32. Small precision loss, but much faster. */
|
||||
_mm_store_ps(dst, _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_load_si128(mmsrc), 8)), divby8388607));
|
||||
i -= 4;
|
||||
mmsrc++;
|
||||
dst += 4;
|
||||
}
|
||||
src = (const Sint32 *)mmsrc;
|
||||
}
|
||||
|
||||
/* Finish off any leftovers with scalar operations. */
|
||||
while (i) {
|
||||
*dst = ((float)(*src >> 8)) * DIVBY8388607;
|
||||
i--;
|
||||
src++;
|
||||
dst++;
|
||||
--i;
|
||||
_mm_store_ss(&dst[i], _mm_mul_ss(_mm_cvt_si2ss(_mm_setzero_ps(), src[i]), scaler));
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_TARGETING("sse2") SDL_Convert_F32_to_S8_SSE2(Sint8 *dst, const float *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
int i = num_samples;
|
||||
|
||||
/* 1) Shift the float range from [-1.0, 1.0] to [98303.0, 98305.0]
|
||||
* 2) Extract the lowest 16 bits and clamp to [-128, 127]
|
||||
* Overflow is correctly handled for inputs between roughly [-255.0, 255.0]
|
||||
* dst[i] = clamp(i16(f2i(src[i] + 98304.0) & 0xFFFF), -128, 127) */
|
||||
const __m128 offset = _mm_set1_ps(98304.0f);
|
||||
const __m128i mask = _mm_set1_epi16(0xFF);
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S8 (using SSE2)");
|
||||
|
||||
/* Get dst aligned to 16 bytes */
|
||||
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||
const float sample = *src;
|
||||
if (sample >= 1.0f) {
|
||||
*dst = 127;
|
||||
} else if (sample <= -1.0f) {
|
||||
*dst = -128;
|
||||
} else {
|
||||
*dst = (Sint8)(sample * 127.0f);
|
||||
}
|
||||
while (i >= 16) {
|
||||
const __m128 floats1 = _mm_loadu_ps(&src[0]);
|
||||
const __m128 floats2 = _mm_loadu_ps(&src[4]);
|
||||
const __m128 floats3 = _mm_loadu_ps(&src[8]);
|
||||
const __m128 floats4 = _mm_loadu_ps(&src[12]);
|
||||
|
||||
const __m128i ints1 = _mm_castps_si128(_mm_add_ps(floats1, offset));
|
||||
const __m128i ints2 = _mm_castps_si128(_mm_add_ps(floats2, offset));
|
||||
const __m128i ints3 = _mm_castps_si128(_mm_add_ps(floats3, offset));
|
||||
const __m128i ints4 = _mm_castps_si128(_mm_add_ps(floats4, offset));
|
||||
|
||||
const __m128i shorts1 = _mm_and_si128(_mm_packs_epi16(ints1, ints2), mask);
|
||||
const __m128i shorts2 = _mm_and_si128(_mm_packs_epi16(ints3, ints4), mask);
|
||||
|
||||
const __m128i bytes = _mm_packus_epi16(shorts1, shorts2);
|
||||
|
||||
_mm_storeu_si128((__m128i*)dst, bytes);
|
||||
|
||||
i -= 16;
|
||||
src += 16;
|
||||
dst += 16;
|
||||
}
|
||||
|
||||
SDL_assert(!i || !(((size_t)dst) & 15));
|
||||
|
||||
/* Make sure src is aligned too. */
|
||||
if (!(((size_t)src) & 15)) {
|
||||
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
|
||||
const __m128 one = _mm_set1_ps(1.0f);
|
||||
const __m128 negone = _mm_set1_ps(-1.0f);
|
||||
const __m128 mulby127 = _mm_set1_ps(127.0f);
|
||||
__m128i *mmdst = (__m128i *)dst;
|
||||
while (i >= 16) { /* 16 * float32 */
|
||||
const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
|
||||
const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src + 4)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
|
||||
const __m128i ints3 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src + 8)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
|
||||
const __m128i ints4 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src + 12)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
|
||||
_mm_store_si128(mmdst, _mm_packs_epi16(_mm_packs_epi32(ints1, ints2), _mm_packs_epi32(ints3, ints4))); /* pack down, store out. */
|
||||
i -= 16;
|
||||
src += 16;
|
||||
mmdst++;
|
||||
}
|
||||
dst = (Sint8 *)mmdst;
|
||||
}
|
||||
|
||||
/* Finish off any leftovers with scalar operations. */
|
||||
while (i) {
|
||||
const float sample = *src;
|
||||
if (sample >= 1.0f) {
|
||||
*dst = 127;
|
||||
} else if (sample <= -1.0f) {
|
||||
*dst = -128;
|
||||
} else {
|
||||
*dst = (Sint8)(sample * 127.0f);
|
||||
}
|
||||
i--;
|
||||
src++;
|
||||
dst++;
|
||||
const __m128i ints = _mm_castps_si128(_mm_add_ss(_mm_load_ss(src), offset));
|
||||
*dst = (Sint8)(_mm_cvtsi128_si32(_mm_packs_epi16(ints, ints)) & 0xFF);
|
||||
|
||||
--i;
|
||||
++src;
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_TARGETING("sse2") SDL_Convert_F32_to_U8_SSE2(Uint8 *dst, const float *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
int i = num_samples;
|
||||
|
||||
/* 1) Shift the float range from [-1.0, 1.0] to [98304.0, 98306.0]
|
||||
* 2) Extract the lowest 16 bits and clamp to [0, 255]
|
||||
* Overflow is correctly handled for inputs between roughly [-254.0, 254.0]
|
||||
* dst[i] = clamp(i16(f2i(src[i] + 98305.0) & 0xFFFF), 0, 255) */
|
||||
const __m128 offset = _mm_set1_ps(98305.0f);
|
||||
const __m128i mask = _mm_set1_epi16(0xFF);
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "U8 (using SSE2)");
|
||||
|
||||
/* Get dst aligned to 16 bytes */
|
||||
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||
const float sample = *src;
|
||||
if (sample >= 1.0f) {
|
||||
*dst = 255;
|
||||
} else if (sample <= -1.0f) {
|
||||
*dst = 0;
|
||||
} else {
|
||||
*dst = (Uint8)((sample + 1.0f) * 127.0f);
|
||||
}
|
||||
while (i >= 16) {
|
||||
const __m128 floats1 = _mm_loadu_ps(&src[0]);
|
||||
const __m128 floats2 = _mm_loadu_ps(&src[4]);
|
||||
const __m128 floats3 = _mm_loadu_ps(&src[8]);
|
||||
const __m128 floats4 = _mm_loadu_ps(&src[12]);
|
||||
|
||||
const __m128i ints1 = _mm_castps_si128(_mm_add_ps(floats1, offset));
|
||||
const __m128i ints2 = _mm_castps_si128(_mm_add_ps(floats2, offset));
|
||||
const __m128i ints3 = _mm_castps_si128(_mm_add_ps(floats3, offset));
|
||||
const __m128i ints4 = _mm_castps_si128(_mm_add_ps(floats4, offset));
|
||||
|
||||
const __m128i shorts1 = _mm_and_si128(_mm_packus_epi16(ints1, ints2), mask);
|
||||
const __m128i shorts2 = _mm_and_si128(_mm_packus_epi16(ints3, ints4), mask);
|
||||
|
||||
const __m128i bytes = _mm_packus_epi16(shorts1, shorts2);
|
||||
|
||||
_mm_storeu_si128((__m128i*)dst, bytes);
|
||||
|
||||
i -= 16;
|
||||
src += 16;
|
||||
dst += 16;
|
||||
}
|
||||
|
||||
SDL_assert(!i || !(((size_t)dst) & 15));
|
||||
|
||||
/* Make sure src is aligned too. */
|
||||
if (!(((size_t)src) & 15)) {
|
||||
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
|
||||
const __m128 one = _mm_set1_ps(1.0f);
|
||||
const __m128 negone = _mm_set1_ps(-1.0f);
|
||||
const __m128 mulby127 = _mm_set1_ps(127.0f);
|
||||
__m128i *mmdst = (__m128i *)dst;
|
||||
while (i >= 16) { /* 16 * float32 */
|
||||
const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
|
||||
const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src + 4)), one), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
|
||||
const __m128i ints3 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src + 8)), one), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
|
||||
const __m128i ints4 = _mm_cvtps_epi32(_mm_mul_ps(_mm_add_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src + 12)), one), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
|
||||
_mm_store_si128(mmdst, _mm_packus_epi16(_mm_packs_epi32(ints1, ints2), _mm_packs_epi32(ints3, ints4))); /* pack down, store out. */
|
||||
i -= 16;
|
||||
src += 16;
|
||||
mmdst++;
|
||||
}
|
||||
dst = (Uint8 *)mmdst;
|
||||
}
|
||||
|
||||
/* Finish off any leftovers with scalar operations. */
|
||||
while (i) {
|
||||
const float sample = *src;
|
||||
if (sample >= 1.0f) {
|
||||
*dst = 255;
|
||||
} else if (sample <= -1.0f) {
|
||||
*dst = 0;
|
||||
} else {
|
||||
*dst = (Uint8)((sample + 1.0f) * 127.0f);
|
||||
}
|
||||
i--;
|
||||
src++;
|
||||
dst++;
|
||||
const __m128i ints = _mm_castps_si128(_mm_add_ss(_mm_load_ss(src), offset));
|
||||
*dst = (Uint8)(_mm_cvtsi128_si32(_mm_packus_epi16(ints, ints)) & 0xFF);
|
||||
|
||||
--i;
|
||||
++src;
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_TARGETING("sse2") SDL_Convert_F32_to_S16_SSE2(Sint16 *dst, const float *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
int i = num_samples;
|
||||
|
||||
/* 1) Shift the float range from [-1.0, 1.0] to [256.0, 258.0]
|
||||
* 2) Shift the int range from [0x43800000, 0x43810000] to [-32768,32768]
|
||||
* 3) Clamp to range [-32768,32767]
|
||||
* Overflow is correctly handled for inputs between roughly [-257.0, +inf)
|
||||
* dst[i] = clamp(f2i(src[i] + 257.0) - 0x43808000, -32768, 32767) */
|
||||
const __m128 offset = _mm_set1_ps(257.0f);
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S16 (using SSE2)");
|
||||
|
||||
/* Get dst aligned to 16 bytes */
|
||||
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||
const float sample = *src;
|
||||
if (sample >= 1.0f) {
|
||||
*dst = 32767;
|
||||
} else if (sample <= -1.0f) {
|
||||
*dst = -32768;
|
||||
} else {
|
||||
*dst = (Sint16)(sample * 32767.0f);
|
||||
}
|
||||
while (i >= 16) {
|
||||
const __m128 floats1 = _mm_loadu_ps(&src[0]);
|
||||
const __m128 floats2 = _mm_loadu_ps(&src[4]);
|
||||
const __m128 floats3 = _mm_loadu_ps(&src[8]);
|
||||
const __m128 floats4 = _mm_loadu_ps(&src[12]);
|
||||
|
||||
const __m128i ints1 = _mm_sub_epi32(_mm_castps_si128(_mm_add_ps(floats1, offset)), _mm_castps_si128(offset));
|
||||
const __m128i ints2 = _mm_sub_epi32(_mm_castps_si128(_mm_add_ps(floats2, offset)), _mm_castps_si128(offset));
|
||||
const __m128i ints3 = _mm_sub_epi32(_mm_castps_si128(_mm_add_ps(floats3, offset)), _mm_castps_si128(offset));
|
||||
const __m128i ints4 = _mm_sub_epi32(_mm_castps_si128(_mm_add_ps(floats4, offset)), _mm_castps_si128(offset));
|
||||
|
||||
const __m128i shorts1 = _mm_packs_epi32(ints1, ints2);
|
||||
const __m128i shorts2 = _mm_packs_epi32(ints3, ints4);
|
||||
|
||||
_mm_storeu_si128((__m128i*)&dst[0], shorts1);
|
||||
_mm_storeu_si128((__m128i*)&dst[8], shorts2);
|
||||
|
||||
i -= 16;
|
||||
src += 16;
|
||||
dst += 16;
|
||||
}
|
||||
|
||||
SDL_assert(!i || !(((size_t)dst) & 15));
|
||||
|
||||
/* Make sure src is aligned too. */
|
||||
if (!(((size_t)src) & 15)) {
|
||||
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
|
||||
const __m128 one = _mm_set1_ps(1.0f);
|
||||
const __m128 negone = _mm_set1_ps(-1.0f);
|
||||
const __m128 mulby32767 = _mm_set1_ps(32767.0f);
|
||||
__m128i *mmdst = (__m128i *)dst;
|
||||
while (i >= 8) { /* 8 * float32 */
|
||||
const __m128i ints1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), mulby32767)); /* load 4 floats, clamp, convert to sint32 */
|
||||
const __m128i ints2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src + 4)), one), mulby32767)); /* load 4 floats, clamp, convert to sint32 */
|
||||
_mm_store_si128(mmdst, _mm_packs_epi32(ints1, ints2)); /* pack to sint16, store out. */
|
||||
i -= 8;
|
||||
src += 8;
|
||||
mmdst++;
|
||||
}
|
||||
dst = (Sint16 *)mmdst;
|
||||
}
|
||||
|
||||
/* Finish off any leftovers with scalar operations. */
|
||||
while (i) {
|
||||
const float sample = *src;
|
||||
if (sample >= 1.0f) {
|
||||
*dst = 32767;
|
||||
} else if (sample <= -1.0f) {
|
||||
*dst = -32768;
|
||||
} else {
|
||||
*dst = (Sint16)(sample * 32767.0f);
|
||||
}
|
||||
i--;
|
||||
src++;
|
||||
dst++;
|
||||
const __m128i ints = _mm_sub_epi32(_mm_castps_si128(_mm_add_ss(_mm_load_ss(src), offset)), _mm_castps_si128(offset));
|
||||
*dst = (Sint16)(_mm_cvtsi128_si32(_mm_packs_epi32(ints, ints)) & 0xFFFF);
|
||||
|
||||
--i;
|
||||
++src;
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL_TARGETING("sse2") SDL_Convert_F32_to_S32_SSE2(Sint32 *dst, const float *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
int i = num_samples;
|
||||
|
||||
/* 1) Scale the float range from [-1.0, 1.0] to [-2147483648.0, 2147483648.0]
|
||||
* 2) Convert to integer (values too small/large become 0x80000000 = -2147483648)
|
||||
* 3) Fixup values which were too large (0x80000000 ^ 0xFFFFFFFF = 2147483647)
|
||||
* dst[i] = i32(src[i] * 2147483648.0) ^ ((src[i] >= 2147483648.0) ? 0xFFFFFFFF : 0x00000000) */
|
||||
const __m128 limit = _mm_set1_ps(2147483648.0f);
|
||||
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S32 (using SSE2)");
|
||||
|
||||
/* Get dst aligned to 16 bytes */
|
||||
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||
const float sample = *src;
|
||||
if (sample >= 1.0f) {
|
||||
*dst = 2147483647;
|
||||
} else if (sample <= -1.0f) {
|
||||
*dst = (Sint32)-2147483648LL;
|
||||
} else {
|
||||
*dst = ((Sint32)(sample * 8388607.0f)) << 8;
|
||||
}
|
||||
while (i >= 16) {
|
||||
const __m128 floats1 = _mm_loadu_ps(&src[0]);
|
||||
const __m128 floats2 = _mm_loadu_ps(&src[4]);
|
||||
const __m128 floats3 = _mm_loadu_ps(&src[8]);
|
||||
const __m128 floats4 = _mm_loadu_ps(&src[12]);
|
||||
|
||||
const __m128 values1 = _mm_mul_ps(floats1, limit);
|
||||
const __m128 values2 = _mm_mul_ps(floats2, limit);
|
||||
const __m128 values3 = _mm_mul_ps(floats3, limit);
|
||||
const __m128 values4 = _mm_mul_ps(floats4, limit);
|
||||
|
||||
const __m128i ints1 = _mm_xor_si128(_mm_cvttps_epi32(values1), _mm_castps_si128(_mm_cmpge_ps(values1, limit)));
|
||||
const __m128i ints2 = _mm_xor_si128(_mm_cvttps_epi32(values2), _mm_castps_si128(_mm_cmpge_ps(values2, limit)));
|
||||
const __m128i ints3 = _mm_xor_si128(_mm_cvttps_epi32(values3), _mm_castps_si128(_mm_cmpge_ps(values3, limit)));
|
||||
const __m128i ints4 = _mm_xor_si128(_mm_cvttps_epi32(values4), _mm_castps_si128(_mm_cmpge_ps(values4, limit)));
|
||||
|
||||
_mm_storeu_si128((__m128i*)&dst[0], ints1);
|
||||
_mm_storeu_si128((__m128i*)&dst[4], ints2);
|
||||
_mm_storeu_si128((__m128i*)&dst[8], ints3);
|
||||
_mm_storeu_si128((__m128i*)&dst[12], ints4);
|
||||
|
||||
i -= 16;
|
||||
src += 16;
|
||||
dst += 16;
|
||||
}
|
||||
|
||||
SDL_assert(!i || !(((size_t)dst) & 15));
|
||||
SDL_assert(!i || !(((size_t)src) & 15));
|
||||
|
||||
{
|
||||
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
|
||||
const __m128 one = _mm_set1_ps(1.0f);
|
||||
const __m128 negone = _mm_set1_ps(-1.0f);
|
||||
const __m128 mulby8388607 = _mm_set1_ps(8388607.0f);
|
||||
__m128i *mmdst = (__m128i *)dst;
|
||||
while (i >= 4) { /* 4 * float32 */
|
||||
_mm_store_si128(mmdst, _mm_slli_epi32(_mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(negone, _mm_load_ps(src)), one), mulby8388607)), 8)); /* load 4 floats, clamp, convert to sint32 */
|
||||
i -= 4;
|
||||
src += 4;
|
||||
mmdst++;
|
||||
}
|
||||
dst = (Sint32 *)mmdst;
|
||||
}
|
||||
|
||||
/* Finish off any leftovers with scalar operations. */
|
||||
while (i) {
|
||||
const float sample = *src;
|
||||
if (sample >= 1.0f) {
|
||||
*dst = 2147483647;
|
||||
} else if (sample <= -1.0f) {
|
||||
*dst = (Sint32)-2147483648LL;
|
||||
} else {
|
||||
*dst = ((Sint32)(sample * 8388607.0f)) << 8;
|
||||
}
|
||||
i--;
|
||||
src++;
|
||||
dst++;
|
||||
const __m128 floats = _mm_load_ss(src);
|
||||
const __m128 values = _mm_mul_ss(floats, limit);
|
||||
const __m128i ints = _mm_xor_si128(_mm_cvttps_epi32(values), _mm_castps_si128(_mm_cmpge_ss(values, limit)));
|
||||
*dst = (Sint32)_mm_cvtsi128_si32(ints);
|
||||
|
||||
--i;
|
||||
++src;
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SDL_NEON_INTRINSICS
|
||||
#define DIVBY128 0.0078125f /* 0x1p-7f */
|
||||
#define DIVBY32768 0.000030517578125f /* 0x1p-15f */
|
||||
#define DIVBY8388607 0.00000011920930376163766f /* 0x1.000002p-23f */
|
||||
|
||||
static void SDL_Convert_S8_to_F32_NEON(float *dst, const Sint8 *src, int num_samples)
|
||||
{
|
||||
int i;
|
||||
|
12
external/sdl/SDL/src/audio/SDL_mixer.c
vendored
12
external/sdl/SDL/src/audio/SDL_mixer.c
vendored
@ -131,7 +131,7 @@ int SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format,
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDL_AUDIO_S16LSB:
|
||||
case SDL_AUDIO_S16LE:
|
||||
{
|
||||
Sint16 src1, src2;
|
||||
int dst_sample;
|
||||
@ -155,7 +155,7 @@ int SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format,
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDL_AUDIO_S16MSB:
|
||||
case SDL_AUDIO_S16BE:
|
||||
{
|
||||
Sint16 src1, src2;
|
||||
int dst_sample;
|
||||
@ -179,7 +179,7 @@ int SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format,
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDL_AUDIO_S32LSB:
|
||||
case SDL_AUDIO_S32LE:
|
||||
{
|
||||
const Uint32 *src32 = (Uint32 *)src;
|
||||
Uint32 *dst32 = (Uint32 *)dst;
|
||||
@ -204,7 +204,7 @@ int SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format,
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDL_AUDIO_S32MSB:
|
||||
case SDL_AUDIO_S32BE:
|
||||
{
|
||||
const Uint32 *src32 = (Uint32 *)src;
|
||||
Uint32 *dst32 = (Uint32 *)dst;
|
||||
@ -229,7 +229,7 @@ int SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format,
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDL_AUDIO_F32LSB:
|
||||
case SDL_AUDIO_F32LE:
|
||||
{
|
||||
const float fmaxvolume = 1.0f / ((float)SDL_MIX_MAXVOLUME);
|
||||
const float fvolume = (float)volume;
|
||||
@ -257,7 +257,7 @@ int SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format,
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDL_AUDIO_F32MSB:
|
||||
case SDL_AUDIO_F32BE:
|
||||
{
|
||||
const float fmaxvolume = 1.0f / ((float)SDL_MIX_MAXVOLUME);
|
||||
const float fvolume = (float)volume;
|
||||
|
93
external/sdl/SDL/src/audio/SDL_sysaudio.h
vendored
93
external/sdl/SDL/src/audio/SDL_sysaudio.h
vendored
@ -24,8 +24,6 @@
|
||||
#ifndef SDL_sysaudio_h_
|
||||
#define SDL_sysaudio_h_
|
||||
|
||||
#include "../SDL_dataqueue.h"
|
||||
|
||||
#define DEBUG_AUDIOSTREAM 0
|
||||
#define DEBUG_AUDIO_CONVERT 0
|
||||
|
||||
@ -58,6 +56,8 @@ extern void (*SDL_Convert_F32_to_S32)(Sint32 *dst, const float *src, int num_sam
|
||||
#define DEFAULT_AUDIO_CAPTURE_CHANNELS 1
|
||||
#define DEFAULT_AUDIO_CAPTURE_FREQUENCY 44100
|
||||
|
||||
#define AUDIO_SPECS_EQUAL(x, y) (((x).format == (y).format) && ((x).channels == (y).channels) && ((x).freq == (y).freq))
|
||||
|
||||
typedef struct SDL_AudioDevice SDL_AudioDevice;
|
||||
typedef struct SDL_LogicalAudioDevice SDL_LogicalAudioDevice;
|
||||
|
||||
@ -70,8 +70,9 @@ extern void SDL_QuitAudio(void);
|
||||
// Function to get a list of audio formats, ordered most similar to `format` to least, 0-terminated. Don't free results.
|
||||
const SDL_AudioFormat *SDL_ClosestAudioFormats(SDL_AudioFormat format);
|
||||
|
||||
// Must be called at least once before using converters (SDL_CreateAudioStream will call it !!! FIXME but probably shouldn't).
|
||||
// Must be called at least once before using converters.
|
||||
extern void SDL_ChooseAudioConverters(void);
|
||||
extern void SDL_SetupAudioResampler(void);
|
||||
|
||||
/* Backends should call this as devices are added to the system (such as
|
||||
a USB headset being plugged in), and should also be called for
|
||||
@ -101,7 +102,7 @@ extern SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(SDL_bool (*callbac
|
||||
extern void SDL_UpdatedAudioDeviceFormat(SDL_AudioDevice *device);
|
||||
|
||||
// Backends can call this to get a standardized name for a thread to power a specific audio device.
|
||||
char *SDL_GetAudioThreadName(SDL_AudioDevice *device, char *buf, size_t buflen);
|
||||
extern char *SDL_GetAudioThreadName(SDL_AudioDevice *device, char *buf, size_t buflen);
|
||||
|
||||
|
||||
// These functions are the heart of the audio threads. Backends can call them directly if they aren't using the SDL-provided thread.
|
||||
@ -113,6 +114,14 @@ extern SDL_bool SDL_CaptureAudioThreadIterate(SDL_AudioDevice *device);
|
||||
extern void SDL_CaptureAudioThreadShutdown(SDL_AudioDevice *device);
|
||||
extern void SDL_AudioThreadFinalize(SDL_AudioDevice *device);
|
||||
|
||||
// this gets used from the audio device threads. It has rules, don't use this if you don't know how to use it!
|
||||
extern void ConvertAudio(int num_frames, const void *src, SDL_AudioFormat src_format, int src_channels,
|
||||
void *dst, SDL_AudioFormat dst_format, int dst_channels, void* scratch);
|
||||
|
||||
// Special case to let something in SDL_audiocvt.c access something in SDL_audio.c. Don't use this.
|
||||
extern void OnAudioStreamCreated(SDL_AudioStream *stream);
|
||||
extern void OnAudioStreamDestroy(SDL_AudioStream *stream);
|
||||
|
||||
typedef struct SDL_AudioDriverImpl
|
||||
{
|
||||
void (*DetectDevices)(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture);
|
||||
@ -120,7 +129,7 @@ typedef struct SDL_AudioDriverImpl
|
||||
void (*ThreadInit)(SDL_AudioDevice *device); // Called by audio thread at start
|
||||
void (*ThreadDeinit)(SDL_AudioDevice *device); // Called by audio thread at end
|
||||
void (*WaitDevice)(SDL_AudioDevice *device);
|
||||
void (*PlayDevice)(SDL_AudioDevice *device, const Uint8 *buffer, int buflen); // buffer and buflen are always from GetDeviceBuf, passed here for convenience.
|
||||
int (*PlayDevice)(SDL_AudioDevice *device, const Uint8 *buffer, int buflen); // buffer and buflen are always from GetDeviceBuf, passed here for convenience.
|
||||
Uint8 *(*GetDeviceBuf)(SDL_AudioDevice *device, int *buffer_size);
|
||||
void (*WaitCaptureDevice)(SDL_AudioDevice *device);
|
||||
int (*CaptureFromDevice)(SDL_AudioDevice *device, void *buffer, int buflen);
|
||||
@ -145,6 +154,7 @@ typedef struct SDL_AudioDriver
|
||||
SDL_RWLock *device_list_lock; // A mutex for device detection
|
||||
SDL_AudioDevice *output_devices; // the list of currently-available audio output devices.
|
||||
SDL_AudioDevice *capture_devices; // the list of currently-available audio capture devices.
|
||||
SDL_AudioStream *existing_streams; // a list of all existing SDL_AudioStreams.
|
||||
SDL_AudioDeviceID default_output_device_id;
|
||||
SDL_AudioDeviceID default_capture_device_id;
|
||||
SDL_AtomicInt output_device_count;
|
||||
@ -153,46 +163,41 @@ typedef struct SDL_AudioDriver
|
||||
SDL_AtomicInt shutting_down; // non-zero during SDL_Quit, so we known not to accept any last-minute device hotplugs.
|
||||
} SDL_AudioDriver;
|
||||
|
||||
struct SDL_AudioQueue; // forward decl.
|
||||
|
||||
struct SDL_AudioStream
|
||||
{
|
||||
SDL_DataQueue *queue;
|
||||
SDL_Mutex *lock; // this is just a copy of `queue`'s mutex. We share a lock.
|
||||
SDL_Mutex* lock;
|
||||
|
||||
SDL_AudioStreamRequestCallback get_callback;
|
||||
SDL_AudioStreamCallback get_callback;
|
||||
void *get_callback_userdata;
|
||||
SDL_AudioStreamRequestCallback put_callback;
|
||||
SDL_AudioStreamCallback put_callback;
|
||||
void *put_callback_userdata;
|
||||
|
||||
Uint8 *work_buffer; // used for scratch space during data conversion/resampling.
|
||||
Uint8 *history_buffer; // history for left padding and future sample rate changes.
|
||||
Uint8 *future_buffer; // stuff that left the queue for the right padding and will be next read's data.
|
||||
float *left_padding; // left padding for resampling.
|
||||
float *right_padding; // right padding for resampling.
|
||||
|
||||
SDL_bool flushed;
|
||||
|
||||
size_t work_buffer_allocation;
|
||||
size_t history_buffer_allocation;
|
||||
size_t future_buffer_allocation;
|
||||
size_t resampler_padding_allocation;
|
||||
|
||||
int resampler_padding_frames;
|
||||
int history_buffer_frames;
|
||||
int future_buffer_filled_frames;
|
||||
|
||||
SDL_AudioSpec src_spec;
|
||||
SDL_AudioSpec dst_spec;
|
||||
float freq_ratio;
|
||||
|
||||
int src_sample_frame_size;
|
||||
int dst_sample_frame_size;
|
||||
int max_sample_frame_size;
|
||||
struct SDL_AudioQueue* queue;
|
||||
Uint64 total_bytes_queued;
|
||||
|
||||
int pre_resample_channels;
|
||||
int packetlen;
|
||||
SDL_AudioSpec input_spec; // The spec of input data currently being processed
|
||||
Sint64 resample_offset;
|
||||
|
||||
Uint8 *work_buffer; // used for scratch space during data conversion/resampling.
|
||||
size_t work_buffer_allocation;
|
||||
|
||||
Uint8 *history_buffer; // history for left padding and future sample rate changes.
|
||||
size_t history_buffer_allocation;
|
||||
|
||||
SDL_bool simplified; // SDL_TRUE if created via SDL_OpenAudioDeviceStream
|
||||
|
||||
SDL_LogicalAudioDevice *bound_device;
|
||||
SDL_AudioStream *next_binding;
|
||||
SDL_AudioStream *prev_binding;
|
||||
|
||||
SDL_AudioStream *prev; // linked list of all existing streams (so we can free them on shutdown).
|
||||
SDL_AudioStream *next; // linked list of all existing streams (so we can free them on shutdown).
|
||||
};
|
||||
|
||||
/* Logical devices are an abstraction in SDL3; you can open the same physical
|
||||
@ -214,7 +219,16 @@ struct SDL_LogicalAudioDevice
|
||||
SDL_AudioStream *bound_streams;
|
||||
|
||||
// SDL_TRUE if this was opened as a default device.
|
||||
SDL_bool is_default;
|
||||
SDL_bool opened_as_default;
|
||||
|
||||
// SDL_TRUE if device was opened with SDL_OpenAudioDeviceStream (so it forbids binding changes, etc).
|
||||
SDL_bool simplified;
|
||||
|
||||
// If non-NULL, callback into the app that lets them access the final postmix buffer.
|
||||
SDL_AudioPostmixCallback postmix;
|
||||
|
||||
// App-supplied pointer for postmix callback.
|
||||
void *postmix_userdata;
|
||||
|
||||
// double-linked list of opened devices on the same physical device.
|
||||
SDL_LogicalAudioDevice *next;
|
||||
@ -263,14 +277,22 @@ struct SDL_AudioDevice
|
||||
// SDL_TRUE if this is a capture device instead of an output device
|
||||
SDL_bool iscapture;
|
||||
|
||||
// Scratch buffer used for mixing.
|
||||
// SDL_TRUE if audio thread can skip silence/mix/convert stages and just do a basic memcpy.
|
||||
SDL_bool simple_copy;
|
||||
|
||||
// Scratch buffers used for mixing.
|
||||
Uint8 *work_buffer;
|
||||
Uint8 *mix_buffer;
|
||||
float *postmix_buffer;
|
||||
|
||||
// Size of work_buffer (and mix_buffer) in bytes.
|
||||
int work_buffer_size;
|
||||
|
||||
// A thread to feed the audio device
|
||||
SDL_Thread *thread;
|
||||
|
||||
// SDL_TRUE if this physical device is currently opened by the backend.
|
||||
SDL_bool is_opened;
|
||||
SDL_bool currently_opened;
|
||||
|
||||
// Data private to this driver
|
||||
struct SDL_PrivateAudioData *hidden;
|
||||
@ -316,7 +338,4 @@ extern AudioBootStrap N3DSAUDIO_bootstrap;
|
||||
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
|
||||
extern AudioBootStrap QSAAUDIO_bootstrap;
|
||||
|
||||
extern SDL_AudioDevice *get_audio_dev(SDL_AudioDeviceID id);
|
||||
extern int get_max_num_audio_dev(void);
|
||||
|
||||
#endif // SDL_sysaudio_h_
|
||||
|
8
external/sdl/SDL/src/audio/SDL_wave.c
vendored
8
external/sdl/SDL/src/audio/SDL_wave.c
vendored
@ -2039,10 +2039,10 @@ static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 *
|
||||
case ALAW_CODE:
|
||||
case MULAW_CODE:
|
||||
/* These can be easily stored in the byte order of the system. */
|
||||
spec->format = SDL_AUDIO_S16SYS;
|
||||
spec->format = SDL_AUDIO_S16;
|
||||
break;
|
||||
case IEEE_FLOAT_CODE:
|
||||
spec->format = SDL_AUDIO_F32LSB;
|
||||
spec->format = SDL_AUDIO_F32LE;
|
||||
break;
|
||||
case PCM_CODE:
|
||||
switch (format->bitspersample) {
|
||||
@ -2050,11 +2050,11 @@ static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 *
|
||||
spec->format = SDL_AUDIO_U8;
|
||||
break;
|
||||
case 16:
|
||||
spec->format = SDL_AUDIO_S16LSB;
|
||||
spec->format = SDL_AUDIO_S16LE;
|
||||
break;
|
||||
case 24: /* Has been shifted to 32 bits. */
|
||||
case 32:
|
||||
spec->format = SDL_AUDIO_S32LSB;
|
||||
spec->format = SDL_AUDIO_S32LE;
|
||||
break;
|
||||
default:
|
||||
/* Just in case something unexpected happened in the checks. */
|
||||
|
15
external/sdl/SDL/src/audio/aaudio/SDL_aaudio.c
vendored
15
external/sdl/SDL/src/audio/aaudio/SDL_aaudio.c
vendored
@ -111,13 +111,14 @@ static void AAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
SDL_WaitSemaphore(device->hidden->semaphore);
|
||||
}
|
||||
|
||||
static void AAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int AAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
// AAUDIO_dataCallback picks up our work and unblocks AAUDIO_WaitDevice. But make sure we didn't fail here.
|
||||
if (SDL_AtomicGet(&device->hidden->error_callback_triggered)) {
|
||||
SDL_AtomicSet(&device->hidden->error_callback_triggered, 0);
|
||||
SDL_AudioDeviceDisconnected(device);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// no need for a FlushCapture implementation, just don't read mixbuf until the next iteration.
|
||||
@ -197,9 +198,9 @@ static int AAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
const aaudio_direction_t direction = (iscapture ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
|
||||
ctx.AAudioStreamBuilder_setDirection(builder, direction);
|
||||
aaudio_format_t format;
|
||||
if ((device->spec.format == SDL_AUDIO_S32SYS) && (SDL_GetAndroidSDKVersion() >= 31)) {
|
||||
if ((device->spec.format == SDL_AUDIO_S32) && (SDL_GetAndroidSDKVersion() >= 31)) {
|
||||
format = AAUDIO_FORMAT_PCM_I32;
|
||||
} else if (device->spec.format == SDL_AUDIO_F32SYS) {
|
||||
} else if (device->spec.format == SDL_AUDIO_F32) {
|
||||
format = AAUDIO_FORMAT_PCM_FLOAT;
|
||||
} else {
|
||||
format = AAUDIO_FORMAT_PCM_I16; // sint16 is a safe bet for everything else.
|
||||
@ -244,11 +245,11 @@ static int AAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
format = ctx.AAudioStream_getFormat(hidden->stream);
|
||||
if (format == AAUDIO_FORMAT_PCM_I16) {
|
||||
device->spec.format = SDL_AUDIO_S16SYS;
|
||||
device->spec.format = SDL_AUDIO_S16;
|
||||
} else if (format == AAUDIO_FORMAT_PCM_I32) {
|
||||
device->spec.format = SDL_AUDIO_S32SYS;
|
||||
device->spec.format = SDL_AUDIO_S32;
|
||||
} else if (format == AAUDIO_FORMAT_PCM_FLOAT) {
|
||||
device->spec.format = SDL_AUDIO_F32SYS;
|
||||
device->spec.format = SDL_AUDIO_F32;
|
||||
} else {
|
||||
return SDL_SetError("Got unexpected audio format %d from AAudioStream_getFormat", (int) format);
|
||||
}
|
||||
|
25
external/sdl/SDL/src/audio/alsa/SDL_alsa_audio.c
vendored
25
external/sdl/SDL/src/audio/alsa/SDL_alsa_audio.c
vendored
@ -351,12 +351,11 @@ static void ALSA_WaitDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static void ALSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int ALSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
SDL_assert(buffer == device->hidden->mixbuf);
|
||||
Uint8 *sample_buf = device->hidden->mixbuf;
|
||||
const int frame_size = ((SDL_AUDIO_BITSIZE(device->spec.format)) / 8) *
|
||||
device->spec.channels;
|
||||
const int frame_size = SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
snd_pcm_uframes_t frames_left = (snd_pcm_uframes_t) (buflen / frame_size);
|
||||
|
||||
device->hidden->swizzle_func(device, sample_buf, frames_left);
|
||||
@ -378,8 +377,7 @@ static void ALSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int bu
|
||||
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
|
||||
"ALSA write failed (unrecoverable): %s",
|
||||
ALSA_snd_strerror(status));
|
||||
SDL_AudioDeviceDisconnected(device);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
} else if (status == 0) {
|
||||
@ -391,6 +389,8 @@ static void ALSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int bu
|
||||
sample_buf += status * frame_size;
|
||||
frames_left -= status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint8 *ALSA_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
@ -401,8 +401,7 @@ static Uint8 *ALSA_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
static int ALSA_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
Uint8 *sample_buf = (Uint8 *)buffer;
|
||||
const int frame_size = ((SDL_AUDIO_BITSIZE(device->spec.format)) / 8) *
|
||||
device->spec.channels;
|
||||
const int frame_size = SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
const int total_frames = buflen / frame_size;
|
||||
snd_pcm_uframes_t frames_left = total_frames;
|
||||
|
||||
@ -564,22 +563,22 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
case SDL_AUDIO_S8:
|
||||
format = SND_PCM_FORMAT_S8;
|
||||
break;
|
||||
case SDL_AUDIO_S16LSB:
|
||||
case SDL_AUDIO_S16LE:
|
||||
format = SND_PCM_FORMAT_S16_LE;
|
||||
break;
|
||||
case SDL_AUDIO_S16MSB:
|
||||
case SDL_AUDIO_S16BE:
|
||||
format = SND_PCM_FORMAT_S16_BE;
|
||||
break;
|
||||
case SDL_AUDIO_S32LSB:
|
||||
case SDL_AUDIO_S32LE:
|
||||
format = SND_PCM_FORMAT_S32_LE;
|
||||
break;
|
||||
case SDL_AUDIO_S32MSB:
|
||||
case SDL_AUDIO_S32BE:
|
||||
format = SND_PCM_FORMAT_S32_BE;
|
||||
break;
|
||||
case SDL_AUDIO_F32LSB:
|
||||
case SDL_AUDIO_F32LE:
|
||||
format = SND_PCM_FORMAT_FLOAT_LE;
|
||||
break;
|
||||
case SDL_AUDIO_F32MSB:
|
||||
case SDL_AUDIO_F32BE:
|
||||
format = SND_PCM_FORMAT_FLOAT_BE;
|
||||
break;
|
||||
default:
|
||||
|
@ -87,9 +87,10 @@ static int ANDROIDAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
// !!! FIXME: this needs a WaitDevice implementation.
|
||||
|
||||
static void ANDROIDAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int ANDROIDAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
Android_JNI_WriteAudioBuffer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint8 *ANDROIDAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "SDL_coreaudio.h"
|
||||
#include "../../thread/SDL_systhread.h"
|
||||
|
||||
#define DEBUG_COREAUDIO 1
|
||||
#define DEBUG_COREAUDIO 0
|
||||
|
||||
#if DEBUG_COREAUDIO
|
||||
#define CHECK_RESULT(msg) \
|
||||
@ -525,7 +525,7 @@ static SDL_bool UpdateAudioSession(SDL_AudioDevice *device, SDL_bool open, SDL_b
|
||||
#endif
|
||||
|
||||
|
||||
static void COREAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
static int COREAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
{
|
||||
AudioQueueBufferRef current_buffer = device->hidden->current_buffer;
|
||||
SDL_assert(current_buffer != NULL); // should have been called from OutputBufferReadyCallback
|
||||
@ -533,6 +533,7 @@ static void COREAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, i
|
||||
current_buffer->mAudioDataByteSize = current_buffer->mAudioDataBytesCapacity;
|
||||
device->hidden->current_buffer = NULL;
|
||||
AudioQueueEnqueueBuffer(device->hidden->audioQueue, current_buffer, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint8 *COREAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
@ -875,12 +876,12 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
switch (test_format) {
|
||||
case SDL_AUDIO_U8:
|
||||
case SDL_AUDIO_S8:
|
||||
case SDL_AUDIO_S16LSB:
|
||||
case SDL_AUDIO_S16MSB:
|
||||
case SDL_AUDIO_S32LSB:
|
||||
case SDL_AUDIO_S32MSB:
|
||||
case SDL_AUDIO_F32LSB:
|
||||
case SDL_AUDIO_F32MSB:
|
||||
case SDL_AUDIO_S16LE:
|
||||
case SDL_AUDIO_S16BE:
|
||||
case SDL_AUDIO_S32LE:
|
||||
case SDL_AUDIO_S32BE:
|
||||
case SDL_AUDIO_F32LE:
|
||||
case SDL_AUDIO_F32BE:
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -179,7 +179,7 @@ static BOOL CALLBACK FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVO
|
||||
if (str != NULL) {
|
||||
LPGUID cpyguid = (LPGUID)SDL_malloc(sizeof(GUID));
|
||||
if (cpyguid) {
|
||||
SDL_memcpy(cpyguid, guid, sizeof(GUID));
|
||||
SDL_copyp(cpyguid, guid);
|
||||
|
||||
/* Note that spec is NULL, because we are required to connect to the
|
||||
* device before getting the channel mask and output format, making
|
||||
@ -285,11 +285,14 @@ static void DSOUND_WaitDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static void DSOUND_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int DSOUND_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
// Unlock the buffer, allowing it to play
|
||||
SDL_assert(buflen == device->buffer_size);
|
||||
IDirectSoundBuffer_Unlock(device->hidden->mixbuf, (LPVOID) buffer, buflen, NULL, 0);
|
||||
if (IDirectSoundBuffer_Unlock(device->hidden->mixbuf, (LPVOID) buffer, buflen, NULL, 0) != DS_OK) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint8 *DSOUND_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
@ -378,7 +381,7 @@ static int DSOUND_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int b
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_assert(ptr1len == buflen);
|
||||
SDL_assert(ptr1len == (DWORD)buflen);
|
||||
SDL_assert(ptr2 == NULL);
|
||||
SDL_assert(ptr2len == 0);
|
||||
|
||||
@ -614,7 +617,7 @@ static int DSOUND_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
wfmt.Format.wBitsPerSample = SDL_AUDIO_BITSIZE(device->spec.format);
|
||||
wfmt.Format.nChannels = device->spec.channels;
|
||||
wfmt.Format.nChannels = (WORD)device->spec.channels;
|
||||
wfmt.Format.nSamplesPerSec = device->spec.freq;
|
||||
wfmt.Format.nBlockAlign = wfmt.Format.nChannels * (wfmt.Format.wBitsPerSample / 8);
|
||||
wfmt.Format.nAvgBytesPerSec = wfmt.Format.nSamplesPerSec * wfmt.Format.nBlockAlign;
|
||||
|
@ -40,15 +40,16 @@ static void DISKAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
SDL_Delay(device->hidden->io_delay);
|
||||
}
|
||||
|
||||
static void DISKAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
static int DISKAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
{
|
||||
const int written = (int)SDL_RWwrite(device->hidden->io, buffer, (size_t)buffer_size);
|
||||
if (written != buffer_size) { // If we couldn't write, assume fatal error for now
|
||||
SDL_AudioDeviceDisconnected(device);
|
||||
return -1;
|
||||
}
|
||||
#ifdef DEBUG_AUDIO
|
||||
SDL_Log("DISKAUDIO: Wrote %d bytes of audio data", (int) written);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint8 *DISKAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
|
10
external/sdl/SDL/src/audio/dsp/SDL_dspaudio.c
vendored
10
external/sdl/SDL/src/audio/dsp/SDL_dspaudio.c
vendored
@ -111,12 +111,12 @@ static int DSP_OpenDevice(SDL_AudioDevice *device)
|
||||
format = AFMT_U8;
|
||||
}
|
||||
break;
|
||||
case SDL_AUDIO_S16LSB:
|
||||
case SDL_AUDIO_S16LE:
|
||||
if (value & AFMT_S16_LE) {
|
||||
format = AFMT_S16_LE;
|
||||
}
|
||||
break;
|
||||
case SDL_AUDIO_S16MSB:
|
||||
case SDL_AUDIO_S16BE:
|
||||
if (value & AFMT_S16_BE) {
|
||||
format = AFMT_S16_BE;
|
||||
}
|
||||
@ -225,17 +225,17 @@ static void DSP_WaitDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static void DSP_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int DSP_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
if (write(h->audio_fd, buffer, buflen) == -1) {
|
||||
perror("Audio write");
|
||||
SDL_AudioDeviceDisconnected(device);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Wrote %d bytes of audio data\n", h->mixlen);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint8 *DSP_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
|
@ -36,9 +36,9 @@ static Uint8 *EMSCRIPTENAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_
|
||||
return device->hidden->mixbuf;
|
||||
}
|
||||
|
||||
static void EMSCRIPTENAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
static int EMSCRIPTENAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
{
|
||||
const int framelen = (SDL_AUDIO_BITSIZE(device->spec.format) / 8) * device->spec.channels;
|
||||
const int framelen = SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
MAIN_THREAD_EM_ASM({
|
||||
var SDL3 = Module['SDL3'];
|
||||
var numChannels = SDL3.audio.currentOutputBuffer['numberOfChannels'];
|
||||
@ -53,11 +53,7 @@ static void EMSCRIPTENAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buf
|
||||
}
|
||||
}
|
||||
}, buffer, buffer_size / framelen);
|
||||
}
|
||||
|
||||
static void HandleAudioProcess(SDL_AudioDevice *device) // this fires when the main thread is idle.
|
||||
{
|
||||
SDL_OutputAudioThreadIterate(device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -92,11 +88,6 @@ static int EMSCRIPTENAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buff
|
||||
return buflen;
|
||||
}
|
||||
|
||||
static void HandleCaptureProcess(SDL_AudioDevice *device) // this fires when the main thread is idle.
|
||||
{
|
||||
SDL_CaptureAudioThreadIterate(device);
|
||||
}
|
||||
|
||||
static void EMSCRIPTENAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
if (!device->hidden) {
|
||||
@ -107,32 +98,28 @@ static void EMSCRIPTENAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||
var SDL3 = Module['SDL3'];
|
||||
if ($0) {
|
||||
if (SDL3.capture.silenceTimer !== undefined) {
|
||||
clearTimeout(SDL3.capture.silenceTimer);
|
||||
clearInterval(SDL3.capture.silenceTimer);
|
||||
}
|
||||
if (SDL3.capture.stream !== undefined) {
|
||||
var tracks = SDL3.capture.stream.getAudioTracks();
|
||||
for (var i = 0; i < tracks.length; i++) {
|
||||
SDL3.capture.stream.removeTrack(tracks[i]);
|
||||
}
|
||||
SDL3.capture.stream = undefined;
|
||||
}
|
||||
if (SDL3.capture.scriptProcessorNode !== undefined) {
|
||||
SDL3.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {};
|
||||
SDL3.capture.scriptProcessorNode.disconnect();
|
||||
SDL3.capture.scriptProcessorNode = undefined;
|
||||
}
|
||||
if (SDL3.capture.mediaStreamNode !== undefined) {
|
||||
SDL3.capture.mediaStreamNode.disconnect();
|
||||
SDL3.capture.mediaStreamNode = undefined;
|
||||
}
|
||||
if (SDL3.capture.silenceBuffer !== undefined) {
|
||||
SDL3.capture.silenceBuffer = undefined
|
||||
}
|
||||
SDL3.capture = undefined;
|
||||
} else {
|
||||
if (SDL3.audio.scriptProcessorNode != undefined) {
|
||||
SDL3.audio.scriptProcessorNode.disconnect();
|
||||
SDL3.audio.scriptProcessorNode = undefined;
|
||||
}
|
||||
if (SDL3.audio.silenceTimer !== undefined) {
|
||||
clearInterval(SDL3.audio.silenceTimer);
|
||||
}
|
||||
SDL3.audio = undefined;
|
||||
}
|
||||
@ -174,7 +161,9 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
SDL3.audioContext = new webkitAudioContext();
|
||||
}
|
||||
if (SDL3.audioContext) {
|
||||
autoResumeAudioContext(SDL3.audioContext);
|
||||
if ((typeof navigator.userActivation) === 'undefined') { // Firefox doesn't have this (as of August 2023), use autoResumeAudioContext instead.
|
||||
autoResumeAudioContext(SDL3.audioContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SDL3.audioContext === undefined ? -1 : 0;
|
||||
@ -227,8 +216,9 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
var have_microphone = function(stream) {
|
||||
//console.log('SDL audio capture: we have a microphone! Replacing silence callback.');
|
||||
if (SDL3.capture.silenceTimer !== undefined) {
|
||||
clearTimeout(SDL3.capture.silenceTimer);
|
||||
clearInterval(SDL3.capture.silenceTimer);
|
||||
SDL3.capture.silenceTimer = undefined;
|
||||
SDL3.capture.silenceBuffer = undefined
|
||||
}
|
||||
SDL3.capture.mediaStreamNode = SDL3.audioContext.createMediaStreamSource(stream);
|
||||
SDL3.capture.scriptProcessorNode = SDL3.audioContext.createScriptProcessor($1, $0, 1);
|
||||
@ -255,14 +245,14 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
dynCall('vi', $2, [$3]);
|
||||
};
|
||||
|
||||
SDL3.capture.silenceTimer = setTimeout(silence_callback, ($1 / SDL3.audioContext.sampleRate) * 1000);
|
||||
SDL3.capture.silenceTimer = setInterval(silence_callback, ($1 / SDL3.audioContext.sampleRate) * 1000);
|
||||
|
||||
if ((navigator.mediaDevices !== undefined) && (navigator.mediaDevices.getUserMedia !== undefined)) {
|
||||
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(have_microphone).catch(no_microphone);
|
||||
} else if (navigator.webkitGetUserMedia !== undefined) {
|
||||
navigator.webkitGetUserMedia({ audio: true, video: false }, have_microphone, no_microphone);
|
||||
}
|
||||
}, device->spec.channels, device->sample_frames, HandleCaptureProcess, device);
|
||||
}, device->spec.channels, device->sample_frames, SDL_CaptureAudioThreadIterate, device);
|
||||
} else {
|
||||
// setup a ScriptProcessorNode
|
||||
MAIN_THREAD_EM_ASM({
|
||||
@ -270,11 +260,38 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
SDL3.audio.scriptProcessorNode = SDL3.audioContext['createScriptProcessor']($1, 0, $0);
|
||||
SDL3.audio.scriptProcessorNode['onaudioprocess'] = function (e) {
|
||||
if ((SDL3 === undefined) || (SDL3.audio === undefined)) { return; }
|
||||
// if we're actually running the node, we don't need the fake callback anymore, so kill it.
|
||||
if (SDL3.audio.silenceTimer !== undefined) {
|
||||
clearInterval(SDL3.audio.silenceTimer);
|
||||
SDL3.audio.silenceTimer = undefined;
|
||||
SDL3.audio.silenceBuffer = undefined;
|
||||
}
|
||||
SDL3.audio.currentOutputBuffer = e['outputBuffer'];
|
||||
dynCall('vi', $2, [$3]);
|
||||
};
|
||||
|
||||
SDL3.audio.scriptProcessorNode['connect'](SDL3.audioContext['destination']);
|
||||
}, device->spec.channels, device->sample_frames, HandleAudioProcess, device);
|
||||
|
||||
if (SDL3.audioContext.state === 'suspended') { // uhoh, autoplay is blocked.
|
||||
SDL3.audio.silenceBuffer = SDL3.audioContext.createBuffer($0, $1, SDL3.audioContext.sampleRate);
|
||||
SDL3.audio.silenceBuffer.getChannelData(0).fill(0.0);
|
||||
var silence_callback = function() {
|
||||
if ((typeof navigator.userActivation) !== 'undefined') { // Almost everything modern except Firefox (as of August 2023)
|
||||
if (navigator.userActivation.hasBeenActive) {
|
||||
SDL3.audioContext.resume();
|
||||
}
|
||||
}
|
||||
|
||||
// the buffer that gets filled here just gets ignored, so the app can make progress
|
||||
// and/or avoid flooding audio queues until we can actually play audio.
|
||||
SDL3.audio.currentOutputBuffer = SDL3.audio.silenceBuffer;
|
||||
dynCall('vi', $2, [$3]);
|
||||
SDL3.audio.currentOutputBuffer = undefined;
|
||||
};
|
||||
|
||||
SDL3.audio.silenceTimer = setInterval(silence_callback, ($1 / SDL3.audioContext.sampleRate) * 1000);
|
||||
}
|
||||
}, device->spec.channels, device->sample_frames, SDL_OutputAudioThreadIterate, device);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -46,13 +46,14 @@ static Uint8 *HAIKUAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
return device->hidden->current_buffer;
|
||||
}
|
||||
|
||||
static void HAIKUAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
static int HAIKUAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
{
|
||||
// We already wrote our output right into the BSoundPlayer's callback's stream. Just clean up our stuff.
|
||||
SDL_assert(device->hidden->current_buffer != NULL);
|
||||
SDL_assert(device->hidden->current_buffer_len > 0);
|
||||
device->hidden->current_buffer = NULL;
|
||||
device->hidden->current_buffer_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The Haiku callback for handling the audio buffer
|
||||
@ -130,29 +131,29 @@ static int HAIKUAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
format.format = media_raw_audio_format::B_AUDIO_UCHAR;
|
||||
break;
|
||||
|
||||
case SDL_AUDIO_S16LSB:
|
||||
case SDL_AUDIO_S16LE:
|
||||
format.format = media_raw_audio_format::B_AUDIO_SHORT;
|
||||
break;
|
||||
|
||||
case SDL_AUDIO_S16MSB:
|
||||
case SDL_AUDIO_S16BE:
|
||||
format.format = media_raw_audio_format::B_AUDIO_SHORT;
|
||||
format.byte_order = B_MEDIA_BIG_ENDIAN;
|
||||
break;
|
||||
|
||||
case SDL_AUDIO_S32LSB:
|
||||
case SDL_AUDIO_S32LE:
|
||||
format.format = media_raw_audio_format::B_AUDIO_INT;
|
||||
break;
|
||||
|
||||
case SDL_AUDIO_S32MSB:
|
||||
case SDL_AUDIO_S32BE:
|
||||
format.format = media_raw_audio_format::B_AUDIO_INT;
|
||||
format.byte_order = B_MEDIA_BIG_ENDIAN;
|
||||
break;
|
||||
|
||||
case SDL_AUDIO_F32LSB:
|
||||
case SDL_AUDIO_F32LE:
|
||||
format.format = media_raw_audio_format::B_AUDIO_FLOAT;
|
||||
break;
|
||||
|
||||
case SDL_AUDIO_F32MSB:
|
||||
case SDL_AUDIO_F32BE:
|
||||
format.format = media_raw_audio_format::B_AUDIO_FLOAT;
|
||||
format.byte_order = B_MEDIA_BIG_ENDIAN;
|
||||
break;
|
||||
|
@ -149,7 +149,7 @@ static int jackProcessPlaybackCallback(jack_nframes_t nframes, void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void JACK_PlayDevice(SDL_AudioDevice *device, const Uint8 *ui8buffer, int buflen)
|
||||
static int JACK_PlayDevice(SDL_AudioDevice *device, const Uint8 *ui8buffer, int buflen)
|
||||
{
|
||||
const float *buffer = (float *) ui8buffer;
|
||||
jack_port_t **ports = device->hidden->sdlports;
|
||||
@ -167,6 +167,8 @@ static void JACK_PlayDevice(SDL_AudioDevice *device, const Uint8 *ui8buffer, int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint8 *JACK_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
@ -307,7 +309,7 @@ static int JACK_OpenDevice(SDL_AudioDevice *device)
|
||||
/* !!! FIXME: docs say about buffer size: "This size may change, clients that depend on it must register a bufsize_callback so they will be notified if it does." */
|
||||
|
||||
/* Jack pretty much demands what it wants. */
|
||||
device->spec.format = SDL_AUDIO_F32SYS;
|
||||
device->spec.format = SDL_AUDIO_F32;
|
||||
device->spec.freq = JACK_jack_get_sample_rate(client);
|
||||
device->spec.channels = channels;
|
||||
device->sample_frames = JACK_jack_get_buffer_size(client);
|
||||
|
@ -161,7 +161,7 @@ static int N3DSAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
SDL_memset(device->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
|
||||
|
||||
const int sample_frame_size = device->spec.channels * (SDL_AUDIO_BITSIZE(device->spec.format) / 8);
|
||||
const int sample_frame_size = SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
for (unsigned i = 0; i < NUM_BUFFERS; i++) {
|
||||
device->hidden->waveBuf[i].data_vaddr = data_vaddr;
|
||||
device->hidden->waveBuf[i].nsamples = device->buffer_size / sample_frame_size;
|
||||
@ -176,7 +176,7 @@ static int N3DSAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void N3DSAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int N3DSAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
contextLock(device);
|
||||
|
||||
@ -185,7 +185,7 @@ static void N3DSAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, i
|
||||
if (device->hidden->isCancelled ||
|
||||
device->hidden->waveBuf[nextbuf].status != NDSP_WBUF_FREE) {
|
||||
contextUnlock(device);
|
||||
return;
|
||||
return 0; // !!! FIXME: is this a fatal error? If so, this should return -1.
|
||||
}
|
||||
|
||||
device->hidden->nextbuf = (nextbuf + 1) % NUM_BUFFERS;
|
||||
@ -196,6 +196,8 @@ static void N3DSAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, i
|
||||
DSP_FlushDataCache(device->hidden->waveBuf[nextbuf].data_vaddr, buflen);
|
||||
|
||||
ndspChnWaveBufAdd(0, &device->hidden->waveBuf[nextbuf]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void N3DSAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
|
@ -130,7 +130,7 @@ static void NETBSDAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
SDL_AudioDeviceDisconnected(device);
|
||||
return;
|
||||
}
|
||||
const size_t remain = (size_t)((iscapture ? info.record.seek : info.play.seek) * (SDL_AUDIO_BITSIZE(device->spec.format) / 8));
|
||||
const size_t remain = (size_t)((iscapture ? info.record.seek : info.play.seek) * SDL_AUDIO_BYTESIZE(device->spec.format));
|
||||
if (!iscapture && (remain >= device->buffer_size)) {
|
||||
SDL_Delay(10);
|
||||
} else if (iscapture && (remain < device->buffer_size)) {
|
||||
@ -141,20 +141,18 @@ static void NETBSDAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static void NETBSDAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int NETBSDAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
const int written = write(h->audio_fd, buffer, buflen);
|
||||
if (written == -1) {
|
||||
// Non recoverable error has occurred. It should be reported!!!
|
||||
SDL_AudioDeviceDisconnected(device);
|
||||
perror("audio");
|
||||
return;
|
||||
if (written != buflen) { // Treat even partial writes as fatal errors.
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint8 *NETBSDAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
@ -183,7 +181,7 @@ static void NETBSDAUDIO_FlushCapture(SDL_AudioDevice *device)
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
audio_info_t info;
|
||||
if (ioctl(device->hidden->audio_fd, AUDIO_GETINFO, &info) == 0) {
|
||||
size_t remain = (size_t)(info.record.seek * (SDL_AUDIO_BITSIZE(device->spec.format) / 8));
|
||||
size_t remain = (size_t)(info.record.seek * SDL_AUDIO_BYTESIZE(device->spec.format));
|
||||
while (remain > 0) {
|
||||
char buf[512];
|
||||
const size_t len = SDL_min(sizeof(buf), remain);
|
||||
@ -250,16 +248,16 @@ static int NETBSDAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
case SDL_AUDIO_S8:
|
||||
encoding = AUDIO_ENCODING_SLINEAR;
|
||||
break;
|
||||
case SDL_AUDIO_S16LSB:
|
||||
case SDL_AUDIO_S16LE:
|
||||
encoding = AUDIO_ENCODING_SLINEAR_LE;
|
||||
break;
|
||||
case SDL_AUDIO_S16MSB:
|
||||
case SDL_AUDIO_S16BE:
|
||||
encoding = AUDIO_ENCODING_SLINEAR_BE;
|
||||
break;
|
||||
case SDL_AUDIO_S32LSB:
|
||||
case SDL_AUDIO_S32LE:
|
||||
encoding = AUDIO_ENCODING_SLINEAR_LE;
|
||||
break;
|
||||
case SDL_AUDIO_S32MSB:
|
||||
case SDL_AUDIO_S32BE:
|
||||
encoding = AUDIO_ENCODING_SLINEAR_BE;
|
||||
break;
|
||||
default:
|
||||
|
@ -248,7 +248,7 @@ static int openslES_CreatePCMRecorder(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
// Just go with signed 16-bit audio as it's the most compatible
|
||||
device->spec.format = SDL_AUDIO_S16SYS;
|
||||
device->spec.format = SDL_AUDIO_S16;
|
||||
device->spec.channels = 1;
|
||||
//device->spec.freq = SL_SAMPLINGRATE_16 / 1000;*/
|
||||
|
||||
@ -424,12 +424,12 @@ static int openslES_CreatePCMPlayer(SDL_AudioDevice *device)
|
||||
if (!test_format) {
|
||||
// Didn't find a compatible format :
|
||||
LOGI("No compatible audio format, using signed 16-bit audio");
|
||||
test_format = SDL_AUDIO_S16SYS;
|
||||
test_format = SDL_AUDIO_S16;
|
||||
}
|
||||
device->spec.format = test_format;
|
||||
} else {
|
||||
// Just go with signed 16-bit audio as it's the most compatible
|
||||
device->spec.format = SDL_AUDIO_S16SYS;
|
||||
device->spec.format = SDL_AUDIO_S16;
|
||||
}
|
||||
|
||||
// Update the fragment size as size in bytes
|
||||
@ -638,7 +638,7 @@ static void openslES_WaitDevice(SDL_AudioDevice *device)
|
||||
SDL_WaitSemaphore(audiodata->playsem);
|
||||
}
|
||||
|
||||
static void openslES_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int openslES_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
struct SDL_PrivateAudioData *audiodata = device->hidden;
|
||||
|
||||
@ -657,6 +657,8 @@ static void openslES_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, in
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
SDL_PostSemaphore(audiodata->playsem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// n playn sem
|
||||
|
@ -898,22 +898,22 @@ static void initialize_spa_info(const SDL_AudioSpec *spec, struct spa_audio_info
|
||||
case SDL_AUDIO_S8:
|
||||
info->format = SPA_AUDIO_FORMAT_S8;
|
||||
break;
|
||||
case SDL_AUDIO_S16LSB:
|
||||
case SDL_AUDIO_S16LE:
|
||||
info->format = SPA_AUDIO_FORMAT_S16_LE;
|
||||
break;
|
||||
case SDL_AUDIO_S16MSB:
|
||||
case SDL_AUDIO_S16BE:
|
||||
info->format = SPA_AUDIO_FORMAT_S16_BE;
|
||||
break;
|
||||
case SDL_AUDIO_S32LSB:
|
||||
case SDL_AUDIO_S32LE:
|
||||
info->format = SPA_AUDIO_FORMAT_S32_LE;
|
||||
break;
|
||||
case SDL_AUDIO_S32MSB:
|
||||
case SDL_AUDIO_S32BE:
|
||||
info->format = SPA_AUDIO_FORMAT_S32_BE;
|
||||
break;
|
||||
case SDL_AUDIO_F32LSB:
|
||||
case SDL_AUDIO_F32LE:
|
||||
info->format = SPA_AUDIO_FORMAT_F32_LE;
|
||||
break;
|
||||
case SDL_AUDIO_F32MSB:
|
||||
case SDL_AUDIO_F32BE:
|
||||
info->format = SPA_AUDIO_FORMAT_F32_BE;
|
||||
break;
|
||||
}
|
||||
@ -940,7 +940,7 @@ static Uint8 *PIPEWIRE_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
return (Uint8 *) spa_buf->datas[0].data;
|
||||
}
|
||||
|
||||
static void PIPEWIRE_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
static int PIPEWIRE_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
{
|
||||
struct pw_stream *stream = device->hidden->stream;
|
||||
struct pw_buffer *pw_buf = device->hidden->pw_buf;
|
||||
@ -951,6 +951,8 @@ static void PIPEWIRE_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, in
|
||||
|
||||
PIPEWIRE_pw_stream_queue_buffer(stream, pw_buf);
|
||||
device->hidden->pw_buf = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void output_callback(void *data)
|
||||
@ -1106,7 +1108,7 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
/* Size of a single audio frame in bytes */
|
||||
priv->stride = (SDL_AUDIO_BITSIZE(device->spec.format) / 8) * device->spec.channels;
|
||||
priv->stride = SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
|
||||
if (device->sample_frames < min_period) {
|
||||
device->sample_frames = min_period;
|
||||
|
@ -85,9 +85,10 @@ static int PS2AUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PS2AUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int PS2AUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
audsrv_play_audio((char *)buffer, buflen);
|
||||
// this returns number of bytes accepted or a negative error. We assume anything other than buflen is a fatal error.
|
||||
return (audsrv_play_audio((char *)buffer, buflen) != buflen) ? -1 : 0;
|
||||
}
|
||||
|
||||
static void PS2AUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
|
10
external/sdl/SDL/src/audio/psp/SDL_pspaudio.c
vendored
10
external/sdl/SDL/src/audio/psp/SDL_pspaudio.c
vendored
@ -47,7 +47,7 @@ static int PSPAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
// device only natively supports S16LSB
|
||||
device->spec.format = SDL_AUDIO_S16LSB;
|
||||
device->spec.format = SDL_AUDIO_S16LE;
|
||||
|
||||
/* PSP has some limitations with the Audio. It fully supports 44.1KHz (Mono & Stereo),
|
||||
however with frequencies different than 44.1KHz, it just supports Stereo,
|
||||
@ -106,14 +106,16 @@ static int PSPAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PSPAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int PSPAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
int rc;
|
||||
if (!isBasicAudioConfig(&device->spec)) {
|
||||
SDL_assert(device->spec.channels == 2);
|
||||
sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, (void *) buffer);
|
||||
rc = sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, (void *) buffer);
|
||||
} else {
|
||||
sceAudioOutputPannedBlocking(device->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, (void *) buffer);
|
||||
rc = sceAudioOutputPannedBlocking(device->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, (void *) buffer);
|
||||
}
|
||||
return (rc == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
static void PSPAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
|
@ -388,7 +388,7 @@ static void PULSEAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
|
||||
}
|
||||
|
||||
static void PULSEAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
static int PULSEAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
|
||||
@ -401,14 +401,14 @@ static void PULSEAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer,
|
||||
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
|
||||
|
||||
if (rc < 0) {
|
||||
SDL_AudioDeviceDisconnected(device);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*printf("PULSEAUDIO FEED! nbytes=%d\n", buffer_size);*/
|
||||
h->bytes_requested -= buffer_size;
|
||||
|
||||
/*printf("PULSEAUDIO PLAYDEVICE END! written=%d\n", written);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint8 *PULSEAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
@ -606,22 +606,22 @@ static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
case SDL_AUDIO_U8:
|
||||
format = PA_SAMPLE_U8;
|
||||
break;
|
||||
case SDL_AUDIO_S16LSB:
|
||||
case SDL_AUDIO_S16LE:
|
||||
format = PA_SAMPLE_S16LE;
|
||||
break;
|
||||
case SDL_AUDIO_S16MSB:
|
||||
case SDL_AUDIO_S16BE:
|
||||
format = PA_SAMPLE_S16BE;
|
||||
break;
|
||||
case SDL_AUDIO_S32LSB:
|
||||
case SDL_AUDIO_S32LE:
|
||||
format = PA_SAMPLE_S32LE;
|
||||
break;
|
||||
case SDL_AUDIO_S32MSB:
|
||||
case SDL_AUDIO_S32BE:
|
||||
format = PA_SAMPLE_S32BE;
|
||||
break;
|
||||
case SDL_AUDIO_F32LSB:
|
||||
case SDL_AUDIO_F32LE:
|
||||
format = PA_SAMPLE_FLOAT32LE;
|
||||
break;
|
||||
case SDL_AUDIO_F32MSB:
|
||||
case SDL_AUDIO_F32BE:
|
||||
format = PA_SAMPLE_FLOAT32BE;
|
||||
break;
|
||||
default:
|
||||
@ -723,17 +723,17 @@ static SDL_AudioFormat PulseFormatToSDLFormat(pa_sample_format_t format)
|
||||
case PA_SAMPLE_U8:
|
||||
return SDL_AUDIO_U8;
|
||||
case PA_SAMPLE_S16LE:
|
||||
return SDL_AUDIO_S16LSB;
|
||||
return SDL_AUDIO_S16LE;
|
||||
case PA_SAMPLE_S16BE:
|
||||
return SDL_AUDIO_S16MSB;
|
||||
return SDL_AUDIO_S16BE;
|
||||
case PA_SAMPLE_S32LE:
|
||||
return SDL_AUDIO_S32LSB;
|
||||
return SDL_AUDIO_S32LE;
|
||||
case PA_SAMPLE_S32BE:
|
||||
return SDL_AUDIO_S32MSB;
|
||||
return SDL_AUDIO_S32BE;
|
||||
case PA_SAMPLE_FLOAT32LE:
|
||||
return SDL_AUDIO_F32LSB;
|
||||
return SDL_AUDIO_F32LE;
|
||||
case PA_SAMPLE_FLOAT32BE:
|
||||
return SDL_AUDIO_F32MSB;
|
||||
return SDL_AUDIO_F32BE;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
18
external/sdl/SDL/src/audio/qnx/SDL_qsa_audio.c
vendored
18
external/sdl/SDL/src/audio/qnx/SDL_qsa_audio.c
vendored
@ -110,10 +110,10 @@ static void QSA_WaitDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static void QSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int QSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
if (SDL_AtomicGet(&device->shutdown) || !device->hidden) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int towrite = buflen;
|
||||
@ -125,7 +125,7 @@ static void QSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buf
|
||||
// Check if samples playback got stuck somewhere in hardware or in the audio device driver
|
||||
if ((errno == EAGAIN) && (bw == 0)) {
|
||||
if (device->hidden->timeout_on_wait) {
|
||||
return; // oh well, try again next time. !!! FIXME: Should we just disconnect the device in this case?
|
||||
return 0; // oh well, try again next time. !!! FIXME: Should we just disconnect the device in this case?
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,17 +145,17 @@ static void QSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buf
|
||||
int status = snd_pcm_plugin_status(device->hidden->audio_handle, &cstatus);
|
||||
if (status < 0) {
|
||||
QSA_SetError("snd_pcm_plugin_status", status);
|
||||
return; // !!! FIXME: disconnect the device?
|
||||
return -1;
|
||||
} else if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) || (cstatus.status == SND_PCM_STATUS_READY)) {
|
||||
status = snd_pcm_plugin_prepare(device->hidden->audio_handle, device->iscapture ? SND_PCM_CHANNEL_CAPTURE : SND_PCM_CHANNEL_PLAYBACK);
|
||||
if (status < 0) {
|
||||
QSA_SetError("snd_pcm_plugin_prepare", status);
|
||||
return; // !!! FIXME: disconnect the device?
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
return; // !!! FIXME: disconnect the device?
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
// we wrote all remaining data
|
||||
@ -165,9 +165,7 @@ static void QSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buf
|
||||
}
|
||||
|
||||
// If we couldn't write, assume fatal error for now
|
||||
if (towrite != 0) {
|
||||
SDL_AudioDeviceDisconnected(device);
|
||||
}
|
||||
return (towrite != 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
static Uint8 *QSA_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
@ -311,7 +309,7 @@ static SDL_AudioFormat QnxFormatToSDLFormat(const int32_t qnxfmt)
|
||||
#undef CHECKFMT
|
||||
default: break;
|
||||
}
|
||||
return SDL_AUDIO_S16SYS; // oh well.
|
||||
return SDL_AUDIO_S16; // oh well.
|
||||
}
|
||||
|
||||
static void QSA_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
|
@ -175,16 +175,17 @@ static void SNDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static void SNDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int SNDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
// !!! FIXME: this should be non-blocking so we can check device->shutdown.
|
||||
// this is set to blocking, because we _have_ to send the entire buffer down, but hopefully WaitDevice took most of the delay time.
|
||||
if (SNDIO_sio_write(device->hidden->dev, buffer, buflen) != buflen) {
|
||||
SDL_AudioDeviceDisconnected(device); // If we couldn't write, assume fatal error for now
|
||||
return -1; // If we couldn't write, assume fatal error for now
|
||||
}
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SNDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
@ -283,13 +284,13 @@ static int SNDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
if ((par.bps == 4) && (par.sig) && (par.le)) {
|
||||
device->spec.format = SDL_AUDIO_S32LSB;
|
||||
device->spec.format = SDL_AUDIO_S32LE;
|
||||
} else if ((par.bps == 4) && (par.sig) && (!par.le)) {
|
||||
device->spec.format = SDL_AUDIO_S32MSB;
|
||||
device->spec.format = SDL_AUDIO_S32BE;
|
||||
} else if ((par.bps == 2) && (par.sig) && (par.le)) {
|
||||
device->spec.format = SDL_AUDIO_S16LSB;
|
||||
device->spec.format = SDL_AUDIO_S16LE;
|
||||
} else if ((par.bps == 2) && (par.sig) && (!par.le)) {
|
||||
device->spec.format = SDL_AUDIO_S16MSB;
|
||||
device->spec.format = SDL_AUDIO_S16BE;
|
||||
} else if ((par.bps == 1) && (par.sig)) {
|
||||
device->spec.format = SDL_AUDIO_S8;
|
||||
} else if ((par.bps == 1) && (!par.sig)) {
|
||||
|
@ -71,7 +71,7 @@ static int VITAAUD_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
closefmts = SDL_ClosestAudioFormats(device->spec.format);
|
||||
while ((test_format = *(closefmts++)) != 0) {
|
||||
if (test_format == SDL_AUDIO_S16LSB) {
|
||||
if (test_format == SDL_AUDIO_S16LE) {
|
||||
device->spec.format = test_format;
|
||||
break;
|
||||
}
|
||||
@ -130,9 +130,9 @@ static int VITAAUD_OpenDevice(SDL_AudioDevice *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void VITAAUD_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
static int VITAAUD_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
{
|
||||
sceAudioOutOutput(device->hidden->port, buffer);
|
||||
return (sceAudioOutOutput(device->hidden->port, buffer) == 0) ? 0 : -1;
|
||||
}
|
||||
|
||||
// This function waits until it is possible to write a full sound buffer
|
||||
|
12
external/sdl/SDL/src/audio/wasapi/SDL_wasapi.c
vendored
12
external/sdl/SDL/src/audio/wasapi/SDL_wasapi.c
vendored
@ -403,22 +403,22 @@ static Uint8 *WASAPI_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
// get an endpoint buffer from WASAPI.
|
||||
BYTE *buffer = NULL;
|
||||
|
||||
while (RecoverWasapiIfLost(device) && device->hidden->render) {
|
||||
if (!WasapiFailed(device, IAudioRenderClient_GetBuffer(device->hidden->render, device->sample_frames, &buffer))) {
|
||||
return (Uint8 *)buffer;
|
||||
if (RecoverWasapiIfLost(device) && device->hidden->render) {
|
||||
if (WasapiFailed(device, IAudioRenderClient_GetBuffer(device->hidden->render, device->sample_frames, &buffer))) {
|
||||
SDL_assert(buffer == NULL);
|
||||
}
|
||||
SDL_assert(buffer == NULL);
|
||||
}
|
||||
|
||||
return (Uint8 *)buffer;
|
||||
}
|
||||
|
||||
static void WASAPI_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
static int WASAPI_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||
{
|
||||
if (device->hidden->render != NULL) { // definitely activated?
|
||||
// WasapiFailed() will mark the device for reacquisition or removal elsewhere.
|
||||
WasapiFailed(device, IAudioRenderClient_ReleaseBuffer(device->hidden->render, device->sample_frames, 0));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void WASAPI_WaitDevice(SDL_AudioDevice *device)
|
||||
@ -620,7 +620,7 @@ static int mgmtthrtask_PrepDevice(void *userdata)
|
||||
return -1;
|
||||
}
|
||||
|
||||
device->hidden->framesize = (SDL_AUDIO_BITSIZE(device->spec.format) / 8) * device->spec.channels;
|
||||
device->hidden->framesize = SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
|
||||
if (device->iscapture) {
|
||||
IAudioCaptureClient *capture = NULL;
|
||||
|
20
external/sdl/SDL/src/core/gdk/SDL_gdk.cpp
vendored
20
external/sdl/SDL/src/core/gdk/SDL_gdk.cpp
vendored
@ -214,3 +214,23 @@ SDL_GDKSuspendComplete()
|
||||
SetEvent(plmSuspendComplete);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" DECLSPEC int
|
||||
SDL_GDKGetDefaultUser(XUserHandle *outUserHandle)
|
||||
{
|
||||
XAsyncBlock block = { 0 };
|
||||
HRESULT result;
|
||||
|
||||
if (FAILED(result = XUserAddAsync(XUserAddOptions::AddDefaultUserAllowingUI, &block))) {
|
||||
return WIN_SetErrorFromHRESULT("XUserAddAsync", result);
|
||||
}
|
||||
|
||||
do {
|
||||
result = XUserAddResult(&block, outUserHandle);
|
||||
} while (result == E_PENDING);
|
||||
if (FAILED(result)) {
|
||||
return WIN_SetErrorFromHRESULT("XUserAddResult", result);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
66
external/sdl/SDL/src/core/linux/SDL_dbus.c
vendored
66
external/sdl/SDL/src/core/linux/SDL_dbus.c
vendored
@ -565,4 +565,70 @@ char *SDL_DBus_GetLocalMachineId(void)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert file drops with mime type "application/vnd.portal.filetransfer" to file paths
|
||||
* Result must be freed with dbus->free_string_array().
|
||||
* https://flatpak.github.io/xdg-desktop-portal/#gdbus-method-org-freedesktop-portal-FileTransfer.RetrieveFiles
|
||||
*/
|
||||
char **SDL_DBus_DocumentsPortalRetrieveFiles(const char *key, int *path_count)
|
||||
{
|
||||
DBusError err;
|
||||
DBusMessageIter iter, iterDict;
|
||||
char **paths = NULL;
|
||||
DBusMessage *reply = NULL;
|
||||
DBusMessage *msg = dbus.message_new_method_call("org.freedesktop.portal.Documents", /* Node */
|
||||
"/org/freedesktop/portal/documents", /* Path */
|
||||
"org.freedesktop.portal.FileTransfer", /* Interface */
|
||||
"RetrieveFiles"); /* Method */
|
||||
|
||||
/* Make sure we have a connection to the dbus session bus */
|
||||
if (!SDL_DBus_GetContext() || !dbus.session_conn) {
|
||||
/* We either cannot connect to the session bus or were unable to
|
||||
* load the D-Bus library at all. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus.error_init(&err);
|
||||
|
||||
/* First argument is a "application/vnd.portal.filetransfer" key from a DnD or clipboard event */
|
||||
if (!dbus.message_append_args(msg, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID)) {
|
||||
SDL_OutOfMemory();
|
||||
dbus.message_unref(msg);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Second argument is a variant dictionary for options.
|
||||
* The spec doesn't define any entries yet so it's empty. */
|
||||
dbus.message_iter_init_append(msg, &iter);
|
||||
if (!dbus.message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &iterDict) ||
|
||||
!dbus.message_iter_close_container(&iter, &iterDict)) {
|
||||
SDL_OutOfMemory();
|
||||
dbus.message_unref(msg);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
reply = dbus.connection_send_with_reply_and_block(dbus.session_conn, msg, DBUS_TIMEOUT_USE_DEFAULT, &err);
|
||||
dbus.message_unref(msg);
|
||||
|
||||
if (reply) {
|
||||
dbus.message_get_args(reply, &err, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &paths, path_count, DBUS_TYPE_INVALID);
|
||||
dbus.message_unref(reply);
|
||||
}
|
||||
|
||||
if (paths) {
|
||||
return paths;
|
||||
}
|
||||
|
||||
failed:
|
||||
if (dbus.error_is_set(&err)) {
|
||||
SDL_SetError("%s: %s", err.name, err.message);
|
||||
dbus.error_free(&err);
|
||||
} else {
|
||||
SDL_SetError("Error retrieving paths for documents portal \"%s\"", key);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
2
external/sdl/SDL/src/core/linux/SDL_dbus.h
vendored
2
external/sdl/SDL/src/core/linux/SDL_dbus.h
vendored
@ -102,6 +102,8 @@ extern SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit);
|
||||
extern void SDL_DBus_PumpEvents(void);
|
||||
extern char *SDL_DBus_GetLocalMachineId(void);
|
||||
|
||||
extern char **SDL_DBus_DocumentsPortalRetrieveFiles(const char *key, int *files_count);
|
||||
|
||||
#endif /* HAVE_DBUS_DBUS_H */
|
||||
|
||||
#endif /* SDL_dbus_h_ */
|
||||
|
@ -57,8 +57,14 @@ static const PROPERTYKEY SDL_PKEY_AudioEndpoint_GUID = { { 0x1da5d803, 0xd492, 0
|
||||
|
||||
static SDL_bool FindByDevIDCallback(SDL_AudioDevice *device, void *userdata)
|
||||
{
|
||||
const SDL_IMMDevice_HandleData *handle = (const SDL_IMMDevice_HandleData *) device->handle;
|
||||
return (SDL_wcscmp(handle->immdevice_id, (LPCWSTR) userdata) == 0) ? SDL_TRUE : SDL_FALSE;
|
||||
LPCWSTR devid = (LPCWSTR)userdata;
|
||||
if (devid && device && device->handle) {
|
||||
const SDL_IMMDevice_HandleData *handle = (const SDL_IMMDevice_HandleData *)device->handle;
|
||||
if (handle->immdevice_id && SDL_wcscmp(handle->immdevice_id, devid) == 0) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *SDL_IMMDevice_FindByDevID(LPCWSTR devid)
|
||||
|
12
external/sdl/SDL/src/core/windows/SDL_windows.c
vendored
12
external/sdl/SDL/src/core/windows/SDL_windows.c
vendored
@ -344,19 +344,19 @@ static const GUID SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x
|
||||
SDL_AudioFormat SDL_WaveFormatExToSDLFormat(WAVEFORMATEX *waveformat)
|
||||
{
|
||||
if ((waveformat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) && (waveformat->wBitsPerSample == 32)) {
|
||||
return SDL_AUDIO_F32SYS;
|
||||
return SDL_AUDIO_F32;
|
||||
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 16)) {
|
||||
return SDL_AUDIO_S16SYS;
|
||||
return SDL_AUDIO_S16;
|
||||
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 32)) {
|
||||
return SDL_AUDIO_S32SYS;
|
||||
return SDL_AUDIO_S32;
|
||||
} else if (waveformat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||
const WAVEFORMATEXTENSIBLE *ext = (const WAVEFORMATEXTENSIBLE *)waveformat;
|
||||
if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
|
||||
return SDL_AUDIO_F32SYS;
|
||||
return SDL_AUDIO_F32;
|
||||
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID)) == 0) && (waveformat->wBitsPerSample == 16)) {
|
||||
return SDL_AUDIO_S16SYS;
|
||||
return SDL_AUDIO_S16;
|
||||
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
|
||||
return SDL_AUDIO_S32SYS;
|
||||
return SDL_AUDIO_S32;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
14
external/sdl/SDL/src/dynapi/SDL_dynapi.sym
vendored
14
external/sdl/SDL/src/dynapi/SDL_dynapi.sym
vendored
@ -172,6 +172,7 @@ SDL3_0.0.0 {
|
||||
SDL_GetGamepadAppleSFSymbolsNameForButton;
|
||||
SDL_GetGamepadAxis;
|
||||
SDL_GetGamepadAxisFromString;
|
||||
SDL_GetGamepadBindings;
|
||||
SDL_GetGamepadButton;
|
||||
SDL_GetGamepadButtonFromString;
|
||||
SDL_GetGamepadFirmwareVersion;
|
||||
@ -876,7 +877,7 @@ SDL3_0.0.0 {
|
||||
SDL_SetAudioStreamGetCallback;
|
||||
SDL_SetAudioStreamPutCallback;
|
||||
SDL_DestroyAudioStream;
|
||||
SDL_CreateAndBindAudioStream;
|
||||
SDL_OpenAudioDeviceStream;
|
||||
SDL_LoadWAV_RW;
|
||||
SDL_LoadWAV;
|
||||
SDL_MixAudioFormat;
|
||||
@ -885,8 +886,8 @@ SDL3_0.0.0 {
|
||||
SDL_LoadWAV;
|
||||
SDL_PauseAudioDevice;
|
||||
SDL_ResumeAudioDevice;
|
||||
SDL_IsAudioDevicePaused;
|
||||
SDL_GetAudioStreamBinding;
|
||||
SDL_AudioDevicePaused;
|
||||
SDL_GetAudioStreamDevice;
|
||||
SDL_ShowWindowSystemMenu;
|
||||
SDL_ReadS16LE;
|
||||
SDL_ReadS16BE;
|
||||
@ -899,6 +900,13 @@ SDL3_0.0.0 {
|
||||
SDL_WriteS32LE;
|
||||
SDL_WriteS32BE;
|
||||
SDL_WriteS64LE;
|
||||
SDL_WriteS64BE;
|
||||
SDL_GDKGetDefaultUser;
|
||||
SDL_SetWindowFocusable;
|
||||
SDL_GetAudioStreamFrequencyRatio;
|
||||
SDL_SetAudioStreamFrequencyRatio;
|
||||
SDL_SetAudioPostmixCallback;
|
||||
SDL_GetAudioStreamQueued;
|
||||
# extra symbols go here (don't modify this line)
|
||||
local: *;
|
||||
};
|
||||
|
@ -196,6 +196,7 @@
|
||||
#define SDL_GetGamepadAppleSFSymbolsNameForButton SDL_GetGamepadAppleSFSymbolsNameForButton_REAL
|
||||
#define SDL_GetGamepadAxis SDL_GetGamepadAxis_REAL
|
||||
#define SDL_GetGamepadAxisFromString SDL_GetGamepadAxisFromString_REAL
|
||||
#define SDL_GetGamepadBindings SDL_GetGamepadBindings_REAL
|
||||
#define SDL_GetGamepadButton SDL_GetGamepadButton_REAL
|
||||
#define SDL_GetGamepadButtonFromString SDL_GetGamepadButtonFromString_REAL
|
||||
#define SDL_GetGamepadFirmwareVersion SDL_GetGamepadFirmwareVersion_REAL
|
||||
@ -901,7 +902,7 @@
|
||||
#define SDL_SetAudioStreamGetCallback SDL_SetAudioStreamGetCallback_REAL
|
||||
#define SDL_SetAudioStreamPutCallback SDL_SetAudioStreamPutCallback_REAL
|
||||
#define SDL_DestroyAudioStream SDL_DestroyAudioStream_REAL
|
||||
#define SDL_CreateAndBindAudioStream SDL_CreateAndBindAudioStream_REAL
|
||||
#define SDL_OpenAudioDeviceStream SDL_OpenAudioDeviceStream_REAL
|
||||
#define SDL_LoadWAV_RW SDL_LoadWAV_RW_REAL
|
||||
#define SDL_LoadWAV SDL_LoadWAV_REAL
|
||||
#define SDL_MixAudioFormat SDL_MixAudioFormat_REAL
|
||||
@ -910,8 +911,8 @@
|
||||
#define SDL_LoadWAV SDL_LoadWAV_REAL
|
||||
#define SDL_PauseAudioDevice SDL_PauseAudioDevice_REAL
|
||||
#define SDL_ResumeAudioDevice SDL_ResumeAudioDevice_REAL
|
||||
#define SDL_IsAudioDevicePaused SDL_IsAudioDevicePaused_REAL
|
||||
#define SDL_GetAudioStreamBinding SDL_GetAudioStreamBinding_REAL
|
||||
#define SDL_AudioDevicePaused SDL_AudioDevicePaused_REAL
|
||||
#define SDL_GetAudioStreamDevice SDL_GetAudioStreamDevice_REAL
|
||||
#define SDL_ShowWindowSystemMenu SDL_ShowWindowSystemMenu_REAL
|
||||
#define SDL_ReadS16LE SDL_ReadS16LE_REAL
|
||||
#define SDL_ReadS16BE SDL_ReadS16BE_REAL
|
||||
@ -924,3 +925,10 @@
|
||||
#define SDL_WriteS32LE SDL_WriteS32LE_REAL
|
||||
#define SDL_WriteS32BE SDL_WriteS32BE_REAL
|
||||
#define SDL_WriteS64LE SDL_WriteS64LE_REAL
|
||||
#define SDL_WriteS64BE SDL_WriteS64BE_REAL
|
||||
#define SDL_GDKGetDefaultUser SDL_GDKGetDefaultUser_REAL
|
||||
#define SDL_SetWindowFocusable SDL_SetWindowFocusable_REAL
|
||||
#define SDL_GetAudioStreamFrequencyRatio SDL_GetAudioStreamFrequencyRatio_REAL
|
||||
#define SDL_SetAudioStreamFrequencyRatio SDL_SetAudioStreamFrequencyRatio_REAL
|
||||
#define SDL_SetAudioPostmixCallback SDL_SetAudioPostmixCallback_REAL
|
||||
#define SDL_GetAudioStreamQueued SDL_GetAudioStreamQueued_REAL
|
||||
|
22
external/sdl/SDL/src/dynapi/SDL_dynapi_procs.h
vendored
22
external/sdl/SDL/src/dynapi/SDL_dynapi_procs.h
vendored
@ -271,6 +271,7 @@ SDL_DYNAPI_PROC(const char*,SDL_GetGamepadAppleSFSymbolsNameForAxis,(SDL_Gamepad
|
||||
SDL_DYNAPI_PROC(const char*,SDL_GetGamepadAppleSFSymbolsNameForButton,(SDL_Gamepad *a, SDL_GamepadButton b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(Sint16,SDL_GetGamepadAxis,(SDL_Gamepad *a, SDL_GamepadAxis b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_GamepadAxis,SDL_GetGamepadAxisFromString,(const char *a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_GamepadBinding **,SDL_GetGamepadBindings,(SDL_Gamepad *a, int *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(Uint8,SDL_GetGamepadButton,(SDL_Gamepad *a, SDL_GamepadButton b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_GamepadButton,SDL_GetGamepadButtonFromString,(const char *a),(a),return)
|
||||
SDL_DYNAPI_PROC(Uint16,SDL_GetGamepadFirmwareVersion,(SDL_Gamepad *a),(a),return)
|
||||
@ -926,7 +927,7 @@ SDL_DYNAPI_PROC(const char*,SDL_GetCurrentAudioDriver,(void),(),return)
|
||||
SDL_DYNAPI_PROC(SDL_AudioDeviceID*,SDL_GetAudioOutputDevices,(int *a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_AudioDeviceID*,SDL_GetAudioCaptureDevices,(int *a),(a),return)
|
||||
SDL_DYNAPI_PROC(char*,SDL_GetAudioDeviceName,(SDL_AudioDeviceID a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_GetAudioDeviceFormat,(SDL_AudioDeviceID a, SDL_AudioSpec *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_GetAudioDeviceFormat,(SDL_AudioDeviceID a, SDL_AudioSpec *b, int *c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(SDL_AudioDeviceID,SDL_OpenAudioDevice,(SDL_AudioDeviceID a, const SDL_AudioSpec *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_CloseAudioDevice,(SDL_AudioDeviceID a),(a),)
|
||||
SDL_DYNAPI_PROC(int,SDL_BindAudioStreams,(SDL_AudioDeviceID a, SDL_AudioStream **b, int c),(a,b,c),return)
|
||||
@ -943,10 +944,10 @@ SDL_DYNAPI_PROC(int,SDL_FlushAudioStream,(SDL_AudioStream *a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_ClearAudioStream,(SDL_AudioStream *a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_LockAudioStream,(SDL_AudioStream *a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_UnlockAudioStream,(SDL_AudioStream *a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamGetCallback,(SDL_AudioStream *a, SDL_AudioStreamRequestCallback b, void *c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamPutCallback,(SDL_AudioStream *a, SDL_AudioStreamRequestCallback b, void *c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamGetCallback,(SDL_AudioStream *a, SDL_AudioStreamCallback b, void *c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamPutCallback,(SDL_AudioStream *a, SDL_AudioStreamCallback b, void *c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_DestroyAudioStream,(SDL_AudioStream *a),(a),)
|
||||
SDL_DYNAPI_PROC(SDL_AudioStream*,SDL_CreateAndBindAudioStream,(SDL_AudioDeviceID a, const SDL_AudioSpec *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_AudioStream*,SDL_OpenAudioDeviceStream,(SDL_AudioDeviceID a, const SDL_AudioSpec *b, SDL_AudioStreamCallback c, void *d),(a,b,c,d),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_LoadWAV_RW,(SDL_RWops *a, SDL_bool b, SDL_AudioSpec *c, Uint8 **d, Uint32 *e),(a,b,c,d,e),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_MixAudioFormat,(Uint8 *a, const Uint8 *b, SDL_AudioFormat c, Uint32 d, int e),(a,b,c,d,e),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_ConvertAudioSamples,(const SDL_AudioSpec *a, const Uint8 *b, int c, const SDL_AudioSpec *d, Uint8 **e, int *f),(a,b,c,d,e,f),return)
|
||||
@ -954,8 +955,8 @@ SDL_DYNAPI_PROC(int,SDL_GetSilenceValueForFormat,(SDL_AudioFormat a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_LoadWAV,(const char *a, SDL_AudioSpec *b, Uint8 **c, Uint32 *d),(a,b,c,d),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_PauseAudioDevice,(SDL_AudioDeviceID a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_ResumeAudioDevice,(SDL_AudioDeviceID a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_IsAudioDevicePaused,(SDL_AudioDeviceID a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_AudioDeviceID,SDL_GetAudioStreamBinding,(SDL_AudioStream *a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_AudioDevicePaused,(SDL_AudioDeviceID a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_AudioDeviceID,SDL_GetAudioStreamDevice,(SDL_AudioStream *a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_ShowWindowSystemMenu,(SDL_Window *a, int b, int c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_ReadS16LE,(SDL_RWops *a, Sint16 *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_ReadS16BE,(SDL_RWops *a, Sint16 *b),(a,b),return)
|
||||
@ -968,3 +969,12 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_WriteS16BE,(SDL_RWops *a, Sint16 b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_WriteS32LE,(SDL_RWops *a, Sint32 b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_WriteS32BE,(SDL_RWops *a, Sint32 b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_WriteS64LE,(SDL_RWops *a, Sint64 b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_WriteS64BE,(SDL_RWops *a, Sint64 b),(a,b),return)
|
||||
#ifdef __GDK__
|
||||
SDL_DYNAPI_PROC(int,SDL_GDKGetDefaultUser,(XUserHandle *a),(a),return)
|
||||
#endif
|
||||
SDL_DYNAPI_PROC(int,SDL_SetWindowFocusable,(SDL_Window *a, SDL_bool b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(float,SDL_GetAudioStreamFrequencyRatio,(SDL_AudioStream *a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamFrequencyRatio,(SDL_AudioStream *a, float b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetAudioPostmixCallback,(SDL_AudioDeviceID a, SDL_AudioPostmixCallback b, void *c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_GetAudioStreamQueued,(SDL_AudioStream *a),(a),return)
|
||||
|
8
external/sdl/SDL/src/events/SDL_events.c
vendored
8
external/sdl/SDL/src/events/SDL_events.c
vendored
@ -418,7 +418,7 @@ static void SDL_LogEvent(const SDL_Event *event)
|
||||
break;
|
||||
#undef PRINT_FINGER_EVENT
|
||||
|
||||
#define PRINT_DROP_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (file='%s' timestamp=%u windowid=%u)", event->drop.file, (uint)event->drop.timestamp, (uint)event->drop.windowID)
|
||||
#define PRINT_DROP_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (file='%s' timestamp=%u windowid=%u x=%f y=%f)", event->drop.file, (uint)event->drop.timestamp, (uint)event->drop.windowID, event->drop.x, event->drop.y)
|
||||
SDL_EVENT_CASE(SDL_EVENT_DROP_FILE)
|
||||
PRINT_DROP_EVENT(event);
|
||||
break;
|
||||
@ -431,6 +431,9 @@ static void SDL_LogEvent(const SDL_Event *event)
|
||||
SDL_EVENT_CASE(SDL_EVENT_DROP_COMPLETE)
|
||||
PRINT_DROP_EVENT(event);
|
||||
break;
|
||||
SDL_EVENT_CASE(SDL_EVENT_DROP_POSITION)
|
||||
PRINT_DROP_EVENT(event);
|
||||
break;
|
||||
#undef PRINT_DROP_EVENT
|
||||
|
||||
#define PRINT_AUDIODEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u iscapture=%s)", (uint)event->adevice.timestamp, (uint)event->adevice.which, event->adevice.iscapture ? "true" : "false")
|
||||
@ -440,6 +443,9 @@ static void SDL_LogEvent(const SDL_Event *event)
|
||||
SDL_EVENT_CASE(SDL_EVENT_AUDIO_DEVICE_REMOVED)
|
||||
PRINT_AUDIODEV_EVENT(event);
|
||||
break;
|
||||
SDL_EVENT_CASE(SDL_EVENT_AUDIO_DEVICE_FORMAT_CHANGED)
|
||||
PRINT_AUDIODEV_EVENT(event);
|
||||
break;
|
||||
#undef PRINT_AUDIODEV_EVENT
|
||||
|
||||
SDL_EVENT_CASE(SDL_EVENT_SENSOR_UPDATE)
|
||||
|
34
external/sdl/SDL/src/events/SDL_mouse.c
vendored
34
external/sdl/SDL/src/events/SDL_mouse.c
vendored
@ -233,13 +233,31 @@ void SDL_SetDefaultCursor(SDL_Cursor *cursor)
|
||||
|
||||
if (mouse->def_cursor) {
|
||||
SDL_Cursor *default_cursor = mouse->def_cursor;
|
||||
SDL_Cursor *prev, *curr;
|
||||
|
||||
if (mouse->cur_cursor == mouse->def_cursor) {
|
||||
mouse->cur_cursor = NULL;
|
||||
}
|
||||
mouse->def_cursor = NULL;
|
||||
|
||||
SDL_DestroyCursor(default_cursor);
|
||||
for (prev = NULL, curr = mouse->cursors; curr;
|
||||
prev = curr, curr = curr->next) {
|
||||
if (curr == default_cursor) {
|
||||
if (prev) {
|
||||
prev->next = curr->next;
|
||||
} else {
|
||||
mouse->cursors = curr->next;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mouse->FreeCursor && default_cursor->driverdata) {
|
||||
mouse->FreeCursor(default_cursor);
|
||||
} else {
|
||||
SDL_free(default_cursor);
|
||||
}
|
||||
}
|
||||
|
||||
mouse->def_cursor = cursor;
|
||||
@ -591,6 +609,13 @@ static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_
|
||||
}
|
||||
}
|
||||
|
||||
if (mouse->has_position && xrel == 0.0f && yrel == 0.0f) { /* Drop events that don't change state */
|
||||
#ifdef DEBUG_MOUSE
|
||||
SDL_Log("Mouse event didn't change state - dropped!\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ignore relative motion positioning the first touch */
|
||||
if (mouseID == SDL_TOUCH_MOUSEID && !GetButtonState(mouse, SDL_TRUE)) {
|
||||
xrel = 0.0f;
|
||||
@ -598,13 +623,6 @@ static int SDL_PrivateSendMouseMotion(Uint64 timestamp, SDL_Window *window, SDL_
|
||||
}
|
||||
|
||||
if (mouse->has_position) {
|
||||
if (xrel == 0.0f && yrel == 0.0f) { /* Drop events that don't change state */
|
||||
#ifdef DEBUG_MOUSE
|
||||
SDL_Log("Mouse event didn't change state - dropped!\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update internal mouse coordinates */
|
||||
if (!mouse->relative_mode) {
|
||||
mouse->x = x;
|
||||
|
2
external/sdl/SDL/src/events/imKStoUCS.h
vendored
2
external/sdl/SDL/src/events/imKStoUCS.h
vendored
@ -3,7 +3,7 @@
|
||||
|
||||
/*
|
||||
Copyright (C) 2003-2006,2008 Jamey Sharp, Josh Triplett
|
||||
Copyright © 2009 Red Hat, Inc.
|
||||
Copyright © 2009 Red Hat, Inc.
|
||||
Copyright 1990-1992,1999,2000,2004,2009,2010 Oracle and/or its affiliates.
|
||||
All rights reserved.
|
||||
|
||||
|
140
external/sdl/SDL/src/filesystem/gdk/SDL_sysfilesystem.cpp
vendored
Normal file
140
external/sdl/SDL/src/filesystem/gdk/SDL_sysfilesystem.cpp
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 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"
|
||||
|
||||
#ifdef SDL_FILESYSTEM_XBOX
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
/* System dependent filesystem routines */
|
||||
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
#include "SDL_hints.h"
|
||||
#include "SDL_system.h"
|
||||
#include "SDL_filesystem.h"
|
||||
#include <XGameSaveFiles.h>
|
||||
|
||||
char *
|
||||
SDL_GetBasePath(void)
|
||||
{
|
||||
/* NOTE: This function is a UTF8 version of the Win32 SDL_GetBasePath()!
|
||||
* The GDK actually _recommends_ the 'A' functions over the 'W' functions :o
|
||||
*/
|
||||
DWORD buflen = 128;
|
||||
CHAR *path = NULL;
|
||||
DWORD len = 0;
|
||||
int i;
|
||||
|
||||
while (SDL_TRUE) {
|
||||
void *ptr = SDL_realloc(path, buflen * sizeof(CHAR));
|
||||
if (ptr == NULL) {
|
||||
SDL_free(path);
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = (CHAR *)ptr;
|
||||
|
||||
len = GetModuleFileNameA(NULL, path, buflen);
|
||||
/* if it truncated, then len >= buflen - 1 */
|
||||
/* if there was enough room (or failure), len < buflen - 1 */
|
||||
if (len < buflen - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* buffer too small? Try again. */
|
||||
buflen *= 2;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
SDL_free(path);
|
||||
WIN_SetError("Couldn't locate our .exe");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = len - 1; i > 0; i--) {
|
||||
if (path[i] == '\\') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_assert(i > 0); /* Should have been an absolute path. */
|
||||
path[i + 1] = '\0'; /* chop off filename. */
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
char *
|
||||
SDL_GetPrefPath(const char *org, const char *app)
|
||||
{
|
||||
XUserHandle user = NULL;
|
||||
XAsyncBlock block = { 0 };
|
||||
char *folderPath;
|
||||
HRESULT result;
|
||||
const char *csid = SDL_GetHint("SDL_GDK_SERVICE_CONFIGURATION_ID");
|
||||
|
||||
if (app == NULL) {
|
||||
SDL_InvalidParamError("app");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This should be set before calling SDL_GetPrefPath! */
|
||||
if (csid == NULL) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_SYSTEM, "Set SDL_GDK_SERVICE_CONFIGURATION_ID before calling SDL_GetPrefPath!");
|
||||
return SDL_strdup("T:\\");
|
||||
}
|
||||
|
||||
if (SDL_GDKGetDefaultUser(&user) < 0) {
|
||||
/* Error already set, just return */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (FAILED(result = XGameSaveFilesGetFolderWithUiAsync(user, csid, &block))) {
|
||||
WIN_SetErrorFromHRESULT("XGameSaveFilesGetFolderWithUiAsync", result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
folderPath = (char*) SDL_malloc(MAX_PATH);
|
||||
do {
|
||||
result = XGameSaveFilesGetFolderWithUiResult(&block, MAX_PATH, folderPath);
|
||||
} while (result == E_PENDING);
|
||||
if (FAILED(result)) {
|
||||
WIN_SetErrorFromHRESULT("XGameSaveFilesGetFolderWithUiResult", result);
|
||||
SDL_free(folderPath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We aren't using 'app' here because the container rules are a lot more
|
||||
* strict than the NTFS rules, so it will most likely be invalid :(
|
||||
*/
|
||||
SDL_strlcat(folderPath, "\\SDLPrefPath\\", MAX_PATH);
|
||||
if (CreateDirectoryA(folderPath, NULL) == FALSE) {
|
||||
if (GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
WIN_SetError("CreateDirectoryA");
|
||||
SDL_free(folderPath);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return folderPath;
|
||||
}
|
||||
|
||||
#endif /* SDL_FILESYSTEM_XBOX */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
@ -332,23 +332,3 @@ done:
|
||||
return retval;
|
||||
}
|
||||
#endif /* SDL_FILESYSTEM_WINDOWS */
|
||||
|
||||
#ifdef SDL_FILESYSTEM_XBOX
|
||||
char *SDL_GetBasePath(void)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *SDL_GetPrefPath(const char *org, const char *app)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *SDL_GetUserFolder(SDL_Folder folder)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return NULL;
|
||||
}
|
||||
#endif /* SDL_FILESYSTEM_XBOX */
|
||||
|
289
external/sdl/SDL/src/hidapi/SDL_hidapi.c
vendored
289
external/sdl/SDL/src/hidapi/SDL_hidapi.c
vendored
@ -873,10 +873,47 @@ typedef struct LIBUSB_hid_device_ LIBUSB_hid_device;
|
||||
#undef read_thread
|
||||
#undef return_data
|
||||
|
||||
/* If the platform has any backend other than libusb, try to avoid using
|
||||
* libusb as the main backend for devices, since it detaches drivers and
|
||||
* therefore makes devices inaccessible to the rest of the OS.
|
||||
*
|
||||
* We do this by whitelisting devices we know to be accessible _exclusively_
|
||||
* via libusb; these are typically devices that look like HIDs but have a
|
||||
* quirk that requires direct access to the hardware.
|
||||
*/
|
||||
static const struct {
|
||||
Uint16 vendor;
|
||||
Uint16 product;
|
||||
} SDL_libusb_whitelist[] = {
|
||||
{ 0x057e, 0x0337 } /* Nintendo WUP-028, Wii U/Switch GameCube Adapter */
|
||||
};
|
||||
|
||||
static SDL_bool IsInWhitelist(Uint16 vendor, Uint16 product)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < SDL_arraysize(SDL_libusb_whitelist); i += 1) {
|
||||
if (vendor == SDL_libusb_whitelist[i].vendor &&
|
||||
product == SDL_libusb_whitelist[i].product) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBUSB */
|
||||
|
||||
#endif /* !SDL_HIDAPI_DISABLED */
|
||||
|
||||
#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND)
|
||||
/* We have another way to get HID devices, so use the whitelist to get devices where libusb is preferred */
|
||||
#define SDL_HIDAPI_LIBUSB_WHITELIST_DEFAULT SDL_TRUE
|
||||
#else
|
||||
/* libusb is the only way to get HID devices, so don't use the whitelist, get them all */
|
||||
#define SDL_HIDAPI_LIBUSB_WHITELIST_DEFAULT SDL_FALSE
|
||||
#endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND */
|
||||
|
||||
static SDL_bool use_libusb_whitelist = SDL_HIDAPI_LIBUSB_WHITELIST_DEFAULT;
|
||||
|
||||
/* Shared HIDAPI Implementation */
|
||||
|
||||
struct hidapi_backend
|
||||
@ -1117,6 +1154,8 @@ int SDL_hid_init(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
use_libusb_whitelist = SDL_GetHintBoolean("SDL_HIDAPI_LIBUSB_WHITELIST",
|
||||
SDL_HIDAPI_LIBUSB_WHITELIST_DEFAULT);
|
||||
#ifdef HAVE_LIBUSB
|
||||
if (SDL_getenv("SDL_HIDAPI_DISABLE_LIBUSB") != NULL) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
@ -1280,144 +1319,170 @@ Uint32 SDL_hid_device_change_count(void)
|
||||
return counter;
|
||||
}
|
||||
|
||||
static void AddDeviceToEnumeration(const char *driver_name, struct hid_device_info *dev, struct SDL_hid_device_info **devs, struct SDL_hid_device_info **last)
|
||||
{
|
||||
struct SDL_hid_device_info *new_dev;
|
||||
|
||||
#ifdef DEBUG_HIDAPI
|
||||
SDL_Log("Adding %s device to enumeration: %ls %ls 0x%.4hx/0x%.4hx/%d",
|
||||
driver_name, dev->manufacturer_string, dev->product_string, dev->vendor_id, dev->product_id, dev->interface_number);
|
||||
#else
|
||||
(void)driver_name;
|
||||
#endif
|
||||
|
||||
new_dev = (struct SDL_hid_device_info *)SDL_malloc(sizeof(struct SDL_hid_device_info));
|
||||
if (new_dev == NULL) {
|
||||
/* Don't bother returning an error, get as many devices as possible */
|
||||
return;
|
||||
}
|
||||
CopyHIDDeviceInfo(dev, new_dev);
|
||||
|
||||
if ((*last) != NULL) {
|
||||
(*last)->next = new_dev;
|
||||
} else {
|
||||
*devs = new_dev;
|
||||
}
|
||||
*last = new_dev;
|
||||
}
|
||||
|
||||
#if defined(HAVE_LIBUSB) || defined(HAVE_PLATFORM_BACKEND)
|
||||
static void RemoveDeviceFromEnumeration(const char *driver_name, struct hid_device_info *dev, struct hid_device_info **devs, void (*free_device_info)(struct hid_device_info *))
|
||||
{
|
||||
struct hid_device_info *last = NULL, *curr, *next;
|
||||
|
||||
for (curr = *devs; curr; curr = next) {
|
||||
next = curr->next;
|
||||
|
||||
if (dev->vendor_id == curr->vendor_id &&
|
||||
dev->product_id == curr->product_id &&
|
||||
(dev->interface_number < 0 || curr->interface_number < 0 || dev->interface_number == curr->interface_number)) {
|
||||
#ifdef DEBUG_HIDAPI
|
||||
SDL_Log("Skipping %s device: %ls %ls 0x%.4hx/0x%.4hx/%d",
|
||||
driver_name, curr->manufacturer_string, curr->product_string, curr->vendor_id, curr->product_id, curr->interface_number);
|
||||
#else
|
||||
(void)driver_name;
|
||||
#endif
|
||||
if (last) {
|
||||
last->next = next;
|
||||
} else {
|
||||
*devs = next;
|
||||
}
|
||||
|
||||
curr->next = NULL;
|
||||
free_device_info(curr);
|
||||
continue;
|
||||
}
|
||||
last = curr;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_LIBUSB || HAVE_PLATFORM_BACKEND */
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
static void RemoveNonWhitelistedDevicesFromEnumeration(struct hid_device_info **devs, void (*free_device_info)(struct hid_device_info *))
|
||||
{
|
||||
struct hid_device_info *last = NULL, *curr, *next;
|
||||
|
||||
for (curr = *devs; curr; curr = next) {
|
||||
next = curr->next;
|
||||
|
||||
if (!IsInWhitelist(curr->vendor_id, curr->product_id)) {
|
||||
#ifdef DEBUG_HIDAPI
|
||||
SDL_Log("Device was not in libusb whitelist, skipping: %ls %ls 0x%.4hx/0x%.4hx/%d",
|
||||
curr->manufacturer_string, curr->product_string, curr->vendor_id, curr->product_id, curr->interface_number);
|
||||
#endif
|
||||
if (last) {
|
||||
last->next = next;
|
||||
} else {
|
||||
*devs = next;
|
||||
}
|
||||
|
||||
curr->next = NULL;
|
||||
free_device_info(curr);
|
||||
continue;
|
||||
}
|
||||
last = curr;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_LIBUSB */
|
||||
|
||||
struct SDL_hid_device_info *SDL_hid_enumerate(unsigned short vendor_id, unsigned short product_id)
|
||||
{
|
||||
#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) || defined(HAVE_LIBUSB)
|
||||
#ifdef HAVE_LIBUSB
|
||||
struct hid_device_info *usb_devs = NULL;
|
||||
struct hid_device_info *usb_dev;
|
||||
#endif
|
||||
#ifdef HAVE_DRIVER_BACKEND
|
||||
struct hid_device_info *driver_devs = NULL;
|
||||
struct hid_device_info *driver_dev;
|
||||
#endif
|
||||
#ifdef HAVE_PLATFORM_BACKEND
|
||||
struct hid_device_info *usb_devs = NULL;
|
||||
struct hid_device_info *raw_devs = NULL;
|
||||
struct hid_device_info *raw_dev;
|
||||
#endif
|
||||
struct SDL_hid_device_info *devs = NULL, *last = NULL, *new_dev;
|
||||
struct hid_device_info *dev;
|
||||
struct SDL_hid_device_info *devs = NULL, *last = NULL;
|
||||
|
||||
if (SDL_hidapi_refcount == 0 && SDL_hid_init() != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Collect the available devices */
|
||||
#ifdef HAVE_DRIVER_BACKEND
|
||||
driver_devs = DRIVER_hid_enumerate(vendor_id, product_id);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
if (libusb_ctx.libhandle) {
|
||||
usb_devs = LIBUSB_hid_enumerate(vendor_id, product_id);
|
||||
#ifdef DEBUG_HIDAPI
|
||||
SDL_Log("libusb devices found:");
|
||||
#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 == NULL) {
|
||||
LIBUSB_hid_free_enumeration(usb_devs);
|
||||
SDL_hid_free_enumeration(devs);
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
CopyHIDDeviceInfo(usb_dev, new_dev);
|
||||
#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
|
||||
|
||||
if (last != NULL) {
|
||||
last->next = new_dev;
|
||||
} else {
|
||||
devs = new_dev;
|
||||
}
|
||||
last = new_dev;
|
||||
if (use_libusb_whitelist) {
|
||||
RemoveNonWhitelistedDevicesFromEnumeration(&usb_devs, LIBUSB_hid_free_enumeration);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_LIBUSB */
|
||||
|
||||
#ifdef HAVE_DRIVER_BACKEND
|
||||
driver_devs = DRIVER_hid_enumerate(vendor_id, product_id);
|
||||
for (driver_dev = driver_devs; driver_dev; driver_dev = driver_dev->next) {
|
||||
new_dev = (struct SDL_hid_device_info *)SDL_malloc(sizeof(struct SDL_hid_device_info));
|
||||
CopyHIDDeviceInfo(driver_dev, new_dev);
|
||||
|
||||
if (last != NULL) {
|
||||
last->next = new_dev;
|
||||
} else {
|
||||
devs = new_dev;
|
||||
}
|
||||
last = new_dev;
|
||||
}
|
||||
#endif /* HAVE_DRIVER_BACKEND */
|
||||
|
||||
#ifdef HAVE_PLATFORM_BACKEND
|
||||
if (udev_ctx) {
|
||||
raw_devs = PLATFORM_hid_enumerate(vendor_id, product_id);
|
||||
#ifdef DEBUG_HIDAPI
|
||||
SDL_Log("hidraw devices found:");
|
||||
}
|
||||
#endif
|
||||
for (raw_dev = raw_devs; raw_dev; raw_dev = raw_dev->next) {
|
||||
SDL_bool bFound = SDL_FALSE;
|
||||
#ifdef DEBUG_HIDAPI
|
||||
SDL_Log(" - %ls %ls 0x%.4hx 0x%.4hx",
|
||||
raw_dev->manufacturer_string, raw_dev->product_string,
|
||||
raw_dev->vendor_id, raw_dev->product_id);
|
||||
#endif
|
||||
#ifdef HAVE_LIBUSB
|
||||
for (usb_dev = usb_devs; usb_dev; usb_dev = usb_dev->next) {
|
||||
if (raw_dev->vendor_id == usb_dev->vendor_id &&
|
||||
raw_dev->product_id == usb_dev->product_id &&
|
||||
(raw_dev->interface_number < 0 || raw_dev->interface_number == usb_dev->interface_number)) {
|
||||
bFound = SDL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_DRIVER_BACKEND
|
||||
for (driver_dev = driver_devs; driver_dev; driver_dev = driver_dev->next) {
|
||||
if (raw_dev->vendor_id == driver_dev->vendor_id &&
|
||||
raw_dev->product_id == driver_dev->product_id &&
|
||||
(raw_dev->interface_number < 0 || raw_dev->interface_number == driver_dev->interface_number)) {
|
||||
bFound = SDL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!bFound) {
|
||||
new_dev = (struct SDL_hid_device_info *)SDL_malloc(sizeof(struct SDL_hid_device_info));
|
||||
if (new_dev == NULL) {
|
||||
#ifdef HAVE_LIBUSB
|
||||
if (libusb_ctx.libhandle) {
|
||||
LIBUSB_hid_free_enumeration(usb_devs);
|
||||
}
|
||||
#endif
|
||||
PLATFORM_hid_free_enumeration(raw_devs);
|
||||
SDL_hid_free_enumeration(devs);
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
CopyHIDDeviceInfo(raw_dev, new_dev);
|
||||
new_dev->next = NULL;
|
||||
|
||||
if (last != NULL) {
|
||||
last->next = new_dev;
|
||||
} else {
|
||||
devs = new_dev;
|
||||
}
|
||||
last = new_dev;
|
||||
}
|
||||
/* Highest priority are custom driver devices */
|
||||
for (dev = driver_devs; dev; dev = dev->next) {
|
||||
AddDeviceToEnumeration("driver", dev, &devs, &last);
|
||||
#ifdef HAVE_LIBUSB
|
||||
RemoveDeviceFromEnumeration("libusb", dev, &usb_devs, LIBUSB_hid_free_enumeration);
|
||||
#endif
|
||||
#ifdef HAVE_PLATFORM_BACKEND
|
||||
RemoveDeviceFromEnumeration("raw", dev, &raw_devs, PLATFORM_hid_free_enumeration);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* If whitelist is in effect, libusb has priority, otherwise raw devices do */
|
||||
if (use_libusb_whitelist) {
|
||||
for (dev = usb_devs; dev; dev = dev->next) {
|
||||
AddDeviceToEnumeration("libusb", dev, &devs, &last);
|
||||
#ifdef HAVE_PLATFORM_BACKEND
|
||||
RemoveDeviceFromEnumeration("raw", dev, &raw_devs, PLATFORM_hid_free_enumeration);
|
||||
#endif
|
||||
}
|
||||
PLATFORM_hid_free_enumeration(raw_devs);
|
||||
}
|
||||
#endif /* HAVE_PLATFORM_BACKEND */
|
||||
|
||||
for (dev = raw_devs; dev; dev = dev->next) {
|
||||
AddDeviceToEnumeration("platform", dev, &devs, &last);
|
||||
}
|
||||
} else {
|
||||
for (dev = raw_devs; dev; dev = dev->next) {
|
||||
AddDeviceToEnumeration("raw", dev, &devs, &last);
|
||||
#ifdef HAVE_LIBUSB
|
||||
if (libusb_ctx.libhandle) {
|
||||
LIBUSB_hid_free_enumeration(usb_devs);
|
||||
}
|
||||
RemoveDeviceFromEnumeration("libusb", dev, &usb_devs, LIBUSB_hid_free_enumeration);
|
||||
#endif
|
||||
return devs;
|
||||
}
|
||||
for (dev = usb_devs; dev; dev = dev->next) {
|
||||
AddDeviceToEnumeration("libusb", dev, &devs, &last);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
return NULL;
|
||||
#endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || HAVE_LIBUSB */
|
||||
#ifdef HAVE_DRIVER_BACKEND
|
||||
DRIVER_hid_free_enumeration(driver_devs);
|
||||
#endif
|
||||
#ifdef HAVE_LIBUSB
|
||||
LIBUSB_hid_free_enumeration(usb_devs);
|
||||
#endif
|
||||
#ifdef HAVE_PLATFORM_BACKEND
|
||||
PLATFORM_hid_free_enumeration(raw_devs);
|
||||
#endif
|
||||
|
||||
return devs;
|
||||
}
|
||||
|
||||
void SDL_hid_free_enumeration(struct SDL_hid_device_info *devs)
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
/* #pragma push_macro/pop_macro works correctly only as of gcc >= 4.4.3
|
||||
clang-3.0 _seems_ to be OK. */
|
||||
#pragma push_macro("calloc")
|
||||
#pragma push_macro("malloc")
|
||||
#pragma push_macro("realloc")
|
||||
#pragma push_macro("free")
|
||||
@ -38,6 +39,7 @@
|
||||
#pragma push_macro("tolower")
|
||||
#pragma push_macro("wcsdup")
|
||||
|
||||
#undef calloc
|
||||
#undef malloc
|
||||
#undef realloc
|
||||
#undef free
|
||||
@ -53,6 +55,7 @@
|
||||
#undef tolower
|
||||
#undef wcsdup
|
||||
|
||||
#define calloc SDL_calloc
|
||||
#define malloc SDL_malloc
|
||||
#define realloc SDL_realloc
|
||||
#define free SDL_free
|
||||
@ -106,6 +109,7 @@ static int SDL_libusb_get_string_descriptor(libusb_device_handle *dev,
|
||||
#undef ICONV_CONST
|
||||
#undef UNDEF_ICONV_CONST
|
||||
#endif
|
||||
#pragma pop_macro("calloc")
|
||||
#pragma pop_macro("malloc")
|
||||
#pragma pop_macro("realloc")
|
||||
#pragma pop_macro("free")
|
||||
|
8
external/sdl/SDL/src/hidapi/android/hid.cpp
vendored
8
external/sdl/SDL/src/hidapi/android/hid.cpp
vendored
@ -1031,7 +1031,7 @@ extern "C"
|
||||
|
||||
int hid_init(void)
|
||||
{
|
||||
if ( !g_initialized )
|
||||
if ( !g_initialized && g_HIDDeviceManagerCallbackHandler )
|
||||
{
|
||||
// HIDAPI doesn't work well with Android < 4.3
|
||||
if (SDL_GetAndroidSDKVersion() >= 18) {
|
||||
@ -1040,12 +1040,6 @@ int hid_init(void)
|
||||
g_JVM->AttachCurrentThread( &env, NULL );
|
||||
pthread_setspecific( g_ThreadKey, (void*)env );
|
||||
|
||||
if ( !g_HIDDeviceManagerCallbackHandler )
|
||||
{
|
||||
LOGV( "hid_init() without callback handler" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Bluetooth is currently only used for Steam Controllers, so check that hint
|
||||
// before initializing Bluetooth, which will prompt the user for permission.
|
||||
bool init_usb = true;
|
||||
|
2
external/sdl/SDL/src/hidapi/configure.ac
vendored
2
external/sdl/SDL/src/hidapi/configure.ac
vendored
@ -74,7 +74,7 @@ case $host in
|
||||
backend="mac"
|
||||
os="darwin"
|
||||
threads="pthreads"
|
||||
LIBS="${LIBS} -framework IOKit -framework CoreFoundation -framework AppKit"
|
||||
LIBS="${LIBS} -framework IOKit -framework CoreFoundation"
|
||||
;;
|
||||
*-freebsd*)
|
||||
AC_MSG_RESULT([ (FreeBSD back-end)])
|
||||
|
@ -26,6 +26,6 @@ Pod::Spec.new do |spec|
|
||||
|
||||
spec.public_header_files = "hidapi/hidapi.h", "mac/hidapi_darwin.h"
|
||||
|
||||
spec.frameworks = "IOKit", "CoreFoundation", "AppKit"
|
||||
spec.frameworks = "IOKit", "CoreFoundation"
|
||||
|
||||
end
|
||||
|
13
external/sdl/SDL/src/hidapi/libusb/hid.c
vendored
13
external/sdl/SDL/src/hidapi/libusb/hid.c
vendored
@ -259,8 +259,16 @@ static int get_usage(uint8_t *report_descriptor, size_t size,
|
||||
//printf("Usage Page: %x\n", (uint32_t)*usage_page);
|
||||
}
|
||||
if (key_cmd == 0x8) {
|
||||
*usage = get_bytes(report_descriptor, size, data_len, i);
|
||||
usage_found = 1;
|
||||
if (data_len == 4) { /* Usages 5.5 / Usage Page 6.2.2.7 */
|
||||
*usage_page = get_bytes(report_descriptor, size, 2, i + 2);
|
||||
usage_page_found = 1;
|
||||
*usage = get_bytes(report_descriptor, size, 2, i);
|
||||
usage_found = 1;
|
||||
}
|
||||
else {
|
||||
*usage = get_bytes(report_descriptor, size, data_len, i);
|
||||
usage_found = 1;
|
||||
}
|
||||
//printf("Usage: %x\n", (uint32_t)*usage);
|
||||
}
|
||||
|
||||
@ -1015,6 +1023,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||
libusb_close(handle);
|
||||
handle = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} /* altsettings */
|
||||
} /* interfaces */
|
||||
|
130
external/sdl/SDL/src/hidapi/linux/hid.c
vendored
130
external/sdl/SDL/src/hidapi/linux/hid.c
vendored
@ -206,7 +206,7 @@ static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name)
|
||||
* Returns 1 if successful, 0 if an invalid key
|
||||
* Sets data_len and key_size when successful
|
||||
*/
|
||||
static int get_hid_item_size(__u8 *report_descriptor, unsigned int pos, __u32 size, int *data_len, int *key_size)
|
||||
static int get_hid_item_size(const __u8 *report_descriptor, __u32 size, unsigned int pos, int *data_len, int *key_size)
|
||||
{
|
||||
int key = report_descriptor[pos];
|
||||
int size_code;
|
||||
@ -262,7 +262,7 @@ static int get_hid_item_size(__u8 *report_descriptor, unsigned int pos, __u32 si
|
||||
* Get bytes from a HID Report Descriptor.
|
||||
* Only call with a num_bytes of 0, 1, 2, or 4.
|
||||
*/
|
||||
static __u32 get_hid_report_bytes(__u8 *rpt, size_t len, size_t num_bytes, size_t cur)
|
||||
static __u32 get_hid_report_bytes(const __u8 *rpt, size_t len, size_t num_bytes, size_t cur)
|
||||
{
|
||||
/* Return if there aren't enough bytes. */
|
||||
if (cur + num_bytes >= len)
|
||||
@ -285,6 +285,60 @@ static __u32 get_hid_report_bytes(__u8 *rpt, size_t len, size_t num_bytes, size_
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterates until the end of a Collection.
|
||||
* Assumes that *pos is exactly at the beginning of a Collection.
|
||||
* Skips all nested Collection, i.e. iterates until the end of current level Collection.
|
||||
*
|
||||
* The return value is non-0 when an end of current Collection is found,
|
||||
* 0 when error is occured (broken Descriptor, end of a Collection is found before its begin,
|
||||
* or no Collection is found at all).
|
||||
*/
|
||||
static int hid_iterate_over_collection(const __u8 *report_descriptor, __u32 size, unsigned int *pos, int *data_len, int *key_size)
|
||||
{
|
||||
int collection_level = 0;
|
||||
|
||||
while (*pos < size) {
|
||||
int key = report_descriptor[*pos];
|
||||
int key_cmd = key & 0xfc;
|
||||
|
||||
/* Determine data_len and key_size */
|
||||
if (!get_hid_item_size(report_descriptor, size, *pos, data_len, key_size))
|
||||
return 0; /* malformed report */
|
||||
|
||||
switch (key_cmd) {
|
||||
case 0xa0: /* Collection 6.2.2.4 (Main) */
|
||||
collection_level++;
|
||||
break;
|
||||
case 0xc0: /* End Collection 6.2.2.4 (Main) */
|
||||
collection_level--;
|
||||
break;
|
||||
}
|
||||
|
||||
if (collection_level < 0) {
|
||||
/* Broken descriptor or someone is using this function wrong,
|
||||
* i.e. should be called exactly at the collection start */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (collection_level == 0) {
|
||||
/* Found it!
|
||||
* Also possible when called not at the collection start, but should not happen if used correctly */
|
||||
return 1;
|
||||
}
|
||||
|
||||
*pos += *data_len + *key_size;
|
||||
}
|
||||
|
||||
return 0; /* Did not find the end of a Collection */
|
||||
}
|
||||
|
||||
struct hid_usage_iterator {
|
||||
unsigned int pos;
|
||||
int usage_page_found;
|
||||
unsigned short usage_page;
|
||||
};
|
||||
|
||||
/*
|
||||
* Retrieves the device's Usage Page and Usage from the report descriptor.
|
||||
* The algorithm returns the current Usage Page/Usage pair whenever a new
|
||||
@ -302,63 +356,64 @@ static __u32 get_hid_report_bytes(__u8 *rpt, size_t len, size_t num_bytes, size_
|
||||
* 1 when finished processing descriptor.
|
||||
* -1 on a malformed report.
|
||||
*/
|
||||
static int get_next_hid_usage(__u8 *report_descriptor, __u32 size, unsigned int *pos, unsigned short *usage_page, unsigned short *usage)
|
||||
static int get_next_hid_usage(const __u8 *report_descriptor, __u32 size, struct hid_usage_iterator *ctx, unsigned short *usage_page, unsigned short *usage)
|
||||
{
|
||||
int data_len, key_size;
|
||||
int initial = *pos == 0; /* Used to handle case where no top-level application collection is defined */
|
||||
int usage_pair_ready = 0;
|
||||
int initial = ctx->pos == 0; /* Used to handle case where no top-level application collection is defined */
|
||||
|
||||
/* Usage is a Local Item, it must be set before each Main Item (Collection) before a pair is returned */
|
||||
int usage_found = 0;
|
||||
|
||||
while (*pos < size) {
|
||||
int key = report_descriptor[*pos];
|
||||
while (ctx->pos < size) {
|
||||
int key = report_descriptor[ctx->pos];
|
||||
int key_cmd = key & 0xfc;
|
||||
|
||||
/* Determine data_len and key_size */
|
||||
if (!get_hid_item_size(report_descriptor, *pos, size, &data_len, &key_size))
|
||||
if (!get_hid_item_size(report_descriptor, size, ctx->pos, &data_len, &key_size))
|
||||
return -1; /* malformed report */
|
||||
|
||||
switch (key_cmd) {
|
||||
case 0x4: /* Usage Page 6.2.2.7 (Global) */
|
||||
*usage_page = get_hid_report_bytes(report_descriptor, size, data_len, *pos);
|
||||
ctx->usage_page = get_hid_report_bytes(report_descriptor, size, data_len, ctx->pos);
|
||||
ctx->usage_page_found = 1;
|
||||
break;
|
||||
|
||||
case 0x8: /* Usage 6.2.2.8 (Local) */
|
||||
*usage = get_hid_report_bytes(report_descriptor, size, data_len, *pos);
|
||||
usage_found = 1;
|
||||
if (data_len == 4) { /* Usages 5.5 / Usage Page 6.2.2.7 */
|
||||
ctx->usage_page = get_hid_report_bytes(report_descriptor, size, 2, ctx->pos + 2);
|
||||
ctx->usage_page_found = 1;
|
||||
*usage = get_hid_report_bytes(report_descriptor, size, 2, ctx->pos);
|
||||
usage_found = 1;
|
||||
}
|
||||
else {
|
||||
*usage = get_hid_report_bytes(report_descriptor, size, data_len, ctx->pos);
|
||||
usage_found = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xa0: /* Collection 6.2.2.4 (Main) */
|
||||
/* A Usage Item (Local) must be found for the pair to be valid */
|
||||
if (usage_found)
|
||||
usage_pair_ready = 1;
|
||||
if (!hid_iterate_over_collection(report_descriptor, size, &ctx->pos, &data_len, &key_size)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Usage is a Local Item, unset it */
|
||||
usage_found = 0;
|
||||
break;
|
||||
/* A pair is valid - to be reported when Collection is found */
|
||||
if (usage_found && ctx->usage_page_found) {
|
||||
*usage_page = ctx->usage_page;
|
||||
return 0;
|
||||
}
|
||||
|
||||
case 0x80: /* Input 6.2.2.4 (Main) */
|
||||
case 0x90: /* Output 6.2.2.4 (Main) */
|
||||
case 0xb0: /* Feature 6.2.2.4 (Main) */
|
||||
case 0xc0: /* End Collection 6.2.2.4 (Main) */
|
||||
/* Usage is a Local Item, unset it */
|
||||
usage_found = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Skip over this key and its associated data */
|
||||
*pos += data_len + key_size;
|
||||
|
||||
/* Return usage pair */
|
||||
if (usage_pair_ready)
|
||||
return 0;
|
||||
ctx->pos += data_len + key_size;
|
||||
}
|
||||
|
||||
/* If no top-level application collection is found and usage page/usage pair is found, pair is valid
|
||||
https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/top-level-collections */
|
||||
if (initial && usage_found)
|
||||
return 0; /* success */
|
||||
if (initial && usage_found && ctx->usage_page_found) {
|
||||
*usage_page = ctx->usage_page;
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
return 1; /* finished processing */
|
||||
}
|
||||
@ -804,12 +859,14 @@ static struct hid_device_info * create_device_info_for_device(struct udev_device
|
||||
result = get_hid_report_descriptor_from_sysfs(sysfs_path, &report_desc);
|
||||
if (result >= 0) {
|
||||
unsigned short page = 0, usage = 0;
|
||||
unsigned int pos = 0;
|
||||
struct hid_usage_iterator usage_iterator;
|
||||
memset(&usage_iterator, 0, sizeof(usage_iterator));
|
||||
|
||||
/*
|
||||
* Parse the first usage and usage page
|
||||
* out of the report descriptor.
|
||||
*/
|
||||
if (!get_next_hid_usage(report_desc.value, report_desc.size, &pos, &page, &usage)) {
|
||||
if (!get_next_hid_usage(report_desc.value, report_desc.size, &usage_iterator, &page, &usage)) {
|
||||
cur_dev->usage_page = page;
|
||||
cur_dev->usage = usage;
|
||||
}
|
||||
@ -818,7 +875,7 @@ static struct hid_device_info * create_device_info_for_device(struct udev_device
|
||||
* Parse any additional usage and usage pages
|
||||
* out of the report descriptor.
|
||||
*/
|
||||
while (!get_next_hid_usage(report_desc.value, report_desc.size, &pos, &page, &usage)) {
|
||||
while (!get_next_hid_usage(report_desc.value, report_desc.size, &usage_iterator, &page, &usage)) {
|
||||
/* Create new record for additional usage pairs */
|
||||
struct hid_device_info *tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
|
||||
struct hid_device_info *prev_dev = cur_dev;
|
||||
@ -980,9 +1037,10 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
||||
|
||||
struct hidraw_report_descriptor report_desc;
|
||||
unsigned short page = 0, usage = 0;
|
||||
unsigned int pos = 0;
|
||||
if (get_hid_report_descriptor_from_sysfs(sysfs_path, &report_desc) >= 0) {
|
||||
get_next_hid_usage(report_desc.value, report_desc.size, &pos, &page, &usage);
|
||||
struct hid_usage_iterator usage_iterator;
|
||||
memset(&usage_iterator, 0, sizeof(usage_iterator));
|
||||
get_next_hid_usage(report_desc.value, report_desc.size, &usage_iterator, &page, &usage);
|
||||
}
|
||||
if (HIDAPI_IGNORE_DEVICE(bus_type, dev_vid, dev_pid, page, usage)) {
|
||||
continue;
|
||||
|
@ -12,7 +12,7 @@ find_package(Threads REQUIRED)
|
||||
target_link_libraries(hidapi_darwin
|
||||
PUBLIC hidapi_include
|
||||
PRIVATE Threads::Threads
|
||||
PRIVATE "-framework IOKit" "-framework CoreFoundation" "-framework AppKit"
|
||||
PRIVATE "-framework IOKit" "-framework CoreFoundation"
|
||||
)
|
||||
|
||||
set_target_properties(hidapi_darwin
|
||||
|
@ -12,7 +12,7 @@ CC=gcc
|
||||
COBJS=hid.o ../hidtest/test.o
|
||||
OBJS=$(COBJS)
|
||||
CFLAGS+=-I../hidapi -I. -Wall -g -c
|
||||
LIBS=-framework IOKit -framework CoreFoundation -framework AppKit
|
||||
LIBS=-framework IOKit -framework CoreFoundation
|
||||
|
||||
|
||||
hidtest: $(OBJS)
|
||||
|
5
external/sdl/SDL/src/hidapi/mac/hid.c
vendored
5
external/sdl/SDL/src/hidapi/mac/hid.c
vendored
@ -38,9 +38,6 @@
|
||||
|
||||
#include "hidapi_darwin.h"
|
||||
|
||||
/* As defined in AppKit.h, but we don't need the entire AppKit for a single constant. */
|
||||
extern const double NSAppKitVersionNumber;
|
||||
|
||||
/* Barrier implementation because Mac OSX doesn't have pthread_barrier.
|
||||
It also doesn't have clock_gettime(). So much for POSIX and SUSv2.
|
||||
This implementation came from Brent Priddy and was posted on
|
||||
@ -477,7 +474,7 @@ int HID_API_EXPORT hid_init(void)
|
||||
register_global_error(NULL);
|
||||
|
||||
if (!hid_mgr) {
|
||||
is_macos_10_10_or_greater = (NSAppKitVersionNumber >= 1343); /* NSAppKitVersionNumber10_10 */
|
||||
is_macos_10_10_or_greater = (kCFCoreFoundationVersionNumber >= 1151.16); /* kCFCoreFoundationVersionNumber10_10 */
|
||||
hid_darwin_set_open_exclusive(1); /* Backward compatibility */
|
||||
return init_hid_manager();
|
||||
}
|
||||
|
85
external/sdl/SDL/src/joystick/SDL_gamepad.c
vendored
85
external/sdl/SDL/src/joystick/SDL_gamepad.c
vendored
@ -57,52 +57,6 @@
|
||||
static SDL_bool SDL_gamepads_initialized;
|
||||
static SDL_Gamepad *SDL_gamepads SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SDL_GAMEPAD_BINDTYPE_NONE = 0,
|
||||
SDL_GAMEPAD_BINDTYPE_BUTTON,
|
||||
SDL_GAMEPAD_BINDTYPE_AXIS,
|
||||
SDL_GAMEPAD_BINDTYPE_HAT
|
||||
} SDL_GamepadBindingType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SDL_GamepadBindingType inputType;
|
||||
union
|
||||
{
|
||||
int button;
|
||||
|
||||
struct
|
||||
{
|
||||
int axis;
|
||||
int axis_min;
|
||||
int axis_max;
|
||||
} axis;
|
||||
|
||||
struct
|
||||
{
|
||||
int hat;
|
||||
int hat_mask;
|
||||
} hat;
|
||||
|
||||
} input;
|
||||
|
||||
SDL_GamepadBindingType outputType;
|
||||
union
|
||||
{
|
||||
SDL_GamepadButton button;
|
||||
|
||||
struct
|
||||
{
|
||||
SDL_GamepadAxis axis;
|
||||
int axis_min;
|
||||
int axis_max;
|
||||
} axis;
|
||||
|
||||
} output;
|
||||
|
||||
} SDL_GamepadBinding;
|
||||
|
||||
/* our hard coded list of mapping support */
|
||||
typedef enum
|
||||
{
|
||||
@ -3180,6 +3134,45 @@ SDL_Gamepad *SDL_GetGamepadFromPlayerIndex(int player_index)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the SDL joystick layer bindings for this gamepad
|
||||
*/
|
||||
SDL_GamepadBinding **SDL_GetGamepadBindings(SDL_Gamepad *gamepad, int *count)
|
||||
{
|
||||
SDL_GamepadBinding **bindings = NULL;
|
||||
|
||||
if (count) {
|
||||
*count = 0;
|
||||
}
|
||||
|
||||
SDL_LockJoysticks();
|
||||
{
|
||||
CHECK_GAMEPAD_MAGIC(gamepad, NULL);
|
||||
|
||||
size_t pointers_size = ((gamepad->num_bindings + 1) * sizeof(SDL_GamepadBinding *));
|
||||
size_t elements_size = (gamepad->num_bindings * sizeof(SDL_GamepadBinding));
|
||||
bindings = (SDL_GamepadBinding **)SDL_malloc(pointers_size + elements_size);
|
||||
if (bindings) {
|
||||
SDL_GamepadBinding *binding = (SDL_GamepadBinding *)((Uint8 *)bindings + pointers_size);
|
||||
int i;
|
||||
for (i = 0; i < gamepad->num_bindings; ++i, ++binding) {
|
||||
bindings[i] = binding;
|
||||
SDL_copyp(binding, &gamepad->bindings[i]);
|
||||
}
|
||||
bindings[i] = NULL;
|
||||
|
||||
if (count) {
|
||||
*count = gamepad->num_bindings;
|
||||
}
|
||||
} else {
|
||||
SDL_OutOfMemory();
|
||||
}
|
||||
}
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
int SDL_RumbleGamepad(SDL_Gamepad *gamepad, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
SDL_Joystick *joystick = SDL_GetGamepadJoystick(gamepad);
|
||||
|
14
external/sdl/SDL/src/joystick/SDL_joystick.c
vendored
14
external/sdl/SDL/src/joystick/SDL_joystick.c
vendored
@ -2640,8 +2640,11 @@ static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
|
||||
MAKE_VIDPID(0x046d, 0xc262), /* Logitech G920 (active mode) */
|
||||
MAKE_VIDPID(0x046d, 0xc268), /* Logitech PRO Racing Wheel (PC mode) */
|
||||
MAKE_VIDPID(0x046d, 0xc269), /* Logitech PRO Racing Wheel (PS4/PS5 mode) */
|
||||
MAKE_VIDPID(0x046d, 0xc272), /* Logitech PRO Racing Wheel for Xbox (PC mode) */
|
||||
MAKE_VIDPID(0x046d, 0xc26d), /* Logitech G923 (Xbox) */
|
||||
MAKE_VIDPID(0x046d, 0xc26e), /* Logitech G923 */
|
||||
MAKE_VIDPID(0x046d, 0xc266), /* Logitech G923 for Playstation 4 and PC (PC mode) */
|
||||
MAKE_VIDPID(0x046d, 0xc267), /* Logitech G923 for Playstation 4 and PC (PS4 mode)*/
|
||||
MAKE_VIDPID(0x046d, 0xca03), /* Logitech Momo Racing */
|
||||
MAKE_VIDPID(0x044f, 0xb65d), /* Thrustmaster Wheel FFB */
|
||||
MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster Wheel FFB */
|
||||
@ -2653,6 +2656,17 @@ static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
|
||||
MAKE_VIDPID(0x044f, 0xb65e), /* Thrustmaster T500RS */
|
||||
MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */
|
||||
MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */
|
||||
MAKE_VIDPID(0x0483, 0x0522), /* Simagic Wheelbase (including M10, Alpha Mini, Alpha, Alpha U) */
|
||||
MAKE_VIDPID(0x0eb7, 0x0001), /* Fanatec ClubSport Wheel Base V2 */
|
||||
MAKE_VIDPID(0x0eb7, 0x0004), /* Fanatec ClubSport Wheel Base V2.5 */
|
||||
MAKE_VIDPID(0x0eb7, 0x0005), /* Fanatec CSL Elite Wheel Base+ (PS4) */
|
||||
MAKE_VIDPID(0x0eb7, 0x0006), /* Fanatec Podium Wheel Base DD1 */
|
||||
MAKE_VIDPID(0x0eb7, 0x0007), /* Fanatec Podium Wheel Base DD2 */
|
||||
MAKE_VIDPID(0x0eb7, 0x0011), /* Fanatec Forza Motorsport (CSR Wheel / CSR Elite Wheel) */
|
||||
MAKE_VIDPID(0x0eb7, 0x0020), /* Fanatec generic wheel / CSL DD / GT DD Pro */
|
||||
MAKE_VIDPID(0x0eb7, 0x0197), /* Fanatec Porsche Wheel (Turbo / GT3 RS / Turbo S / GT3 V2 / GT2) */
|
||||
MAKE_VIDPID(0x0eb7, 0x038e), /* Fanatec ClubSport Wheel Base V1 */
|
||||
MAKE_VIDPID(0x0eb7, 0x0e03), /* Fanatec CSL Elite Wheel Base */
|
||||
MAKE_VIDPID(0x11ff, 0x0511), /* DragonRise Inc. Wired Wheel (initial mode) (also known as PXN V900 (PS3), Superdrive SV-750, or a Genesis Seaborg 400) */
|
||||
};
|
||||
int i;
|
||||
|
@ -102,7 +102,7 @@ typedef struct
|
||||
Uint8 rgucAccelX[2]; /* 21 */
|
||||
Uint8 rgucAccelY[2]; /* 23 */
|
||||
Uint8 rgucAccelZ[2]; /* 25 */
|
||||
Uint8 rgucSensorTimestamp[4]; /* 27 - 32 bit little endian */
|
||||
Uint8 rgucSensorTimestamp[4]; /* 27 - 16/32 bit little endian */
|
||||
|
||||
} PS5StatePacketCommon_t;
|
||||
|
||||
@ -154,7 +154,9 @@ typedef struct
|
||||
Uint8 rgucAccelX[2]; /* 21 */
|
||||
Uint8 rgucAccelY[2]; /* 23 */
|
||||
Uint8 rgucAccelZ[2]; /* 25 */
|
||||
Uint8 rgucSensorTimestamp[4]; /* 27 - 32 bit little endian */
|
||||
Uint8 rgucSensorTimestamp[2]; /* 27 - 16 bit little endian */
|
||||
Uint8 ucBatteryLevel; /* 29 */
|
||||
Uint8 ucUnknown; /* 30 */
|
||||
Uint8 ucTouchpadCounter1; /* 31 - high bit clear + counter */
|
||||
Uint8 rgucTouchpadData1[3]; /* 32 - X/Y, 12 bits per axis */
|
||||
Uint8 ucTouchpadCounter2; /* 35 - high bit clear + counter */
|
||||
@ -494,6 +496,7 @@ static SDL_bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
|
||||
/* The Razer Wolverine V2 Pro doesn't respond to the detection protocol, but has a touchpad and sensors, but no vibration */
|
||||
ctx->sensors_supported = SDL_TRUE;
|
||||
ctx->touchpad_supported = SDL_TRUE;
|
||||
ctx->use_alternate_report = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
ctx->effects_supported = (ctx->lightbar_supported || ctx->vibration_supported || ctx->playerled_supported);
|
||||
@ -722,7 +725,7 @@ static void HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_DriverPS5_Context *ctx)
|
||||
{
|
||||
SDL_bool led_reset_complete = SDL_FALSE;
|
||||
|
||||
if (ctx->enhanced_reports && ctx->sensors_supported) {
|
||||
if (ctx->enhanced_reports && ctx->sensors_supported && !ctx->use_alternate_report) {
|
||||
const PS5StatePacketCommon_t *packet = &ctx->last_state.state;
|
||||
|
||||
/* Check the timer to make sure the Bluetooth connection LED animation is complete */
|
||||
@ -1102,10 +1105,9 @@ static int HIDAPI_DriverPS5_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverPS5_HandleSimpleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5SimpleStatePacket_t *packet)
|
||||
static void HIDAPI_DriverPS5_HandleSimpleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5SimpleStatePacket_t *packet, Uint64 timestamp)
|
||||
{
|
||||
Sint16 axis;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
if (ctx->last_state.simple.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) {
|
||||
{
|
||||
@ -1204,10 +1206,9 @@ static void HIDAPI_DriverPS5_HandleSimpleStatePacket(SDL_Joystick *joystick, SDL
|
||||
SDL_memcpy(&ctx->last_state.simple, packet, sizeof(ctx->last_state.simple));
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketCommon_t *packet)
|
||||
static void HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketCommon_t *packet, Uint64 timestamp)
|
||||
{
|
||||
Sint16 axis;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
if (ctx->last_state.state.rgucButtonsAndHat[0] != packet->rgucButtonsAndHat[0]) {
|
||||
{
|
||||
@ -1309,25 +1310,42 @@ static void HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
|
||||
|
||||
if (ctx->report_sensors) {
|
||||
Uint32 tick;
|
||||
Uint32 delta;
|
||||
Uint64 sensor_timestamp;
|
||||
float data[3];
|
||||
|
||||
tick = LOAD32(packet->rgucSensorTimestamp[0],
|
||||
packet->rgucSensorTimestamp[1],
|
||||
packet->rgucSensorTimestamp[2],
|
||||
packet->rgucSensorTimestamp[3]);
|
||||
if (ctx->last_tick < tick) {
|
||||
delta = (tick - ctx->last_tick);
|
||||
} else {
|
||||
delta = (SDL_MAX_UINT32 - ctx->last_tick + tick + 1);
|
||||
}
|
||||
ctx->sensor_ticks += delta;
|
||||
ctx->last_tick = tick;
|
||||
if (ctx->use_alternate_report) {
|
||||
/* 16-bit timestamp */
|
||||
Uint32 delta;
|
||||
Uint16 tick = LOAD16(packet->rgucSensorTimestamp[0],
|
||||
packet->rgucSensorTimestamp[1]);
|
||||
if (ctx->last_tick < tick) {
|
||||
delta = (tick - ctx->last_tick);
|
||||
} else {
|
||||
delta = (SDL_MAX_UINT16 - ctx->last_tick + tick + 1);
|
||||
}
|
||||
ctx->last_tick = tick;
|
||||
ctx->sensor_ticks += delta;
|
||||
|
||||
/* Sensor timestamp is in 0.33us units */
|
||||
sensor_timestamp = (ctx->sensor_ticks * SDL_NS_PER_US) / 3;
|
||||
/* Sensor timestamp is in 1us units */
|
||||
sensor_timestamp = SDL_US_TO_NS(ctx->sensor_ticks);
|
||||
} else {
|
||||
/* 32-bit timestamp */
|
||||
Uint32 delta;
|
||||
Uint32 tick = LOAD32(packet->rgucSensorTimestamp[0],
|
||||
packet->rgucSensorTimestamp[1],
|
||||
packet->rgucSensorTimestamp[2],
|
||||
packet->rgucSensorTimestamp[3]);
|
||||
if (ctx->last_tick < tick) {
|
||||
delta = (tick - ctx->last_tick);
|
||||
} else {
|
||||
delta = (SDL_MAX_UINT32 - ctx->last_tick + tick + 1);
|
||||
}
|
||||
ctx->last_tick = tick;
|
||||
ctx->sensor_ticks += delta;
|
||||
|
||||
/* Sensor timestamp is in 0.33us units */
|
||||
sensor_timestamp = (ctx->sensor_ticks * SDL_NS_PER_US) / 3;
|
||||
}
|
||||
|
||||
data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 0, LOAD16(packet->rgucGyroX[0], packet->rgucGyroX[1]));
|
||||
data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 1, LOAD16(packet->rgucGyroY[0], packet->rgucGyroY[1]));
|
||||
@ -1341,13 +1359,12 @@ static void HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL
|
||||
}
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacket_t *packet)
|
||||
static void HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacket_t *packet, Uint64 timestamp)
|
||||
{
|
||||
static const float TOUCHPAD_SCALEX = 1.0f / 1920;
|
||||
static const float TOUCHPAD_SCALEY = 1.0f / 1070;
|
||||
Uint8 touchpad_state;
|
||||
int touchpad_x, touchpad_y;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
if (ctx->report_touchpad) {
|
||||
touchpad_state = !(packet->ucTouchpadCounter1 & 0x80) ? SDL_PRESSED : SDL_RELEASED;
|
||||
@ -1378,13 +1395,12 @@ static void HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_d
|
||||
SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverPS5_HandleStatePacketAlt(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketAlt_t *packet)
|
||||
static void HIDAPI_DriverPS5_HandleStatePacketAlt(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketAlt_t *packet, Uint64 timestamp)
|
||||
{
|
||||
static const float TOUCHPAD_SCALEX = 1.0f / 1920;
|
||||
static const float TOUCHPAD_SCALEY = 1.0f / 1070;
|
||||
Uint8 touchpad_state;
|
||||
int touchpad_x, touchpad_y;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
if (ctx->report_touchpad) {
|
||||
touchpad_state = !(packet->ucTouchpadCounter1 & 0x80) ? SDL_PRESSED : SDL_RELEASED;
|
||||
@ -1447,6 +1463,8 @@ static SDL_bool HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
}
|
||||
|
||||
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
#ifdef DEBUG_PS5_PROTOCOL
|
||||
HIDAPI_DumpPacket("PS5 packet: size = %d", data, size);
|
||||
#endif
|
||||
@ -1464,13 +1482,13 @@ static SDL_bool HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
switch (data[0]) {
|
||||
case k_EPS5ReportIdState:
|
||||
if (size == 10 || size == 78) {
|
||||
HIDAPI_DriverPS5_HandleSimpleStatePacket(joystick, device->dev, ctx, (PS5SimpleStatePacket_t *)&data[1]);
|
||||
HIDAPI_DriverPS5_HandleSimpleStatePacket(joystick, device->dev, ctx, (PS5SimpleStatePacket_t *)&data[1], timestamp);
|
||||
} else {
|
||||
HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, device->dev, ctx, (PS5StatePacketCommon_t *)&data[1]);
|
||||
HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, device->dev, ctx, (PS5StatePacketCommon_t *)&data[1], timestamp);
|
||||
if (ctx->use_alternate_report) {
|
||||
HIDAPI_DriverPS5_HandleStatePacketAlt(joystick, device->dev, ctx, (PS5StatePacketAlt_t *)&data[1]);
|
||||
HIDAPI_DriverPS5_HandleStatePacketAlt(joystick, device->dev, ctx, (PS5StatePacketAlt_t *)&data[1], timestamp);
|
||||
} else {
|
||||
HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[1]);
|
||||
HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[1], timestamp);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1478,11 +1496,11 @@ static SDL_bool HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
/* This is the extended report, we can enable effects now in default mode */
|
||||
HIDAPI_DriverPS5_UpdateEnhancedModeOnEnhancedReport(ctx);
|
||||
|
||||
HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, device->dev, ctx, (PS5StatePacketCommon_t *)&data[2]);
|
||||
HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, device->dev, ctx, (PS5StatePacketCommon_t *)&data[2], timestamp);
|
||||
if (ctx->use_alternate_report) {
|
||||
HIDAPI_DriverPS5_HandleStatePacketAlt(joystick, device->dev, ctx, (PS5StatePacketAlt_t *)&data[2]);
|
||||
HIDAPI_DriverPS5_HandleStatePacketAlt(joystick, device->dev, ctx, (PS5StatePacketAlt_t *)&data[2], timestamp);
|
||||
} else {
|
||||
HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[2]);
|
||||
HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[2], timestamp);
|
||||
}
|
||||
if (ctx->led_reset_state == k_EDS5LEDResetStatePending) {
|
||||
HIDAPI_DriverPS5_CheckPendingLEDReset(ctx);
|
||||
|
@ -663,6 +663,8 @@ static void HIDAPI_UpdateJoystickSerial(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
int i;
|
||||
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
for (i = 0; i < device->num_joysticks; ++i) {
|
||||
SDL_Joystick *joystick = SDL_GetJoystickFromInstanceID(device->joysticks[i]);
|
||||
if (joystick && device->serial) {
|
||||
|
12
external/sdl/SDL/src/power/linux/SDL_syspower.c
vendored
12
external/sdl/SDL/src/power/linux/SDL_syspower.c
vendored
@ -561,9 +561,17 @@ static void check_upower_device(DBusConnection *conn, const char *path, SDL_Powe
|
||||
st = SDL_POWERSTATE_UNKNOWN; /* uh oh */
|
||||
} else if (ui32 == 1) { /* 1 == charging */
|
||||
st = SDL_POWERSTATE_CHARGING;
|
||||
} else if ((ui32 == 2) || (ui32 == 3)) { /* 2 == discharging, 3 == empty. */
|
||||
} else if ((ui32 == 2) || (ui32 == 3) || (ui32 == 6)) {
|
||||
/* 2 == discharging;
|
||||
* 3 == empty;
|
||||
* 6 == "pending discharge" which GNOME interprets as equivalent
|
||||
* to discharging */
|
||||
st = SDL_POWERSTATE_ON_BATTERY;
|
||||
} else if (ui32 == 4) { /* 4 == full */
|
||||
} else if ((ui32 == 4) || (ui32 == 5)) {
|
||||
/* 4 == full;
|
||||
* 5 == "pending charge" which GNOME shows as "Not charging",
|
||||
* used when a battery is configured to stop charging at a
|
||||
* lower than 100% threshold */
|
||||
st = SDL_POWERSTATE_CHARGED;
|
||||
} else {
|
||||
st = SDL_POWERSTATE_UNKNOWN; /* uh oh */
|
||||
|
2
external/sdl/SDL/src/render/SDL_render.c
vendored
2
external/sdl/SDL/src/render/SDL_render.c
vendored
@ -2534,7 +2534,7 @@ int SDL_SetRenderClipRect(SDL_Renderer *renderer, const SDL_Rect *rect)
|
||||
int retval;
|
||||
CHECK_RENDERER_MAGIC(renderer, -1)
|
||||
|
||||
if (rect && rect->w > 0 && rect->h > 0) {
|
||||
if (rect && rect->w >= 0 && rect->h >= 0) {
|
||||
renderer->view->clipping_enabled = SDL_TRUE;
|
||||
renderer->view->clip_rect.x = rect->x;
|
||||
renderer->view->clip_rect.y = rect->y;
|
||||
|
@ -1754,8 +1754,22 @@ static SDL_Renderer *METAL_CreateRenderer(SDL_Window *window, Uint32 flags)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// !!! FIXME: MTLCopyAllDevices() can find other GPUs on macOS...
|
||||
mtldevice = MTLCreateSystemDefaultDevice();
|
||||
#ifdef __MACOS__
|
||||
if (SDL_GetHintBoolean(SDL_HINT_RENDER_METAL_PREFER_LOW_POWER_DEVICE, SDL_TRUE)) {
|
||||
NSArray<id<MTLDevice>> *devices = MTLCopyAllDevices();
|
||||
|
||||
for (id<MTLDevice> device in devices) {
|
||||
if (device.isLowPower) {
|
||||
mtldevice = device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mtldevice == nil) {
|
||||
mtldevice = MTLCreateSystemDefaultDevice();
|
||||
}
|
||||
|
||||
if (mtldevice == nil) {
|
||||
SDL_free(renderer);
|
||||
|
52
external/sdl/SDL/src/test/SDL_test_common.c
vendored
52
external/sdl/SDL/src/test/SDL_test_common.c
vendored
@ -25,6 +25,7 @@
|
||||
static const char *common_usage[] = {
|
||||
"[-h | --help]",
|
||||
"[--trackmem]",
|
||||
"[--randmem]",
|
||||
"[--log all|error|system|audio|video|render|input]",
|
||||
};
|
||||
|
||||
@ -70,7 +71,7 @@ static const char *video_usage[] = {
|
||||
|
||||
/* !!! FIXME: Float32? Sint32? */
|
||||
static const char *audio_usage[] = {
|
||||
"[--audio driver]", "[--rate N]", "[--format U8|S8|S16|S16LE|S16BE]",
|
||||
"[--audio driver]", "[--rate N]", "[--format U8|S8|S16|S16LE|S16BE|S32|S32LE|S32BE|F32|F32LE|F32BE]",
|
||||
"[--channels N]"
|
||||
};
|
||||
|
||||
@ -95,7 +96,8 @@ SDLTest_CommonState *SDLTest_CommonCreateState(char **argv, Uint32 flags)
|
||||
for (i = 1; argv[i]; ++i) {
|
||||
if (SDL_strcasecmp(argv[i], "--trackmem") == 0) {
|
||||
SDLTest_TrackAllocations();
|
||||
break;
|
||||
} else if (SDL_strcasecmp(argv[i], "--randmem") == 0) {
|
||||
SDLTest_RandFillAllocations();
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,8 +147,8 @@ SDLTest_CommonState *SDLTest_CommonCreateState(char **argv, Uint32 flags)
|
||||
}
|
||||
|
||||
void SDLTest_CommonDestroyState(SDLTest_CommonState *state) {
|
||||
SDLTest_LogAllocations();
|
||||
SDL_free(state);
|
||||
SDLTest_LogAllocations();
|
||||
}
|
||||
|
||||
#define SEARCHARG(dim) \
|
||||
@ -170,6 +172,10 @@ int SDLTest_CommonArg(SDLTest_CommonState *state, int index)
|
||||
/* Already handled in SDLTest_CommonCreateState() */
|
||||
return 1;
|
||||
}
|
||||
if (SDL_strcasecmp(argv[index], "--randmem") == 0) {
|
||||
/* Already handled in SDLTest_CommonCreateState() */
|
||||
return 1;
|
||||
}
|
||||
if (SDL_strcasecmp(argv[index], "--log") == 0) {
|
||||
++index;
|
||||
if (!argv[index]) {
|
||||
@ -624,16 +630,37 @@ int SDLTest_CommonArg(SDLTest_CommonState *state, int index)
|
||||
return 2;
|
||||
}
|
||||
if (SDL_strcasecmp(argv[index], "S16LE") == 0) {
|
||||
state->audio_format = SDL_AUDIO_S16LSB;
|
||||
state->audio_format = SDL_AUDIO_S16LE;
|
||||
return 2;
|
||||
}
|
||||
if (SDL_strcasecmp(argv[index], "S16BE") == 0) {
|
||||
state->audio_format = SDL_AUDIO_S16MSB;
|
||||
state->audio_format = SDL_AUDIO_S16BE;
|
||||
return 2;
|
||||
}
|
||||
if (SDL_strcasecmp(argv[index], "S32") == 0) {
|
||||
state->audio_format = SDL_AUDIO_S32;
|
||||
return 2;
|
||||
}
|
||||
if (SDL_strcasecmp(argv[index], "S32LE") == 0) {
|
||||
state->audio_format = SDL_AUDIO_S32LE;
|
||||
return 2;
|
||||
}
|
||||
if (SDL_strcasecmp(argv[index], "S32BE") == 0) {
|
||||
state->audio_format = SDL_AUDIO_S32BE;
|
||||
return 2;
|
||||
}
|
||||
if (SDL_strcasecmp(argv[index], "F32") == 0) {
|
||||
state->audio_format = SDL_AUDIO_F32;
|
||||
return 2;
|
||||
}
|
||||
if (SDL_strcasecmp(argv[index], "F32LE") == 0) {
|
||||
state->audio_format = SDL_AUDIO_F32LE;
|
||||
return 2;
|
||||
}
|
||||
if (SDL_strcasecmp(argv[index], "F32BE") == 0) {
|
||||
state->audio_format = SDL_AUDIO_F32BE;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* !!! FIXME: Float32? Sint32? */
|
||||
|
||||
return -1;
|
||||
}
|
||||
if (SDL_strcasecmp(argv[index], "--channels") == 0) {
|
||||
@ -2019,6 +2046,8 @@ void SDLTest_CommonEvent(SDLTest_CommonState *state, SDL_Event *event, int *done
|
||||
{
|
||||
SDL_Window *window = SDL_GetWindowFromID(event->window.windowID);
|
||||
if (window) {
|
||||
/* Clear cache to avoid stale textures */
|
||||
SDLTest_CleanupTextDrawing();
|
||||
for (i = 0; i < state->num_windows; ++i) {
|
||||
if (window == state->windows[i]) {
|
||||
if (state->targets[i]) {
|
||||
@ -2408,7 +2437,6 @@ void SDLTest_CommonQuit(SDLTest_CommonState *state)
|
||||
common_usage_audio = NULL;
|
||||
common_usage_videoaudio = NULL;
|
||||
|
||||
SDL_free(state->windows);
|
||||
if (state->targets) {
|
||||
for (i = 0; i < state->num_windows; ++i) {
|
||||
if (state->targets[i]) {
|
||||
@ -2425,6 +2453,12 @@ void SDLTest_CommonQuit(SDLTest_CommonState *state)
|
||||
}
|
||||
SDL_free(state->renderers);
|
||||
}
|
||||
if (state->windows) {
|
||||
for (i = 0; i < state->num_windows; i++) {
|
||||
SDL_DestroyWindow(state->windows[i]);
|
||||
}
|
||||
SDL_free(state->windows);
|
||||
}
|
||||
if (state->flags & SDL_INIT_VIDEO) {
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
}
|
||||
|
11
external/sdl/SDL/src/test/SDL_test_font.c
vendored
11
external/sdl/SDL/src/test/SDL_test_font.c
vendored
@ -3126,11 +3126,12 @@ struct SDLTest_CharTextureCache
|
||||
*/
|
||||
static struct SDLTest_CharTextureCache *SDLTest_CharTextureCacheList;
|
||||
|
||||
int FONT_CHARACTER_SIZE = 8;
|
||||
|
||||
int SDLTest_DrawCharacter(SDL_Renderer *renderer, float x, float y, Uint32 c)
|
||||
{
|
||||
const Uint32 charWidth = FONT_CHARACTER_SIZE;
|
||||
const Uint32 charHeight = FONT_CHARACTER_SIZE;
|
||||
const Uint32 charSize = FONT_CHARACTER_SIZE;
|
||||
SDL_FRect srect;
|
||||
SDL_FRect drect;
|
||||
int result;
|
||||
@ -3149,8 +3150,8 @@ int SDLTest_DrawCharacter(SDL_Renderer *renderer, float x, float y, Uint32 c)
|
||||
*/
|
||||
srect.x = 0.0f;
|
||||
srect.y = 0.0f;
|
||||
srect.w = (float)charWidth;
|
||||
srect.h = (float)charHeight;
|
||||
srect.w = 8.0f;
|
||||
srect.h = 8.0f;
|
||||
|
||||
/*
|
||||
* Setup destination rectangle
|
||||
@ -3190,7 +3191,7 @@ int SDLTest_DrawCharacter(SDL_Renderer *renderer, float x, float y, Uint32 c)
|
||||
return -1;
|
||||
}
|
||||
|
||||
charpos = SDLTest_FontData + ci * charSize;
|
||||
charpos = SDLTest_FontData + ci * 8;
|
||||
linepos = (Uint8 *)character->pixels;
|
||||
pitch = character->pitch;
|
||||
|
||||
@ -3221,6 +3222,8 @@ int SDLTest_DrawCharacter(SDL_Renderer *renderer, float x, float y, Uint32 c)
|
||||
if (cache->charTextureCache[ci] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_SetTextureScaleMode(cache->charTextureCache[ci], SDL_SCALEMODE_NEAREST);
|
||||
}
|
||||
|
||||
/*
|
||||
|
149
external/sdl/SDL/src/test/SDL_test_memory.c
vendored
149
external/sdl/SDL/src/test/SDL_test_memory.c
vendored
@ -25,6 +25,26 @@
|
||||
#include <libunwind.h>
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
static void *s_dbghelp;
|
||||
|
||||
typedef BOOL (__stdcall *dbghelp_SymInitialize_fn)(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess);
|
||||
|
||||
typedef BOOL (__stdcall *dbghelp_SymFromAddr_fn)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol);
|
||||
static dbghelp_SymFromAddr_fn dbghelp_SymFromAddr;
|
||||
|
||||
#ifdef _WIN64
|
||||
typedef BOOL (__stdcall *dbghelp_SymGetLineFromAddr_fn)(HANDLE hProcess, DWORD64 qwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line);
|
||||
#else
|
||||
typedef BOOL (__stdcall *dbghelp_SymGetLineFromAddr_fn)(HANDLE hProcess, DWORD qwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE Line);
|
||||
#endif
|
||||
static dbghelp_SymGetLineFromAddr_fn dbghelp_SymGetLineFromAddr;
|
||||
|
||||
#endif
|
||||
|
||||
/* This is a simple tracking allocator to demonstrate the use of SDL's
|
||||
memory allocation replacement functionality.
|
||||
|
||||
@ -32,12 +52,14 @@
|
||||
for production code.
|
||||
*/
|
||||
|
||||
#define MAXIMUM_TRACKED_STACK_DEPTH 32
|
||||
|
||||
typedef struct SDL_tracked_allocation
|
||||
{
|
||||
void *mem;
|
||||
size_t size;
|
||||
Uint64 stack[10];
|
||||
char stack_names[10][256];
|
||||
Uint64 stack[MAXIMUM_TRACKED_STACK_DEPTH];
|
||||
char stack_names[MAXIMUM_TRACKED_STACK_DEPTH][256];
|
||||
struct SDL_tracked_allocation *next;
|
||||
} SDL_tracked_allocation;
|
||||
|
||||
@ -48,6 +70,7 @@ static SDL_realloc_func SDL_realloc_orig = NULL;
|
||||
static SDL_free_func SDL_free_orig = NULL;
|
||||
static int s_previous_allocations = 0;
|
||||
static SDL_tracked_allocation *s_tracked_allocations[256];
|
||||
static SDL_bool s_randfill_allocations = SDL_FALSE;
|
||||
|
||||
static unsigned int get_allocation_bucket(void *mem)
|
||||
{
|
||||
@ -58,16 +81,28 @@ static unsigned int get_allocation_bucket(void *mem)
|
||||
return index;
|
||||
}
|
||||
|
||||
static SDL_bool SDL_IsAllocationTracked(void *mem)
|
||||
static SDL_tracked_allocation* SDL_GetTrackedAllocation(void *mem)
|
||||
{
|
||||
SDL_tracked_allocation *entry;
|
||||
int index = get_allocation_bucket(mem);
|
||||
for (entry = s_tracked_allocations[index]; entry; entry = entry->next) {
|
||||
if (mem == entry->mem) {
|
||||
return SDL_TRUE;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return SDL_FALSE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t SDL_GetTrackedAllocationSize(void *mem)
|
||||
{
|
||||
SDL_tracked_allocation *entry = SDL_GetTrackedAllocation(mem);
|
||||
|
||||
return entry ? entry->size : SIZE_MAX;
|
||||
}
|
||||
|
||||
static SDL_bool SDL_IsAllocationTracked(void *mem)
|
||||
{
|
||||
return SDL_GetTrackedAllocation(mem) != NULL;
|
||||
}
|
||||
|
||||
static void SDL_TrackAllocation(void *mem, size_t size)
|
||||
@ -114,6 +149,40 @@ static void SDL_TrackAllocation(void *mem, size_t size)
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(__WINDOWS__)
|
||||
{
|
||||
Uint32 count;
|
||||
PVOID frames[63];
|
||||
Uint32 i;
|
||||
|
||||
count = CaptureStackBackTrace(1, SDL_arraysize(frames), frames, NULL);
|
||||
|
||||
entry->size = SDL_min(count, MAXIMUM_TRACKED_STACK_DEPTH);
|
||||
for (i = 0; i < entry->size; i++) {
|
||||
char symbol_buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
|
||||
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbol_buffer;
|
||||
DWORD64 dwDisplacement = 0;
|
||||
DWORD lineColumn = 0;
|
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
pSymbol->MaxNameLen = MAX_SYM_NAME;
|
||||
IMAGEHLP_LINE line;
|
||||
line.SizeOfStruct = sizeof(line);
|
||||
|
||||
entry->stack[i] = (Uint64)(uintptr_t)frames[i];
|
||||
if (s_dbghelp) {
|
||||
if (!dbghelp_SymFromAddr(GetCurrentProcess(), (DWORD64)(uintptr_t)frames[i], &dwDisplacement, pSymbol)) {
|
||||
SDL_strlcpy(pSymbol->Name, "???", MAX_SYM_NAME);
|
||||
dwDisplacement = 0;
|
||||
}
|
||||
if (!dbghelp_SymGetLineFromAddr(GetCurrentProcess(), (DWORD64)(uintptr_t)frames[i], &lineColumn, &line)) {
|
||||
line.FileName = "";
|
||||
line.LineNumber = 0;
|
||||
}
|
||||
|
||||
SDL_snprintf(entry->stack_names[i], sizeof(entry->stack_names[i]), "%s+0x%llx %s:%u", pSymbol->Name, (unsigned long long)dwDisplacement, line.FileName, (Uint32)line.LineNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_LIBUNWIND_H */
|
||||
|
||||
entry->next = s_tracked_allocations[index];
|
||||
@ -140,6 +209,19 @@ static void SDL_UntrackAllocation(void *mem)
|
||||
}
|
||||
}
|
||||
|
||||
static void rand_fill_memory(void* ptr, size_t start, size_t end)
|
||||
{
|
||||
Uint8* mem = (Uint8*) ptr;
|
||||
size_t i;
|
||||
|
||||
if (!s_randfill_allocations)
|
||||
return;
|
||||
|
||||
for (i = start; i < end; ++i) {
|
||||
mem[i] = SDLTest_RandomUint8();
|
||||
}
|
||||
}
|
||||
|
||||
static void *SDLCALL SDLTest_TrackedMalloc(size_t size)
|
||||
{
|
||||
void *mem;
|
||||
@ -147,6 +229,7 @@ static void *SDLCALL SDLTest_TrackedMalloc(size_t size)
|
||||
mem = SDL_malloc_orig(size);
|
||||
if (mem) {
|
||||
SDL_TrackAllocation(mem, size);
|
||||
rand_fill_memory(mem, 0, size);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
@ -165,14 +248,20 @@ static void *SDLCALL SDLTest_TrackedCalloc(size_t nmemb, size_t size)
|
||||
static void *SDLCALL SDLTest_TrackedRealloc(void *ptr, size_t size)
|
||||
{
|
||||
void *mem;
|
||||
|
||||
SDL_assert(ptr == NULL || SDL_IsAllocationTracked(ptr));
|
||||
size_t old_size = 0;
|
||||
if (ptr) {
|
||||
old_size = SDL_GetTrackedAllocationSize(ptr);
|
||||
SDL_assert(old_size != SIZE_MAX);
|
||||
}
|
||||
mem = SDL_realloc_orig(ptr, size);
|
||||
if (mem && mem != ptr) {
|
||||
if (ptr) {
|
||||
SDL_UntrackAllocation(ptr);
|
||||
}
|
||||
if (ptr) {
|
||||
SDL_UntrackAllocation(ptr);
|
||||
}
|
||||
if (mem) {
|
||||
SDL_TrackAllocation(mem, size);
|
||||
if (size > old_size) {
|
||||
rand_fill_memory(mem, old_size, size);
|
||||
}
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
@ -190,10 +279,10 @@ static void SDLCALL SDLTest_TrackedFree(void *ptr)
|
||||
SDL_free_orig(ptr);
|
||||
}
|
||||
|
||||
int SDLTest_TrackAllocations(void)
|
||||
void SDLTest_TrackAllocations(void)
|
||||
{
|
||||
if (SDL_malloc_orig) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
SDLTest_Crc32Init(&s_crc32_context);
|
||||
@ -202,6 +291,30 @@ int SDLTest_TrackAllocations(void)
|
||||
if (s_previous_allocations != 0) {
|
||||
SDL_Log("SDLTest_TrackAllocations(): There are %d previous allocations, disabling free() validation", s_previous_allocations);
|
||||
}
|
||||
#ifdef __WINDOWS__
|
||||
{
|
||||
s_dbghelp = SDL_LoadObject("dbghelp.dll");
|
||||
if (s_dbghelp) {
|
||||
dbghelp_SymInitialize_fn dbghelp_SymInitialize;
|
||||
dbghelp_SymInitialize = (dbghelp_SymInitialize_fn)SDL_LoadFunction(s_dbghelp, "SymInitialize");
|
||||
dbghelp_SymFromAddr = (dbghelp_SymFromAddr_fn)SDL_LoadFunction(s_dbghelp, "SymFromAddr");
|
||||
#ifdef _WIN64
|
||||
dbghelp_SymGetLineFromAddr = (dbghelp_SymGetLineFromAddr_fn)SDL_LoadFunction(s_dbghelp, "SymGetLineFromAddr64");
|
||||
#else
|
||||
dbghelp_SymGetLineFromAddr = (dbghelp_SymGetLineFromAddr_fn)SDL_LoadFunction(s_dbghelp, "SymGetLineFromAddr");
|
||||
#endif
|
||||
if (!dbghelp_SymFromAddr || !dbghelp_SymFromAddr || !dbghelp_SymGetLineFromAddr) {
|
||||
SDL_UnloadObject(s_dbghelp);
|
||||
s_dbghelp = NULL;
|
||||
} else {
|
||||
if (!dbghelp_SymInitialize(GetCurrentProcess(), NULL, TRUE)) {
|
||||
SDL_UnloadObject(s_dbghelp);
|
||||
s_dbghelp = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SDL_GetMemoryFunctions(&SDL_malloc_orig,
|
||||
&SDL_calloc_orig,
|
||||
@ -212,7 +325,13 @@ int SDLTest_TrackAllocations(void)
|
||||
SDLTest_TrackedCalloc,
|
||||
SDLTest_TrackedRealloc,
|
||||
SDLTest_TrackedFree);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SDLTest_RandFillAllocations()
|
||||
{
|
||||
SDLTest_TrackAllocations();
|
||||
|
||||
s_randfill_allocations = SDL_TRUE;
|
||||
}
|
||||
|
||||
void SDLTest_LogAllocations(void)
|
||||
@ -245,8 +364,6 @@ void SDLTest_LogAllocations(void)
|
||||
|
||||
SDL_strlcpy(line, "Memory allocations:\n", sizeof(line));
|
||||
ADD_LINE();
|
||||
SDL_strlcpy(line, "Expect 2 allocations from within SDL_GetErrBuf()\n", sizeof(line));
|
||||
ADD_LINE();
|
||||
|
||||
count = 0;
|
||||
total_allocated = 0;
|
||||
|
4
external/sdl/SDL/src/video/SDL_bmp.c
vendored
4
external/sdl/SDL/src/video/SDL_bmp.c
vendored
@ -560,7 +560,7 @@ SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
|
||||
} break;
|
||||
|
||||
default:
|
||||
if (SDL_RWread(src, bits, surface->pitch) != surface->pitch) {
|
||||
if (SDL_RWread(src, bits, surface->pitch) != (size_t)surface->pitch) {
|
||||
goto done;
|
||||
}
|
||||
if (biBitCount == 8 && palette && biClrUsed < (1u << biBitCount)) {
|
||||
@ -743,7 +743,7 @@ int SDL_SaveBMP_RW(SDL_Surface *surface, SDL_RWops *dst, SDL_bool freedst)
|
||||
}
|
||||
|
||||
if (SDL_LockSurface(intermediate_surface) == 0) {
|
||||
const int bw = intermediate_surface->w * intermediate_surface->format->BytesPerPixel;
|
||||
const size_t bw = intermediate_surface->w * intermediate_surface->format->BytesPerPixel;
|
||||
|
||||
/* Set the BMP file header values */
|
||||
bfSize = 0; /* We'll write this when we're done */
|
||||
|
9
external/sdl/SDL/src/video/SDL_sysvideo.h
vendored
9
external/sdl/SDL/src/video/SDL_sysvideo.h
vendored
@ -23,7 +23,7 @@
|
||||
#ifndef SDL_sysvideo_h_
|
||||
#define SDL_sysvideo_h_
|
||||
|
||||
#include "SDL_vulkan_internal.h"
|
||||
#include <SDL3/SDL_vulkan.h>
|
||||
|
||||
/* The SDL video driver */
|
||||
|
||||
@ -264,6 +264,7 @@ struct SDL_VideoDevice
|
||||
void (*DestroyWindowFramebuffer)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
void (*OnWindowEnter)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
int (*FlashWindow)(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
||||
int (*SetWindowFocusable)(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool focusable);
|
||||
|
||||
/* * * */
|
||||
/*
|
||||
@ -442,8 +443,8 @@ struct SDL_VideoDevice
|
||||
/* Data used by the Vulkan drivers */
|
||||
struct
|
||||
{
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
|
||||
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
|
||||
SDL_FunctionPointer vkGetInstanceProcAddr;
|
||||
SDL_FunctionPointer vkEnumerateInstanceExtensionProperties;
|
||||
int loader_loaded;
|
||||
char loader_path[256];
|
||||
void *loader_handle;
|
||||
@ -543,7 +544,7 @@ extern void SDL_OnWindowFocusGained(SDL_Window *window);
|
||||
extern void SDL_OnWindowFocusLost(SDL_Window *window);
|
||||
extern void SDL_OnWindowDisplayChanged(SDL_Window *window);
|
||||
extern void SDL_UpdateWindowGrab(SDL_Window *window);
|
||||
extern SDL_Window *SDL_GetFocusWindow(void);
|
||||
extern SDL_Window *SDL_GetToplevelForKeyboardFocus(void);
|
||||
|
||||
extern SDL_bool SDL_ShouldAllowTopmost(void);
|
||||
|
||||
|
47
external/sdl/SDL/src/video/SDL_video.c
vendored
47
external/sdl/SDL/src/video/SDL_video.c
vendored
@ -1740,7 +1740,7 @@ Uint32 SDL_GetWindowPixelFormat(SDL_Window *window)
|
||||
}
|
||||
|
||||
#define CREATE_FLAGS \
|
||||
(SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_METAL | SDL_WINDOW_TRANSPARENT)
|
||||
(SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_METAL | SDL_WINDOW_TRANSPARENT | SDL_WINDOW_NOT_FOCUSABLE)
|
||||
|
||||
static SDL_INLINE SDL_bool IsAcceptingDragAndDrop(void)
|
||||
{
|
||||
@ -3205,6 +3205,24 @@ int SDL_SetWindowInputFocus(SDL_Window *window)
|
||||
return _this->SetWindowInputFocus(_this, window);
|
||||
}
|
||||
|
||||
int SDL_SetWindowFocusable(SDL_Window *window, SDL_bool focusable)
|
||||
{
|
||||
CHECK_WINDOW_MAGIC(window, -1);
|
||||
|
||||
const int want = (focusable != SDL_FALSE); /* normalize the flag. */
|
||||
const int have = !(window->flags & SDL_WINDOW_NOT_FOCUSABLE);
|
||||
if ((want != have) && (_this->SetWindowFocusable)) {
|
||||
if (want) {
|
||||
window->flags &= ~SDL_WINDOW_NOT_FOCUSABLE;
|
||||
} else {
|
||||
window->flags |= SDL_WINDOW_NOT_FOCUSABLE;
|
||||
}
|
||||
_this->SetWindowFocusable(_this, window, (SDL_bool)want);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SDL_UpdateWindowGrab(SDL_Window *window)
|
||||
{
|
||||
SDL_bool keyboard_grabbed, mouse_grabbed;
|
||||
@ -3543,21 +3561,18 @@ void SDL_OnWindowFocusLost(SDL_Window *window)
|
||||
}
|
||||
}
|
||||
|
||||
/* !!! FIXME: is this different than SDL_GetKeyboardFocus()?
|
||||
!!! FIXME: Also, SDL_GetKeyboardFocus() is O(1), this isn't. */
|
||||
SDL_Window *SDL_GetFocusWindow(void)
|
||||
SDL_Window *SDL_GetToplevelForKeyboardFocus(void)
|
||||
{
|
||||
SDL_Window *window;
|
||||
SDL_Window *focus = SDL_GetKeyboardFocus();
|
||||
|
||||
if (_this == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
for (window = _this->windows; window; window = window->next) {
|
||||
if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
|
||||
return window;
|
||||
if (focus) {
|
||||
/* Get the toplevel parent window. */
|
||||
while (focus->parent) {
|
||||
focus = focus->parent;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
return focus;
|
||||
}
|
||||
|
||||
void SDL_DestroyWindow(SDL_Window *window)
|
||||
@ -4741,7 +4756,7 @@ void SDL_StartTextInput(void)
|
||||
|
||||
/* Then show the on-screen keyboard, if any */
|
||||
if (SDL_GetHintBoolean(SDL_HINT_ENABLE_SCREEN_KEYBOARD, SDL_TRUE)) {
|
||||
window = SDL_GetFocusWindow();
|
||||
window = SDL_GetKeyboardFocus();
|
||||
if (window && _this && _this->ShowScreenKeyboard) {
|
||||
_this->ShowScreenKeyboard(_this, window);
|
||||
}
|
||||
@ -4785,7 +4800,7 @@ void SDL_StopTextInput(void)
|
||||
|
||||
/* Hide the on-screen keyboard, if any */
|
||||
if (SDL_GetHintBoolean(SDL_HINT_ENABLE_SCREEN_KEYBOARD, SDL_TRUE)) {
|
||||
window = SDL_GetFocusWindow();
|
||||
window = SDL_GetKeyboardFocus();
|
||||
if (window && _this && _this->HideScreenKeyboard) {
|
||||
_this->HideScreenKeyboard(_this, window);
|
||||
}
|
||||
@ -5101,9 +5116,9 @@ void SDL_OnApplicationWillResignActive(void)
|
||||
if (_this) {
|
||||
SDL_Window *window;
|
||||
for (window = _this->windows; window != NULL; window = window->next) {
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_FOCUS_LOST, 0, 0);
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0);
|
||||
}
|
||||
SDL_SetKeyboardFocus(NULL);
|
||||
}
|
||||
SDL_SendAppEvent(SDL_EVENT_WILL_ENTER_BACKGROUND);
|
||||
}
|
||||
@ -5125,7 +5140,7 @@ void SDL_OnApplicationDidBecomeActive(void)
|
||||
if (_this) {
|
||||
SDL_Window *window;
|
||||
for (window = _this->windows; window != NULL; window = window->next) {
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_FOCUS_GAINED, 0, 0);
|
||||
SDL_SetKeyboardFocus(window);
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_ANDROID)
|
||||
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
|
||||
#include "SDL_androidvideo.h"
|
||||
#include "SDL_androidwindow.h"
|
||||
|
||||
|
@ -119,6 +119,7 @@ static SDL_VideoDevice *Cocoa_CreateDevice(void)
|
||||
device->SetWindowHitTest = Cocoa_SetWindowHitTest;
|
||||
device->AcceptDragAndDrop = Cocoa_AcceptDragAndDrop;
|
||||
device->FlashWindow = Cocoa_FlashWindow;
|
||||
device->SetWindowFocusable = Cocoa_SetWindowFocusable;
|
||||
|
||||
device->shape_driver.CreateShaper = Cocoa_CreateShaper;
|
||||
device->shape_driver.SetWindowShape = Cocoa_SetWindowShape;
|
||||
|
@ -169,5 +169,6 @@ extern int Cocoa_GetWindowWMInfo(SDL_VideoDevice *_this, SDL_Window *window, str
|
||||
extern int Cocoa_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
|
||||
extern void Cocoa_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept);
|
||||
extern int Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
||||
extern int Cocoa_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool focusable);
|
||||
|
||||
#endif /* SDL_cocoawindow_h_ */
|
||||
|
@ -116,7 +116,7 @@
|
||||
- (BOOL)canBecomeKeyWindow
|
||||
{
|
||||
SDL_Window *window = [self findSDLWindow];
|
||||
if (window && !(window->flags & SDL_WINDOW_TOOLTIP)) {
|
||||
if (window && !(window->flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_NOT_FOCUSABLE))) {
|
||||
return YES;
|
||||
} else {
|
||||
return NO;
|
||||
@ -643,7 +643,7 @@ static void Cocoa_SendExposedEventIfVisible(SDL_Window *window)
|
||||
int newVisibility = [[change objectForKey:@"new"] intValue];
|
||||
if (newVisibility) {
|
||||
SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_SHOWN, 0, 0);
|
||||
} else {
|
||||
} else if (![_data.nswindow isMiniaturized]) {
|
||||
SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_HIDDEN, 0, 0);
|
||||
}
|
||||
}
|
||||
@ -662,7 +662,7 @@ static void Cocoa_SendExposedEventIfVisible(SDL_Window *window)
|
||||
if (wasVisible != isVisible) {
|
||||
if (isVisible) {
|
||||
SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_SHOWN, 0, 0);
|
||||
} else {
|
||||
} else if (![_data.nswindow isMiniaturized]) {
|
||||
SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_HIDDEN, 0, 0);
|
||||
}
|
||||
|
||||
@ -955,7 +955,12 @@ static void Cocoa_SendExposedEventIfVisible(SDL_Window *window)
|
||||
|
||||
- (void)windowDidDeminiaturize:(NSNotification *)aNotification
|
||||
{
|
||||
SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
|
||||
/* isZoomed always returns true if the window is not resizable */
|
||||
if ((_data.window->flags & SDL_WINDOW_RESIZABLE) && [_data.nswindow isZoomed]) {
|
||||
SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_MAXIMIZED, 0, 0);
|
||||
} else {
|
||||
SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeKey:(NSNotification *)aNotification
|
||||
@ -2165,16 +2170,17 @@ void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
if (SDL_WINDOW_IS_POPUP(window)) {
|
||||
NSWindow *nsparent = ((__bridge SDL_CocoaWindowData *)window->parent->driverdata).nswindow;
|
||||
[nsparent addChildWindow:nswindow ordered:NSWindowAbove];
|
||||
}
|
||||
if (bActivate) {
|
||||
[nswindow makeKeyAndOrderFront:nil];
|
||||
} else {
|
||||
/* Order this window below the key window if we're not activating it */
|
||||
if ([NSApp keyWindow]) {
|
||||
[nswindow orderWindow:NSWindowBelow relativeTo:[[NSApp keyWindow] windowNumber]];
|
||||
if (bActivate) {
|
||||
[nswindow makeKeyAndOrderFront:nil];
|
||||
} else {
|
||||
/* Order this window below the key window if we're not activating it */
|
||||
if ([NSApp keyWindow]) {
|
||||
[nswindow orderWindow:NSWindowBelow relativeTo:[[NSApp keyWindow] windowNumber]];
|
||||
}
|
||||
}
|
||||
[nswindow setIsVisible:YES];
|
||||
}
|
||||
[nswindow setIsVisible:YES];
|
||||
[windowData.listener resumeVisibleObservation];
|
||||
}
|
||||
}
|
||||
@ -2185,7 +2191,18 @@ void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
@autoreleasepool {
|
||||
NSWindow *nswindow = ((__bridge SDL_CocoaWindowData *)window->driverdata).nswindow;
|
||||
|
||||
[nswindow orderOut:nil];
|
||||
/* orderOut has no effect on miniaturized windows, so close must be used to remove
|
||||
* the window from the desktop and window list in this case.
|
||||
*
|
||||
* SDL holds a strong reference to the window (oneShot/releasedWhenClosed are 'NO'),
|
||||
* and calling 'close' doesn't send a 'windowShouldClose' message, so it's safe to
|
||||
* use for this purpose as nothing is implicitly released.
|
||||
*/
|
||||
if (![nswindow isMiniaturized]) {
|
||||
[nswindow orderOut:nil];
|
||||
} else {
|
||||
[nswindow close];
|
||||
}
|
||||
|
||||
/* Transfer keyboard focus back to the parent */
|
||||
if (window->flags & SDL_WINDOW_POPUP_MENU) {
|
||||
@ -2218,13 +2235,13 @@ void Cocoa_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
if (SDL_WINDOW_IS_POPUP(window)) {
|
||||
NSWindow *nsparent = ((__bridge SDL_CocoaWindowData *)window->parent->driverdata).nswindow;
|
||||
[nsparent addChildWindow:nswindow ordered:NSWindowAbove];
|
||||
}
|
||||
|
||||
if (bActivate) {
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
[nswindow makeKeyAndOrderFront:nil];
|
||||
} else {
|
||||
[nswindow orderFront:nil];
|
||||
if (bActivate) {
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
[nswindow makeKeyAndOrderFront:nil];
|
||||
} else {
|
||||
[nswindow orderFront:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
[windowData.listener resumeVisibleObservation];
|
||||
@ -2662,6 +2679,11 @@ int Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOpera
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool focusable)
|
||||
{
|
||||
return 0; /* just succeed, the real work is done elsewhere. */
|
||||
}
|
||||
|
||||
int Cocoa_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity)
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
@ -732,7 +732,7 @@ static EM_BOOL Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent
|
||||
}
|
||||
|
||||
sdl_event_type = (eventType == EMSCRIPTEN_EVENT_FOCUS) ? SDL_EVENT_WINDOW_FOCUS_GAINED : SDL_EVENT_WINDOW_FOCUS_LOST;
|
||||
SDL_SendWindowEvent(window_data->window, sdl_event_type, 0, 0);
|
||||
SDL_SetKeyboardFocus(sdl_event_type == SDL_EVENT_WINDOW_FOCUS_GAINED ? window_data->window : NULL);
|
||||
return SDL_EventEnabled(sdl_event_type);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,15 @@
|
||||
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
|
||||
/* older Emscriptens don't have this, but we need to for wasm64 compatibility. */
|
||||
#ifndef MAIN_THREAD_EM_ASM_PTR
|
||||
#ifdef __wasm64__
|
||||
#error You need to upgrade your Emscripten compiler to support wasm64
|
||||
#else
|
||||
#define MAIN_THREAD_EM_ASM_PTR MAIN_THREAD_EM_ASM_INT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static SDL_Cursor *Emscripten_CreateCursorFromString(const char *cursor_str, SDL_bool is_custom)
|
||||
{
|
||||
SDL_Cursor *cursor;
|
||||
@ -74,7 +83,7 @@ static SDL_Cursor *Emscripten_CreateCursor(SDL_Surface *surface, int hot_x, int
|
||||
}
|
||||
|
||||
/* *INDENT-OFF* */ /* clang-format off */
|
||||
cursor_url = (const char *)MAIN_THREAD_EM_ASM_INT({
|
||||
cursor_url = (const char *)MAIN_THREAD_EM_ASM_PTR({
|
||||
var w = $0;
|
||||
var h = $1;
|
||||
var hot_x = $2;
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_KMSDRM)
|
||||
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
|
||||
#include "SDL_kmsdrmvideo.h"
|
||||
#include "SDL_kmsdrmdyn.h"
|
||||
#include "SDL_kmsdrmvulkan.h"
|
||||
|
@ -249,7 +249,7 @@ void UIKit_ForceUpdateHomeIndicator(void)
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
/* Force the main SDL window to re-evaluate home indicator state */
|
||||
SDL_Window *focus = SDL_GetFocusWindow();
|
||||
SDL_Window *focus = SDL_GetKeyboardFocus();
|
||||
if (focus) {
|
||||
SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)focus->driverdata;
|
||||
if (data != nil) {
|
||||
|
@ -624,7 +624,7 @@ SDL_bool UIKit_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
int UIKit_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_uikitviewcontroller *vc = GetWindowViewController(SDL_GetFocusWindow());
|
||||
SDL_uikitviewcontroller *vc = GetWindowViewController(SDL_GetKeyboardFocus());
|
||||
if (vc != nil) {
|
||||
vc.textInputRect = *rect;
|
||||
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_VIVANTE)
|
||||
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
|
||||
#include "SDL_vivantevideo.h"
|
||||
|
||||
#include "SDL_vivantevulkan.h"
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#define TEXT_MIME "text/plain;charset=utf-8"
|
||||
#define FILE_MIME "text/uri-list"
|
||||
#define FILE_PORTAL_MIME "application/vnd.portal.filetransfer"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -34,34 +34,30 @@ typedef struct
|
||||
const char *libname;
|
||||
} waylanddynlib;
|
||||
|
||||
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
|
||||
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL NULL
|
||||
#endif
|
||||
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
|
||||
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR NULL
|
||||
#endif
|
||||
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
|
||||
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON NULL
|
||||
#endif
|
||||
#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR
|
||||
#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR NULL
|
||||
#endif
|
||||
|
||||
static waylanddynlib waylandlibs[] = {
|
||||
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC },
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
|
||||
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL },
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
|
||||
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR },
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
|
||||
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON },
|
||||
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR }
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR
|
||||
{ NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR },
|
||||
#endif
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void *WAYLAND_GetSym(const char *fnname, int *pHasModule, SDL_bool required)
|
||||
{
|
||||
int i;
|
||||
void *fn = NULL;
|
||||
for (i = 0; i < SDL_TABLESIZE(waylandlibs); i++) {
|
||||
if (waylandlibs[i].lib != NULL) {
|
||||
fn = SDL_LoadFunction(waylandlibs[i].lib, fnname);
|
||||
waylanddynlib *dynlib;
|
||||
for (dynlib = waylandlibs; dynlib->libname; dynlib++) {
|
||||
if (dynlib->lib != NULL) {
|
||||
fn = SDL_LoadFunction(dynlib->lib, fnname);
|
||||
if (fn != NULL) {
|
||||
break;
|
||||
}
|
||||
@ -69,10 +65,11 @@ static void *WAYLAND_GetSym(const char *fnname, int *pHasModule, SDL_bool requir
|
||||
}
|
||||
|
||||
#if DEBUG_DYNAMIC_WAYLAND
|
||||
if (fn != NULL)
|
||||
SDL_Log("WAYLAND: Found '%s' in %s (%p)\n", fnname, waylandlibs[i].libname, fn);
|
||||
else
|
||||
if (fn != NULL) {
|
||||
SDL_Log("WAYLAND: Found '%s' in %s (%p)\n", fnname, dynlib->libname, fn);
|
||||
} else {
|
||||
SDL_Log("WAYLAND: Symbol '%s' NOT FOUND!\n", fnname);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fn == NULL && required) {
|
||||
|
@ -823,7 +823,7 @@ static void pointer_handle_axis(void *data, struct wl_pointer *pointer,
|
||||
{
|
||||
struct SDL_WaylandInput *input = data;
|
||||
|
||||
if (wl_seat_get_version(input->seat) >= 5) {
|
||||
if (wl_seat_get_version(input->seat) >= WL_POINTER_FRAME_SINCE_VERSION) {
|
||||
input->pointer_curr_axis_info.timestamp_ns = Wayland_GetPointerTimestamp(input, time);
|
||||
pointer_handle_axis_common(input, AXIS_EVENT_CONTINUOUS, axis, value);
|
||||
} else {
|
||||
@ -1848,28 +1848,40 @@ static void data_device_handle_enter(void *data, struct wl_data_device *wl_data_
|
||||
data_device->drag_offer = wl_data_offer_get_user_data(id);
|
||||
|
||||
/* TODO: SDL Support more mime types */
|
||||
has_mime = Wayland_data_offer_has_mime(
|
||||
data_device->drag_offer, FILE_MIME);
|
||||
|
||||
/* If drag_mime is NULL this will decline the offer */
|
||||
wl_data_offer_accept(id, serial,
|
||||
(has_mime == SDL_TRUE) ? FILE_MIME : NULL);
|
||||
#ifdef SDL_USE_LIBDBUS
|
||||
if (Wayland_data_offer_has_mime(data_device->drag_offer, FILE_PORTAL_MIME)) {
|
||||
has_mime = SDL_TRUE;
|
||||
wl_data_offer_accept(id, serial, FILE_PORTAL_MIME);
|
||||
}
|
||||
#endif
|
||||
if (Wayland_data_offer_has_mime(data_device->drag_offer, FILE_MIME)) {
|
||||
has_mime = SDL_TRUE;
|
||||
wl_data_offer_accept(id, serial, FILE_MIME);
|
||||
}
|
||||
|
||||
/* SDL only supports "copy" style drag and drop */
|
||||
if (has_mime == SDL_TRUE) {
|
||||
if (has_mime) {
|
||||
dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
||||
} else {
|
||||
/* drag_mime is NULL this will decline the offer */
|
||||
wl_data_offer_accept(id, serial, NULL);
|
||||
}
|
||||
if (wl_data_offer_get_version(data_device->drag_offer->offer) >= 3) {
|
||||
if (wl_data_offer_get_version(data_device->drag_offer->offer) >=
|
||||
WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) {
|
||||
wl_data_offer_set_actions(data_device->drag_offer->offer,
|
||||
dnd_action, dnd_action);
|
||||
}
|
||||
|
||||
/* find the current window */
|
||||
if (surface && SDL_WAYLAND_own_surface(surface)) {
|
||||
SDL_WindowData *window = (SDL_WindowData *)wl_surface_get_user_data(surface);
|
||||
if (window) {
|
||||
data_device->dnd_window = window->sdlwindow;
|
||||
}
|
||||
if (surface) {
|
||||
if (SDL_WAYLAND_own_surface(surface)) {
|
||||
SDL_WindowData *window = (SDL_WindowData *)wl_surface_get_user_data(surface);
|
||||
if (window) {
|
||||
data_device->dnd_window = window->sdlwindow;
|
||||
}
|
||||
} else {
|
||||
data_device->dnd_window = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1877,11 +1889,10 @@ static void data_device_handle_enter(void *data, struct wl_data_device *wl_data_
|
||||
static void data_device_handle_leave(void *data, struct wl_data_device *wl_data_device)
|
||||
{
|
||||
SDL_WaylandDataDevice *data_device = data;
|
||||
SDL_WaylandDataOffer *offer = NULL;
|
||||
|
||||
if (data_device->selection_offer != NULL) {
|
||||
data_device->selection_offer = NULL;
|
||||
Wayland_data_offer_destroy(offer);
|
||||
if (data_device->drag_offer != NULL) {
|
||||
Wayland_data_offer_destroy(data_device->drag_offer);
|
||||
data_device->drag_offer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1890,27 +1901,15 @@ static void data_device_handle_motion(void *data, struct wl_data_device *wl_data
|
||||
{
|
||||
SDL_WaylandDataDevice *data_device = data;
|
||||
|
||||
if (data_device->drag_offer != NULL) {
|
||||
/* TODO: SDL Support more mime types */
|
||||
size_t length;
|
||||
void *buffer = Wayland_data_offer_receive(data_device->drag_offer,
|
||||
FILE_MIME, &length);
|
||||
if (buffer) {
|
||||
char *saveptr = NULL;
|
||||
char *token = SDL_strtok_r((char *)buffer, "\r\n", &saveptr);
|
||||
while (token != NULL) {
|
||||
char *fn = Wayland_URIToLocal(token);
|
||||
if (fn) {
|
||||
double dx;
|
||||
double dy;
|
||||
dx = wl_fixed_to_double(x);
|
||||
dy = wl_fixed_to_double(y);
|
||||
SDL_SendDropPosition(data_device->dnd_window, fn, (float)dx, (float)dy);
|
||||
}
|
||||
token = SDL_strtok_r(NULL, "\r\n", &saveptr);
|
||||
}
|
||||
SDL_free(buffer);
|
||||
}
|
||||
if (data_device->drag_offer != NULL && data_device->dnd_window) {
|
||||
const float dx = (float)wl_fixed_to_double(x);
|
||||
const float dy = (float)wl_fixed_to_double(y);
|
||||
|
||||
/* XXX: Send the filename here if the event system ever starts passing it though.
|
||||
* Any future implementation should cache the filenames, as otherwise this could
|
||||
* hammer the DBus interface hundreds or even thousands of times per second.
|
||||
*/
|
||||
SDL_SendDropPosition(data_device->dnd_window, NULL, dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2039,25 +2038,66 @@ static void data_device_handle_drop(void *data, struct wl_data_device *wl_data_d
|
||||
{
|
||||
SDL_WaylandDataDevice *data_device = data;
|
||||
|
||||
if (data_device->drag_offer != NULL) {
|
||||
if (data_device->drag_offer != NULL && data_device->dnd_window) {
|
||||
/* TODO: SDL Support more mime types */
|
||||
size_t length;
|
||||
void *buffer = Wayland_data_offer_receive(data_device->drag_offer,
|
||||
FILE_MIME, &length);
|
||||
if (buffer) {
|
||||
char *saveptr = NULL;
|
||||
char *token = SDL_strtok_r((char *)buffer, "\r\n", &saveptr);
|
||||
while (token != NULL) {
|
||||
char *fn = Wayland_URIToLocal(token);
|
||||
if (fn) {
|
||||
SDL_SendDropFile(data_device->dnd_window, fn);
|
||||
SDL_bool drop_handled = SDL_FALSE;
|
||||
#ifdef SDL_USE_LIBDBUS
|
||||
if (Wayland_data_offer_has_mime(
|
||||
data_device->drag_offer, FILE_PORTAL_MIME)) {
|
||||
void *buffer = Wayland_data_offer_receive(data_device->drag_offer,
|
||||
FILE_PORTAL_MIME, &length);
|
||||
if (buffer) {
|
||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||
if (dbus) {
|
||||
int path_count = 0;
|
||||
char **paths = SDL_DBus_DocumentsPortalRetrieveFiles(buffer, &path_count);
|
||||
/* If dropped files contain a directory the list is empty */
|
||||
if (paths && path_count > 0) {
|
||||
for (int i = 0; i < path_count; i++) {
|
||||
SDL_SendDropFile(data_device->dnd_window, paths[i]);
|
||||
}
|
||||
dbus->free_string_array(paths);
|
||||
SDL_SendDropComplete(data_device->dnd_window);
|
||||
drop_handled = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
token = SDL_strtok_r(NULL, "\r\n", &saveptr);
|
||||
SDL_free(buffer);
|
||||
}
|
||||
SDL_SendDropComplete(data_device->dnd_window);
|
||||
SDL_free(buffer);
|
||||
}
|
||||
#endif
|
||||
/* If XDG document portal fails fallback.
|
||||
* When running a flatpak sandbox this will most likely be a list of
|
||||
* non paths that are not visible to the application
|
||||
*/
|
||||
if (!drop_handled && Wayland_data_offer_has_mime(
|
||||
data_device->drag_offer, FILE_MIME)) {
|
||||
void *buffer = Wayland_data_offer_receive(data_device->drag_offer,
|
||||
FILE_MIME, &length);
|
||||
if (buffer) {
|
||||
char *saveptr = NULL;
|
||||
char *token = SDL_strtok_r((char *)buffer, "\r\n", &saveptr);
|
||||
while (token != NULL) {
|
||||
char *fn = Wayland_URIToLocal(token);
|
||||
if (fn) {
|
||||
SDL_SendDropFile(data_device->dnd_window, fn);
|
||||
}
|
||||
token = SDL_strtok_r(NULL, "\r\n", &saveptr);
|
||||
}
|
||||
SDL_SendDropComplete(data_device->dnd_window);
|
||||
SDL_free(buffer);
|
||||
drop_handled = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (drop_handled && wl_data_offer_get_version(data_device->drag_offer->offer) >=
|
||||
WL_DATA_OFFER_FINISH_SINCE_VERSION) {
|
||||
wl_data_offer_finish(data_device->drag_offer->offer);
|
||||
}
|
||||
}
|
||||
|
||||
Wayland_data_offer_destroy(data_device->drag_offer);
|
||||
data_device->drag_offer = NULL;
|
||||
}
|
||||
|
||||
static void data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
|
||||
|
@ -916,7 +916,7 @@ static int Wayland_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *di
|
||||
/* When an emulated, exclusive fullscreen window has focus, treat the mode dimensions as the display bounds. */
|
||||
if (display->fullscreen_window &&
|
||||
display->fullscreen_window->fullscreen_exclusive &&
|
||||
display->fullscreen_window == SDL_GetFocusWindow() &&
|
||||
display->fullscreen_window->driverdata->active &&
|
||||
display->fullscreen_window->current_fullscreen_mode.w != 0 &&
|
||||
display->fullscreen_window->current_fullscreen_mode.h != 0) {
|
||||
rect->w = display->fullscreen_window->current_fullscreen_mode.w;
|
||||
|
@ -28,9 +28,12 @@
|
||||
|
||||
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WAYLAND)
|
||||
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
|
||||
#include "SDL_waylandvideo.h"
|
||||
#include "SDL_waylandwindow.h"
|
||||
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
#include "SDL_waylandvulkan.h"
|
||||
|
||||
#include <SDL3/SDL_syswm.h>
|
||||
|
@ -29,7 +29,7 @@
|
||||
#ifndef SDL_waylandvulkan_h_
|
||||
#define SDL_waylandvulkan_h_
|
||||
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
#include <SDL3/SDL_vulkan.h>
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WAYLAND)
|
||||
|
@ -639,7 +639,7 @@ static void handle_configure_xdg_toplevel(void *data,
|
||||
SDL_bool fullscreen = SDL_FALSE;
|
||||
SDL_bool maximized = SDL_FALSE;
|
||||
SDL_bool floating = SDL_TRUE;
|
||||
SDL_bool focused = SDL_FALSE;
|
||||
SDL_bool active = SDL_FALSE;
|
||||
SDL_bool suspended = SDL_FALSE;
|
||||
wl_array_for_each (state, states) {
|
||||
switch (*state) {
|
||||
@ -652,7 +652,7 @@ static void handle_configure_xdg_toplevel(void *data,
|
||||
floating = SDL_FALSE;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_ACTIVATED:
|
||||
focused = SDL_TRUE;
|
||||
active = SDL_TRUE;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_TILED_LEFT:
|
||||
case XDG_TOPLEVEL_STATE_TILED_RIGHT:
|
||||
@ -715,7 +715,7 @@ static void handle_configure_xdg_toplevel(void *data,
|
||||
* dependent, but in general, we can assume that the flag should remain set until
|
||||
* the next focused configure event occurs.
|
||||
*/
|
||||
if (focused || !(window->flags & SDL_WINDOW_MINIMIZED)) {
|
||||
if (active || !(window->flags & SDL_WINDOW_MINIMIZED)) {
|
||||
SDL_SendWindowEvent(window,
|
||||
maximized ? SDL_EVENT_WINDOW_MAXIMIZED : SDL_EVENT_WINDOW_RESTORED,
|
||||
0, 0);
|
||||
@ -745,15 +745,11 @@ static void handle_configure_xdg_toplevel(void *data,
|
||||
}
|
||||
}
|
||||
|
||||
/* Similar to maximized/restore events above, send focus events too! */
|
||||
SDL_SendWindowEvent(window,
|
||||
focused ? SDL_EVENT_WINDOW_FOCUS_GAINED : SDL_EVENT_WINDOW_FOCUS_LOST,
|
||||
0, 0);
|
||||
|
||||
wind->requested_window_width = width;
|
||||
wind->requested_window_height = height;
|
||||
wind->floating = floating;
|
||||
wind->suspended = suspended;
|
||||
wind->active = active;
|
||||
if (wind->surface_status == WAYLAND_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
|
||||
wind->surface_status = WAYLAND_SURFACE_STATUS_WAITING_FOR_FRAME;
|
||||
}
|
||||
@ -855,11 +851,10 @@ static void handle_configure_zxdg_decoration(void *data,
|
||||
WAYLAND_wl_display_roundtrip(driverdata->waylandData->display);
|
||||
|
||||
Wayland_HideWindow(device, window);
|
||||
SDL_zero(driverdata->shell_surface);
|
||||
driverdata->shell_surface_type = WAYLAND_SURFACE_LIBDECOR;
|
||||
|
||||
if (!window->is_hiding && !(window->flags & SDL_WINDOW_HIDDEN)) {
|
||||
Wayland_ShowWindow(device, window);
|
||||
}
|
||||
Wayland_ShowWindow(device, window);
|
||||
}
|
||||
}
|
||||
|
||||
@ -921,7 +916,7 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
|
||||
int width, height;
|
||||
|
||||
SDL_bool prev_fullscreen = wind->is_fullscreen;
|
||||
SDL_bool focused = SDL_FALSE;
|
||||
SDL_bool active = SDL_FALSE;
|
||||
SDL_bool fullscreen = SDL_FALSE;
|
||||
SDL_bool maximized = SDL_FALSE;
|
||||
SDL_bool tiled = SDL_FALSE;
|
||||
@ -935,7 +930,7 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
|
||||
if (libdecor_configuration_get_window_state(configuration, &window_state)) {
|
||||
fullscreen = (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) != 0;
|
||||
maximized = (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) != 0;
|
||||
focused = (window_state & LIBDECOR_WINDOW_STATE_ACTIVE) != 0;
|
||||
active = (window_state & LIBDECOR_WINDOW_STATE_ACTIVE) != 0;
|
||||
tiled = (window_state & tiled_states) != 0;
|
||||
#ifdef SDL_HAVE_LIBDECOR_VER_0_1_2
|
||||
suspended = (window_state & LIBDECOR_WINDOW_STATE_SUSPENDED) != 0;
|
||||
@ -954,18 +949,13 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
|
||||
* dependent, but in general, we can assume that the flag should remain set until
|
||||
* the next focused configure event occurs.
|
||||
*/
|
||||
if (focused || !(window->flags & SDL_WINDOW_MINIMIZED)) {
|
||||
if (active || !(window->flags & SDL_WINDOW_MINIMIZED)) {
|
||||
SDL_SendWindowEvent(window,
|
||||
maximized ? SDL_EVENT_WINDOW_MAXIMIZED : SDL_EVENT_WINDOW_RESTORED,
|
||||
0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Similar to maximized/restore events above, send focus events too! */
|
||||
SDL_SendWindowEvent(window,
|
||||
focused ? SDL_EVENT_WINDOW_FOCUS_GAINED : SDL_EVENT_WINDOW_FOCUS_LOST,
|
||||
0, 0);
|
||||
|
||||
/* For fullscreen or fixed-size windows we know our size.
|
||||
* Always assume the configure is wrong.
|
||||
*/
|
||||
@ -1055,6 +1045,7 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
|
||||
/* Store the new state. */
|
||||
wind->floating = floating;
|
||||
wind->suspended = suspended;
|
||||
wind->active = active;
|
||||
|
||||
/* Calculate the new window geometry */
|
||||
wind->requested_window_width = width;
|
||||
@ -1529,12 +1520,6 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
|
||||
/* Restore state that was set prior to this call */
|
||||
Wayland_SetWindowTitle(_this, window);
|
||||
if (window->flags & SDL_WINDOW_MAXIMIZED) {
|
||||
Wayland_MaximizeWindow(_this, window);
|
||||
}
|
||||
if (window->flags & SDL_WINDOW_MINIMIZED) {
|
||||
Wayland_MinimizeWindow(_this, window);
|
||||
}
|
||||
|
||||
/* We have to wait until the surface gets a "configure" event, or use of
|
||||
* this surface will fail. This is a new rule for xdg_shell.
|
||||
@ -1940,11 +1925,6 @@ void Wayland_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *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 (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) {
|
||||
if (wind->shell_surface.libdecor.frame == NULL) {
|
||||
@ -2025,11 +2005,6 @@ void Wayland_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set this flag now even if we don't actually maximize yet, eventually
|
||||
* ShowWindow will take care of it along with the other window state.
|
||||
*/
|
||||
window->flags |= SDL_WINDOW_MAXIMIZED;
|
||||
|
||||
#ifdef HAVE_LIBDECOR_H
|
||||
if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) {
|
||||
if (wind->shell_surface.libdecor.frame == NULL) {
|
||||
@ -2057,6 +2032,8 @@ void Wayland_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
SDL_VideoData *viddata = _this->driverdata;
|
||||
SDL_WindowData *wind = window->driverdata;
|
||||
|
||||
/* Maximized and minimized flags are mutually exclusive */
|
||||
window->flags &= ~SDL_WINDOW_MAXIMIZED;
|
||||
window->flags |= SDL_WINDOW_MINIMIZED;
|
||||
|
||||
#ifdef HAVE_LIBDECOR_H
|
||||
|
@ -123,6 +123,7 @@ struct SDL_WindowData
|
||||
SDL_DisplayID last_displayID;
|
||||
SDL_bool floating;
|
||||
SDL_bool suspended;
|
||||
SDL_bool active;
|
||||
SDL_bool is_fullscreen;
|
||||
SDL_bool in_fullscreen_transition;
|
||||
SDL_bool fullscreen_was_positioned;
|
||||
|
@ -22,6 +22,9 @@
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
|
||||
#ifdef SDL_VIDEO_VULKAN
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
#endif
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "../SDL_pixels_c.h"
|
||||
#include "../../SDL_hints_c.h"
|
||||
@ -208,6 +211,7 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
|
||||
device->AcceptDragAndDrop = WIN_AcceptDragAndDrop;
|
||||
device->FlashWindow = WIN_FlashWindow;
|
||||
device->ShowWindowSystemMenu = WIN_ShowWindowSystemMenu;
|
||||
device->SetWindowFocusable = WIN_SetWindowFocusable;
|
||||
|
||||
device->shape_driver.CreateShaper = Win32_CreateShaper;
|
||||
device->shape_driver.SetWindowShape = Win32_SetWindowShape;
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WINDOWS)
|
||||
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
|
||||
#include "SDL_windowsvideo.h"
|
||||
#include "SDL_windowswindow.h"
|
||||
|
||||
|
@ -29,11 +29,11 @@
|
||||
#ifndef SDL_windowsvulkan_h_
|
||||
#define SDL_windowsvulkan_h_
|
||||
|
||||
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WINDOWS)
|
||||
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_WINDOWS)
|
||||
|
||||
int WIN_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
void WIN_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
|
||||
SDL_bool WIN_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
|
||||
|
@ -46,6 +46,22 @@
|
||||
#endif
|
||||
typedef HRESULT (WINAPI *DwmSetWindowAttribute_t)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
|
||||
|
||||
/* Transparent window support */
|
||||
#ifndef DWM_BB_ENABLE
|
||||
#define DWM_BB_ENABLE 0x00000001
|
||||
#endif
|
||||
#ifndef DWM_BB_BLURREGION
|
||||
#define DWM_BB_BLURREGION 0x00000002
|
||||
#endif
|
||||
typedef struct
|
||||
{
|
||||
DWORD flags;
|
||||
BOOL enable;
|
||||
HRGN blur_region;
|
||||
BOOL transition_on_maxed;
|
||||
} DWM_BLURBEHIND;
|
||||
typedef HRESULT(WINAPI *DwmEnableBlurBehindWindow_t)(HWND hwnd, const DWM_BLURBEHIND *pBlurBehind);
|
||||
|
||||
/* Windows CE compatibility */
|
||||
#ifndef SWP_NOCOPYBITS
|
||||
#define SWP_NOCOPYBITS 0
|
||||
@ -128,10 +144,11 @@ static DWORD GetWindowStyleEx(SDL_Window *window)
|
||||
{
|
||||
DWORD style = 0;
|
||||
|
||||
if (SDL_WINDOW_IS_POPUP(window)) {
|
||||
style = WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE;
|
||||
} else if (window->flags & SDL_WINDOW_UTILITY) {
|
||||
style = WS_EX_TOOLWINDOW;
|
||||
if (SDL_WINDOW_IS_POPUP(window) || (window->flags & SDL_WINDOW_UTILITY)) {
|
||||
style |= WS_EX_TOOLWINDOW;
|
||||
}
|
||||
if (SDL_WINDOW_IS_POPUP(window) || (window->flags & SDL_WINDOW_NOT_FOCUSABLE)) {
|
||||
style |= WS_EX_NOACTIVATE;
|
||||
}
|
||||
return style;
|
||||
}
|
||||
@ -173,23 +190,9 @@ static int WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL m
|
||||
if (WIN_IsPerMonitorV2DPIAware(SDL_GetVideoDevice())) {
|
||||
/* With per-monitor v2, the window border/titlebar size depend on the DPI, so we need to call AdjustWindowRectExForDpi instead of
|
||||
AdjustWindowRectEx. */
|
||||
UINT unused;
|
||||
RECT screen_rect;
|
||||
HMONITOR mon;
|
||||
|
||||
screen_rect.left = *x;
|
||||
screen_rect.top = *y;
|
||||
screen_rect.right = (LONG)*x + *width;
|
||||
screen_rect.bottom = (LONG)*y + *height;
|
||||
|
||||
mon = MonitorFromRect(&screen_rect, MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
if (videodata != NULL) {
|
||||
/* GetDpiForMonitor docs promise to return the same hdpi / vdpi */
|
||||
if (videodata->GetDpiForMonitor(mon, MDT_EFFECTIVE_DPI, &frame_dpi, &unused) != S_OK) {
|
||||
frame_dpi = 96;
|
||||
}
|
||||
|
||||
SDL_WindowData *data = window->driverdata;
|
||||
frame_dpi = (data && videodata->GetDpiForWindow) ? videodata->GetDpiForWindow(data->hwnd) : 96;
|
||||
if (videodata->AdjustWindowRectExForDpi(&rect, style, menu, 0, frame_dpi) == 0) {
|
||||
return WIN_SetError("AdjustWindowRectExForDpi()");
|
||||
}
|
||||
@ -583,6 +586,25 @@ int WIN_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
ShowWindow(hwnd, SW_SHOWMINNOACTIVE);
|
||||
}
|
||||
|
||||
/* FIXME: does not work on all hardware configurations with different renders (i.e. hybrid GPUs) */
|
||||
if (window->flags & SDL_WINDOW_TRANSPARENT) {
|
||||
void *handle = SDL_LoadObject("dwmapi.dll");
|
||||
if (handle) {
|
||||
DwmEnableBlurBehindWindow_t DwmEnableBlurBehindWindowFunc = (DwmEnableBlurBehindWindow_t)SDL_LoadFunction(handle, "DwmEnableBlurBehindWindow");
|
||||
if (DwmEnableBlurBehindWindowFunc) {
|
||||
/* The region indicates which part of the window will be blurred and rest will be transparent. This
|
||||
is because the alpha value of the window will be used for non-blurred areas
|
||||
We can use (-1, -1, 0, 0) boundary to make sure no pixels are being blurred
|
||||
*/
|
||||
HRGN rgn = CreateRectRgn(-1, -1, 0, 0);
|
||||
DWM_BLURBEHIND bb = {DWM_BB_ENABLE | DWM_BB_BLURREGION, TRUE, rgn, FALSE};
|
||||
DwmEnableBlurBehindWindowFunc(hwnd, &bb);
|
||||
DeleteObject(rgn);
|
||||
}
|
||||
SDL_UnloadObject(handle);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(window->flags & SDL_WINDOW_OPENGL)) {
|
||||
return 0;
|
||||
}
|
||||
@ -1504,6 +1526,31 @@ void WIN_ShowWindowSystemMenu(SDL_Window *window, int x, int y)
|
||||
ClientToScreen(data->hwnd, &pt);
|
||||
SendMessage(data->hwnd, WM_POPUPSYSTEMMENU, 0, MAKELPARAM(pt.x, pt.y));
|
||||
}
|
||||
|
||||
int WIN_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool focusable)
|
||||
{
|
||||
SDL_WindowData *data = window->driverdata;
|
||||
HWND hwnd = data->hwnd;
|
||||
const LONG style = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
|
||||
SDL_assert(style != 0);
|
||||
|
||||
if (focusable) {
|
||||
if (style & WS_EX_NOACTIVATE) {
|
||||
if (SetWindowLong(hwnd, GWL_EXSTYLE, style & ~WS_EX_NOACTIVATE) == 0) {
|
||||
return WIN_SetError("SetWindowLong()");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(style & WS_EX_NOACTIVATE)) {
|
||||
if (SetWindowLong(hwnd, GWL_EXSTYLE, style | WS_EX_NOACTIVATE) == 0) {
|
||||
return WIN_SetError("SetWindowLong()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /*!defined(__XBOXONE__) && !defined(__XBOXSERIES__)*/
|
||||
|
||||
void WIN_UpdateDarkModeForHWND(HWND hwnd)
|
||||
|
@ -109,6 +109,7 @@ extern int WIN_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Flash
|
||||
extern void WIN_UpdateDarkModeForHWND(HWND hwnd);
|
||||
extern int WIN_SetWindowPositionInternal(SDL_Window *window, UINT flags);
|
||||
extern void WIN_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
|
||||
extern int WIN_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool focusable);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
|
@ -92,9 +92,7 @@ static int SetSelectionData(SDL_VideoDevice *_this, Atom selection, SDL_Clipboar
|
||||
clipboard->mime_count = mime_count;
|
||||
clipboard->sequence = sequence;
|
||||
|
||||
if (!clipboard_owner) {
|
||||
X11_XSetSelectionOwner(display, selection, window, CurrentTime);
|
||||
}
|
||||
X11_XSetSelectionOwner(display, selection, window, CurrentTime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
19
external/sdl/SDL/src/video/x11/SDL_x11events.c
vendored
19
external/sdl/SDL/src/video/x11/SDL_x11events.c
vendored
@ -1579,12 +1579,19 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
|
||||
}
|
||||
}
|
||||
|
||||
if (changed & SDL_WINDOW_MAXIMIZED) {
|
||||
if (flags & SDL_WINDOW_MAXIMIZED) {
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MAXIMIZED, 0, 0);
|
||||
} else {
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
|
||||
}
|
||||
if ((changed & SDL_WINDOW_MAXIMIZED) && ((flags & SDL_WINDOW_MAXIMIZED) && !(flags & SDL_WINDOW_MINIMIZED))) {
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MAXIMIZED, 0, 0);
|
||||
}
|
||||
if ((changed & SDL_WINDOW_MINIMIZED) && (flags & SDL_WINDOW_MINIMIZED)) {
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0);
|
||||
}
|
||||
if (((changed & SDL_WINDOW_MAXIMIZED) || (changed & SDL_WINDOW_MINIMIZED)) &&
|
||||
(!(flags & SDL_WINDOW_MAXIMIZED) && !(flags & SDL_WINDOW_MINIMIZED))) {
|
||||
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
|
||||
}
|
||||
|
||||
if (changed & SDL_WINDOW_OCCLUDED) {
|
||||
SDL_SendWindowEvent(data->window, (flags & SDL_WINDOW_OCCLUDED) ? SDL_EVENT_WINDOW_OCCLUDED : SDL_EVENT_WINDOW_EXPOSED, 0, 0);
|
||||
}
|
||||
} else if (xevent->xproperty.atom == videodata->XKLAVIER_STATE) {
|
||||
/* Hack for Ubuntu 12.04 (etc) that doesn't send MappingNotify
|
||||
|
@ -39,8 +39,6 @@
|
||||
#include "SDL_x11opengles.h"
|
||||
#endif
|
||||
|
||||
#include "SDL_x11vulkan.h"
|
||||
|
||||
/* Initialization/Query functions */
|
||||
static int X11_VideoInit(SDL_VideoDevice *_this);
|
||||
static void X11_VideoQuit(SDL_VideoDevice *_this);
|
||||
@ -214,6 +212,7 @@ static SDL_VideoDevice *X11_CreateDevice(void)
|
||||
device->AcceptDragAndDrop = X11_AcceptDragAndDrop;
|
||||
device->FlashWindow = X11_FlashWindow;
|
||||
device->ShowWindowSystemMenu = X11_ShowWindowSystemMenu;
|
||||
device->SetWindowFocusable = X11_SetWindowFocusable;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
|
||||
device->SetWindowMouseRect = X11_SetWindowMouseRect;
|
||||
|
24
external/sdl/SDL/src/video/x11/SDL_x11video.h
vendored
24
external/sdl/SDL/src/video/x11/SDL_x11video.h
vendored
@ -25,30 +25,6 @@
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xresource.h>
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XCURSOR
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XDBE
|
||||
#include <X11/extensions/Xdbe.h>
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XSCRNSAVER
|
||||
#include <X11/extensions/scrnsaver.h>
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XSHAPE
|
||||
#include <X11/extensions/shape.h>
|
||||
#endif
|
||||
|
||||
#include "../../core/linux/SDL_dbus.h"
|
||||
#include "../../core/linux/SDL_ime.h"
|
||||
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_X11)
|
||||
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
|
||||
#include "SDL_x11video.h"
|
||||
|
||||
#include "SDL_x11vulkan.h"
|
||||
|
@ -23,11 +23,11 @@
|
||||
#ifndef SDL_x11vulkan_h_
|
||||
#define SDL_x11vulkan_h_
|
||||
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
#include <SDL3/SDL_vulkan.h>
|
||||
|
||||
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_X11)
|
||||
|
||||
/*typedef struct xcb_connection_t xcb_connection_t;*/
|
||||
typedef struct xcb_connection_t xcb_connection_t;
|
||||
typedef xcb_connection_t *(*PFN_XGetXCBConnection)(Display *dpy);
|
||||
|
||||
int X11_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user