|
1 /*------------------------------------------------------------------------ |
|
2 * |
|
3 * EGL 1.3 |
|
4 * ------- |
|
5 * |
|
6 * Copyright (c) 2007 The Khronos Group Inc. |
|
7 * Portions copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
8 * |
|
9 * Permission is hereby granted, free of charge, to any person obtaining a |
|
10 * copy of this software and /or associated documentation files |
|
11 * (the "Materials "), to deal in the Materials without restriction, |
|
12 * including without limitation the rights to use, copy, modify, merge, |
|
13 * publish, distribute, sublicense, and/or sell copies of the Materials, |
|
14 * and to permit persons to whom the Materials are furnished to do so, |
|
15 * subject to the following conditions: |
|
16 * |
|
17 * The above copyright notice and this permission notice shall be included |
|
18 * in all copies or substantial portions of the Materials. |
|
19 * |
|
20 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
23 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
24 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
25 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR |
|
26 * THE USE OR OTHER DEALINGS IN THE MATERIALS. |
|
27 * |
|
28 *//** |
|
29 * \file |
|
30 * \brief Simple implementation of EGL 1.3 |
|
31 * \note caveats: |
|
32 - always renders into the backbuffer and blits it to window (no single buffered rendering) |
|
33 - no native Windows or Mac OS X pixmap support |
|
34 - no power management events |
|
35 - no support for swap interval |
|
36 * \todo what happens in egl functions when eglTerminate has been called but the context and surface are still in use? |
|
37 * \todo OSDeinitMutex should be called in case getEGL fails. |
|
38 * \todo clarify getThread and getCurrentThread distinction. |
|
39 *//*-------------------------------------------------------------------*/ |
|
40 |
|
41 #include "EGL/egl.h" |
|
42 #include "openvg.h" |
|
43 #include "riArray.h" |
|
44 #include "riMath.h" |
|
45 #include "riContext.h" |
|
46 #include "riImage.h" |
|
47 |
|
48 namespace OpenVGRI |
|
49 { |
|
50 |
|
51 #include <windows.h> |
|
52 |
|
53 void* OSGetCurrentThreadID(void) |
|
54 { |
|
55 return (void*)GetCurrentThreadId(); //TODO this is not safe |
|
56 } |
|
57 |
|
58 static HANDLE mutex = NULL; |
|
59 static int mutexRefCount = 0; |
|
60 //acquired mutex cannot be deinited. |
|
61 void OSDeinitMutex(void) |
|
62 { |
|
63 RI_ASSERT(mutex); |
|
64 RI_ASSERT(mutexRefCount == 0); |
|
65 BOOL ret = CloseHandle(mutex); |
|
66 RI_ASSERT(ret); |
|
67 RI_UNREF(ret); |
|
68 } |
|
69 void OSAcquireMutex(void) |
|
70 { |
|
71 if(!mutex) |
|
72 { |
|
73 mutex = CreateMutex(NULL, FALSE, NULL); //initially not locked |
|
74 mutexRefCount = 0; |
|
75 } |
|
76 RI_ASSERT(mutex); |
|
77 DWORD ret = WaitForSingleObject(mutex, INFINITE); |
|
78 RI_ASSERT(ret != WAIT_FAILED); |
|
79 RI_UNREF(ret); |
|
80 mutexRefCount++; |
|
81 } |
|
82 void OSReleaseMutex(void) |
|
83 { |
|
84 RI_ASSERT(mutex); |
|
85 mutexRefCount--; |
|
86 RI_ASSERT(mutexRefCount >= 0); |
|
87 BOOL ret = ReleaseMutex(mutex); |
|
88 RI_ASSERT(ret); |
|
89 RI_UNREF(ret); |
|
90 } |
|
91 |
|
92 static bool isBigEndian() |
|
93 { |
|
94 static const RIuint32 v = 0x12345678u; |
|
95 const RIuint8* p = (const RIuint8*)&v; |
|
96 RI_ASSERT (*p == (RIuint8)0x12u || *p == (RIuint8)0x78u); |
|
97 return (*p == (RIuint8)(0x12)) ? true : false; |
|
98 } |
|
99 |
|
100 |
|
101 #ifdef RI_USE_GLUT |
|
102 # include <GL/gl.h> |
|
103 # define GLUT_DISABLE_ATEXIT_HACK |
|
104 # include "glut.h" |
|
105 |
|
106 struct OSWindowContext |
|
107 { |
|
108 int window; |
|
109 unsigned int* tmp; |
|
110 int tmpWidth; |
|
111 int tmpHeight; |
|
112 }; |
|
113 |
|
114 void* OSCreateWindowContext(EGLNativeWindowType window) |
|
115 { |
|
116 try |
|
117 { |
|
118 OSWindowContext* ctx = RI_NEW(OSWindowContext, ()); |
|
119 ctx->window = (int)window; |
|
120 ctx->tmp = NULL; |
|
121 ctx->tmpWidth = 0; |
|
122 ctx->tmpHeight = 0; |
|
123 return ctx; |
|
124 } |
|
125 catch(std::bad_alloc) |
|
126 { |
|
127 return NULL; |
|
128 } |
|
129 } |
|
130 |
|
131 void OSDestroyWindowContext(void* context) |
|
132 { |
|
133 OSWindowContext* ctx = (OSWindowContext*)context; |
|
134 if(ctx) |
|
135 { |
|
136 RI_DELETE_ARRAY(ctx->tmp); |
|
137 RI_DELETE(ctx); |
|
138 } |
|
139 } |
|
140 |
|
141 bool OSIsWindow(const void* context) |
|
142 { |
|
143 OSWindowContext* ctx = (OSWindowContext*)context; |
|
144 if(ctx) |
|
145 { |
|
146 //TODO implement |
|
147 return true; |
|
148 } |
|
149 return false; |
|
150 } |
|
151 |
|
152 void OSGetWindowSize(const void* context, int& width, int& height) |
|
153 { |
|
154 OSWindowContext* ctx = (OSWindowContext*)context; |
|
155 if(ctx) |
|
156 { |
|
157 int currWin = glutGetWindow(); |
|
158 glutSetWindow(ctx->window); |
|
159 width = glutGet(GLUT_WINDOW_WIDTH); |
|
160 height = glutGet(GLUT_WINDOW_HEIGHT); |
|
161 glutSetWindow(currWin); |
|
162 } |
|
163 else |
|
164 { |
|
165 width = 0; |
|
166 height = 0; |
|
167 } |
|
168 } |
|
169 |
|
170 void OSBlitToWindow(void* context, const Drawable* drawable) |
|
171 { |
|
172 OSWindowContext* ctx = (OSWindowContext*)context; |
|
173 if(ctx) |
|
174 { |
|
175 int w = drawable->getWidth(); |
|
176 int h = drawable->getHeight(); |
|
177 |
|
178 int currWin = glutGetWindow(); |
|
179 glutSetWindow(ctx->window); |
|
180 |
|
181 if(!ctx->tmp || ctx->tmpWidth != w || ctx->tmpHeight != h) |
|
182 { |
|
183 RI_DELETE_ARRAY(ctx->tmp); |
|
184 ctx->tmp = NULL; |
|
185 try |
|
186 { |
|
187 ctx->tmp = RI_NEW_ARRAY(unsigned int, w*h); //throws bad_alloc |
|
188 ctx->tmpWidth = w; |
|
189 ctx->tmpHeight = h; |
|
190 } |
|
191 catch(std::bad_alloc) |
|
192 { |
|
193 //do nothing |
|
194 } |
|
195 } |
|
196 |
|
197 if(ctx->tmp) |
|
198 { |
|
199 glViewport(0, 0, w, h); |
|
200 glDisable(GL_DEPTH_TEST); |
|
201 glMatrixMode(GL_PROJECTION); |
|
202 glLoadIdentity(); |
|
203 glMatrixMode(GL_MODELVIEW); |
|
204 glLoadIdentity(); |
|
205 //NOTE: we assume here that the display is always in sRGB color space |
|
206 VGImageFormat f = VG_sXBGR_8888; |
|
207 if(isBigEndian()) |
|
208 f = VG_sRGBX_8888; |
|
209 vgReadPixels(ctx->tmp, w*sizeof(unsigned int), f, 0, 0, w, h); |
|
210 glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, ctx->tmp); |
|
211 } |
|
212 |
|
213 glutSwapBuffers(); //shows the OpenGL frame buffer |
|
214 glutSetWindow(currWin); //restore the current window |
|
215 } |
|
216 } |
|
217 |
|
218 EGLDisplay OSGetDisplay(EGLNativeDisplayType display_id) |
|
219 { |
|
220 return (EGLDisplay)display_id; //just casting to (EGLDisplay) should be enough to make a unique identifier out of this |
|
221 } |
|
222 |
|
223 #else |
|
224 //Windows native |
|
225 #ifndef _WINDOWS_ |
|
226 # define _WIN32_WINNT 0x0400 |
|
227 # define WIN32_LEAN_AND_MEAN |
|
228 # include <windows.h> |
|
229 #endif |
|
230 |
|
231 struct OSWindowContext |
|
232 { |
|
233 HWND window; |
|
234 HDC bufDC; |
|
235 HBITMAP bufDIB; |
|
236 unsigned int* tmp; |
|
237 int tmpWidth; |
|
238 int tmpHeight; |
|
239 }; |
|
240 |
|
241 OSWindowContext* OSCreateWindowContext(EGLNativeWindowType window) |
|
242 { |
|
243 OSWindowContext* ctx = NULL; |
|
244 try |
|
245 { |
|
246 ctx = RI_NEW(OSWindowContext, ()); |
|
247 } |
|
248 catch(std::bad_alloc) |
|
249 { |
|
250 return NULL; |
|
251 } |
|
252 |
|
253 ctx->window = (HWND)window; |
|
254 HDC winDC = GetDC(ctx->window); |
|
255 ctx->bufDC = CreateCompatibleDC(winDC); |
|
256 ReleaseDC(ctx->window, winDC); |
|
257 if(!ctx->bufDC) |
|
258 { |
|
259 RI_DELETE(ctx); |
|
260 return NULL; |
|
261 } |
|
262 |
|
263 ctx->bufDIB = NULL; |
|
264 ctx->tmp = NULL; |
|
265 ctx->tmpWidth = 0; |
|
266 ctx->tmpHeight = 0; |
|
267 return ctx; |
|
268 } |
|
269 |
|
270 void OSDestroyWindowContext(OSWindowContext* context) |
|
271 { |
|
272 OSWindowContext* ctx = (OSWindowContext*)context; |
|
273 if(ctx) |
|
274 { |
|
275 if(ctx->bufDC) |
|
276 { |
|
277 SelectObject(ctx->bufDC, NULL); |
|
278 DeleteDC(ctx->bufDC); |
|
279 } |
|
280 if(ctx->bufDIB) |
|
281 DeleteObject(ctx->bufDIB); |
|
282 RI_DELETE(ctx); |
|
283 } |
|
284 } |
|
285 |
|
286 bool OSIsWindow(const OSWindowContext* context) |
|
287 { |
|
288 OSWindowContext* ctx = (OSWindowContext*)context; |
|
289 if(ctx) |
|
290 { |
|
291 if(IsWindow(ctx->window)) |
|
292 return true; |
|
293 } |
|
294 return false; |
|
295 } |
|
296 |
|
297 void OSGetWindowSize(const OSWindowContext* context, int& width, int& height) |
|
298 { |
|
299 OSWindowContext* ctx = (OSWindowContext*)context; |
|
300 if(ctx) |
|
301 { |
|
302 RECT rect; |
|
303 GetClientRect(ctx->window, &rect); |
|
304 width = rect.right - rect.left; |
|
305 height = rect.bottom - rect.top; |
|
306 } |
|
307 else |
|
308 { |
|
309 width = 0; |
|
310 height = 0; |
|
311 } |
|
312 } |
|
313 |
|
314 void OSBlitToWindow(OSWindowContext* context, const Drawable* drawable) |
|
315 { |
|
316 OSWindowContext* ctx = (OSWindowContext*)context; |
|
317 if(ctx) |
|
318 { |
|
319 int w = drawable->getWidth(); |
|
320 int h = drawable->getHeight(); |
|
321 |
|
322 if(!ctx->tmp || !ctx->bufDIB || ctx->tmpWidth != w || ctx->tmpHeight != h) |
|
323 { |
|
324 if(ctx->bufDIB) |
|
325 DeleteObject(ctx->bufDIB); |
|
326 ctx->tmp = NULL; |
|
327 ctx->bufDIB = NULL; |
|
328 |
|
329 ctx->tmpWidth = w; |
|
330 ctx->tmpHeight = h; |
|
331 |
|
332 struct |
|
333 { |
|
334 BITMAPINFOHEADER header; |
|
335 DWORD rMask; |
|
336 DWORD gMask; |
|
337 DWORD bMask; |
|
338 } bmi; |
|
339 bmi.header.biSize = sizeof(BITMAPINFOHEADER); |
|
340 bmi.header.biWidth = w; |
|
341 bmi.header.biHeight = h; |
|
342 bmi.header.biPlanes = 1; |
|
343 bmi.header.biBitCount = (WORD)32; |
|
344 bmi.header.biCompression = BI_BITFIELDS; |
|
345 bmi.rMask = 0x000000ff; |
|
346 bmi.gMask = 0x0000ff00; |
|
347 bmi.bMask = 0x00ff0000; |
|
348 ctx->bufDIB = CreateDIBSection(ctx->bufDC, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, (void**)&ctx->tmp, NULL, 0); |
|
349 if(!ctx->bufDIB) |
|
350 { |
|
351 ctx->tmp = NULL; |
|
352 return; |
|
353 } |
|
354 } |
|
355 |
|
356 if(ctx->tmp) |
|
357 { |
|
358 //NOTE: we assume here that the display is always in sRGB color space |
|
359 GdiFlush(); |
|
360 VGImageFormat f = VG_sABGR_8888_PRE; |
|
361 if(isBigEndian()) |
|
362 f = VG_sRGBA_8888_PRE; |
|
363 vgReadPixels(ctx->tmp, w*sizeof(unsigned int), f, 0, 0, w, h); |
|
364 |
|
365 SelectObject(ctx->bufDC, ctx->bufDIB); |
|
366 HDC winDC = GetDC(ctx->window); |
|
367 BitBlt(winDC, 0, 0, w, h, ctx->bufDC, 0, 0, SRCCOPY); |
|
368 ReleaseDC(ctx->window, winDC); |
|
369 SelectObject(ctx->bufDC, NULL); |
|
370 } |
|
371 } |
|
372 } |
|
373 |
|
374 EGLDisplay OSGetDisplay(EGLNativeDisplayType display_id) |
|
375 { |
|
376 RI_UNREF(display_id); |
|
377 return (EGLDisplay)1; //support only a single display |
|
378 } |
|
379 |
|
380 #endif |
|
381 |
|
382 } //namespace OpenVGRI |