Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/**************************************************************************
2
 *
3
 * Copyright 2008-2009 Vmware, Inc.
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 VMWARE 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 
29
 
30
#include "pipe/p_format.h"
31
#include "pipe/p_screen.h"
32
#include "util/u_format.h"
33
#include "util/u_memory.h"
34
#include "hud/hud_context.h"
35
#include "state_tracker/st_api.h"
36
 
37
#include "stw_icd.h"
38
#include "stw_framebuffer.h"
39
#include "stw_device.h"
40
#include "stw_winsys.h"
41
#include "stw_tls.h"
42
#include "stw_context.h"
43
#include "stw_st.h"
44
 
45
 
46
/**
47
 * Search the framebuffer with the matching HWND while holding the
48
 * stw_dev::fb_mutex global lock.
49
 */
50
static INLINE struct stw_framebuffer *
51
stw_framebuffer_from_hwnd_locked(
52
   HWND hwnd )
53
{
54
   struct stw_framebuffer *fb;
55
 
56
   for (fb = stw_dev->fb_head; fb != NULL; fb = fb->next)
57
      if (fb->hWnd == hwnd) {
58
         pipe_mutex_lock(fb->mutex);
59
         break;
60
      }
61
 
62
   return fb;
63
}
64
 
65
 
66
/**
67
 * Destroy this framebuffer. Both stw_dev::fb_mutex and stw_framebuffer::mutex
68
 * must be held, by this order.  If there are still references to the
69
 * framebuffer, nothing will happen.
70
 */
71
static INLINE void
72
stw_framebuffer_destroy_locked(
73
   struct stw_framebuffer *fb )
74
{
75
   struct stw_framebuffer **link;
76
 
77
   /* check the reference count */
78
   fb->refcnt--;
79
   if (fb->refcnt) {
80
      pipe_mutex_unlock( fb->mutex );
81
      return;
82
   }
83
 
84
   link = &stw_dev->fb_head;
85
   while (*link != fb)
86
      link = &(*link)->next;
87
   assert(*link);
88
   *link = fb->next;
89
   fb->next = NULL;
90
 
91
   if(fb->shared_surface)
92
      stw_dev->stw_winsys->shared_surface_close(stw_dev->screen, fb->shared_surface);
93
 
94
   stw_st_destroy_framebuffer_locked(fb->stfb);
95
 
96
   pipe_mutex_unlock( fb->mutex );
97
 
98
   pipe_mutex_destroy( fb->mutex );
99
 
100
   FREE( fb );
101
}
102
 
103
 
104
void
105
stw_framebuffer_release(
106
   struct stw_framebuffer *fb)
107
{
108
   assert(fb);
109
   pipe_mutex_unlock( fb->mutex );
110
}
111
 
112
 
113
static INLINE void
114
stw_framebuffer_get_size( struct stw_framebuffer *fb )
115
{
116
   LONG width, height;
117
   RECT client_rect;
118
   RECT window_rect;
119
   POINT client_pos;
120
 
121
   /*
122
    * Sanity checking.
123
    */
124
 
125
   assert(fb->hWnd);
126
   assert(fb->width && fb->height);
127
   assert(fb->client_rect.right  == fb->client_rect.left + fb->width);
128
   assert(fb->client_rect.bottom == fb->client_rect.top  + fb->height);
129
 
130
   /*
131
    * Get the client area size.
132
    */
133
 
134
   if (!GetClientRect(fb->hWnd, &client_rect)) {
135
      return;
136
   }
137
 
138
   assert(client_rect.left == 0);
139
   assert(client_rect.top == 0);
140
   width  = client_rect.right  - client_rect.left;
141
   height = client_rect.bottom - client_rect.top;
142
 
143
   fb->minimized = width == 0 || height == 0;
144
 
145
   if (width <= 0 || height <= 0) {
146
      /*
147
       * When the window is minimized GetClientRect will return zeros.  Simply
148
       * preserve the current window size, until the window is restored or
149
       * maximized again.
150
       */
151
 
152
      return;
153
   }
154
 
155
   if (width != fb->width || height != fb->height) {
156
      fb->must_resize = TRUE;
157
      fb->width = width;
158
      fb->height = height;
159
   }
160
 
161
   client_pos.x = 0;
162
   client_pos.y = 0;
163
   if (ClientToScreen(fb->hWnd, &client_pos) &&
164
       GetWindowRect(fb->hWnd, &window_rect)) {
165
      fb->client_rect.left = client_pos.x - window_rect.left;
166
      fb->client_rect.top  = client_pos.y - window_rect.top;
167
   }
168
 
169
   fb->client_rect.right  = fb->client_rect.left + fb->width;
170
   fb->client_rect.bottom = fb->client_rect.top  + fb->height;
171
 
172
#if 0
173
   debug_printf("\n");
174
   debug_printf("%s: hwnd = %p\n", __FUNCTION__, fb->hWnd);
175
   debug_printf("%s: client_position = (%li, %li)\n",
176
                __FUNCTION__, client_pos.x, client_pos.y);
177
   debug_printf("%s: window_rect = (%li, %li) - (%li, %li)\n",
178
                __FUNCTION__,
179
                window_rect.left, window_rect.top,
180
                window_rect.right, window_rect.bottom);
181
   debug_printf("%s: client_rect = (%li, %li) - (%li, %li)\n",
182
                __FUNCTION__,
183
                fb->client_rect.left, fb->client_rect.top,
184
                fb->client_rect.right, fb->client_rect.bottom);
185
#endif
186
}
187
 
188
 
189
/**
190
 * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
191
 * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx
192
 */
193
LRESULT CALLBACK
194
stw_call_window_proc(
195
   int nCode,
196
   WPARAM wParam,
197
   LPARAM lParam )
198
{
199
   struct stw_tls_data *tls_data;
200
   PCWPSTRUCT pParams = (PCWPSTRUCT)lParam;
201
   struct stw_framebuffer *fb;
202
 
203
   tls_data = stw_tls_get_data();
204
   if(!tls_data)
205
      return 0;
206
 
207
   if (nCode < 0 || !stw_dev)
208
       return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam);
209
 
210
   if (pParams->message == WM_WINDOWPOSCHANGED) {
211
      /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to
212
       * http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx
213
       * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it
214
       * can be masked out by the application. */
215
      LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam;
216
      if((lpWindowPos->flags & SWP_SHOWWINDOW) ||
217
         !(lpWindowPos->flags & SWP_NOMOVE) ||
218
         !(lpWindowPos->flags & SWP_NOSIZE)) {
219
         fb = stw_framebuffer_from_hwnd( pParams->hwnd );
220
         if(fb) {
221
            /* Size in WINDOWPOS includes the window frame, so get the size
222
             * of the client area via GetClientRect.  */
223
            stw_framebuffer_get_size(fb);
224
            stw_framebuffer_release(fb);
225
         }
226
      }
227
   }
228
   else if (pParams->message == WM_DESTROY) {
229
      pipe_mutex_lock( stw_dev->fb_mutex );
230
      fb = stw_framebuffer_from_hwnd_locked( pParams->hwnd );
231
      if(fb)
232
         stw_framebuffer_destroy_locked(fb);
233
      pipe_mutex_unlock( stw_dev->fb_mutex );
234
   }
235
 
236
   return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam);
237
}
238
 
239
 
240
struct stw_framebuffer *
241
stw_framebuffer_create(
242
   HDC hdc,
243
   int iPixelFormat )
244
{
245
   HWND hWnd;
246
   struct stw_framebuffer *fb;
247
   const struct stw_pixelformat_info *pfi;
248
 
249
   /* We only support drawing to a window. */
250
   hWnd = WindowFromDC( hdc );
251
   if(!hWnd)
252
      return NULL;
253
 
254
   fb = CALLOC_STRUCT( stw_framebuffer );
255
   if (fb == NULL)
256
      return NULL;
257
 
258
   fb->hWnd = hWnd;
259
   fb->iPixelFormat = iPixelFormat;
260
 
261
   /*
262
    * We often need a displayable pixel format to make GDI happy. Set it here (always 1, i.e.,
263
    * out first pixel format) where appropriat.
264
    */
265
   fb->iDisplayablePixelFormat = iPixelFormat <= stw_dev->pixelformat_count ? iPixelFormat : 1;
266
 
267
   fb->pfi = pfi = stw_pixelformat_get_info( iPixelFormat );
268
   fb->stfb = stw_st_create_framebuffer( fb );
269
   if (!fb->stfb) {
270
      FREE( fb );
271
      return NULL;
272
   }
273
 
274
   fb->refcnt = 1;
275
 
276
   /*
277
    * Windows can be sometimes have zero width and or height, but we ensure
278
    * a non-zero framebuffer size at all times.
279
    */
280
 
281
   fb->must_resize = TRUE;
282
   fb->width  = 1;
283
   fb->height = 1;
284
   fb->client_rect.left   = 0;
285
   fb->client_rect.top    = 0;
286
   fb->client_rect.right  = fb->client_rect.left + fb->width;
287
   fb->client_rect.bottom = fb->client_rect.top  + fb->height;
288
 
289
   stw_framebuffer_get_size(fb);
290
 
291
   pipe_mutex_init( fb->mutex );
292
 
293
   /* This is the only case where we lock the stw_framebuffer::mutex before
294
    * stw_dev::fb_mutex, since no other thread can know about this framebuffer
295
    * and we must prevent any other thread from destroying it before we return.
296
    */
297
   pipe_mutex_lock( fb->mutex );
298
 
299
   pipe_mutex_lock( stw_dev->fb_mutex );
300
   fb->next = stw_dev->fb_head;
301
   stw_dev->fb_head = fb;
302
   pipe_mutex_unlock( stw_dev->fb_mutex );
303
 
304
   return fb;
305
}
306
 
307
/**
308
 * Have ptr reference fb.  The referenced framebuffer should be locked.
309
 */
310
void
311
stw_framebuffer_reference(
312
   struct stw_framebuffer **ptr,
313
   struct stw_framebuffer *fb)
314
{
315
   struct stw_framebuffer *old_fb = *ptr;
316
 
317
   if (old_fb == fb)
318
      return;
319
 
320
   if (fb)
321
      fb->refcnt++;
322
   if (old_fb) {
323
      pipe_mutex_lock(stw_dev->fb_mutex);
324
 
325
      pipe_mutex_lock(old_fb->mutex);
326
      stw_framebuffer_destroy_locked(old_fb);
327
 
328
      pipe_mutex_unlock(stw_dev->fb_mutex);
329
   }
330
 
331
   *ptr = fb;
332
}
333
 
334
 
335
/**
336
 * Update the framebuffer's size if necessary.
337
 */
338
void
339
stw_framebuffer_update(
340
   struct stw_framebuffer *fb)
341
{
342
   assert(fb->stfb);
343
   assert(fb->height);
344
   assert(fb->width);
345
 
346
   /* XXX: It would be nice to avoid checking the size again -- in theory
347
    * stw_call_window_proc would have cought the resize and stored the right
348
    * size already, but unfortunately threads created before the DllMain is
349
    * called don't get a DLL_THREAD_ATTACH notification, and there is no way
350
    * to know of their existing without using the not very portable PSAPI.
351
    */
352
   stw_framebuffer_get_size(fb);
353
}
354
 
355
 
356
void
357
stw_framebuffer_cleanup( void )
358
{
359
   struct stw_framebuffer *fb;
360
   struct stw_framebuffer *next;
361
 
362
   if (!stw_dev)
363
      return;
364
 
365
   pipe_mutex_lock( stw_dev->fb_mutex );
366
 
367
   fb = stw_dev->fb_head;
368
   while (fb) {
369
      next = fb->next;
370
 
371
      pipe_mutex_lock(fb->mutex);
372
      stw_framebuffer_destroy_locked(fb);
373
 
374
      fb = next;
375
   }
376
   stw_dev->fb_head = NULL;
377
 
378
   pipe_mutex_unlock( stw_dev->fb_mutex );
379
}
380
 
381
 
382
/**
383
 * Given an hdc, return the corresponding stw_framebuffer.
384
 */
385
static INLINE struct stw_framebuffer *
386
stw_framebuffer_from_hdc_locked(
387
   HDC hdc )
388
{
389
   HWND hwnd;
390
 
391
   hwnd = WindowFromDC(hdc);
392
   if (!hwnd) {
393
      return NULL;
394
   }
395
 
396
   return stw_framebuffer_from_hwnd_locked(hwnd);
397
}
398
 
399
 
400
/**
401
 * Given an hdc, return the corresponding stw_framebuffer.
402
 */
403
struct stw_framebuffer *
404
stw_framebuffer_from_hdc(
405
   HDC hdc )
406
{
407
   struct stw_framebuffer *fb;
408
 
409
   if (!stw_dev)
410
      return NULL;
411
 
412
   pipe_mutex_lock( stw_dev->fb_mutex );
413
   fb = stw_framebuffer_from_hdc_locked(hdc);
414
   pipe_mutex_unlock( stw_dev->fb_mutex );
415
 
416
   return fb;
417
}
418
 
419
 
420
/**
421
 * Given an hdc, return the corresponding stw_framebuffer.
422
 */
423
struct stw_framebuffer *
424
stw_framebuffer_from_hwnd(
425
   HWND hwnd )
426
{
427
   struct stw_framebuffer *fb;
428
 
429
   pipe_mutex_lock( stw_dev->fb_mutex );
430
   fb = stw_framebuffer_from_hwnd_locked(hwnd);
431
   pipe_mutex_unlock( stw_dev->fb_mutex );
432
 
433
   return fb;
434
}
435
 
436
 
437
BOOL APIENTRY
438
DrvSetPixelFormat(
439
   HDC hdc,
440
   LONG iPixelFormat )
441
{
442
   uint count;
443
   uint index;
444
   struct stw_framebuffer *fb;
445
 
446
   if (!stw_dev)
447
      return FALSE;
448
 
449
   index = (uint) iPixelFormat - 1;
450
   count = stw_pixelformat_get_count();
451
   if (index >= count)
452
      return FALSE;
453
 
454
   fb = stw_framebuffer_from_hdc_locked(hdc);
455
   if(fb) {
456
      /*
457
       * SetPixelFormat must be called only once.  However ignore
458
       * pbuffers, for which the framebuffer object is created first.
459
       */
460
      boolean bPbuffer = fb->bPbuffer;
461
 
462
      stw_framebuffer_release( fb );
463
 
464
      return bPbuffer;
465
   }
466
 
467
   fb = stw_framebuffer_create(hdc, iPixelFormat);
468
   if(!fb) {
469
      return FALSE;
470
   }
471
 
472
   stw_framebuffer_release( fb );
473
 
474
   /* Some applications mistakenly use the undocumented wglSetPixelFormat
475
    * function instead of SetPixelFormat, so we call SetPixelFormat here to
476
    * avoid opengl32.dll's wglCreateContext to fail */
477
   if (GetPixelFormat(hdc) == 0) {
478
      BOOL bRet = SetPixelFormat(hdc, iPixelFormat, NULL);
479
      assert(bRet);
480
   }
481
 
482
   return TRUE;
483
}
484
 
485
 
486
int
487
stw_pixelformat_get(
488
   HDC hdc )
489
{
490
   int iPixelFormat = 0;
491
   struct stw_framebuffer *fb;
492
 
493
   fb = stw_framebuffer_from_hdc(hdc);
494
   if(fb) {
495
      iPixelFormat = fb->iPixelFormat;
496
      stw_framebuffer_release(fb);
497
   }
498
 
499
   return iPixelFormat;
500
}
501
 
502
 
503
BOOL APIENTRY
504
DrvPresentBuffers(HDC hdc, PGLPRESENTBUFFERSDATA data)
505
{
506
   struct stw_framebuffer *fb;
507
   struct pipe_screen *screen;
508
   struct pipe_resource *res;
509
 
510
   if (!stw_dev)
511
      return FALSE;
512
 
513
   fb = stw_framebuffer_from_hdc( hdc );
514
   if (fb == NULL)
515
      return FALSE;
516
 
517
   screen = stw_dev->screen;
518
 
519
   res = (struct pipe_resource *)data->pPrivateData;
520
 
521
   if(data->hSharedSurface != fb->hSharedSurface) {
522
      if(fb->shared_surface) {
523
         stw_dev->stw_winsys->shared_surface_close(screen, fb->shared_surface);
524
         fb->shared_surface = NULL;
525
      }
526
 
527
      fb->hSharedSurface = data->hSharedSurface;
528
 
529
      if(data->hSharedSurface &&
530
         stw_dev->stw_winsys->shared_surface_open) {
531
         fb->shared_surface = stw_dev->stw_winsys->shared_surface_open(screen, fb->hSharedSurface);
532
      }
533
   }
534
 
535
   if (!fb->minimized) {
536
      if (fb->shared_surface) {
537
         stw_dev->stw_winsys->compose(screen,
538
                                      res,
539
                                      fb->shared_surface,
540
                                      &fb->client_rect,
541
                                      data->PresentHistoryToken);
542
      }
543
      else {
544
         stw_dev->stw_winsys->present( screen, res, hdc );
545
      }
546
   }
547
 
548
   stw_framebuffer_update(fb);
549
   stw_notify_current_locked(fb);
550
 
551
   stw_framebuffer_release(fb);
552
 
553
   return TRUE;
554
}
555
 
556
 
557
/**
558
 * Queue a composition.
559
 *
560
 * It will drop the lock on success.
561
 */
562
BOOL
563
stw_framebuffer_present_locked(HDC hdc,
564
                               struct stw_framebuffer *fb,
565
                               struct pipe_resource *res)
566
{
567
   if(stw_dev->callbacks.wglCbPresentBuffers &&
568
      stw_dev->stw_winsys->compose) {
569
      GLCBPRESENTBUFFERSDATA data;
570
 
571
      memset(&data, 0, sizeof data);
572
      data.magic1 = 2;
573
      data.magic2 = 0;
574
      data.AdapterLuid = stw_dev->AdapterLuid;
575
      data.rect = fb->client_rect;
576
      data.pPrivateData = (void *)res;
577
 
578
      stw_notify_current_locked(fb);
579
      stw_framebuffer_release(fb);
580
 
581
      return stw_dev->callbacks.wglCbPresentBuffers(hdc, &data);
582
   }
583
   else {
584
      struct pipe_screen *screen = stw_dev->screen;
585
 
586
      stw_dev->stw_winsys->present( screen, res, hdc );
587
 
588
      stw_framebuffer_update(fb);
589
      stw_notify_current_locked(fb);
590
      stw_framebuffer_release(fb);
591
 
592
      return TRUE;
593
   }
594
}
595
 
596
 
597
BOOL APIENTRY
598
DrvSwapBuffers(
599
   HDC hdc )
600
{
601
   struct stw_context *ctx;
602
   struct stw_framebuffer *fb;
603
 
604
   if (!stw_dev)
605
      return FALSE;
606
 
607
   fb = stw_framebuffer_from_hdc( hdc );
608
   if (fb == NULL)
609
      return FALSE;
610
 
611
   if (!(fb->pfi->pfd.dwFlags & PFD_DOUBLEBUFFER)) {
612
      stw_framebuffer_release(fb);
613
      return TRUE;
614
   }
615
 
616
   /* Display the HUD */
617
   ctx = stw_current_context();
618
   if (ctx && ctx->hud) {
619
      struct pipe_resource *back =
620
         stw_get_framebuffer_resource(fb->stfb, ST_ATTACHMENT_BACK_LEFT);
621
      hud_draw(ctx->hud, back);
622
   }
623
 
624
   stw_flush_current_locked(fb);
625
 
626
   return stw_st_swap_framebuffer_locked(hdc, fb->stfb);
627
}
628
 
629
 
630
BOOL APIENTRY
631
DrvSwapLayerBuffers(
632
   HDC hdc,
633
   UINT fuPlanes )
634
{
635
   if(fuPlanes & WGL_SWAP_MAIN_PLANE)
636
      return DrvSwapBuffers(hdc);
637
 
638
   return FALSE;
639
}