Merge branch 'master' of git://github.com/Themaister/SSNES
This commit is contained in:
commit
657b4ce8c7
3
Makefile
3
Makefile
|
@ -40,7 +40,8 @@ endif
|
||||||
|
|
||||||
ifeq ($(HAVE_RSOUND), 1)
|
ifeq ($(HAVE_RSOUND), 1)
|
||||||
OBJ += audio/rsound.o
|
OBJ += audio/rsound.o
|
||||||
LIBS += -lrsound
|
LIBS += $(RSOUND_LIBS)
|
||||||
|
DEFINES += $(RSOUND_CFLAGS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_OSS), 1)
|
ifeq ($(HAVE_OSS), 1)
|
||||||
|
|
|
@ -13,6 +13,7 @@ HAVE_SDL_IMAGE = 1
|
||||||
HAVE_XML = 1
|
HAVE_XML = 1
|
||||||
HAVE_FREETYPE = 1
|
HAVE_FREETYPE = 1
|
||||||
HAVE_XAUDIO = 1
|
HAVE_XAUDIO = 1
|
||||||
|
HAVE_DSOUND = 1
|
||||||
HAVE_RSOUND = 1
|
HAVE_RSOUND = 1
|
||||||
HAVE_DYLIB = 1
|
HAVE_DYLIB = 1
|
||||||
HAVE_NETPLAY = 1
|
HAVE_NETPLAY = 1
|
||||||
|
@ -59,6 +60,12 @@ ifeq ($(HAVE_XAUDIO), 1)
|
||||||
DEFINES += -DHAVE_XAUDIO
|
DEFINES += -DHAVE_XAUDIO
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_DSOUND), 1)
|
||||||
|
OBJ += audio/dsound.o
|
||||||
|
DEFINES += -DHAVE_DSOUND
|
||||||
|
LIBS += -ldxguid -ldsound
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_RSOUND), 1)
|
ifeq ($(HAVE_RSOUND), 1)
|
||||||
OBJ += audio/rsound.o
|
OBJ += audio/rsound.o
|
||||||
DEFINES += -DHAVE_RSOUND
|
DEFINES += -DHAVE_RSOUND
|
||||||
|
@ -155,7 +162,7 @@ clean:
|
||||||
rm -f tools/*.o
|
rm -f tools/*.o
|
||||||
|
|
||||||
dist: all
|
dist: all
|
||||||
zip -r ssnes-win32-0.6.1.zip $(TARGET) ssnes.cfg snes.dll libxml2.dll iconv.dll zlib1.dll SDL.dll freetype6.dll xaudio-c.dll rsound.dll pthreadGC2.dll cg.dll cgGL.dll libjpeg-8.dll libpng15-15.dll python32.dll SDL_image.dll $(JTARGET)
|
zip -r ssnes-win32-0.6.2.zip $(TARGET) ssnes.cfg snes.dll libxml2.dll iconv.dll zlib1.dll SDL.dll freetype6.dll xaudio-c.dll rsound.dll pthreadGC2.dll cg.dll cgGL.dll libjpeg-8.dll libpng15-15.dll python32.dll SDL_image.dll $(JTARGET)
|
||||||
|
|
||||||
libs:
|
libs:
|
||||||
wget https://github.com/downloads/Themaister/SSNES/SSNES-win32-libs.zip --no-check-certificate
|
wget https://github.com/downloads/Themaister/SSNES/SSNES-win32-libs.zip --no-check-certificate
|
||||||
|
|
|
@ -12,6 +12,7 @@ HAVE_SDL = 1
|
||||||
HAVE_XML = 1
|
HAVE_XML = 1
|
||||||
HAVE_FREETYPE = 1
|
HAVE_FREETYPE = 1
|
||||||
HAVE_XAUDIO = 1
|
HAVE_XAUDIO = 1
|
||||||
|
HAVE_DSOUND = 1
|
||||||
HAVE_RSOUND = 0
|
HAVE_RSOUND = 0
|
||||||
HAVE_DYLIB = 1
|
HAVE_DYLIB = 1
|
||||||
HAVE_NETPLAY = 1
|
HAVE_NETPLAY = 1
|
||||||
|
@ -52,6 +53,12 @@ ifeq ($(HAVE_XAUDIO), 1)
|
||||||
DEFINES += -DHAVE_XAUDIO
|
DEFINES += -DHAVE_XAUDIO
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HAVE_DSOUND), 1)
|
||||||
|
OBJ += audio/dsound.o
|
||||||
|
DEFINES += -DHAVE_DSOUND
|
||||||
|
LIBS += -ldxguid -ldsound
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(HAVE_RSOUND), 1)
|
ifeq ($(HAVE_RSOUND), 1)
|
||||||
OBJ += audio/rsound.o
|
OBJ += audio/rsound.o
|
||||||
DEFINES += -DHAVE_RSOUND
|
DEFINES += -DHAVE_RSOUND
|
||||||
|
@ -142,7 +149,7 @@ clean:
|
||||||
rm -f tools/*.o
|
rm -f tools/*.o
|
||||||
|
|
||||||
dist: all
|
dist: all
|
||||||
zip -r ssnes-win64-0.6.1.zip $(TARGET) ssnes.cfg snes.dll xaudio-c.dll README.win32.txt $(JTARGET)
|
zip -r ssnes-win64-0.6.2.zip $(TARGET) ssnes.cfg snes.dll xaudio-c.dll README.win32.txt $(JTARGET)
|
||||||
|
|
||||||
libs:
|
libs:
|
||||||
wget https://github.com/downloads/Themaister/SSNES/ssnes-win64-libs.zip --no-check-certificate
|
wget https://github.com/downloads/Themaister/SSNES/ssnes-win64-libs.zip --no-check-certificate
|
||||||
|
|
|
@ -0,0 +1,387 @@
|
||||||
|
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
|
||||||
|
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
|
||||||
|
*
|
||||||
|
* Some code herein may be based on code found in BSNES.
|
||||||
|
*
|
||||||
|
* SSNES is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with SSNES.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "driver.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <dsound.h>
|
||||||
|
#include "fifo_buffer.h"
|
||||||
|
#include "general.h"
|
||||||
|
|
||||||
|
typedef struct dsound
|
||||||
|
{
|
||||||
|
LPDIRECTSOUND ds;
|
||||||
|
LPDIRECTSOUNDBUFFER dsb;
|
||||||
|
HANDLE event;
|
||||||
|
bool nonblock;
|
||||||
|
|
||||||
|
fifo_buffer_t *buffer;
|
||||||
|
CRITICAL_SECTION crit;
|
||||||
|
|
||||||
|
volatile bool thread_alive;
|
||||||
|
HANDLE thread;
|
||||||
|
unsigned buffer_size;
|
||||||
|
} dsound_t;
|
||||||
|
|
||||||
|
static inline unsigned write_avail(unsigned read_ptr, unsigned write_ptr, unsigned buffer_size)
|
||||||
|
{
|
||||||
|
return (read_ptr + buffer_size - write_ptr) % buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void get_positions(dsound_t *ds, DWORD *read_ptr, DWORD *write_ptr)
|
||||||
|
{
|
||||||
|
IDirectSoundBuffer_GetCurrentPosition(ds->dsb, read_ptr, write_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHUNK_SIZE 256
|
||||||
|
|
||||||
|
struct audio_lock
|
||||||
|
{
|
||||||
|
void *chunk1;
|
||||||
|
DWORD size1;
|
||||||
|
void *chunk2;
|
||||||
|
DWORD size2;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline bool grab_region(dsound_t *ds, DWORD write_ptr, struct audio_lock *region)
|
||||||
|
{
|
||||||
|
HRESULT res = IDirectSoundBuffer_Lock(ds->dsb, write_ptr, CHUNK_SIZE, ®ion->chunk1, ®ion->size1, ®ion->chunk2, ®ion->size2, 0);
|
||||||
|
if (res == DSERR_BUFFERLOST)
|
||||||
|
{
|
||||||
|
res = IDirectSoundBuffer_Restore(ds->dsb);
|
||||||
|
if (res != DS_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
res = IDirectSoundBuffer_Lock(ds->dsb, write_ptr, CHUNK_SIZE, ®ion->chunk1, ®ion->size1, ®ion->chunk2, ®ion->size2, 0);
|
||||||
|
if (res != DS_OK)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *err;
|
||||||
|
switch (res)
|
||||||
|
{
|
||||||
|
case DSERR_BUFFERLOST:
|
||||||
|
err = "DSERR_BUFFERLOST";
|
||||||
|
break;
|
||||||
|
case DSERR_INVALIDCALL:
|
||||||
|
err = "DSERR_INVALIDCALL";
|
||||||
|
break;
|
||||||
|
case DSERR_INVALIDPARAM:
|
||||||
|
err = "DSERR_INVALIDPARAM";
|
||||||
|
break;
|
||||||
|
case DSERR_PRIOLEVELNEEDED:
|
||||||
|
err = "DSERR_PRIOLEVELNEEDED";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
SSNES_WARN("[DirectSound error]: %s\n", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void release_region(dsound_t *ds, const struct audio_lock *region)
|
||||||
|
{
|
||||||
|
IDirectSoundBuffer_Unlock(ds->dsb, region->chunk1, region->size1, region->chunk2, region->size2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD CALLBACK dsound_thread(PVOID data)
|
||||||
|
{
|
||||||
|
dsound_t *ds = data;
|
||||||
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
||||||
|
|
||||||
|
DWORD write_ptr;
|
||||||
|
get_positions(ds, NULL, &write_ptr);
|
||||||
|
write_ptr = (write_ptr + ds->buffer_size / 2) % ds->buffer_size;
|
||||||
|
|
||||||
|
while (ds->thread_alive)
|
||||||
|
{
|
||||||
|
DWORD read_ptr;
|
||||||
|
get_positions(ds, &read_ptr, NULL);
|
||||||
|
|
||||||
|
DWORD avail = write_avail(read_ptr, write_ptr, ds->buffer_size);
|
||||||
|
|
||||||
|
EnterCriticalSection(&ds->crit);
|
||||||
|
DWORD fifo_avail = fifo_read_avail(ds->buffer);
|
||||||
|
LeaveCriticalSection(&ds->crit);
|
||||||
|
|
||||||
|
// No space to write, or we don't have data in our fifo, but we can wait some time before it underruns ...
|
||||||
|
if (avail < CHUNK_SIZE || ((fifo_avail < CHUNK_SIZE) && (avail < ds->buffer_size / 2)))
|
||||||
|
{
|
||||||
|
Sleep(1);
|
||||||
|
// We could opt for using the notification interface,
|
||||||
|
// but it is not guaranteed to work, so use high priority sleeping patterns. :(
|
||||||
|
}
|
||||||
|
else if (fifo_avail < CHUNK_SIZE) // Got space to write, but nothing in FIFO (underrun), fill block with silence.
|
||||||
|
{
|
||||||
|
struct audio_lock region;
|
||||||
|
if (!grab_region(ds, write_ptr, ®ion))
|
||||||
|
{
|
||||||
|
ds->thread_alive = false;
|
||||||
|
SetEvent(ds->event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(region.chunk1, 0, region.size1);
|
||||||
|
memset(region.chunk2, 0, region.size2);
|
||||||
|
|
||||||
|
release_region(ds, ®ion);
|
||||||
|
write_ptr = (write_ptr + region.size1 + region.size2) % ds->buffer_size;
|
||||||
|
}
|
||||||
|
else // All is good. Pull from it and notify FIFO :D
|
||||||
|
{
|
||||||
|
struct audio_lock region;
|
||||||
|
if (!grab_region(ds, write_ptr, ®ion))
|
||||||
|
{
|
||||||
|
ds->thread_alive = false;
|
||||||
|
SetEvent(ds->event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnterCriticalSection(&ds->crit);
|
||||||
|
if (region.chunk1)
|
||||||
|
fifo_read(ds->buffer, region.chunk1, region.size1);
|
||||||
|
if (region.chunk2)
|
||||||
|
fifo_read(ds->buffer, region.chunk2, region.size2);
|
||||||
|
LeaveCriticalSection(&ds->crit);
|
||||||
|
|
||||||
|
release_region(ds, ®ion);
|
||||||
|
write_ptr = (write_ptr + region.size1 + region.size2) % ds->buffer_size;
|
||||||
|
|
||||||
|
SetEvent(ds->event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitThread(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dsound_stop_thread(dsound_t *ds)
|
||||||
|
{
|
||||||
|
if (ds->thread)
|
||||||
|
{
|
||||||
|
ds->thread_alive = false;
|
||||||
|
WaitForSingleObject(ds->thread, INFINITE);
|
||||||
|
CloseHandle(ds->thread);
|
||||||
|
ds->thread = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dsound_start_thread(dsound_t *ds)
|
||||||
|
{
|
||||||
|
if (!ds->thread)
|
||||||
|
{
|
||||||
|
ds->thread_alive = true;
|
||||||
|
ds->thread = CreateThread(NULL, 0, dsound_thread, ds, 0, NULL);
|
||||||
|
if (ds->thread == NULL)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dsound_clear_buffer(dsound_t *ds)
|
||||||
|
{
|
||||||
|
IDirectSoundBuffer_SetCurrentPosition(ds->dsb, 0);
|
||||||
|
void *ptr;
|
||||||
|
DWORD size;
|
||||||
|
|
||||||
|
if (IDirectSoundBuffer_Lock(ds->dsb, 0, 0, &ptr, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER) == DS_OK)
|
||||||
|
{
|
||||||
|
memset(ptr, 0, size);
|
||||||
|
IDirectSoundBuffer_Unlock(ds->dsb, ptr, size, NULL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dsound_free(void *data)
|
||||||
|
{
|
||||||
|
dsound_t *ds = data;
|
||||||
|
if (ds)
|
||||||
|
{
|
||||||
|
if (ds->thread)
|
||||||
|
{
|
||||||
|
ds->thread_alive = false;
|
||||||
|
WaitForSingleObject(ds->thread, INFINITE);
|
||||||
|
CloseHandle(ds->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteCriticalSection(&ds->crit);
|
||||||
|
|
||||||
|
if (ds->dsb)
|
||||||
|
{
|
||||||
|
IDirectSoundBuffer_Stop(ds->dsb);
|
||||||
|
IDirectSoundBuffer_Release(ds->dsb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ds)
|
||||||
|
IDirectSound_Release(ds->ds);
|
||||||
|
|
||||||
|
if (ds->event)
|
||||||
|
CloseHandle(ds->event);
|
||||||
|
|
||||||
|
if (ds->buffer)
|
||||||
|
fifo_free(ds->buffer);
|
||||||
|
|
||||||
|
free(ds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* dsound_init(const char *device, unsigned rate, unsigned latency)
|
||||||
|
{
|
||||||
|
dsound_t *ds = calloc(1, sizeof(*ds));
|
||||||
|
if (!ds)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
InitializeCriticalSection(&ds->crit);
|
||||||
|
|
||||||
|
if (DirectSoundCreate(NULL, &ds->ds, NULL) != DS_OK)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (IDirectSound_SetCooperativeLevel(ds->ds, GetDesktopWindow(), DSSCL_PRIORITY) != DS_OK)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
WAVEFORMATEX wfx = {
|
||||||
|
.wFormatTag = WAVE_FORMAT_PCM,
|
||||||
|
.nChannels = 2,
|
||||||
|
.nSamplesPerSec = rate,
|
||||||
|
.wBitsPerSample = 16,
|
||||||
|
.nBlockAlign = 2 * sizeof(int16_t),
|
||||||
|
.nAvgBytesPerSec = rate * 2 * sizeof(int16_t),
|
||||||
|
};
|
||||||
|
|
||||||
|
ds->buffer_size = (latency * wfx.nAvgBytesPerSec) / 1000;
|
||||||
|
ds->buffer_size /= CHUNK_SIZE;
|
||||||
|
ds->buffer_size *= CHUNK_SIZE;
|
||||||
|
if (ds->buffer_size < 4 * CHUNK_SIZE)
|
||||||
|
ds->buffer_size = 4 * CHUNK_SIZE;
|
||||||
|
|
||||||
|
SSNES_LOG("[DirectSound]: Setting buffer size of %u bytes\n", ds->buffer_size);
|
||||||
|
SSNES_LOG("[DirectSound]: Latency = %u ms\n", (unsigned)((1000 * ds->buffer_size) / wfx.nAvgBytesPerSec));
|
||||||
|
|
||||||
|
DSBUFFERDESC bufdesc = {
|
||||||
|
.dwSize = sizeof(DSBUFFERDESC),
|
||||||
|
.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS,
|
||||||
|
.dwBufferBytes = ds->buffer_size,
|
||||||
|
.lpwfxFormat = &wfx,
|
||||||
|
};
|
||||||
|
|
||||||
|
ds->event = CreateEvent(NULL, false, false, NULL);
|
||||||
|
if (!ds->event)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ds->buffer = fifo_new(4 * 1024);
|
||||||
|
if (!ds->buffer)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (IDirectSound_CreateSoundBuffer(ds->ds, &bufdesc, &ds->dsb, 0) != DS_OK)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
IDirectSoundBuffer_SetCurrentPosition(ds->dsb, 0);
|
||||||
|
|
||||||
|
dsound_clear_buffer(ds);
|
||||||
|
|
||||||
|
if (IDirectSoundBuffer_Play(ds->dsb, 0, 0, DSBPLAY_LOOPING) != DS_OK)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!dsound_start_thread(ds))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return ds;
|
||||||
|
|
||||||
|
error:
|
||||||
|
SSNES_ERR("[DirectSound] Error occured in init!\n");
|
||||||
|
dsound_free(ds);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dsound_stop(void *data)
|
||||||
|
{
|
||||||
|
dsound_t *ds = data;
|
||||||
|
dsound_stop_thread(ds);
|
||||||
|
return IDirectSoundBuffer_Stop(ds->dsb) == DS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dsound_start(void *data)
|
||||||
|
{
|
||||||
|
dsound_t *ds = data;
|
||||||
|
dsound_clear_buffer(ds);
|
||||||
|
|
||||||
|
if (!dsound_start_thread(ds))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return IDirectSoundBuffer_Play(ds->dsb, 0, 0, DSBPLAY_LOOPING) == DS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dsound_set_nonblock_state(void *data, bool state)
|
||||||
|
{
|
||||||
|
dsound_t *ds = data;
|
||||||
|
ds->nonblock = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t dsound_write(void *data, const void *buf_, size_t size)
|
||||||
|
{
|
||||||
|
dsound_t *ds = data;
|
||||||
|
const uint8_t *buf = buf_;
|
||||||
|
|
||||||
|
if (!ds->thread_alive)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
size_t written = 0;
|
||||||
|
while (size > 0)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&ds->crit);
|
||||||
|
size_t avail = fifo_write_avail(ds->buffer);
|
||||||
|
if (avail > size)
|
||||||
|
avail = size;
|
||||||
|
|
||||||
|
fifo_write(ds->buffer, buf, avail);
|
||||||
|
LeaveCriticalSection(&ds->crit);
|
||||||
|
|
||||||
|
buf += avail;
|
||||||
|
size -= avail;
|
||||||
|
written += avail;
|
||||||
|
|
||||||
|
if (ds->nonblock || !ds->thread_alive)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (avail == 0)
|
||||||
|
WaitForSingleObject(ds->event, INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const audio_driver_t audio_dsound = {
|
||||||
|
.init = dsound_init,
|
||||||
|
.write = dsound_write,
|
||||||
|
.stop = dsound_stop,
|
||||||
|
.start = dsound_start,
|
||||||
|
.set_nonblock_state = dsound_set_nonblock_state,
|
||||||
|
.free = dsound_free,
|
||||||
|
.ident = "dsound"
|
||||||
|
};
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
|
#include "general.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#ifdef HAVE_OSS_BSD
|
#ifdef HAVE_OSS_BSD
|
||||||
|
@ -68,7 +69,8 @@ static void* __oss_init(const char* device, unsigned rate, unsigned latency)
|
||||||
}
|
}
|
||||||
|
|
||||||
int channels = 2;
|
int channels = 2;
|
||||||
int format = AFMT_S16_LE;
|
int format = is_little_endian() ?
|
||||||
|
AFMT_S16_LE : AFMT_S16_BE;
|
||||||
|
|
||||||
if (ioctl(*fd, SNDCTL_DSP_CHANNELS, &channels) < 0)
|
if (ioctl(*fd, SNDCTL_DSP_CHANNELS, &channels) < 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -59,18 +59,6 @@ static void __pulse_free(void *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t is_little_endian(void)
|
|
||||||
{
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint16_t x;
|
|
||||||
uint8_t y[2];
|
|
||||||
} u;
|
|
||||||
|
|
||||||
u.x = 1;
|
|
||||||
return u.y[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void context_state_cb(pa_context *c, void *data)
|
static void context_state_cb(pa_context *c, void *data)
|
||||||
{
|
{
|
||||||
pa_t *pa = data;
|
pa_t *pa = data;
|
||||||
|
|
|
@ -196,9 +196,4 @@ const audio_driver_t audio_sdl = {
|
||||||
.free = sdl_audio_free,
|
.free = sdl_audio_free,
|
||||||
.ident = "sdl"
|
.ident = "sdl"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
#define AUDIO_XAUDIO 9
|
#define AUDIO_XAUDIO 9
|
||||||
#define AUDIO_PULSE 10
|
#define AUDIO_PULSE 10
|
||||||
#define AUDIO_EXT 15
|
#define AUDIO_EXT 15
|
||||||
|
#define AUDIO_DSOUND 16
|
||||||
////////////////////////
|
////////////////////////
|
||||||
#define INPUT_SDL 7
|
#define INPUT_SDL 7
|
||||||
#define INPUT_X 12
|
#define INPUT_X 12
|
||||||
|
@ -84,6 +85,8 @@
|
||||||
#define AUDIO_DEFAULT_DRIVER AUDIO_JACK
|
#define AUDIO_DEFAULT_DRIVER AUDIO_JACK
|
||||||
#elif defined(HAVE_AL)
|
#elif defined(HAVE_AL)
|
||||||
#define AUDIO_DEFAULT_DRIVER AUDIO_AL
|
#define AUDIO_DEFAULT_DRIVER AUDIO_AL
|
||||||
|
#elif defined(HAVE_DSOUND)
|
||||||
|
#define AUDIO_DEFAULT_DRIVER AUDIO_DSOUND
|
||||||
#elif defined(HAVE_SDL)
|
#elif defined(HAVE_SDL)
|
||||||
#define AUDIO_DEFAULT_DRIVER AUDIO_SDL
|
#define AUDIO_DEFAULT_DRIVER AUDIO_SDL
|
||||||
#elif defined(HAVE_XAUDIO)
|
#elif defined(HAVE_XAUDIO)
|
||||||
|
@ -123,6 +126,9 @@ static const unsigned fullscreen_y = 0;
|
||||||
// Force 16-bit colors.
|
// Force 16-bit colors.
|
||||||
static const bool force_16bit = false;
|
static const bool force_16bit = false;
|
||||||
|
|
||||||
|
// Forcibly disable composition. Only valid on Windows Vista/7 for now.
|
||||||
|
static const bool disable_composition = false;
|
||||||
|
|
||||||
// Video VSYNC (recommended)
|
// Video VSYNC (recommended)
|
||||||
static const bool vsync = true;
|
static const bool vsync = true;
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,10 @@ Without this flag, the save state path will be inferred from the rom path name,
|
||||||
When rom is loaded from \fBstdin\fR, this flag is mandatory to define as no path can be inferred.
|
When rom is loaded from \fBstdin\fR, this flag is mandatory to define as no path can be inferred.
|
||||||
Do note that save states are bound to the libsnes implementation being used. Using a different libsnes could invalidate the save state file.
|
Do note that save states are bound to the libsnes implementation being used. Using a different libsnes could invalidate the save state file.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB--fullscreen, -f\fR
|
||||||
|
Always starts SSNES in fullscreen. Disregards settings in configuration file.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB--config PATH, -c PATH\fR
|
\fB--config PATH, -c PATH\fR
|
||||||
Sets the configuration file path. \fBssnes\fR will use this path to load the configuration file.
|
Sets the configuration file path. \fBssnes\fR will use this path to load the configuration file.
|
||||||
|
|
3
driver.c
3
driver.c
|
@ -53,6 +53,9 @@ static const audio_driver_t *audio_drivers[] = {
|
||||||
#ifdef HAVE_XAUDIO
|
#ifdef HAVE_XAUDIO
|
||||||
&audio_xa,
|
&audio_xa,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_DSOUND
|
||||||
|
&audio_dsound,
|
||||||
|
#endif
|
||||||
#ifdef HAVE_PULSE
|
#ifdef HAVE_PULSE
|
||||||
&audio_pulse,
|
&audio_pulse,
|
||||||
#endif
|
#endif
|
||||||
|
|
1
driver.h
1
driver.h
|
@ -158,6 +158,7 @@ extern const audio_driver_t audio_sdl;
|
||||||
extern const audio_driver_t audio_xa;
|
extern const audio_driver_t audio_xa;
|
||||||
extern const audio_driver_t audio_pulse;
|
extern const audio_driver_t audio_pulse;
|
||||||
extern const audio_driver_t audio_ext;
|
extern const audio_driver_t audio_ext;
|
||||||
|
extern const audio_driver_t audio_dsound;
|
||||||
extern const video_driver_t video_gl;
|
extern const video_driver_t video_gl;
|
||||||
extern const video_driver_t video_xvideo;
|
extern const video_driver_t video_xvideo;
|
||||||
extern const video_driver_t video_sdl;
|
extern const video_driver_t video_sdl;
|
||||||
|
|
14
general.h
14
general.h
|
@ -89,6 +89,7 @@ struct settings
|
||||||
float msg_pos_y;
|
float msg_pos_y;
|
||||||
|
|
||||||
bool force_16bit;
|
bool force_16bit;
|
||||||
|
bool disable_composition;
|
||||||
|
|
||||||
char external_driver[256];
|
char external_driver[256];
|
||||||
} video;
|
} video;
|
||||||
|
@ -147,6 +148,7 @@ struct global
|
||||||
bool verbose;
|
bool verbose;
|
||||||
bool audio_active;
|
bool audio_active;
|
||||||
bool video_active;
|
bool video_active;
|
||||||
|
bool force_fullscreen;
|
||||||
|
|
||||||
bool has_mouse[2];
|
bool has_mouse[2];
|
||||||
bool has_scope[2];
|
bool has_scope[2];
|
||||||
|
@ -304,6 +306,18 @@ static inline uint32_t next_pow2(uint32_t v)
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint8_t is_little_endian(void)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint16_t x;
|
||||||
|
uint8_t y[2];
|
||||||
|
} u;
|
||||||
|
|
||||||
|
u.x = 1;
|
||||||
|
return u.y[0];
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
13
gfx/ext.c
13
gfx/ext.c
|
@ -224,6 +224,15 @@ static bool setup_video(ext_t *ext, const video_info_t *video, const input_drive
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *cg_shader = NULL;
|
||||||
|
const char *xml_shader = NULL;
|
||||||
|
enum ssnes_shader_type type = g_settings.video.shader_type;
|
||||||
|
if ((type == SSNES_SHADER_CG || type == SSNES_SHADER_AUTO) && *g_settings.video.cg_shader_path)
|
||||||
|
cg_shader = g_settings.video.cg_shader_path;
|
||||||
|
else if ((type == SSNES_SHADER_BSNES || type == SSNES_SHADER_AUTO) && *g_settings.video.bsnes_shader_path)
|
||||||
|
xml_shader = g_settings.video.bsnes_shader_path;
|
||||||
|
|
||||||
|
|
||||||
ssnes_video_info_t info = {
|
ssnes_video_info_t info = {
|
||||||
.width = video->width,
|
.width = video->width,
|
||||||
.height = video->height,
|
.height = video->height,
|
||||||
|
@ -234,8 +243,8 @@ static bool setup_video(ext_t *ext, const video_info_t *video, const input_drive
|
||||||
.smooth = video->smooth,
|
.smooth = video->smooth,
|
||||||
.input_scale = video->input_scale,
|
.input_scale = video->input_scale,
|
||||||
.color_format = video->rgb32 ? SSNES_COLOR_FORMAT_ARGB8888 : SSNES_COLOR_FORMAT_XRGB1555,
|
.color_format = video->rgb32 ? SSNES_COLOR_FORMAT_ARGB8888 : SSNES_COLOR_FORMAT_XRGB1555,
|
||||||
.xml_shader = g_settings.video.bsnes_shader_path,
|
.xml_shader = xml_shader,
|
||||||
.cg_shader = g_settings.video.cg_shader_path,
|
.cg_shader = cg_shader,
|
||||||
.ttf_font = *g_settings.video.font_path ? g_settings.video.font_path : NULL,
|
.ttf_font = *g_settings.video.font_path ? g_settings.video.font_path : NULL,
|
||||||
.ttf_font_size = g_settings.video.font_size
|
.ttf_font_size = g_settings.video.font_size
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,21 +25,26 @@ static float tv_to_fps(const struct timeval *tv, const struct timeval *new_tv, i
|
||||||
return frames/time;
|
return frames/time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned gl_frames = 0;
|
||||||
|
|
||||||
|
void gfx_window_title_reset(void)
|
||||||
|
{
|
||||||
|
gl_frames = 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool gfx_window_title(char *buf, size_t size)
|
bool gfx_window_title(char *buf, size_t size)
|
||||||
{
|
{
|
||||||
static int frames = 0;
|
|
||||||
static struct timeval tv;
|
static struct timeval tv;
|
||||||
struct timeval new_tv;
|
struct timeval new_tv;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
if (frames == 0)
|
if (gl_frames == 0)
|
||||||
{
|
{
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
snprintf(buf, size, "%s", g_extern.title_buf);
|
snprintf(buf, size, "%s", g_extern.title_buf);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
else if ((gl_frames % 180) == 0)
|
||||||
if ((frames % 180) == 0 && frames > 0)
|
|
||||||
{
|
{
|
||||||
gettimeofday(&new_tv, NULL);
|
gettimeofday(&new_tv, NULL);
|
||||||
struct timeval tmp_tv = tv;
|
struct timeval tmp_tv = tv;
|
||||||
|
@ -47,12 +52,64 @@ bool gfx_window_title(char *buf, size_t size)
|
||||||
|
|
||||||
float fps = tv_to_fps(&tmp_tv, &new_tv, 180);
|
float fps = tv_to_fps(&tmp_tv, &new_tv, 180);
|
||||||
|
|
||||||
snprintf(buf, size, "%s || FPS: %6.1f || Frames: %d", g_extern.title_buf, fps, frames);
|
snprintf(buf, size, "%s || FPS: %6.1f || Frames: %d", g_extern.title_buf, fps, gl_frames);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
frames++;
|
gl_frames++;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include "dynamic.h"
|
||||||
|
// We only load this library once, so we let it be unloaded at application shutdown,
|
||||||
|
// since unloading it early seems to cause issues on some systems.
|
||||||
|
|
||||||
|
static dylib_t dwmlib = NULL;
|
||||||
|
|
||||||
|
static void gfx_dwm_shutdown(void)
|
||||||
|
{
|
||||||
|
if (dwmlib)
|
||||||
|
dylib_close(dwmlib);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gfx_set_dwm(void)
|
||||||
|
{
|
||||||
|
static bool inited = false;
|
||||||
|
if (inited)
|
||||||
|
return;
|
||||||
|
inited = true;
|
||||||
|
|
||||||
|
dwmlib = dylib_load("dwmapi.dll");
|
||||||
|
if (!dwmlib)
|
||||||
|
{
|
||||||
|
SSNES_LOG("Did not find dwmapi.dll");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
atexit(gfx_dwm_shutdown);
|
||||||
|
|
||||||
|
HRESULT (WINAPI *mmcss)(BOOL) = (HRESULT (WINAPI*)(BOOL))dylib_proc(dwmlib, "DwmEnableMMCSS");
|
||||||
|
if (mmcss)
|
||||||
|
{
|
||||||
|
SSNES_LOG("Setting multimedia scheduling for DWM.\n");
|
||||||
|
mmcss(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_settings.video.disable_composition)
|
||||||
|
return;
|
||||||
|
|
||||||
|
HRESULT (WINAPI *composition_enable)(UINT) = (HRESULT (WINAPI*)(UINT))dylib_proc(dwmlib, "DwmEnableComposition");
|
||||||
|
if (!composition_enable)
|
||||||
|
{
|
||||||
|
SSNES_ERR("Did not find DwmEnableComposition ...\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT ret = composition_enable(0);
|
||||||
|
if (FAILED(ret))
|
||||||
|
SSNES_ERR("Failed to set composition state ...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -22,5 +22,10 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
bool gfx_window_title(char *buf, size_t size);
|
bool gfx_window_title(char *buf, size_t size);
|
||||||
|
void gfx_window_title_reset(void);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
void gfx_set_dwm(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
117
gfx/gl.c
117
gfx/gl.c
|
@ -125,7 +125,9 @@ static inline bool load_gl_proc(void) { return true; }
|
||||||
typedef struct gl
|
typedef struct gl
|
||||||
{
|
{
|
||||||
bool vsync;
|
bool vsync;
|
||||||
GLuint texture;
|
GLuint texture[2];
|
||||||
|
unsigned tex_index; // For use with PREV.
|
||||||
|
struct gl_tex_info prev_info;
|
||||||
GLuint tex_filter;
|
GLuint tex_filter;
|
||||||
|
|
||||||
void *empty_buf;
|
void *empty_buf;
|
||||||
|
@ -153,8 +155,8 @@ typedef struct gl
|
||||||
unsigned win_height;
|
unsigned win_height;
|
||||||
unsigned vp_width, vp_out_width;
|
unsigned vp_width, vp_out_width;
|
||||||
unsigned vp_height, vp_out_height;
|
unsigned vp_height, vp_out_height;
|
||||||
unsigned last_width;
|
unsigned last_width[2];
|
||||||
unsigned last_height;
|
unsigned last_height[2];
|
||||||
unsigned tex_w, tex_h;
|
unsigned tex_w, tex_h;
|
||||||
GLfloat tex_coords[8];
|
GLfloat tex_coords[8];
|
||||||
#ifdef HAVE_FBO
|
#ifdef HAVE_FBO
|
||||||
|
@ -255,20 +257,21 @@ static void gl_shader_set_params(unsigned width, unsigned height,
|
||||||
unsigned out_width, unsigned out_height,
|
unsigned out_width, unsigned out_height,
|
||||||
unsigned frame_count,
|
unsigned frame_count,
|
||||||
const struct gl_tex_info *info,
|
const struct gl_tex_info *info,
|
||||||
|
const struct gl_tex_info *prev_info,
|
||||||
const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt)
|
const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_CG
|
#ifdef HAVE_CG
|
||||||
gl_cg_set_params(width, height,
|
gl_cg_set_params(width, height,
|
||||||
tex_width, tex_height,
|
tex_width, tex_height,
|
||||||
out_width, out_height,
|
out_width, out_height,
|
||||||
frame_count, info, fbo_info, fbo_info_cnt);
|
frame_count, info, prev_info, fbo_info, fbo_info_cnt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_XML
|
#ifdef HAVE_XML
|
||||||
gl_glsl_set_params(width, height,
|
gl_glsl_set_params(width, height,
|
||||||
tex_width, tex_height,
|
tex_width, tex_height,
|
||||||
out_width, out_height,
|
out_width, out_height,
|
||||||
frame_count, info, fbo_info, fbo_info_cnt);
|
frame_count, info, prev_info, fbo_info, fbo_info_cnt);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +341,7 @@ static inline void gl_init_font(gl_t *gl, const char *font_path, unsigned font_s
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glBindTexture(GL_TEXTURE_2D, gl->texture);
|
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SSNES_WARN("Couldn't init font renderer with font \"%s\"...\n", font_path);
|
SSNES_WARN("Couldn't init font renderer with font \"%s\"...\n", font_path);
|
||||||
|
@ -653,7 +656,7 @@ static void gl_render_msg(gl_t *gl, const char *msg)
|
||||||
// Go back to old rendering path.
|
// Go back to old rendering path.
|
||||||
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->tex_coords);
|
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->tex_coords);
|
||||||
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes_flipped);
|
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes_flipped);
|
||||||
glBindTexture(GL_TEXTURE_2D, gl->texture);
|
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -712,6 +715,10 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
|
||||||
gl_shader_use(1);
|
gl_shader_use(1);
|
||||||
gl->frame_count++;
|
gl->frame_count++;
|
||||||
|
|
||||||
|
#if defined(HAVE_XML) || defined(HAVE_CG)
|
||||||
|
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_FBO
|
#ifdef HAVE_FBO
|
||||||
// Render to texture in first pass.
|
// Render to texture in first pass.
|
||||||
if (gl->fbo_inited)
|
if (gl->fbo_inited)
|
||||||
|
@ -767,7 +774,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
|
||||||
last_max_height = gl->fbo_rect[i].max_img_height;
|
last_max_height = gl->fbo_rect[i].max_img_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, gl->texture);
|
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
|
||||||
pglBindFramebuffer(GL_FRAMEBUFFER, gl->fbo[0]);
|
pglBindFramebuffer(GL_FRAMEBUFFER, gl->fbo[0]);
|
||||||
gl->render_to_tex = true;
|
gl->render_to_tex = true;
|
||||||
set_viewport(gl, gl->fbo_rect[0].img_width, gl->fbo_rect[0].img_height, true);
|
set_viewport(gl, gl->fbo_rect[0].img_width, gl->fbo_rect[0].img_height, true);
|
||||||
|
@ -814,7 +821,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go back to what we're supposed to do, render to FBO #0 :D
|
// Go back to what we're supposed to do, render to FBO #0 :D
|
||||||
glBindTexture(GL_TEXTURE_2D, gl->texture);
|
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
|
||||||
pglBindFramebuffer(GL_FRAMEBUFFER, gl->fbo[0]);
|
pglBindFramebuffer(GL_FRAMEBUFFER, gl->fbo[0]);
|
||||||
set_viewport(gl, gl->fbo_rect[0].img_width, gl->fbo_rect[0].img_height, true);
|
set_viewport(gl, gl->fbo_rect[0].img_width, gl->fbo_rect[0].img_height, true);
|
||||||
}
|
}
|
||||||
|
@ -823,10 +830,10 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((width != gl->last_width || height != gl->last_height) && gl->empty_buf) // Res change. need to clear out texture.
|
if ((width != gl->last_width[gl->tex_index] || height != gl->last_height[gl->tex_index]) && gl->empty_buf) // Res change. need to clear out texture.
|
||||||
{
|
{
|
||||||
gl->last_width = width;
|
gl->last_width[gl->tex_index] = width;
|
||||||
gl->last_height = height;
|
gl->last_height[gl->tex_index] = height;
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(pitch));
|
glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(pitch));
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, gl->tex_w);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, gl->tex_w);
|
||||||
|
|
||||||
|
@ -839,13 +846,13 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
|
||||||
|
|
||||||
set_texture_coords(gl->tex_coords, xamt, yamt);
|
set_texture_coords(gl->tex_coords, xamt, yamt);
|
||||||
}
|
}
|
||||||
|
#if defined(HAVE_XML) || defined(HAVE_CG)
|
||||||
// Work around a certain issue a Cg where not using TEXUNIT0
|
else if (width != gl->last_width[1 - gl->tex_index] || height != gl->last_height[1 - gl->tex_index])
|
||||||
// in shader causes cgGLEnableTextureParameter() causes it
|
{
|
||||||
// to bind to TEXUNIT0, to avoid really funny bugs, rebind
|
GLfloat xamt = (GLfloat)width / gl->tex_w;
|
||||||
// our texture.
|
GLfloat yamt = (GLfloat)height / gl->tex_h;
|
||||||
#ifdef HAVE_CG
|
set_texture_coords(gl->tex_coords, xamt, yamt);
|
||||||
glBindTexture(GL_TEXTURE_2D, gl->texture);
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_FBO
|
#ifdef HAVE_FBO
|
||||||
|
@ -861,7 +868,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
|
||||||
gl->texture_fmt, frame);
|
gl->texture_fmt, frame);
|
||||||
|
|
||||||
struct gl_tex_info tex_info = {
|
struct gl_tex_info tex_info = {
|
||||||
.tex = gl->texture,
|
.tex = gl->texture[gl->tex_index],
|
||||||
.input_size = {width, height},
|
.input_size = {width, height},
|
||||||
.tex_size = {gl->tex_w, gl->tex_h}
|
.tex_size = {gl->tex_w, gl->tex_h}
|
||||||
};
|
};
|
||||||
|
@ -871,7 +878,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
gl_shader_set_params(width, height, gl->tex_w, gl->tex_h, gl->vp_width, gl->vp_height, gl->frame_count,
|
gl_shader_set_params(width, height, gl->tex_w, gl->tex_h, gl->vp_width, gl->vp_height, gl->frame_count,
|
||||||
&tex_info, fbo_tex_info, fbo_tex_info_cnt);
|
&tex_info, &gl->prev_info, fbo_tex_info, fbo_tex_info_cnt);
|
||||||
|
|
||||||
glDrawArrays(GL_QUADS, 0, 4);
|
glDrawArrays(GL_QUADS, 0, 4);
|
||||||
|
|
||||||
|
@ -916,7 +923,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
|
||||||
gl_shader_set_params(prev_rect->img_width, prev_rect->img_height,
|
gl_shader_set_params(prev_rect->img_width, prev_rect->img_height,
|
||||||
prev_rect->width, prev_rect->height,
|
prev_rect->width, prev_rect->height,
|
||||||
gl->vp_width, gl->vp_height, gl->frame_count,
|
gl->vp_width, gl->vp_height, gl->frame_count,
|
||||||
&tex_info, fbo_tex_info, fbo_tex_info_cnt);
|
&tex_info, &gl->prev_info, fbo_tex_info, fbo_tex_info_cnt);
|
||||||
|
|
||||||
glDrawArrays(GL_QUADS, 0, 4);
|
glDrawArrays(GL_QUADS, 0, 4);
|
||||||
|
|
||||||
|
@ -942,7 +949,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
|
||||||
gl_shader_set_params(prev_rect->img_width, prev_rect->img_height,
|
gl_shader_set_params(prev_rect->img_width, prev_rect->img_height,
|
||||||
prev_rect->width, prev_rect->height,
|
prev_rect->width, prev_rect->height,
|
||||||
gl->vp_width, gl->vp_height, gl->frame_count,
|
gl->vp_width, gl->vp_height, gl->frame_count,
|
||||||
&tex_info, fbo_tex_info, fbo_tex_info_cnt);
|
&tex_info, &gl->prev_info, fbo_tex_info, fbo_tex_info_cnt);
|
||||||
|
|
||||||
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes_flipped);
|
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes_flipped);
|
||||||
glDrawArrays(GL_QUADS, 0, 4);
|
glDrawArrays(GL_QUADS, 0, 4);
|
||||||
|
@ -951,6 +958,11 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_XML) || defined(HAVE_CG)
|
||||||
|
memcpy(&gl->prev_info, &tex_info, sizeof(tex_info));
|
||||||
|
gl->tex_index = 1 - gl->tex_index;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (msg)
|
if (msg)
|
||||||
gl_render_msg(gl, msg);
|
gl_render_msg(gl, msg);
|
||||||
|
|
||||||
|
@ -970,7 +982,7 @@ static void gl_free(void *data)
|
||||||
gl_shader_deinit();
|
gl_shader_deinit();
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
glDeleteTextures(1, &gl->texture);
|
glDeleteTextures(2, gl->texture);
|
||||||
|
|
||||||
#ifdef HAVE_FBO
|
#ifdef HAVE_FBO
|
||||||
if (gl->fbo_inited)
|
if (gl->fbo_inited)
|
||||||
|
@ -1024,6 +1036,10 @@ static void gl_set_nonblock_state(void *data, bool state)
|
||||||
|
|
||||||
static void* gl_init(const video_info_t *video, const input_driver_t **input, void **input_data)
|
static void* gl_init(const video_info_t *video, const input_driver_t **input, void **input_data)
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
gfx_set_dwm();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1039,6 +1055,11 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
|
||||||
if (!SDL_SetVideoMode(video->width, video->height, g_settings.video.force_16bit ? 16 : 0, SDL_OPENGL | SDL_RESIZABLE | (video->fullscreen ? SDL_FULLSCREEN : 0)))
|
if (!SDL_SetVideoMode(video->width, video->height, g_settings.video.force_16bit ? 16 : 0, SDL_OPENGL | SDL_RESIZABLE | (video->fullscreen ? SDL_FULLSCREEN : 0)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
gfx_window_title_reset();
|
||||||
|
char buf[128];
|
||||||
|
if (gfx_window_title(buf, sizeof(buf)))
|
||||||
|
SDL_WM_SetCaption(buf, NULL);
|
||||||
|
|
||||||
// Remove that ugly mouse :D
|
// Remove that ugly mouse :D
|
||||||
SDL_ShowCursor(SDL_DISABLE);
|
SDL_ShowCursor(SDL_DISABLE);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
@ -1126,22 +1147,21 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
|
||||||
glColor4f(1, 1, 1, 1);
|
glColor4f(1, 1, 1, 1);
|
||||||
glClearColor(0, 0, 0, 1);
|
glClearColor(0, 0, 0, 1);
|
||||||
|
|
||||||
char buf[128];
|
|
||||||
if (gfx_window_title(buf, sizeof(buf)))
|
|
||||||
SDL_WM_SetCaption(buf, NULL);
|
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
|
||||||
glGenTextures(1, &gl->texture);
|
glGenTextures(2, gl->texture);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, gl->texture);
|
for (unsigned i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, gl->texture[i]);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl->tex_filter);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl->tex_filter);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl->tex_filter);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl->tex_filter);
|
||||||
|
}
|
||||||
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
@ -1155,15 +1175,30 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
|
||||||
gl->tex_w = 256 * video->input_scale;
|
gl->tex_w = 256 * video->input_scale;
|
||||||
gl->tex_h = 256 * video->input_scale;
|
gl->tex_h = 256 * video->input_scale;
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D,
|
|
||||||
0, GL_RGBA, gl->tex_w, gl->tex_h, 0, gl->texture_type,
|
|
||||||
gl->texture_fmt, NULL);
|
|
||||||
|
|
||||||
// Empty buffer that we use to clear out the texture with on res change.
|
// Empty buffer that we use to clear out the texture with on res change.
|
||||||
gl->empty_buf = calloc(gl->base_size, gl->tex_w * gl->tex_h);
|
gl->empty_buf = calloc(gl->base_size, gl->tex_w * gl->tex_h);
|
||||||
|
|
||||||
gl->last_width = gl->tex_w;
|
for (unsigned i = 0; i < 2; i++)
|
||||||
gl->last_height = gl->tex_h;
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, gl->texture[i]);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D,
|
||||||
|
0, GL_RGBA, gl->tex_w, gl->tex_h, 0, gl->texture_type,
|
||||||
|
gl->texture_fmt, gl->empty_buf ? gl->empty_buf : NULL);
|
||||||
|
}
|
||||||
|
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
gl->last_width[i] = gl->tex_w;
|
||||||
|
gl->last_height[i] = gl->tex_h;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl->prev_info.tex = gl->texture[1 - gl->tex_index];
|
||||||
|
gl->prev_info.input_size[0] = gl->tex_w;
|
||||||
|
gl->prev_info.tex_size[0] = gl->tex_w;
|
||||||
|
gl->prev_info.input_size[1] = gl->tex_h;
|
||||||
|
gl->prev_info.tex_size[1] = gl->tex_h;
|
||||||
|
memcpy(gl->prev_info.coord, tex_coords, sizeof(tex_coords));
|
||||||
|
|
||||||
// Hook up SDL input driver to get SDL_QUIT events and RESIZE.
|
// Hook up SDL input driver to get SDL_QUIT events and RESIZE.
|
||||||
sdl_input_t *sdl_input = input_sdl.init();
|
sdl_input_t *sdl_input = input_sdl.init();
|
||||||
|
@ -1222,7 +1257,7 @@ static bool gl_xml_shader(void *data, const char *path)
|
||||||
gl->render_to_tex = false;
|
gl->render_to_tex = false;
|
||||||
gl->fbo_pass = 0;
|
gl->fbo_pass = 0;
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, gl->texture);
|
glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -101,9 +101,9 @@ struct gl_fbo_scale
|
||||||
struct gl_tex_info
|
struct gl_tex_info
|
||||||
{
|
{
|
||||||
GLuint tex;
|
GLuint tex;
|
||||||
float input_size[2];
|
GLfloat input_size[2];
|
||||||
float tex_size[2];
|
GLfloat tex_size[2];
|
||||||
float coord[8];
|
GLfloat coord[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Not legal to cast void* to fn-pointer. Need dirty hack to be compilant.
|
// Not legal to cast void* to fn-pointer. Need dirty hack to be compilant.
|
||||||
|
|
|
@ -36,18 +36,15 @@ static const char* stock_cg_program =
|
||||||
"void main_vertex"
|
"void main_vertex"
|
||||||
"("
|
"("
|
||||||
" float4 position : POSITION,"
|
" float4 position : POSITION,"
|
||||||
" float4 color : COLOR,"
|
|
||||||
" float2 texCoord : TEXCOORD0,"
|
" float2 texCoord : TEXCOORD0,"
|
||||||
""
|
""
|
||||||
" uniform float4x4 modelViewProj,"
|
" uniform float4x4 modelViewProj,"
|
||||||
""
|
""
|
||||||
" out float4 oPosition : POSITION,"
|
" out float4 oPosition : POSITION,"
|
||||||
" out float4 oColor : COLOR,"
|
|
||||||
" out float2 otexCoord : TEXCOORD0"
|
" out float2 otexCoord : TEXCOORD0"
|
||||||
")"
|
")"
|
||||||
"{"
|
"{"
|
||||||
" oPosition = mul(modelViewProj, position);"
|
" oPosition = mul(modelViewProj, position);"
|
||||||
" oColor = color;"
|
|
||||||
" otexCoord = texCoord;"
|
" otexCoord = texCoord;"
|
||||||
"}"
|
"}"
|
||||||
""
|
""
|
||||||
|
@ -112,6 +109,7 @@ struct cg_program
|
||||||
|
|
||||||
struct cg_fbo_params fbo[MAX_SHADERS];
|
struct cg_fbo_params fbo[MAX_SHADERS];
|
||||||
struct cg_fbo_params orig;
|
struct cg_fbo_params orig;
|
||||||
|
struct cg_fbo_params prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FILTER_UNSPEC 0
|
#define FILTER_UNSPEC 0
|
||||||
|
@ -148,6 +146,7 @@ void gl_cg_set_params(unsigned width, unsigned height,
|
||||||
unsigned out_width, unsigned out_height,
|
unsigned out_width, unsigned out_height,
|
||||||
unsigned frame_count,
|
unsigned frame_count,
|
||||||
const struct gl_tex_info *info,
|
const struct gl_tex_info *info,
|
||||||
|
const struct gl_tex_info *prev_info,
|
||||||
const struct gl_tex_info *fbo_info,
|
const struct gl_tex_info *fbo_info,
|
||||||
unsigned fbo_info_cnt)
|
unsigned fbo_info_cnt)
|
||||||
{
|
{
|
||||||
|
@ -169,7 +168,6 @@ void gl_cg_set_params(unsigned width, unsigned height,
|
||||||
if (param)
|
if (param)
|
||||||
{
|
{
|
||||||
cgGLSetTextureParameter(param, info->tex);
|
cgGLSetTextureParameter(param, info->tex);
|
||||||
//fprintf(stderr, "ORIGtex = (%d) %d\n", cgGLGetTextureParameter(param), cgGLGetTextureEnum(param) - GL_TEXTURE0);
|
|
||||||
cgGLEnableTextureParameter(param);
|
cgGLEnableTextureParameter(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,6 +181,24 @@ void gl_cg_set_params(unsigned width, unsigned height,
|
||||||
cgGLEnableClientState(prg[active_index].orig.coord);
|
cgGLEnableClientState(prg[active_index].orig.coord);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set prev texture
|
||||||
|
param = prg[active_index].prev.tex;
|
||||||
|
if (param)
|
||||||
|
{
|
||||||
|
cgGLSetTextureParameter(param, prev_info->tex);
|
||||||
|
cgGLEnableTextureParameter(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_param_2f(prg[active_index].prev.vid_size_v, prev_info->input_size[0], prev_info->input_size[1]);
|
||||||
|
set_param_2f(prg[active_index].prev.vid_size_f, prev_info->input_size[0], prev_info->input_size[1]);
|
||||||
|
set_param_2f(prg[active_index].prev.tex_size_v, prev_info->tex_size[0], prev_info->tex_size[1]);
|
||||||
|
set_param_2f(prg[active_index].prev.tex_size_f, prev_info->tex_size[0], prev_info->tex_size[1]);
|
||||||
|
if (prg[active_index].prev.coord)
|
||||||
|
{
|
||||||
|
cgGLSetParameterPointer(prg[active_index].prev.coord, 2, GL_FLOAT, 0, prev_info->coord);
|
||||||
|
cgGLEnableClientState(prg[active_index].prev.coord);
|
||||||
|
}
|
||||||
|
|
||||||
// Set lookup textures.
|
// Set lookup textures.
|
||||||
for (unsigned i = 0; i < lut_textures_num; i++)
|
for (unsigned i = 0; i < lut_textures_num; i++)
|
||||||
{
|
{
|
||||||
|
@ -191,7 +207,6 @@ void gl_cg_set_params(unsigned width, unsigned height,
|
||||||
{
|
{
|
||||||
cgGLSetTextureParameter(param, lut_textures[i]);
|
cgGLSetTextureParameter(param, lut_textures[i]);
|
||||||
cgGLEnableTextureParameter(param);
|
cgGLEnableTextureParameter(param);
|
||||||
//fprintf(stderr, "LUTtex = (%d) %d\n", cgGLGetTextureParameter(param), cgGLGetTextureEnum(param) - GL_TEXTURE0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,16 +288,31 @@ static bool load_plain(const char *path)
|
||||||
if (strlen(g_settings.video.second_pass_shader) > 0)
|
if (strlen(g_settings.video.second_pass_shader) > 0)
|
||||||
SSNES_LOG("Loading 2nd pass: %s\n", g_settings.video.second_pass_shader);
|
SSNES_LOG("Loading 2nd pass: %s\n", g_settings.video.second_pass_shader);
|
||||||
|
|
||||||
|
char *listing[3] = {NULL};
|
||||||
|
const char *list = NULL;
|
||||||
|
|
||||||
prg[0].fprg = cgCreateProgram(cgCtx, CG_SOURCE, stock_cg_program, cgFProf, "main_fragment", 0);
|
prg[0].fprg = cgCreateProgram(cgCtx, CG_SOURCE, stock_cg_program, cgFProf, "main_fragment", 0);
|
||||||
prg[0].vprg = cgCreateProgram(cgCtx, CG_SOURCE, stock_cg_program, cgVProf, "main_vertex", 0);
|
prg[0].vprg = cgCreateProgram(cgCtx, CG_SOURCE, stock_cg_program, cgVProf, "main_vertex", 0);
|
||||||
|
|
||||||
|
list = cgGetLastListing(cgCtx);
|
||||||
|
if (list)
|
||||||
|
listing[0] = strdup(list);
|
||||||
|
|
||||||
prg[1].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path, cgFProf, "main_fragment", 0);
|
prg[1].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path, cgFProf, "main_fragment", 0);
|
||||||
prg[1].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path, cgVProf, "main_vertex", 0);
|
prg[1].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, path, cgVProf, "main_vertex", 0);
|
||||||
|
|
||||||
|
list = cgGetLastListing(cgCtx);
|
||||||
|
if (list)
|
||||||
|
listing[1] = strdup(list);
|
||||||
|
|
||||||
if (strlen(g_settings.video.second_pass_shader) > 0)
|
if (strlen(g_settings.video.second_pass_shader) > 0)
|
||||||
{
|
{
|
||||||
prg[2].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, g_settings.video.second_pass_shader, cgFProf, "main_fragment", 0);
|
prg[2].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, g_settings.video.second_pass_shader, cgFProf, "main_fragment", 0);
|
||||||
prg[2].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, g_settings.video.second_pass_shader, cgVProf, "main_vertex", 0);
|
prg[2].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, g_settings.video.second_pass_shader, cgVProf, "main_vertex", 0);
|
||||||
|
|
||||||
|
list = cgGetLastListing(cgCtx);
|
||||||
|
if (list)
|
||||||
|
listing[2] = strdup(list);
|
||||||
cg_shader_num = 2;
|
cg_shader_num = 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -291,13 +321,15 @@ static bool load_plain(const char *path)
|
||||||
cg_shader_num = 1;
|
cg_shader_num = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < cg_shader_num + 1; i++)
|
for (unsigned i = 0; i <= cg_shader_num; i++)
|
||||||
{
|
{
|
||||||
if (!prg[i].fprg || !prg[i].vprg)
|
if (!prg[i].fprg || !prg[i].vprg)
|
||||||
{
|
{
|
||||||
CGerror err = cgGetError();
|
CGerror err = cgGetError();
|
||||||
SSNES_ERR("CG error: %s\n", cgGetErrorString(err));
|
SSNES_ERR("CG error: %s\n", cgGetErrorString(err));
|
||||||
return false;
|
if (listing[i])
|
||||||
|
SSNES_ERR("%s\n", listing[i]);
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
cgGLLoadProgram(prg[i].fprg);
|
cgGLLoadProgram(prg[i].fprg);
|
||||||
|
@ -305,6 +337,14 @@ static bool load_plain(const char *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
for (unsigned i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if (listing[i])
|
||||||
|
free(listing[i]);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define print_buf(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
|
#define print_buf(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
|
||||||
|
@ -802,8 +842,11 @@ static bool load_preset(const char *path)
|
||||||
|
|
||||||
if (!prog->fprg || !prog->vprg)
|
if (!prog->fprg || !prog->vprg)
|
||||||
{
|
{
|
||||||
|
const char *listing = cgGetLastListing(cgCtx);
|
||||||
CGerror err = cgGetError();
|
CGerror err = cgGetError();
|
||||||
SSNES_ERR("CG error: %s\n", cgGetErrorString(err));
|
SSNES_ERR("CG error: %s\n", cgGetErrorString(err));
|
||||||
|
if (listing)
|
||||||
|
SSNES_ERR("%s\n", listing);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -878,7 +921,7 @@ bool gl_cg_init(const char *path)
|
||||||
if (prg[0].mvp)
|
if (prg[0].mvp)
|
||||||
cgGLSetStateMatrixParameter(prg[0].mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
|
cgGLSetStateMatrixParameter(prg[0].mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
|
||||||
|
|
||||||
for (unsigned i = 1; i < cg_shader_num + 1; i++)
|
for (unsigned i = 1; i <= cg_shader_num; i++)
|
||||||
{
|
{
|
||||||
cgGLBindProgram(prg[i].fprg);
|
cgGLBindProgram(prg[i].fprg);
|
||||||
cgGLBindProgram(prg[i].vprg);
|
cgGLBindProgram(prg[i].vprg);
|
||||||
|
@ -902,6 +945,13 @@ bool gl_cg_init(const char *path)
|
||||||
prg[i].orig.tex_size_f = cgGetNamedParameter(prg[i].fprg, "ORIG.texture_size");
|
prg[i].orig.tex_size_f = cgGetNamedParameter(prg[i].fprg, "ORIG.texture_size");
|
||||||
prg[i].orig.coord = cgGetNamedParameter(prg[i].vprg, "ORIG.tex_coord");
|
prg[i].orig.coord = cgGetNamedParameter(prg[i].vprg, "ORIG.tex_coord");
|
||||||
|
|
||||||
|
prg[i].prev.tex = cgGetNamedParameter(prg[i].fprg, "PREV.texture");
|
||||||
|
prg[i].prev.vid_size_v = cgGetNamedParameter(prg[i].vprg, "PREV.video_size");
|
||||||
|
prg[i].prev.vid_size_f = cgGetNamedParameter(prg[i].fprg, "PREV.video_size");
|
||||||
|
prg[i].prev.tex_size_v = cgGetNamedParameter(prg[i].vprg, "PREV.texture_size");
|
||||||
|
prg[i].prev.tex_size_f = cgGetNamedParameter(prg[i].fprg, "PREV.texture_size");
|
||||||
|
prg[i].prev.coord = cgGetNamedParameter(prg[i].vprg, "PREV.tex_coord");
|
||||||
|
|
||||||
for (unsigned j = 0; j < i - 1; j++)
|
for (unsigned j = 0; j < i - 1; j++)
|
||||||
{
|
{
|
||||||
char attr_buf[64];
|
char attr_buf[64];
|
||||||
|
|
|
@ -33,6 +33,7 @@ void gl_cg_set_params(unsigned width, unsigned height,
|
||||||
unsigned out_width, unsigned out_height,
|
unsigned out_width, unsigned out_height,
|
||||||
unsigned frame_count,
|
unsigned frame_count,
|
||||||
const struct gl_tex_info *info,
|
const struct gl_tex_info *info,
|
||||||
|
const struct gl_tex_info *prev_info,
|
||||||
const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt);
|
const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt);
|
||||||
|
|
||||||
void gl_cg_use(unsigned index);
|
void gl_cg_use(unsigned index);
|
||||||
|
|
|
@ -1005,8 +1005,16 @@ void gl_glsl_set_params(unsigned width, unsigned height,
|
||||||
unsigned out_width, unsigned out_height,
|
unsigned out_width, unsigned out_height,
|
||||||
unsigned frame_count,
|
unsigned frame_count,
|
||||||
const struct gl_tex_info *info,
|
const struct gl_tex_info *info,
|
||||||
|
const struct gl_tex_info *prev_info,
|
||||||
const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt)
|
const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt)
|
||||||
{
|
{
|
||||||
|
// We enforce a certain layout for our various texture types in the texunits.
|
||||||
|
// Unit 0: Regular SNES frame (rubyTexture).
|
||||||
|
// Unit 1-A: LUT textures.
|
||||||
|
// Unit A+1: Previous texture.
|
||||||
|
// Unit A+2: Original texture.
|
||||||
|
// Unit A+3-B: FBO textures.
|
||||||
|
|
||||||
if (glsl_enable && gl_program[active_index] > 0)
|
if (glsl_enable && gl_program[active_index] > 0)
|
||||||
{
|
{
|
||||||
GLint location;
|
GLint location;
|
||||||
|
@ -1032,15 +1040,34 @@ void gl_glsl_set_params(unsigned width, unsigned height,
|
||||||
pglUniform1i(location, i + 1);
|
pglUniform1i(location, i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set previous texture.
|
||||||
|
pglActiveTexture(GL_TEXTURE0 + gl_teximage_cnt + 1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, prev_info->tex);
|
||||||
|
location = pglGetUniformLocation(gl_program[active_index], "rubyPrevTexture");
|
||||||
|
pglUniform1i(location, gl_teximage_cnt + 1);
|
||||||
|
|
||||||
|
location = pglGetUniformLocation(gl_program[active_index], "rubyPrevTextureSize");
|
||||||
|
pglUniform2fv(location, 1, prev_info->tex_size);
|
||||||
|
location = pglGetUniformLocation(gl_program[active_index], "rubyPrevInputSize");
|
||||||
|
pglUniform2fv(location, 1, prev_info->input_size);
|
||||||
|
|
||||||
|
// Pass texture coordinates.
|
||||||
|
location = pglGetAttribLocation(gl_program[active_index], "rubyPrevTexCoord");
|
||||||
|
if (location >= 0)
|
||||||
|
{
|
||||||
|
pglEnableVertexAttribArray(location);
|
||||||
|
pglVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, prev_info->coord);
|
||||||
|
}
|
||||||
|
|
||||||
// Set original texture unless we're in first pass (pointless).
|
// Set original texture unless we're in first pass (pointless).
|
||||||
if (active_index > 1)
|
if (active_index > 1)
|
||||||
{
|
{
|
||||||
// Bind original texture.
|
// Bind original texture.
|
||||||
pglActiveTexture(GL_TEXTURE0 + gl_teximage_cnt + 1);
|
pglActiveTexture(GL_TEXTURE0 + gl_teximage_cnt + 2);
|
||||||
glBindTexture(GL_TEXTURE_2D, info->tex);
|
glBindTexture(GL_TEXTURE_2D, info->tex);
|
||||||
|
|
||||||
location = pglGetUniformLocation(gl_program[active_index], "rubyOrigTexture");
|
location = pglGetUniformLocation(gl_program[active_index], "rubyOrigTexture");
|
||||||
pglUniform1i(location, gl_teximage_cnt + 1);
|
pglUniform1i(location, gl_teximage_cnt + 2);
|
||||||
|
|
||||||
location = pglGetUniformLocation(gl_program[active_index], "rubyOrigTextureSize");
|
location = pglGetUniformLocation(gl_program[active_index], "rubyOrigTextureSize");
|
||||||
pglUniform2fv(location, 1, info->tex_size);
|
pglUniform2fv(location, 1, info->tex_size);
|
||||||
|
@ -1055,7 +1082,7 @@ void gl_glsl_set_params(unsigned width, unsigned height,
|
||||||
pglVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, info->coord);
|
pglVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, info->coord);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint base_tex = GL_TEXTURE0 + gl_teximage_cnt + 2;
|
GLuint base_tex = GL_TEXTURE0 + gl_teximage_cnt + 3;
|
||||||
|
|
||||||
// Bind new texture in the chain.
|
// Bind new texture in the chain.
|
||||||
if (fbo_info_cnt > 0)
|
if (fbo_info_cnt > 0)
|
||||||
|
@ -1093,14 +1120,15 @@ void gl_glsl_set_params(unsigned width, unsigned height,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// First pass, so unbind everything to avoid collitions.
|
// First pass, so unbind everything to avoid collitions.
|
||||||
pglActiveTexture(GL_TEXTURE0 + gl_teximage_cnt + 1);
|
// Unbind ORIG.
|
||||||
|
pglActiveTexture(GL_TEXTURE0 + gl_teximage_cnt + 2);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
GLuint base_tex = GL_TEXTURE0 + gl_teximage_cnt + 2;
|
GLuint base_tex = GL_TEXTURE0 + gl_teximage_cnt + 3;
|
||||||
// Unbind any lurking FBO passes.
|
// Unbind any lurking FBO passes.
|
||||||
// Rendering to a texture that is bound to a texture unit
|
// Rendering to a texture that is bound to a texture unit
|
||||||
// sounds very shaky ... ;)
|
// sounds very shaky ... ;)
|
||||||
for (int i = 0; i < gl_num_programs; i++)
|
for (unsigned i = 0; i < gl_num_programs; i++)
|
||||||
{
|
{
|
||||||
pglActiveTexture(GL_TEXTURE0 + base_tex + i);
|
pglActiveTexture(GL_TEXTURE0 + base_tex + i);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
|
@ -33,6 +33,7 @@ void gl_glsl_set_params(unsigned width, unsigned height,
|
||||||
unsigned out_width, unsigned out_height,
|
unsigned out_width, unsigned out_height,
|
||||||
unsigned frame_counter,
|
unsigned frame_counter,
|
||||||
const struct gl_tex_info *info,
|
const struct gl_tex_info *info,
|
||||||
|
const struct gl_tex_info *prev_info,
|
||||||
const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt);
|
const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt);
|
||||||
|
|
||||||
void gl_glsl_use(unsigned index);
|
void gl_glsl_use(unsigned index);
|
||||||
|
|
12
movie.c
12
movie.c
|
@ -107,18 +107,6 @@ struct bsv_movie
|
||||||
#define CRC_INDEX 2
|
#define CRC_INDEX 2
|
||||||
#define STATE_SIZE_INDEX 3
|
#define STATE_SIZE_INDEX 3
|
||||||
|
|
||||||
static inline uint8_t is_little_endian(void)
|
|
||||||
{
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint16_t u16;
|
|
||||||
uint8_t u8[2];
|
|
||||||
} u;
|
|
||||||
|
|
||||||
u.u16 = 1;
|
|
||||||
return u.u8[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to big-endian if needed
|
// Convert to big-endian if needed
|
||||||
static inline uint32_t swap_if_big32(uint32_t val)
|
static inline uint32_t swap_if_big32(uint32_t val)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
. qb/qb.params.sh
|
. qb/qb.params.sh
|
||||||
|
|
||||||
PACKAGE_NAME=ssnes
|
PACKAGE_NAME=ssnes
|
||||||
PACKAGE_VERSION=0.6.1
|
PACKAGE_VERSION=0.6.2
|
||||||
|
|
||||||
# Adds a command line opt to ./configure --help
|
# Adds a command line opt to ./configure --help
|
||||||
# $1: Variable (HAVE_ALSA, HAVE_OSS, etc)
|
# $1: Variable (HAVE_ALSA, HAVE_OSS, etc)
|
||||||
|
|
14
settings.c
14
settings.c
|
@ -77,6 +77,9 @@ static void set_defaults(void)
|
||||||
case AUDIO_SDL:
|
case AUDIO_SDL:
|
||||||
def_audio = "sdl";
|
def_audio = "sdl";
|
||||||
break;
|
break;
|
||||||
|
case AUDIO_DSOUND:
|
||||||
|
def_audio = "dsound";
|
||||||
|
break;
|
||||||
case AUDIO_XAUDIO:
|
case AUDIO_XAUDIO:
|
||||||
def_audio = "xaudio";
|
def_audio = "xaudio";
|
||||||
break;
|
break;
|
||||||
|
@ -111,10 +114,11 @@ static void set_defaults(void)
|
||||||
|
|
||||||
g_settings.video.xscale = xscale;
|
g_settings.video.xscale = xscale;
|
||||||
g_settings.video.yscale = yscale;
|
g_settings.video.yscale = yscale;
|
||||||
g_settings.video.fullscreen = fullscreen;
|
g_settings.video.fullscreen = g_extern.force_fullscreen ? true : fullscreen;
|
||||||
g_settings.video.fullscreen_x = fullscreen_x;
|
g_settings.video.fullscreen_x = fullscreen_x;
|
||||||
g_settings.video.fullscreen_y = fullscreen_y;
|
g_settings.video.fullscreen_y = fullscreen_y;
|
||||||
g_settings.video.force_16bit = force_16bit;
|
g_settings.video.force_16bit = force_16bit;
|
||||||
|
g_settings.video.disable_composition = disable_composition;
|
||||||
g_settings.video.vsync = vsync;
|
g_settings.video.vsync = vsync;
|
||||||
g_settings.video.smooth = video_smooth;
|
g_settings.video.smooth = video_smooth;
|
||||||
g_settings.video.force_aspect = force_aspect;
|
g_settings.video.force_aspect = force_aspect;
|
||||||
|
@ -289,8 +293,14 @@ static void parse_config_file(void)
|
||||||
CONFIG_GET_DOUBLE(video.yscale, "video_yscale");
|
CONFIG_GET_DOUBLE(video.yscale, "video_yscale");
|
||||||
CONFIG_GET_INT(video.fullscreen_x, "video_fullscreen_x");
|
CONFIG_GET_INT(video.fullscreen_x, "video_fullscreen_x");
|
||||||
CONFIG_GET_INT(video.fullscreen_y, "video_fullscreen_y");
|
CONFIG_GET_INT(video.fullscreen_y, "video_fullscreen_y");
|
||||||
CONFIG_GET_BOOL(video.fullscreen, "video_fullscreen");
|
|
||||||
|
if (!g_extern.force_fullscreen)
|
||||||
|
{
|
||||||
|
CONFIG_GET_BOOL(video.fullscreen, "video_fullscreen");
|
||||||
|
}
|
||||||
|
|
||||||
CONFIG_GET_BOOL(video.force_16bit, "video_force_16bit");
|
CONFIG_GET_BOOL(video.force_16bit, "video_force_16bit");
|
||||||
|
CONFIG_GET_BOOL(video.disable_composition, "video_disable_composition");
|
||||||
CONFIG_GET_BOOL(video.vsync, "video_vsync");
|
CONFIG_GET_BOOL(video.vsync, "video_vsync");
|
||||||
CONFIG_GET_BOOL(video.smooth, "video_smooth");
|
CONFIG_GET_BOOL(video.smooth, "video_smooth");
|
||||||
CONFIG_GET_BOOL(video.force_aspect, "video_force_aspect");
|
CONFIG_GET_BOOL(video.force_aspect, "video_force_aspect");
|
||||||
|
|
10
ssnes.c
10
ssnes.c
|
@ -340,7 +340,7 @@ static void fill_pathname_noext(char *out_path, const char *in_path, const char
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define PACKAGE_VERSION "0.6.1"
|
#define PACKAGE_VERSION "0.6.2"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "config.features.h"
|
#include "config.features.h"
|
||||||
|
@ -383,6 +383,7 @@ static void print_help(void)
|
||||||
puts("Usage: ssnes [rom file] [options...]");
|
puts("Usage: ssnes [rom file] [options...]");
|
||||||
puts("\t-h/--help: Show this help message.");
|
puts("\t-h/--help: Show this help message.");
|
||||||
puts("\t-s/--save: Path for save file (*.srm). Required when rom is input from stdin.");
|
puts("\t-s/--save: Path for save file (*.srm). Required when rom is input from stdin.");
|
||||||
|
puts("\t-f/--fullscreen: Start SSNES in fullscreen regardless of config settings.");
|
||||||
puts("\t-S/--savestate: Path to use for save states. If not selected, *.state will be assumed.");
|
puts("\t-S/--savestate: Path to use for save states. If not selected, *.state will be assumed.");
|
||||||
#ifdef HAVE_CONFIGFILE
|
#ifdef HAVE_CONFIGFILE
|
||||||
puts("\t-c/--config: Path for config file." SSNES_DEFAULT_CONF_PATH_STR);
|
puts("\t-c/--config: Path for config file." SSNES_DEFAULT_CONF_PATH_STR);
|
||||||
|
@ -441,6 +442,7 @@ static void parse_input(int argc, char *argv[])
|
||||||
struct option opts[] = {
|
struct option opts[] = {
|
||||||
{ "help", 0, NULL, 'h' },
|
{ "help", 0, NULL, 'h' },
|
||||||
{ "save", 1, NULL, 's' },
|
{ "save", 1, NULL, 's' },
|
||||||
|
{ "fullscreen", 0, NULL, 'f' },
|
||||||
#ifdef HAVE_FFMPEG
|
#ifdef HAVE_FFMPEG
|
||||||
{ "record", 1, NULL, 'r' },
|
{ "record", 1, NULL, 'r' },
|
||||||
#endif
|
#endif
|
||||||
|
@ -485,7 +487,7 @@ static void parse_input(int argc, char *argv[])
|
||||||
#define CONFIG_FILE_ARG
|
#define CONFIG_FILE_ARG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char optstring[] = "hs:vS:m:p4jJg:b:B:Y:Z:P:HC:F:U:DN:X:" FFMPEG_RECORD_ARG CONFIG_FILE_ARG;
|
char optstring[] = "hs:fvS:m:p4jJg:b:B:Y:Z:P:HC:F:U:DN:X:" FFMPEG_RECORD_ARG CONFIG_FILE_ARG;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
val = 0;
|
val = 0;
|
||||||
|
@ -518,6 +520,10 @@ static void parse_input(int argc, char *argv[])
|
||||||
g_extern.has_set_save_path = true;
|
g_extern.has_set_save_path = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
g_extern.force_fullscreen = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'g':
|
case 'g':
|
||||||
strlcpy(g_extern.gb_rom_path, optarg, sizeof(g_extern.gb_rom_path));
|
strlcpy(g_extern.gb_rom_path, optarg, sizeof(g_extern.gb_rom_path));
|
||||||
g_extern.game_type = SSNES_CART_SGB;
|
g_extern.game_type = SSNES_CART_SGB;
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
# Force 16-bit colors. Apparently some video cards in use today have troubles with 32-bit ...
|
# Force 16-bit colors. Apparently some video cards in use today have troubles with 32-bit ...
|
||||||
# video_force_16bit = false
|
# video_force_16bit = false
|
||||||
|
|
||||||
|
# Forcibly disable composition. Only works in Windows Vista/7 for now.
|
||||||
|
# video_disable_composition = false
|
||||||
|
|
||||||
# Video vsync.
|
# Video vsync.
|
||||||
# video_vsync = true
|
# video_vsync = true
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue