Skip to content
Permalink
Browse files

First implementation of IPC command buffers

  • Loading branch information...
Kangz committed Feb 5, 2015
1 parent dd30643 commit b46f4762ea0be806b3be2a7fad0a31802b930b85
@@ -572,9 +572,11 @@ set( COMMONLIST
${COMMON_DIR}/cm/cm_patch.h
${COMMON_DIR}/cm/cm_polylib.h
${COMMON_DIR}/cm/cm_public.h
${COMMON_DIR}/IPC/Channel.h
${COMMON_DIR}/IPC/CommonSyscalls.h
${COMMON_DIR}/IPC/CommandBuffer.h
${COMMON_DIR}/IPC/Primitives.cpp
${COMMON_DIR}/IPC/Primitives.h
${COMMON_DIR}/IPC/Channel.h
)

set( RENDERERLIST
@@ -654,6 +656,8 @@ set( ENGINELIST
${ENGINE_DIR}/framework/CommandSystem.h
${ENGINE_DIR}/framework/CvarSystem.cpp
${ENGINE_DIR}/framework/CvarSystem.h
${ENGINE_DIR}/framework/CommandBufferHost.cpp
${ENGINE_DIR}/framework/CommandBufferHost.h
${ENGINE_DIR}/framework/CommonVMServices.cpp
${ENGINE_DIR}/framework/CommonVMServices.h
${ENGINE_DIR}/framework/ConsoleField.cpp
@@ -782,6 +786,8 @@ set( GAMESHAREDLIST
${GAMELOGIC_DIR}/shared/bg_voice.cpp
${GAMELOGIC_DIR}/shared/bg_teamprogress.cpp
${GAMELOGIC_DIR}/shared/bg_utilities.cpp
${GAMELOGIC_DIR}/shared/CommandBufferClient.cpp
${GAMELOGIC_DIR}/shared/CommandBufferClient.h
${GAMELOGIC_DIR}/shared/CommonProxies.cpp
${GAMELOGIC_DIR}/shared/CommonProxies.h
${GAMELOGIC_DIR}/shared/VMMain.cpp
@@ -1,7 +1,7 @@
/*
===========================================================================
Daemon BSD Source Code
Copyright (c) 2013-2014, Daemon Developers
Copyright (c) 2013-2015, Daemon Developers
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -0,0 +1,79 @@
/*
===========================================================================
Daemon BSD Source Code
Copyright (c) 2013-2015, Daemon Developers
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Daemon developers nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
===========================================================================
*/

#ifndef COMMON_IPC_COMMAND_BUFFER_H_
#define COMMON_IPC_COMMAND_BUFFER_H_

#include "CommonSyscalls.h"
#include "Primitives.h"

namespace IPC {

struct CommandBufferData {
IPC::SharedMemory shm;
char* data;
uint32_t* writePos;
uint32_t* readPos;
size_t size;

static const int READ_OFFSET = 0;
static const int WRITE_OFFSET = 64;
static const int DATA_OFFSET = 128;

void Init(IPC::SharedMemory shmem) {
shm = std::move(shmem);
size = shm.GetSize() - DATA_OFFSET;
char* base = reinterpret_cast<char*>(shm.GetBase());
writePos = reinterpret_cast<uint32_t*>(base + WRITE_OFFSET);
readPos = reinterpret_cast<uint32_t*>(base + READ_OFFSET);
data = reinterpret_cast<char*>(base + DATA_OFFSET);
}

void Close() {
shm.Close();
}
};

enum {
COMMAND_BUFFER_LOCATE,
COMMAND_BUFFER_CONSUME,
};

typedef IPC::SyncMessage<
IPC::Message<IPC::Id<VM::COMMAND_BUFFER, COMMAND_BUFFER_LOCATE>, IPC::SharedMemory, IPC::SharedMemory>
> CommandBufferLocateMsg;

typedef IPC::SyncMessage<
IPC::Message<IPC::Id<VM::COMMAND_BUFFER, COMMAND_BUFFER_CONSUME>, int>
> CommandBufferConsumeMsg;

} // namespace IPC

#endif // COMMON_IPC_COMMAND_BUFFER_H_
@@ -52,6 +52,7 @@ namespace VM {
CVAR,
LOG,
FILESYSTEM,
COMMAND_BUFFER,
LAST_COMMON_SYSCALL
};

@@ -1442,7 +1442,7 @@ void CL_OnTeamChanged( int newTeam )
Cmd::BufferCommandText( "exec -f " TEAMCONFIG_NAME );
}

CGameVM::CGameVM(): VM::VMBase("cgame"), services(nullptr)
CGameVM::CGameVM(): VM::VMBase("cgame"), services(nullptr), cmdBuffer("client")
{
}

@@ -1539,11 +1539,14 @@ void CGameVM::Syscall(uint32_t id, Util::Reader reader, IPC::Channel& channel)
if (major == VM::QVM) {
this->QVMSyscall(minor, reader, channel);

} else if (major == VM::COMMAND_BUFFER) {
this->cmdBuffer.Syscall(minor, reader, channel);

} else if (major < VM::LAST_COMMON_SYSCALL) {
services->Syscall(major, minor, std::move(reader), channel);

} else {
Com_Error(ERR_DROP, "Bad major game syscall number: %d", major);
Sys::Drop("Bad major game syscall number: %d", major);
}
}

@@ -1679,89 +1682,11 @@ void CGameVM::QVMSyscall(int index, Util::Reader& reader, IPC::Channel& channel)

// All sounds

case CG_S_STARTSOUND:
IPC::HandleMsg<Audio::StartSoundMsg>(channel, std::move(reader), [this] (bool isPositional, std::array<float, 3> origin, int entityNum, int sfx) {
Audio::StartSound(entityNum, (isPositional ? origin.data() : nullptr), sfx);
});
break;

case CG_S_STARTLOCALSOUND:
IPC::HandleMsg<Audio::StartLocalSoundMsg>(channel, std::move(reader), [this] (int sfx) {
Audio::StartLocalSound(sfx);
});
break;

case CG_S_CLEARLOOPINGSOUNDS:
IPC::HandleMsg<Audio::ClearLoopingSoundsMsg>(channel, std::move(reader), [this] {
Audio::ClearAllLoopingSounds();
});
break;

case CG_S_ADDLOOPINGSOUND:
IPC::HandleMsg<Audio::AddLoopingSoundMsg>(channel, std::move(reader), [this] (int entityNum, int sfx) {
Audio::AddEntityLoopingSound(entityNum, sfx);
});
break;

case CG_S_STOPLOOPINGSOUND:
IPC::HandleMsg<Audio::StopLoopingSoundMsg>(channel, std::move(reader), [this] (int entityNum) {
Audio::ClearLoopingSoundsForEntity(entityNum);
});
break;

case CG_S_UPDATEENTITYPOSITION:
IPC::HandleMsg<Audio::UpdateEntityPositionMsg>(channel, std::move(reader), [this] (int entityNum, std::array<float, 3> position) {
Audio::UpdateEntityPosition(entityNum, position.data());
});
break;

case CG_S_RESPATIALIZE:
IPC::HandleMsg<Audio::RespatializeMsg>(channel, std::move(reader), [this] (int entityNum, std::array<float, 9> axis) {
Audio::UpdateListener(entityNum, (vec3_t*) axis.data());
});
break;

case CG_S_REGISTERSOUND:
IPC::HandleMsg<Audio::RegisterSoundMsg>(channel, std::move(reader), [this] (std::string sample, int& handle) {
handle = Audio::RegisterSFX(sample.c_str());
});
break;

case CG_S_STARTBACKGROUNDTRACK:
IPC::HandleMsg<Audio::StartBackgroundTrackMsg>(channel, std::move(reader), [this] (std::string intro, std::string loop) {
Audio::StartMusic(intro.c_str(), loop.c_str());
});
break;

case CG_S_STOPBACKGROUNDTRACK:
IPC::HandleMsg<Audio::StopBackgroundTrackMsg>(channel, std::move(reader), [this] {
Audio::StopMusic();
});
break;

case CG_S_UPDATEENTITYVELOCITY:
IPC::HandleMsg<Audio::UpdateEntityVelocityMsg>(channel, std::move(reader), [this] (int entityNum, std::array<float, 3> velocity) {
Audio::UpdateEntityVelocity(entityNum, velocity.data());
});
break;

case CG_S_SETREVERB:
IPC::HandleMsg<Audio::SetReverbMsg>(channel, std::move(reader), [this] (int slotNum, std::string name, float ratio) {
Audio::SetReverb(slotNum, name.c_str(), ratio);
});
break;

case CG_S_BEGINREGISTRATION:
IPC::HandleMsg<Audio::BeginRegistrationMsg>(channel, std::move(reader), [this] {
Audio::BeginRegistration();
});
break;

case CG_S_ENDREGISTRATION:
IPC::HandleMsg<Audio::EndRegistrationMsg>(channel, std::move(reader), [this] {
Audio::EndRegistration();
});
break;
case CG_S_REGISTERSOUND:
IPC::HandleMsg<Audio::RegisterSoundMsg>(channel, std::move(reader), [this] (std::string sample, int& handle) {
handle = Audio::RegisterSFX(sample.c_str());
});
break;

// All renderer

@@ -2312,6 +2237,119 @@ void CGameVM::QVMSyscall(int index, Util::Reader& reader, IPC::Channel& channel)
break;

default:
Com_Error(ERR_DROP, "Bad game system trap: %d", index);
Sys::Drop("Bad CGame QVM syscall minor number: %d", index);
}
}

//TODO move somewhere else
template<typename Func, typename Id, typename... MsgArgs> void HandleMsg(IPC::Message<Id, MsgArgs...>, Util::Reader reader, Func&& func)
{
typedef IPC::Message<Id, MsgArgs...> Message;

typename Util::Reader::MapTuple<typename Message::Inputs>::type inputs;
reader.FillTuple<0>(Util::TypeListFromTuple<typename Message::Inputs>(), inputs);

Util::apply(std::forward<Func>(func), std::move(inputs));
}

template<typename Msg, typename Func> void HandleMsg(Util::Reader reader, Func&& func)
{
HandleMsg(Msg(), std::move(reader), std::forward<Func>(func));
}

CGameVM::CmdBuffer::CmdBuffer(std::string name): IPC::CommandBufferHost(name) {
}

void CGameVM::CmdBuffer::HandleCommandBufferSyscall(int major, int minor, Util::Reader& reader) {
if (major == VM::QVM) {
switch (minor) {

// All sounds

case CG_S_STARTSOUND:
HandleMsg<Audio::StartSoundMsg>(std::move(reader), [this] (bool isPositional, std::array<float, 3> origin, int entityNum, int sfx) {
Audio::StartSound(entityNum, (isPositional ? origin.data() : nullptr), sfx);
});
break;

case CG_S_STARTLOCALSOUND:
HandleMsg<Audio::StartLocalSoundMsg>(std::move(reader), [this] (int sfx) {
Audio::StartLocalSound(sfx);
});
break;

case CG_S_CLEARLOOPINGSOUNDS:
HandleMsg<Audio::ClearLoopingSoundsMsg>(std::move(reader), [this] {
Audio::ClearAllLoopingSounds();
});
break;

case CG_S_ADDLOOPINGSOUND:
HandleMsg<Audio::AddLoopingSoundMsg>(std::move(reader), [this] (int entityNum, int sfx) {
Audio::AddEntityLoopingSound(entityNum, sfx);
});
break;

case CG_S_STOPLOOPINGSOUND:
HandleMsg<Audio::StopLoopingSoundMsg>(std::move(reader), [this] (int entityNum) {
Audio::ClearLoopingSoundsForEntity(entityNum);
});
break;

case CG_S_UPDATEENTITYPOSITION:
HandleMsg<Audio::UpdateEntityPositionMsg>(std::move(reader), [this] (int entityNum, std::array<float, 3> position) {
Audio::UpdateEntityPosition(entityNum, position.data());
});
break;

case CG_S_RESPATIALIZE:
HandleMsg<Audio::RespatializeMsg>(std::move(reader), [this] (int entityNum, std::array<float, 9> axis) {
Audio::UpdateListener(entityNum, (vec3_t*) axis.data());
});
break;

case CG_S_STARTBACKGROUNDTRACK:
HandleMsg<Audio::StartBackgroundTrackMsg>(std::move(reader), [this] (std::string intro, std::string loop) {
Audio::StartMusic(intro.c_str(), loop.c_str());
});
break;

case CG_S_STOPBACKGROUNDTRACK:
HandleMsg<Audio::StopBackgroundTrackMsg>(std::move(reader), [this] {
Audio::StopMusic();
});
break;

case CG_S_UPDATEENTITYVELOCITY:
HandleMsg<Audio::UpdateEntityVelocityMsg>(std::move(reader), [this] (int entityNum, std::array<float, 3> velocity) {
Audio::UpdateEntityVelocity(entityNum, velocity.data());
});
break;

case CG_S_SETREVERB:
HandleMsg<Audio::SetReverbMsg>(std::move(reader), [this] (int slotNum, std::string name, float ratio) {
Audio::SetReverb(slotNum, name.c_str(), ratio);
});
break;

case CG_S_BEGINREGISTRATION:
HandleMsg<Audio::BeginRegistrationMsg>(std::move(reader), [this] {
Audio::BeginRegistration();
});
break;

case CG_S_ENDREGISTRATION:
HandleMsg<Audio::EndRegistrationMsg>(std::move(reader), [this] {
Audio::EndRegistration();
});
break;

default:
Sys::Drop("Bad minor CGame QVM Command Buffer number: %d", minor);
}

} else {
Sys::Drop("Bad major CGame Command Buffer number: %d", major);
}
}

@@ -45,6 +45,8 @@ Maryland 20850 USA.
#include "../client/cg_api.h"
#include "../framework/VirtualMachine.h"
#include "../framework/CommonVMServices.h"
#include "../framework/CommandBufferHost.h"
#include "../../common/IPC/CommandBuffer.h"

#if defined(USE_VOIP) && !defined(BUILD_SERVER)
#include <speex/speex.h>
@@ -440,6 +442,14 @@ class CGameVM: public VM::VMBase {
void QVMSyscall(int index, Util::Reader& reader, IPC::Channel& channel);

std::unique_ptr<VM::CommonVMServices> services;

class CmdBuffer: public IPC::CommandBufferHost {
public:
CmdBuffer(std::string name);
virtual void HandleCommandBufferSyscall(int major, int minor, Util::Reader& reader) OVERRIDE FINAL;
};

CmdBuffer cmdBuffer;
};

extern CGameVM cgvm;

0 comments on commit b46f476

Please sign in to comment.
You can’t perform that action at this time.