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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
|
#include "SDL.h"
#include "SDL_opengl.h"
#include "graphics_threaded.h"
// platform dependent implementations for transfering render context from the main thread to the graphics thread
// TODO: when SDL 1.3 comes, this can be removed
#if defined(CONF_FAMILY_WINDOWS)
struct SGLContext
{
HDC m_hDC;
HGLRC m_hGLRC;
};
static SGLContext GL_GetCurrentContext()
{
SGLContext Context;
Context.m_hDC = wglGetCurrentDC();
Context.m_hGLRC = wglGetCurrentContext();
return Context;
}
static void GL_MakeCurrent(const SGLContext &Context) { wglMakeCurrent(Context.m_hDC, Context.m_hGLRC); }
static void GL_ReleaseContext(const SGLContext &Context) { wglMakeCurrent(NULL, NULL); }
static void GL_SwapBuffers(const SGLContext &Context) { SwapBuffers(Context.m_hDC); }
#elif defined(CONF_PLATFORM_MACOSX)
#include <objc/objc-runtime.h>
class semaphore
{
SDL_sem *sem;
public:
semaphore() { sem = SDL_CreateSemaphore(0); }
~semaphore() { SDL_DestroySemaphore(sem); }
void wait() { SDL_SemWait(sem); }
void signal() { SDL_SemPost(sem); }
};
struct SGLContext
{
id m_Context;
};
static SGLContext GL_GetCurrentContext()
{
SGLContext Context;
Class NSOpenGLContextClass = (Class) objc_getClass("NSOpenGLContext");
SEL selector = sel_registerName("currentContext");
Context.m_Context = objc_msgSend((objc_object*) NSOpenGLContextClass, selector);
return Context;
}
static void GL_MakeCurrent(const SGLContext &Context)
{
SEL selector = sel_registerName("makeCurrentContext");
objc_msgSend(Context.m_Context, selector);
}
static void GL_ReleaseContext(const SGLContext &Context)
{
Class NSOpenGLContextClass = (Class) objc_getClass("NSOpenGLContext");
SEL selector = sel_registerName("clearCurrentContext");
objc_msgSend((objc_object*) NSOpenGLContextClass, selector);
}
static void GL_SwapBuffers(const SGLContext &Context)
{
SEL selector = sel_registerName("flushBuffer");
objc_msgSend(Context.m_Context, selector);
}
class CAutoreleasePool
{
private:
id m_Pool;
public:
CAutoreleasePool()
{
Class NSAutoreleasePoolClass = (Class) objc_getClass("NSAutoreleasePool");
m_Pool = class_createInstance(NSAutoreleasePoolClass, 0);
SEL selector = sel_registerName("init");
objc_msgSend(m_Pool, selector);
}
~CAutoreleasePool()
{
SEL selector = sel_registerName("drain");
objc_msgSend(m_Pool, selector);
}
};
#elif defined(CONF_FAMILY_UNIX)
#include <GL/glx.h>
struct SGLContext
{
Display *m_pDisplay;
GLXDrawable m_Drawable;
GLXContext m_Context;
};
static SGLContext GL_GetCurrentContext()
{
SGLContext Context;
Context.m_pDisplay = glXGetCurrentDisplay();
Context.m_Drawable = glXGetCurrentDrawable();
Context.m_Context = glXGetCurrentContext();
return Context;
}
static void GL_MakeCurrent(const SGLContext &Context) { glXMakeCurrent(Context.m_pDisplay, Context.m_Drawable, Context.m_Context); }
static void GL_ReleaseContext(const SGLContext &Context) { glXMakeCurrent(Context.m_pDisplay, None, 0x0); }
static void GL_SwapBuffers(const SGLContext &Context) { glXSwapBuffers(Context.m_pDisplay, Context.m_Drawable); }
#else
#error missing implementation
#endif
// basic threaded backend, abstract, missing init and shutdown functions
class CGraphicsBackend_Threaded : public IGraphicsBackend
{
public:
// constructed on the main thread, the rest of the functions is runned on the render thread
class ICommandProcessor
{
public:
virtual ~ICommandProcessor() {}
virtual void RunBuffer(CCommandBuffer *pBuffer) = 0;
};
CGraphicsBackend_Threaded();
virtual void RunBuffer(CCommandBuffer *pBuffer);
virtual bool IsIdle() const;
virtual void WaitForIdle();
protected:
void StartProcessor(ICommandProcessor *pProcessor);
void StopProcessor();
private:
ICommandProcessor *m_pProcessor;
CCommandBuffer * volatile m_pBuffer;
volatile bool m_Shutdown;
semaphore m_Activity;
semaphore m_BufferDone;
void *m_pThread;
static void ThreadFunc(void *pUser);
};
// takes care of implementation independent operations
class CCommandProcessorFragment_General
{
void Cmd_Nop();
void Cmd_Signal(const CCommandBuffer::SCommand_Signal *pCommand);
public:
bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand);
};
// takes care of opengl related rendering
class CCommandProcessorFragment_OpenGL
{
struct CTexture
{
GLuint m_Tex;
int m_MemSize;
};
CTexture m_aTextures[CCommandBuffer::MAX_TEXTURES];
volatile int *m_pTextureMemoryUsage;
public:
enum
{
CMD_INIT = CCommandBuffer::CMDGROUP_PLATFORM_OPENGL,
};
struct SCommand_Init : public CCommandBuffer::SCommand
{
SCommand_Init() : SCommand(CMD_INIT) {}
volatile int *m_pTextureMemoryUsage;
};
private:
static int TexFormatToOpenGLFormat(int TexFormat);
void SetState(const CCommandBuffer::SState &State);
void Cmd_Init(const SCommand_Init *pCommand);
void Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand);
void Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand);
void Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand);
void Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand);
void Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand);
void Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand);
public:
CCommandProcessorFragment_OpenGL();
bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand);
};
// takes care of sdl related commands
class CCommandProcessorFragment_SDL
{
// SDL stuff
SGLContext m_GLContext;
public:
enum
{
CMD_INIT = CCommandBuffer::CMDGROUP_PLATFORM_SDL,
CMD_SHUTDOWN,
};
struct SCommand_Init : public CCommandBuffer::SCommand
{
SCommand_Init() : SCommand(CMD_INIT) {}
SGLContext m_Context;
};
struct SCommand_Shutdown : public CCommandBuffer::SCommand
{
SCommand_Shutdown() : SCommand(CMD_SHUTDOWN) {}
};
private:
void Cmd_Init(const SCommand_Init *pCommand);
void Cmd_Shutdown(const SCommand_Shutdown *pCommand);
void Cmd_Swap(const CCommandBuffer::SCommand_Swap *pCommand);
void Cmd_VideoModes(const CCommandBuffer::SCommand_VideoModes *pCommand);
public:
CCommandProcessorFragment_SDL();
bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand);
};
// command processor impelementation, uses the fragments to combine into one processor
class CCommandProcessor_SDL_OpenGL : public CGraphicsBackend_Threaded::ICommandProcessor
{
CCommandProcessorFragment_OpenGL m_OpenGL;
CCommandProcessorFragment_SDL m_SDL;
CCommandProcessorFragment_General m_General;
public:
virtual void RunBuffer(CCommandBuffer *pBuffer);
};
// graphics backend implemented with SDL and OpenGL
class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded
{
SDL_Surface *m_pScreenSurface;
ICommandProcessor *m_pProcessor;
SGLContext m_GLContext;
volatile int m_TextureMemoryUsage;
public:
virtual int Init(const char *pName, int *Width, int *Height, int FsaaSamples, int Flags);
virtual int Shutdown();
virtual int MemoryUsage() const;
virtual void Minimize();
virtual void Maximize();
virtual int WindowActive();
virtual int WindowOpen();
};
|