⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 surface_gdi.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * 2D Surface implementation without OpenGL
 *
 * Copyright 1997-2000 Marcus Meissner
 * Copyright 1998-2000 Lionel Ulmer
 * Copyright 2000-2001 TransGaming Technologies Inc.
 * Copyright 2002-2005 Jason Edmeades
 * Copyright 2002-2003 Raphael Junqueira
 * Copyright 2004 Christian Costa
 * Copyright 2005 Oliver Stieber
 * Copyright 2006-2008 Stefan D鰏inger
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "config.h"
#include "wine/port.h"
#include "wined3d_private.h"

#include <assert.h>
#include <stdio.h>

/* Use the d3d_surface debug channel to have one channel for all surfaces */
WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
WINE_DECLARE_DEBUG_CHANNEL(fps);

/*****************************************************************************
 * x11_copy_to_screen
 *
 * Helper function that blts the front buffer contents to the target window
 *
 * Params:
 *  This: Surface to copy from
 *  rc: Rectangle to copy
 *
 *****************************************************************************/
static void
x11_copy_to_screen(IWineD3DSurfaceImpl *This,
                   LPRECT rc)
{
    if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
    {
        POINT offset = {0,0};
        HWND hDisplayWnd;
        HDC hDisplayDC;
        HDC hSurfaceDC = 0;
        RECT drawrect;
        TRACE("(%p)->(%p): Copying to screen\n", This, rc);

        hSurfaceDC = This->hDC;

        hDisplayWnd = This->resource.wineD3DDevice->ddraw_window;
        hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE);
        if(rc)
        {
            TRACE(" copying rect (%d,%d)->(%d,%d), offset (%d,%d)\n",
            rc->left, rc->top, rc->right, rc->bottom, offset.x, offset.y);
        }

        /* Front buffer coordinates are screen coordinates. Map them to the destination
         * window if not fullscreened
         */
        if(!This->resource.wineD3DDevice->ddraw_fullscreen) {
            ClientToScreen(hDisplayWnd, &offset);
        }
#if 0
        /* FIXME: this doesn't work... if users really want to run
        * X in 8bpp, then we need to call directly into display.drv
        * (or Wine's equivalent), and force a private colormap
        * without default entries. */
        if (This->palette) {
            SelectPalette(hDisplayDC, This->palette->hpal, FALSE);
            RealizePalette(hDisplayDC); /* sends messages => deadlocks */
        }
#endif
        drawrect.left	= 0;
        drawrect.right	= This->currentDesc.Width;
        drawrect.top	= 0;
        drawrect.bottom	= This->currentDesc.Height;

#if 0
        /* TODO: Support clippers */
        if (This->clipper)
        {
            RECT xrc;
            HWND hwnd = ((IWineD3DClipperImpl *) This->clipper)->hWnd;
            if (hwnd && GetClientRect(hwnd,&xrc))
            {
                OffsetRect(&xrc,offset.x,offset.y);
                IntersectRect(&drawrect,&drawrect,&xrc);
            }
        }
#endif
        if (rc)
        {
            IntersectRect(&drawrect,&drawrect,rc);
        }
        else
        {
            /* Only use this if the caller did not pass a rectangle, since
             * due to double locking this could be the wrong one ...
             */
            if (This->lockedRect.left != This->lockedRect.right)
            {
                IntersectRect(&drawrect,&drawrect,&This->lockedRect);
            }
        }

        BitBlt(hDisplayDC,
               drawrect.left-offset.x, drawrect.top-offset.y,
               drawrect.right-drawrect.left, drawrect.bottom-drawrect.top,
               hSurfaceDC,
               drawrect.left, drawrect.top,
               SRCCOPY);
        ReleaseDC(hDisplayWnd, hDisplayDC);
    }
}

/*****************************************************************************
 * IWineD3DSurface::PreLoad, GDI version
 *
 * This call is unsupported on GDI surfaces, if it's called something went
 * wrong in the parent library. Write an informative warning
 *
 *****************************************************************************/
static void WINAPI
IWineGDISurfaceImpl_PreLoad(IWineD3DSurface *iface)
{
    ERR("(%p): PreLoad is not supported on X11 surfaces!\n", iface);
    ERR("(%p): Most likely the parent library did something wrong.\n", iface);
    ERR("(%p): Please report to wine-devel\n", iface);
}

/*****************************************************************************
 * IWineD3DSurface::LockRect, GDI version
 *
 * Locks the surface and returns a pointer to the surface memory
 *
 * Params:
 *  pLockedRect: Address to return the locking info at
 *  pRect: Rectangle to lock
 *  Flags: Some flags
 *
 * Returns:
 *  WINED3D_OK on success
 *  WINED3DERR_INVALIDCALL on errors
 *
 *****************************************************************************/
static HRESULT WINAPI
IWineGDISurfaceImpl_LockRect(IWineD3DSurface *iface,
                             WINED3DLOCKED_RECT* pLockedRect,
                             CONST RECT* pRect,
                             DWORD Flags)
{
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;

    /* Already locked? */
    if(This->Flags & SFLAG_LOCKED)
    {
        ERR("(%p) Surface already locked\n", This);
        /* What should I return here? */
        return WINED3DERR_INVALIDCALL;
    }

    if (!(This->Flags & SFLAG_LOCKABLE))
    {
        /* This is some GL specific thing, see the OpenGL version of
         * this method, but check for the flag and write a trace
         */
        TRACE("Warning: trying to lock unlockable surf@%p\n", This);
    }

    TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
          This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);

    if(!This->resource.allocatedMemory) {
        HDC hdc;
        HRESULT hr;
        /* This happens on gdi surfaces if the application set a user pointer and resets it.
         * Recreate the DIB section
         */
        hr = IWineD3DSurface_GetDC(iface, &hdc);  /* will recursively call lockrect, do not set the LOCKED flag to this line */
        if(hr != WINED3D_OK) return hr;
        hr = IWineD3DSurface_ReleaseDC(iface, hdc);
        if(hr != WINED3D_OK) return hr;
    }

    pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);

    if (NULL == pRect)
    {
        pLockedRect->pBits = This->resource.allocatedMemory;
        This->lockedRect.left   = 0;
        This->lockedRect.top    = 0;
        This->lockedRect.right  = This->currentDesc.Width;
        This->lockedRect.bottom = This->currentDesc.Height;

        TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
        &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
        This->lockedRect.right, This->lockedRect.bottom);
    }
    else
    {
        TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
              pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);

        if (This->resource.format == WINED3DFMT_DXT1)
        {
            /* DXT1 is half byte per pixel */
            pLockedRect->pBits = This->resource.allocatedMemory +
                                  (pLockedRect->Pitch * pRect->top) +
                                  ((pRect->left * This->bytesPerPixel / 2));
        }
        else
        {
            pLockedRect->pBits = This->resource.allocatedMemory +
                                 (pLockedRect->Pitch * pRect->top) +
                                 (pRect->left * This->bytesPerPixel);
        }
        This->lockedRect.left   = pRect->left;
        This->lockedRect.top    = pRect->top;
        This->lockedRect.right  = pRect->right;
        This->lockedRect.bottom = pRect->bottom;
    }

    /* No dirtifying is needed for this surface implementation */
    TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);

    This->Flags |= SFLAG_LOCKED;
    return WINED3D_OK;
}

/*****************************************************************************
 * IWineD3DSurface::UnlockRect, GDI version
 *
 * Unlocks a surface. This implementation doesn't do much, except updating
 * the window if the front buffer is unlocked
 *
 * Returns:
 *  WINED3D_OK on success
 *  WINED3DERR_INVALIDCALL on failure
 *
 *****************************************************************************/
static HRESULT WINAPI
IWineGDISurfaceImpl_UnlockRect(IWineD3DSurface *iface)
{
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
    IWineD3DDeviceImpl *dev = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
    TRACE("(%p)\n", This);

    if (!(This->Flags & SFLAG_LOCKED))
    {
        WARN("trying to Unlock an unlocked surf@%p\n", This);
        return WINED3DERR_INVALIDCALL;
    }

    /* Can be useful for debugging */
#if 0
        {
            static unsigned int gen = 0;
            char buffer[4096];
            ++gen;
            if ((gen % 10) == 0) {
                snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
                IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
            }
            /*
             * debugging crash code
            if (gen == 250) {
              void** test = NULL;
              *test = 0;
            }
            */
        }
#endif

    /* Update the screen */
    if(This == (IWineD3DSurfaceImpl *) dev->ddraw_primary)
    {
        x11_copy_to_screen(This, &This->lockedRect);
    }

    This->Flags &= ~SFLAG_LOCKED;
    memset(&This->lockedRect, 0, sizeof(RECT));
    return WINED3D_OK;
}

/*****************************************************************************
 * IWineD3DSurface::Flip, GDI version
 *
 * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by
 * the parent library. This implementation changes the data pointers of the
 * surfaces and copies the new front buffer content to the screen
 *
 * Params:
 *  override: Flipping target(e.g. back buffer)
 *
 * Returns:
 *  WINED3D_OK on success
 *
 *****************************************************************************/
static HRESULT WINAPI
IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface,
                         IWineD3DSurface *override,
                         DWORD Flags)
{
    IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
    IWineD3DSurfaceImpl *Target = (IWineD3DSurfaceImpl *) override;
    TRACE("(%p)->(%p,%x)\n", This, override, Flags);

    TRACE("(%p) Flipping to surface %p\n", This, Target);

    if(Target == NULL)
    {
        ERR("(%p): Can't flip without a target\n", This);
        return WINED3DERR_INVALIDCALL;
    }

    /* Flip the DC */
    {
        HDC tmp;
        tmp = This->hDC;
        This->hDC = Target->hDC;
        Target->hDC = tmp;
    }

    /* Flip the DIBsection */
    {
        HBITMAP tmp;
        tmp = This->dib.DIBsection;
        This->dib.DIBsection = Target->dib.DIBsection;
        Target->dib.DIBsection = tmp;
    }

    /* Flip the surface data */
    {
        void* tmp;

        tmp = This->dib.bitmap_data;
        This->dib.bitmap_data = Target->dib.bitmap_data;
        Target->dib.bitmap_data = tmp;

        tmp = This->resource.allocatedMemory;
        This->resource.allocatedMemory = Target->resource.allocatedMemory;
        Target->resource.allocatedMemory = tmp;
    }

    /* client_memory should not be different, but just in case */
    {
        BOOL tmp;
        tmp = This->dib.client_memory;
        This->dib.client_memory = Target->dib.client_memory;
        Target->dib.client_memory = tmp;
    }

    /* Useful for debugging */
#if 0
        {
            static unsigned int gen = 0;
            char buffer[4096];
            ++gen;
            if ((gen % 10) == 0) {
                snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
                IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
            }
            /*
             * debugging crash code
            if (gen == 250) {
              void** test = NULL;
              *test = 0;
            }
            */
        }
#endif

    /* Update the screen */
    x11_copy_to_screen(This, NULL);

    /* FPS support */
    if (TRACE_ON(fps))
    {
        static long prev_time, frames;

        DWORD time = GetTickCount();
        frames++;
        /* every 1.5 seconds */
        if (time - prev_time > 1500) {
            TRACE_(fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time));
            prev_time = time;
            frames = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -