(360) Added preliminary xdk 360 drivers

This commit is contained in:
TwinAphex51224 2012-01-05 12:37:27 +01:00
parent 7e3092dc93
commit 2b01f36fc0
5 changed files with 645 additions and 0 deletions

49
360/msvc_compat.h Normal file
View File

@ -0,0 +1,49 @@
/* 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/>.
*/
#ifndef __SSNES_MSVC_COMPAT_H
#define __SSNES_MSVC_COMPAT_H
#ifdef _MSC_VER
#undef UNICODE // Do not bother with UNICODE at this time.
#include <stddef.h>
#include <math.h>
// Python headers defines ssize_t and sets HAVE_SSIZE_T. Cannot duplicate these efforts.
#ifndef HAVE_SSIZE_T
typedef int ssize_t;
#endif
#define snprintf _snprintf
#define strcasecmp _stricmp
// Disable some of the annoying warnings.
#pragma warning(disable : 4800)
#pragma warning(disable : 4244)
#pragma warning(disable : 4305)
#pragma warning(disable : 4146)
#pragma warning(disable : 4267)
static inline float roundf(float in)
{
return in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f);
}
#endif
#endif

173
360/xdk360_audio.c Normal file
View File

@ -0,0 +1,173 @@
/*
Simple C interface for XAudio2
Author: Hans-Kristian Arntzen
License: Public Domain
*/
#include <stdint.h>
#include <xtl.h>
#include <xaudio2.h>
#include "xdk360_audio.h"
#include "../msvc-360/msvc_compat.h"
#define MAX_BUFFERS 16
#define MAX_BUFFERS_MASK (MAX_BUFFERS - 1)
#undef min
#undef max
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
struct xaudio2
{
const IXAudio2VoiceCallbackVtbl *lpVtbl;
uint8_t *buf;
IXAudio2 *pXAudio2;
IXAudio2MasteringVoice *pMasterVoice;
IXAudio2SourceVoice *pSourceVoice;
HANDLE hEvent;
volatile long buffers;
unsigned bufsize;
unsigned bufptr;
unsigned write_buffer;
};
static void WINAPI voice_on_buffer_end(void *handle_, void *data)
{
(void)data;
xaudio2_t *handle = (xaudio2_t*)handle_;
InterlockedDecrement(&handle->buffers);
SetEvent(handle->hEvent);
}
static void WINAPI dummy_voidp(void *handle, void *data) { (void)handle; (void)data; }
static void WINAPI dummy_nil(void *handle) { (void)handle; }
static void WINAPI dummy_uint32(void *handle, UINT32 dummy) { (void)handle; (void)dummy; }
static void WINAPI dummy_voidp_hresult(void *handle, void *data, HRESULT dummy) { (void)handle; (void)data; (void)dummy; }
const struct IXAudio2VoiceCallbackVtbl voice_vtable = {
dummy_uint32,
dummy_nil,
dummy_nil,
dummy_voidp,
voice_on_buffer_end,
dummy_voidp,
dummy_voidp_hresult,
};
xaudio2_t *xaudio2_new(unsigned samplerate, unsigned channels, size_t size)
{
xaudio2_t *handle = (xaudio2_t*)calloc(1, sizeof(*handle));
if (!handle)
return NULL;
handle->lpVtbl = &voice_vtable;
CoInitializeEx(0, COINIT_MULTITHREADED);
WAVEFORMATEX wfx = {0};
if (FAILED(XAudio2Create(&handle->pXAudio2)))
goto error;
if (FAILED(IXAudio2_CreateMasteringVoice(handle->pXAudio2,
&handle->pMasterVoice, channels, samplerate, 0, 0, 0)))
goto error;
wfx.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
wfx.nChannels = channels;
wfx.nSamplesPerSec = samplerate;
wfx.nBlockAlign = channels * sizeof(float);
wfx.wBitsPerSample = sizeof(float) * 8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = 0;
if (FAILED(IXAudio2_CreateSourceVoice(handle->pXAudio2,
&handle->pSourceVoice, &wfx,
XAUDIO2_VOICE_NOSRC, XAUDIO2_DEFAULT_FREQ_RATIO,
(IXAudio2VoiceCallback*)handle, 0, 0)))
goto error;
handle->hEvent = CreateEvent(0, FALSE, FALSE, 0);
if (!handle->hEvent)
goto error;
handle->bufsize = size / MAX_BUFFERS;
handle->buf = (uint8_t*)calloc(1, handle->bufsize * MAX_BUFFERS);
if (!handle->buf)
goto error;
if (FAILED(IXAudio2SourceVoice_Start(handle->pSourceVoice, 0, XAUDIO2_COMMIT_NOW)))
goto error;
return handle;
error:
xaudio2_free(handle);
return NULL;
}
size_t xaudio2_write_avail(xaudio2_t *handle)
{
return handle->bufsize * (MAX_BUFFERS - handle->buffers - 1);
}
size_t xaudio2_write(xaudio2_t *handle, const void *buf, size_t bytes_)
{
unsigned bytes = bytes_;
const uint8_t *buffer = (const uint8_t*)buf;
while (bytes)
{
unsigned need = min(bytes, handle->bufsize - handle->bufptr);
memcpy(handle->buf + handle->write_buffer * handle->bufsize + handle->bufptr,
buffer, need);
handle->bufptr += need;
buffer += need;
bytes -= need;
if (handle->bufptr == handle->bufsize)
{
while (handle->buffers == MAX_BUFFERS - 1)
WaitForSingleObject(handle->hEvent, INFINITE);
XAUDIO2_BUFFER xa2buffer = {0};
xa2buffer.AudioBytes = handle->bufsize;
xa2buffer.pAudioData = handle->buf + handle->write_buffer * handle->bufsize;
if (FAILED(IXAudio2SourceVoice_SubmitSourceBuffer(handle->pSourceVoice, &xa2buffer, NULL)))
return 0;
InterlockedIncrement(&handle->buffers);
handle->bufptr = 0;
handle->write_buffer = (handle->write_buffer + 1) & MAX_BUFFERS_MASK;
}
}
return bytes_;
}
void xaudio2_free(xaudio2_t *handle)
{
if (handle)
{
if (handle->pSourceVoice)
{
IXAudio2SourceVoice_Stop(handle->pSourceVoice, 0, XAUDIO2_COMMIT_NOW);
IXAudio2SourceVoice_DestroyVoice(handle->pSourceVoice);
}
if (handle->pMasterVoice)
IXAudio2MasteringVoice_DestroyVoice(handle->pMasterVoice);
if (handle->pXAudio2)
IXAudio2_Release(handle->pXAudio2);
if (handle->hEvent)
CloseHandle(handle->hEvent);
free(handle->buf);
free(handle);
}
}

27
360/xdk360_audio.h Normal file
View File

@ -0,0 +1,27 @@
/*
Simple C interface for XAudio2
Author: Hans-Kristian Arntzen
License: Public Domain
*/
#ifndef XAUDIO_C_H
#define XAUDIO_C_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct xaudio2 xaudio2_t;
xaudio2_t* xaudio2_new(unsigned samplerate, unsigned channels, size_t bufsize);
size_t xaudio2_write_avail(xaudio2_t *handle);
size_t xaudio2_write(xaudio2_t *handle, const void *data, size_t bytes);
void xaudio2_free(xaudio2_t *handle);
#ifdef __cplusplus
}
#endif
#endif

127
360/xdk360_input.cpp Normal file
View File

@ -0,0 +1,127 @@
/* SSNES - A Super Ninteno Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010 - Hans-Kristian Arntzen
* Copyright (C) 2011 - Daniel De Matteis
*
* 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 <stdint.h>
#include <stdlib.h>
#include <basetsd.h>
#include <windef.h>
#include <winbase.h>
#include <xinputdefs.h>
#include "../driver.h"
#include "../libsnes.hpp"
static XINPUT_STATE state[5];
static void xdk360_input_poll(void *data)
{
(void)data;
ZeroMemory(&state, sizeof(XINPUT_STATE));
for (unsigned i = 0; i < 5; i++)
XInputGetState(i, &state[i]);
}
static int16_t xdk360_input_state(void *data, const struct snes_keybind **binds,
bool port, unsigned device,
unsigned index, unsigned id)
{
(void)data;
(void)binds;
(void)index;
if (device != SNES_DEVICE_JOYPAD)
return 0;
unsigned player = 0;
if (port == SNES_PORT_2 && device == SNES_DEVICE_MULTITAP)
player = index + 1;
else if (port == SNES_PORT_2)
player = 1;
// Hardcoded binds.
uint64_t button;
switch (id)
{
case SNES_DEVICE_ID_JOYPAD_A:
button = XINPUT_GAMEPAD_B;
break;
case SNES_DEVICE_ID_JOYPAD_B:
button = XINPUT_GAMEPAD_A;
break;
case SNES_DEVICE_ID_JOYPAD_X:
button = XINPUT_GAMEPAD_Y;
break;
case SNES_DEVICE_ID_JOYPAD_Y:
button = XINPUT_GAMEPAD_X;
break;
case SNES_DEVICE_ID_JOYPAD_LEFT:
button = XINPUT_GAMEPAD_DPAD_LEFT;
break;
case SNES_DEVICE_ID_JOYPAD_RIGHT:
button = XINPUT_GAMEPAD_DPAD_RIGHT;
break;
case SNES_DEVICE_ID_JOYPAD_UP:
button = XINPUT_GAMEPAD_DPAD_UP;
break;
case SNES_DEVICE_ID_JOYPAD_DOWN:
button = XINPUT_GAMEPAD_DPAD_DOWN;
break;
case SNES_DEVICE_ID_JOYPAD_START:
button = XINPUT_GAMEPAD_START;
break;
case SNES_DEVICE_ID_JOYPAD_SELECT:
button = XINPUT_GAMEPAD_BACK;
break;
case SNES_DEVICE_ID_JOYPAD_L:
button = XINPUT_GAMEPAD_LEFT_SHOULDER;
break;
case SNES_DEVICE_ID_JOYPAD_R:
button = XINPUT_GAMEPAD_RIGHT_SHOULDER;
break;
default:
button = 0;
}
return ((state[player]) & button) ? 1 : 0;
}
static void xdk360_free_input(void *data)
{
(void)data;
}
static void* xdk360_input_init(void)
{
return (void*)-1;
}
static bool xdk360_key_pressed(void *data, int key)
{
(void)data;
(void)key;
return false;
}
const input_driver_t input_xdk360 = {
xdk360_input_init,
xdk360_input_poll,
xdk360_input_state,
xdk360_key_pressed,
xdk360_free_input,
"xdk360"};

269
360/xdk360_video.cpp Normal file
View File

@ -0,0 +1,269 @@
/* 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 <xtl.h>
#include <xboxmath.h>
#include "driver.h"
#include "general.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
// pixel shader
const CHAR* g_strPixelShaderProgram =
" struct PS_IN "
" { "
" float4 Color : COLOR; " // Interpolated color from
" }; " // the vertex shader
" "
" float4 main( PS_IN In ) : COLOR "
" { "
" return In.Color; " // Output color
" } ";
// vertex shader
const CHAR* g_strVertexShaderProgram =
" float4x4 matWVP : register(c0); "
" "
" struct VS_IN "
" "
" { "
" float4 ObjPos : POSITION; " // Object space position
" float4 Color : COLOR; " // Vertex color
" }; "
" "
" struct VS_OUT "
" { "
" float4 ProjPos : POSITION; " // Projected space position
" float4 Color : COLOR; "
" }; "
" "
" VS_OUT main( VS_IN In ) "
" { "
" VS_OUT Out; "
" Out.ProjPos = mul( matWVP, In.ObjPos ); " // Transform vertex into
" Out.Color = In.Color; " // Projected space and
" return Out; " // Transfer color
" } ";
typedef struct DrawVerticeFormats
{
float x, y, z, w;
unsigned int color;
float u, v;
} DrawVerticeFormats;
typedef struct xdk360_video xdk360_video_t;
static bool g_quitting;
typedef struct gl
{
IDirect3D9* xdk360_device;
IDirect3DDevice9* xdk360_render_device;
IDirect3DVertexShader9 *pVertexShader;
IDirect3DPixelShader9* pPixelShader;
XMMATRIX matWVP;
unsigned frame_count;
} gl_t;
static void xdk360_gfx_free(void *data)
{
gl_t *vid = data;
if (!vid)
return;
free(vid);
}
static void *xdk360_gfx_init(const video_info_t *video, const input_driver_t **input, void **input_data)
{
gl_t * gl = calloc(1, sizeof(gl_t));
if (!gl)
return NULL;
gl->xdk360_device = Direct3DCreate9( D3D_SDK_VERSION );
/* Set up the structure used to create the Direct3D device */
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof( d3dpp ) );
d3dpp.BackBufferWidth = 1280;
d3dpp.BackBufferHeight = 720;
d3dpp.BackBufferFormat = ( D3DFORMAT )MAKESRGBFMT( D3DFMT_A8R8G8B8 );
d3dpp.FrontBufferFormat = ( D3DFORMAT )MAKESRGBFMT( D3DFMT_LE_X8R8G8B8 );
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.BackBufferCount = 1;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
/* Create the Direct3D device */
gl->xdk360_device->CreateDevice(0, D3DDEVTYPE_HAL, NULL, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp,
&gl->xdk360_render_device);
/* Buffers to hold compiled shaders and possible error messages */
ID3DXBuffer* pShaderCode = NULL;
ID3DXBuffer* pErrorMsg = NULL;
/* Compile vertex shader */
HRESULT hr = D3DXCompileShader(g_strVertexShaderProgram, ( UINT )strlen(g_strVertexShaderProgram),
NULL, NULL, "main", "vs_2_0", 0, &pShaderCode, &pErrorMsg, NULL);
if (FAILED(hr))
{
OutputDebugStringA( pErrorMsg ? (CHAR *)pErrorMsg->GetBufferPointer() : "");
exit(1);
}
/* Create vertex shader */
gl->xdk360_render_device->CreateVertexShader((DWORD*)pShaderCode->GetBufferPointer(), &gl->pVertexShader);
/* Shader code is no longer required */
pShaderCode->Release();
pShaderCode = NULL;
/* Compile pixel shader */
hr = D3DXCompileShader(g_strPixelShaderProgram, (UINT)strlen(g_strPixelShaderProgram),
NULL, NULL, "main", "ps_2_0", 0, &pShaderCode, &pErrorMsg, NULL);
if (FAILED(hr))
{
OutputDebugStringA( pErrorMsg ? (CHAR *)pErrorMsg->GetBufferPointer() : "");
exit(1);
}
/* Create pixel shader */
gl->xdk360_render_device->CreatePixelShader((DWORD*)pShaderCode->GetBufferPointer(), &gl->pPixelShader);
/* Shader code no longer required */
pShaderCode->Release();
pShaderCode = NULL;
/* Structure to hold vertex data.*/
struct COLORVERTEX
{
FLOAT Position[3];
DWORD Color;
};
COLORVERTEX Vertices[3] =
{
{ -1.0f, -1.0f, 0.0f, 0x00FF0000 },
{ 0.0f, 1.0f, 0.0f, 0x0000FF00 },
{ 1.0f, -1.0f, 0.0f, 0x000000FF }
};
/* Define the vertex elements.*/
static const D3DVERTEXELEMENT9 VertexElements[3] =
{
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
D3DDECL_END()
};
/* Create a vertex declaration from the element descriptions.*/
IDirect3DVertexDeclaration9* pVertexDecl;
g_pd3dDevice->CreateVertexDeclaration( VertexElements, &pVertexDecl );
/* World matrix (identity in this sample)*/
XMMATRIX matWorld = XMMatrixIdentity();
/* View matrix*/
XMVECTOR vEyePt = XMVectorSet( 0.0f, 0.0f, -4.0f, 0.0f );
XMVECTOR vLookatPt = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f );
XMVECTOR vUp = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );
XMMATRIX matView = XMMatrixLookAtLH( vEyePt, vLookatPt, vUp );
/* Determine the aspect ratio*/
FLOAT fAspectRatio = ( FLOAT )d3dpp.BackBufferWidth / ( FLOAT )d3dpp.BackBufferHeight;
/* Projection matrix*/
XMMATRIX matProj = XMMatrixPerspectiveFovLH( XM_PI / 4, fAspectRatio, 1.0f, 200.0f );
/* World*view*projection*/
gl->matWVP = matWorld * matView * matProj;
/* Clear the backbuffer.*/
gl->xdk360_render_device->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,
0xff000000, 1.0f, 0L );
return gl;
}
static bool xdk360_gfx_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
{
gl_t *vid = data;
vid->frame_count++;
/* Clear the backbuffer.*/
vid->xdk360_render_device->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,
0xff000000, 1.0f, 0L );
/* Set shaders. */
vid->xdk360_render_device->SetVertexShader( gl->pVertexShader );
vid->xdk360_render_device->SetPixelShader( gl->pPixelShader );
// Set shader constants.
vid->xdk360_render_device->SetVertexShaderConstantF( 0, ( FLOAT* )&vid->matWVP, 4 );
// Set the vertex declaration.
vid->xdk360_render_device->SetVertexDeclaration( pVertexDecl );
// Draw
vid->xdk360_render_device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2 );
// Resolve
vid->xdk360_render_device->Present(NULL, NULL, NULL, NULL);
return true;
}
static void xdk360_gfx_set_nonblock_state(void *data, bool state)
{
(void)data;
(void)state;
}
static bool xdk360_gfx_alive(void *data)
{
(void)data;
return !g_quitting;
}
static bool xdk360_gfx_focus(void *data)
{
(void)data;
return true;
}
const video_driver_t video_xdk360 = {
.init = xdk360_gfx_init,
.frame = xdk360_gfx_frame,
.alive = xdk360_gfx_alive,
.set_nonblock_state = xdk360_gfx_set_nonblock_state,
.focus = xdk360_gfx_focus,
.free = xdk360_gfx_free,
.ident = "xdk360"
};