45ac3477e82d9521597582bd6fb24a2b856ca15f
[mesa.git] / src / gallium / state_trackers / wgl / shared / stw_framebuffer.c
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include <windows.h>
29
30 #include "main/context.h"
31 #include "pipe/p_format.h"
32 #include "pipe/p_screen.h"
33 #include "state_tracker/st_context.h"
34 #include "state_tracker/st_public.h"
35
36 #ifdef DEBUG
37 #include "trace/tr_screen.h"
38 #include "trace/tr_texture.h"
39 #endif
40
41 #include "stw_framebuffer.h"
42 #include "stw_device.h"
43 #include "stw_public.h"
44 #include "stw_winsys.h"
45 #include "stw_tls.h"
46
47
48 /**
49 * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
50 * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx
51 */
52 static LRESULT CALLBACK
53 stw_call_window_proc(
54 int nCode,
55 WPARAM wParam,
56 LPARAM lParam )
57 {
58 struct stw_tls_data *tls_data;
59 PCWPSTRUCT pParams = (PCWPSTRUCT)lParam;
60
61 tls_data = stw_tls_get_data();
62 if(!tls_data)
63 return 0;
64
65 if (nCode < 0)
66 return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam);
67
68 if (pParams->message == WM_SIZE && pParams->wParam != SIZE_MINIMIZED) {
69 struct stw_framebuffer *fb;
70
71 pipe_mutex_lock( stw_dev->mutex );
72 for (fb = stw_dev->fb_head; fb != NULL; fb = fb->next)
73 if (fb->hWnd == pParams->hwnd)
74 break;
75 pipe_mutex_unlock( stw_dev->mutex );
76
77 if(fb) {
78 unsigned width = LOWORD( pParams->lParam );
79 unsigned height = HIWORD( pParams->lParam );
80
81 /* FIXME: The mesa statetracker makes the assumptions that only
82 * one context is using the framebuffer, and that that context is the
83 * current one. However neither holds true, as WGL allows more than
84 * one context to be bound to the same drawable, and this function can
85 * be called from any thread.
86 */
87 pipe_mutex_lock( fb->mutex );
88 st_resize_framebuffer( fb->stfb, width, height );
89 pipe_mutex_unlock( fb->mutex );
90 }
91 }
92
93 return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam);
94 }
95
96
97 /**
98 * Create a new framebuffer object which will correspond to the given HDC.
99 */
100 struct stw_framebuffer *
101 stw_framebuffer_create_locked(
102 HDC hdc,
103 int iPixelFormat )
104 {
105 struct stw_framebuffer *fb;
106 const struct stw_pixelformat_info *pfi;
107
108 fb = CALLOC_STRUCT( stw_framebuffer );
109 if (fb == NULL)
110 return NULL;
111
112 fb->hDC = hdc;
113 fb->hWnd = WindowFromDC( hdc );
114 fb->iPixelFormat = iPixelFormat;
115
116 fb->pfi = pfi = stw_pixelformat_get_info( iPixelFormat - 1 );
117
118 stw_pixelformat_visual(&fb->visual, pfi);
119
120 pipe_mutex_init( fb->mutex );
121
122 fb->next = stw_dev->fb_head;
123 stw_dev->fb_head = fb;
124
125 return fb;
126 }
127
128
129 static void
130 stw_framebuffer_get_size( struct stw_framebuffer *fb, GLuint *pwidth, GLuint *pheight )
131 {
132 GLuint width, height;
133
134 if (fb->hWnd) {
135 RECT rect;
136 GetClientRect( fb->hWnd, &rect );
137 width = rect.right - rect.left;
138 height = rect.bottom - rect.top;
139 }
140 else {
141 width = GetDeviceCaps( fb->hDC, HORZRES );
142 height = GetDeviceCaps( fb->hDC, VERTRES );
143 }
144
145 if(width < 1)
146 width = 1;
147 if(height < 1)
148 height = 1;
149
150 *pwidth = width;
151 *pheight = height;
152 }
153
154
155 BOOL
156 stw_framebuffer_allocate(
157 struct stw_framebuffer *fb)
158 {
159 pipe_mutex_lock( fb->mutex );
160
161 if(!fb->stfb) {
162 const struct stw_pixelformat_info *pfi = fb->pfi;
163 enum pipe_format colorFormat, depthFormat, stencilFormat;
164 GLuint width, height;
165
166 colorFormat = pfi->color_format;
167
168 assert(pf_layout( pfi->depth_stencil_format ) == PIPE_FORMAT_LAYOUT_RGBAZS );
169
170 if(pf_get_component_bits( pfi->depth_stencil_format, PIPE_FORMAT_COMP_Z ))
171 depthFormat = pfi->depth_stencil_format;
172 else
173 depthFormat = PIPE_FORMAT_NONE;
174
175 if(pf_get_component_bits( pfi->depth_stencil_format, PIPE_FORMAT_COMP_S ))
176 stencilFormat = pfi->depth_stencil_format;
177 else
178 stencilFormat = PIPE_FORMAT_NONE;
179
180 stw_framebuffer_get_size(fb, &width, &height);
181
182 fb->stfb = st_create_framebuffer(
183 &fb->visual,
184 colorFormat,
185 depthFormat,
186 stencilFormat,
187 width,
188 height,
189 (void *) fb );
190 }
191
192 pipe_mutex_unlock( fb->mutex );
193
194 return fb->stfb ? TRUE : FALSE;
195 }
196
197
198 void
199 stw_framebuffer_resize(
200 struct stw_framebuffer *fb)
201 {
202 GLuint width, height;
203 assert(fb->stfb);
204 stw_framebuffer_get_size(fb, &width, &height);
205 st_resize_framebuffer(fb->stfb, width, height);
206 }
207
208
209 static INLINE void
210 stw_framebuffer_destroy(
211 struct stw_framebuffer *fb )
212 {
213 struct stw_framebuffer **link;
214
215 pipe_mutex_lock( stw_dev->mutex );
216
217 link = &stw_dev->fb_head;
218 while (link && *link != fb)
219 link = &(*link)->next;
220 assert(*link);
221 if (link)
222 *link = fb->next;
223 fb->next = NULL;
224
225 pipe_mutex_unlock( stw_dev->mutex );
226
227 st_unreference_framebuffer(fb->stfb);
228
229 pipe_mutex_destroy( fb->mutex );
230
231 FREE( fb );
232 }
233
234
235 void
236 stw_framebuffer_cleanup( void )
237 {
238 struct stw_framebuffer *fb;
239 struct stw_framebuffer *next;
240
241 pipe_mutex_lock( stw_dev->mutex );
242
243 fb = stw_dev->fb_head;
244 while (fb) {
245 next = fb->next;
246 stw_framebuffer_destroy(fb);
247 fb = next;
248 }
249 stw_dev->fb_head = NULL;
250
251 pipe_mutex_unlock( stw_dev->mutex );
252 }
253
254
255 /**
256 * Given an hdc, return the corresponding stw_framebuffer.
257 */
258 struct stw_framebuffer *
259 stw_framebuffer_from_hdc_locked(
260 HDC hdc )
261 {
262 struct stw_framebuffer *fb;
263
264 for (fb = stw_dev->fb_head; fb != NULL; fb = fb->next)
265 if (fb->hDC == hdc)
266 break;
267
268 return fb;
269 }
270
271
272 /**
273 * Given an hdc, return the corresponding stw_framebuffer.
274 */
275 struct stw_framebuffer *
276 stw_framebuffer_from_hdc(
277 HDC hdc )
278 {
279 struct stw_framebuffer *fb;
280
281 pipe_mutex_lock( stw_dev->mutex );
282 fb = stw_framebuffer_from_hdc_locked(hdc);
283 pipe_mutex_unlock( stw_dev->mutex );
284
285 return fb;
286 }
287
288
289 BOOL
290 stw_pixelformat_set(
291 HDC hdc,
292 int iPixelFormat )
293 {
294 uint count;
295 uint index;
296 struct stw_framebuffer *fb;
297
298 index = (uint) iPixelFormat - 1;
299 count = stw_pixelformat_get_extended_count();
300 if (index >= count)
301 return FALSE;
302
303 pipe_mutex_lock( stw_dev->mutex );
304
305 fb = stw_framebuffer_from_hdc_locked(hdc);
306 if(fb) {
307 /* SetPixelFormat must be called only once */
308 pipe_mutex_unlock( stw_dev->mutex );
309 return FALSE;
310 }
311
312 fb = stw_framebuffer_create_locked(hdc, iPixelFormat);
313 if(!fb) {
314 pipe_mutex_unlock( stw_dev->mutex );
315 return FALSE;
316 }
317
318 pipe_mutex_unlock( stw_dev->mutex );
319
320 /* Some applications mistakenly use the undocumented wglSetPixelFormat
321 * function instead of SetPixelFormat, so we call SetPixelFormat here to
322 * avoid opengl32.dll's wglCreateContext to fail */
323 if (GetPixelFormat(hdc) == 0) {
324 SetPixelFormat(hdc, iPixelFormat, NULL);
325 }
326
327 return TRUE;
328 }
329
330
331 int
332 stw_pixelformat_get(
333 HDC hdc )
334 {
335 struct stw_framebuffer *fb;
336
337 fb = stw_framebuffer_from_hdc(hdc);
338 if(!fb)
339 return 0;
340
341 return fb->iPixelFormat;
342 }
343
344
345 BOOL
346 stw_swap_buffers(
347 HDC hdc )
348 {
349 struct stw_framebuffer *fb;
350 struct pipe_screen *screen;
351 struct pipe_surface *surface;
352
353 fb = stw_framebuffer_from_hdc( hdc );
354 if (fb == NULL)
355 return FALSE;
356
357 pipe_mutex_lock( fb->mutex );
358
359 /* If we're swapping the buffer associated with the current context
360 * we have to flush any pending rendering commands first.
361 */
362 st_notify_swapbuffers( fb->stfb );
363
364 screen = stw_dev->screen;
365
366 if(!st_get_framebuffer_surface( fb->stfb, ST_SURFACE_BACK_LEFT, &surface )) {
367 /* FIXME: this shouldn't happen, but does on glean */
368 pipe_mutex_unlock( fb->mutex );
369 return FALSE;
370 }
371
372 #ifdef DEBUG
373 if(stw_dev->trace_running) {
374 screen = trace_screen(screen)->screen;
375 surface = trace_surface(surface)->surface;
376 }
377 #endif
378
379 stw_dev->stw_winsys->flush_frontbuffer( screen, surface, hdc );
380
381 pipe_mutex_unlock( fb->mutex );
382
383 return TRUE;
384 }
385
386
387 BOOL
388 stw_swap_layer_buffers(
389 HDC hdc,
390 UINT fuPlanes )
391 {
392 if(fuPlanes & WGL_SWAP_MAIN_PLANE)
393 return stw_swap_buffers(hdc);
394
395 return FALSE;
396 }
397
398
399 boolean
400 stw_framebuffer_init_thread(void)
401 {
402 struct stw_tls_data *tls_data;
403
404 tls_data = stw_tls_get_data();
405 if(!tls_data)
406 return FALSE;
407
408 tls_data->hCallWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC,
409 stw_call_window_proc,
410 NULL,
411 GetCurrentThreadId());
412 if(tls_data->hCallWndProcHook == NULL)
413 return FALSE;
414
415 return TRUE;
416 }
417
418 void
419 stw_framebuffer_cleanup_thread(void)
420 {
421 struct stw_tls_data *tls_data;
422
423 tls_data = stw_tls_get_data();
424 if(!tls_data)
425 return;
426
427 if(tls_data->hCallWndProcHook) {
428 UnhookWindowsHookEx(tls_data->hCallWndProcHook);
429 tls_data->hCallWndProcHook = NULL;
430 }
431 }