📄 surface_gdi.c
字号:
/*
* 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 + -