-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathCommandPacket.h
183 lines (154 loc) · 6.55 KB
/
CommandPacket.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//
// CommandPacket.h
//
#pragma once
#include <cstdint>
#include "RenderContext.h"
#include "command_debug.h"
#include "command_internal.h"
namespace cb
{
/// Contains one or more commands packed together in a specific order.
struct CommandPacket
{
CB_DECLARE_COMMAND_DEBUG();
template <class CommandClass>
struct is_valid_type
{
enum
{
// must not be CommandPacket and must be pod, not void
value = std::is_same<CommandPacket, CommandClass>::value == 0 && //
std::is_void<CommandClass>::value == 0 && cb::detail::is_pod<CommandClass>::value
};
};
template <class CommandClass, class AllocatorClass>
static CommandPacket* create(AllocatorClass& allocator, uint32_t auxilarySize);
template <class CommandClass>
static CommandPacket* getCommandPacket(CommandClass* commandData);
template <class CommandClass>
static const CommandPacket* getCommandPacket(const CommandClass* commandData);
template <class CommandClass>
static CommandClass* getCommandData(CommandPacket* packet);
template <class CommandClass, typename CastType>
static CastType* getAuxilaryData(CommandClass* commandData);
static void dispatch(const cb::CommandPacket* packet, cb::RenderContext* rc);
#if CB_DEBUG_TAG_COMMANDS
template <class CommandClass>
static CommandPacket& command(CommandClass& cmd);
template <class CommandClass>
static CommandPacket& command(CommandClass* cmd);
template <class CommandClass>
static std::string commandName(CommandClass& cmd);
template <class CommandClass>
static std::string commandName(CommandClass* cmd);
typedef int(*log_function_t)(const char* fmt, ...);
static void log(const cb::CommandPacket* packet, log_function_t logger);
#endif // #if CB_DEBUG_TAG_COMMANDS
private:
// not allowed
template <class CommandClass, typename CastType>
static CastType* getAuxilaryData(CommandClass**);
template <class CommandClass>
static CommandPacket* getCommandPacket(CommandClass**);
template <class CommandClass>
static const CommandPacket* getCommandPacket(const CommandClass**);
public:
cb::RenderContext::function_t dispatchFunction;
void* commandData;
void* auxilaryData; // optional
CommandPacket* nextCommand;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <class CommandClass, class AllocatorClass>
CB_FORCE_INLINE CommandPacket* CommandPacket::create(AllocatorClass& allocator, uint32_t auxilarySize)
{
static_assert(is_valid_type<CommandClass>::value, "COMMAND_INVALID_TYPE");
#if CB_COMMAND_PACKET_ALIGNED
static_assert(alignof(CommandPacket) == alignof(CommandClass), "COMMAND_MUST_BE_ALIGNED_WITH_PACKET");
const uint32_t alignment = alignof(CommandClass);
#else
const uint32_t a1 = alignof(CommandPacket);
const uint32_t a2 = alignof(CommandClass);
const uint32_t alignment = std::max(a1, a2);
#endif
uint8_t* data = allocator.alloc(sizeof(CommandPacket) + sizeof(CommandClass) + auxilarySize, alignment);
CommandPacket* packet = reinterpret_cast<CommandPacket*>(data);
packet->commandData = data + sizeof(CommandPacket);
packet->auxilaryData = data + sizeof(CommandPacket) + sizeof(CommandClass);
#ifndef NDEBUG
if (auxilarySize == 0)
packet->auxilaryData = NULL;
#endif
packet->nextCommand = NULL;
return packet;
}
template <class CommandClass>
CB_FORCE_INLINE CommandPacket* CommandPacket::getCommandPacket(CommandClass* commandData)
{
static_assert(is_valid_type<CommandClass>::value, "COMMAND_INVALID_TYPE");
return reinterpret_cast<CommandPacket*>(reinterpret_cast<uint8_t*>(commandData) - sizeof(CommandPacket));
}
template <class CommandClass>
CB_FORCE_INLINE const CommandPacket* CommandPacket::getCommandPacket(const CommandClass* commandData)
{
static_assert(is_valid_type<CommandClass>::value, "COMMAND_INVALID_TYPE");
return reinterpret_cast<const CommandPacket*>(reinterpret_cast<const uint8_t*>(commandData) -
sizeof(CommandPacket));
}
template <class CommandClass>
CB_FORCE_INLINE CommandClass* CommandPacket::getCommandData(CommandPacket* packet)
{
static_assert(is_valid_type<CommandClass>::value, "COMMAND_INVALID_TYPE");
return reinterpret_cast<CommandClass*>(packet->commandData);
}
template <class CommandClass, typename CastType>
CB_FORCE_INLINE CastType* CommandPacket::getAuxilaryData(CommandClass* commandData)
{
static_assert(is_valid_type<CommandClass>::value, "COMMAND_INVALID_TYPE");
CommandPacket* packet = CommandPacket::getCommandPacket<CommandClass>(commandData);
return reinterpret_cast<CastType*>(packet->auxilaryData);
}
CB_FORCE_INLINE void CommandPacket::dispatch(const cb::CommandPacket* packet, cb::RenderContext* rc)
{
do
{
(*packet->dispatchFunction)(packet->commandData, rc);
packet = packet->nextCommand;
} while (packet != NULL);
}
#if CB_DEBUG_TAG_COMMANDS
template <class CommandClass>
CB_FORCE_INLINE CommandPacket& CommandPacket::command(CommandClass& cmd)
{
return *CommandPacket::getCommandPacket<CommandClass>(&cmd);
}
template <class CommandClass>
CB_FORCE_INLINE CommandPacket& CommandPacket::command(CommandClass* cmd)
{
return *CommandPacket::getCommandPacket<CommandClass>(cmd);
}
template <class CommandClass>
CB_FORCE_INLINE std::string CommandPacket::commandName(CommandClass& cmd)
{
return typeid(&cmd).name();
}
template <class CommandClass>
CB_FORCE_INLINE std::string CommandPacket::commandName(CommandClass* cmd)
{
return typeid(cmd).name();
}
CB_FORCE_INLINE void CommandPacket::log(const cb::CommandPacket* packet, log_function_t logger)
{
do
{
if (packet->nextCommand != NULL)
(*logger)("%s ->", packet->debug.tag);
else
(*logger)("%s", packet->debug.tag);
packet = packet->nextCommand;
} while (packet != NULL);
(*logger)("\n");
}
#endif // #if CB_DEBUG_TAG_COMMANDS
} // namespace cb