Subversion Repositories Kolibri OS

Rev

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

  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 <windows.h>
  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. }
  640.