diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index fab99198696..afb0b78544f 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -690,41 +690,14 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory); + /* This is also done in the base class, but we have to verify this before loading any data from + * gl into the sysmem copy. The PBO may be mapped, a different rectangle locked, the discard flag + * may interfere, and all other bad things may happen + */ if (This->Flags & SFLAG_LOCKED) { WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n"); return WINED3DERR_INVALIDCALL; } - if (!(This->Flags & SFLAG_LOCKABLE)) { - /* Note: UpdateTextures calls CopyRects which calls this routine to populate the - texture regions, and since the destination is an unlockable region we need - to tolerate this */ - TRACE("Warning: trying to lock unlockable surf@%p\n", This); - /*return WINED3DERR_INVALIDCALL; */ - } - - pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface); - - /* Mark the surface locked */ - This->Flags |= SFLAG_LOCKED; - - /* Calculate the correct start address to report */ - if (NULL == pRect) { - 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 { - This->lockedRect.left = pRect->left; - This->lockedRect.top = pRect->top; - This->lockedRect.right = pRect->right; - This->lockedRect.bottom = pRect->bottom; - TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom); - } - - if (This->Flags & SFLAG_NONPOW2) { - TRACE("Locking non-power 2 texture\n"); - } if (Flags & WINED3DLOCK_DISCARD) { /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */ @@ -744,15 +717,17 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED */ IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain); if(swapchain || iface == myDevice->render_targets[0]) { - RECT *read_rect; + const RECT *pass_rect = pRect; - if(This->lockedRect.left == 0 && - This->lockedRect.top == 0 && - This->lockedRect.right == This->currentDesc.Width && - This->lockedRect.bottom == This->currentDesc.Height) { - read_rect = NULL; - } else { - read_rect = &This->lockedRect; + /* IWineD3DSurface_LoadLocation does not check if the rectangle specifies the full surfaces + * because most caller functions do not need that. So do that here + */ + if(pRect && + pRect->top == 0 && + pRect->left == 0 && + pRect->right == This->currentDesc.Width && + pRect->bottom == This->currentDesc.Height) { + pass_rect = NULL; } switch(wined3d_settings.rendertargetlock_mode) { @@ -771,7 +746,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED case RTL_AUTO: case RTL_READDRAW: case RTL_READTEX: - IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, read_rect); + IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, pRect); break; case RTL_DISABLE: @@ -828,27 +803,6 @@ lock_end: LEAVE_GL(); } - /* Calculate the correct start address to report */ - if (NULL == pRect) { - pLockedRect->pBits = This->resource.allocatedMemory; - } else { - /* DXTn textures are based on compressed blocks of 4x4 pixels, each - * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has - * slightly different meaning compared to regular textures. For DXTn - * textures Pitch is the size of a row of blocks, 4 high and "width" - * long. The x offset is calculated differently as well, since moving 4 - * pixels to the right actually moves an entire 4x4 block to right, ie - * 16 bytes (8 in case of DXT1). */ - if (This->resource.format == WINED3DFMT_DXT1) { - pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2); - } else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 - || This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) { - pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4); - } else { - pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel); - } - } - if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) { /* Don't dirtify */ } else { @@ -869,9 +823,7 @@ lock_end: } } - TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, - This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1); - return WINED3D_OK; + return IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags); } static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) { diff --git a/dlls/wined3d/surface_base.c b/dlls/wined3d/surface_base.c index 598c9325982..a9c5a071beb 100644 --- a/dlls/wined3d/surface_base.c +++ b/dlls/wined3d/surface_base.c @@ -1568,3 +1568,80 @@ error: return ret; } + +HRESULT WINAPI IWineD3DBaseSurfaceImpl_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); + + 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); + + /* DXTn textures are based on compressed blocks of 4x4 pixels, each + * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has + * slightly different meaning compared to regular textures. For DXTn + * textures Pitch is the size of a row of blocks, 4 high and "width" + * long. The x offset is calculated differently as well, since moving 4 + * pixels to the right actually moves an entire 4x4 block to right, ie + * 16 bytes (8 in case of DXT1). */ + if (This->resource.format == WINED3DFMT_DXT1) + { + pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2); + } + else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 || + This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) + { + pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4); + } + 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; +} diff --git a/dlls/wined3d/surface_gdi.c b/dlls/wined3d/surface_gdi.c index 263c603a80c..d3cb89d8f7e 100644 --- a/dlls/wined3d/surface_gdi.c +++ b/dlls/wined3d/surface_gdi.c @@ -205,80 +205,15 @@ IWineGDISurfaceImpl_LockRect(IWineD3DSurface *iface, { 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; + IWineD3DBaseSurfaceImpl_CreateDIBSection(iface); + This->resource.allocatedMemory = This->dib.bitmap_data; } - 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; + return IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags); } /***************************************************************************** diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index a79289073b2..8362aa13f6c 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1163,10 +1163,10 @@ HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3D HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface); HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter); HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans); +HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags); const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface); - /* Surface flags: */ #define SFLAG_OVERSIZE 0x00000001 /* Surface is bigger than gl size, blts only */ #define SFLAG_CONVERTED 0x00000002 /* Converted for color keying or Palettized */