ddraw: Added a todo_wine test for SetCooperativeLevel.
[wine/multimedia.git] / dlls / wined3d / surface_base.c
blob2bd0e37a8627d8fc14058153f609e8c2cef15274
1 /*
2 * IWineD3DSurface Implementation of management(non-rendering) functions
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11 * Copyright 2007 Henri Verbeet
12 * Copyright 2006-2007 Roderick Colenbrander
13 * Copyright 2009 Henri Verbeet for CodeWeavers
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "config.h"
31 #include "wine/port.h"
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
36 /* See also float_16_to_32() in wined3d_private.h */
37 static inline unsigned short float_32_to_16(const float *in)
39 int exp = 0;
40 float tmp = fabs(*in);
41 unsigned int mantissa;
42 unsigned short ret;
44 /* Deal with special numbers */
45 if (*in == 0.0f) return 0x0000;
46 if(isnan(*in)) return 0x7C01;
47 if (isinf(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
49 if(tmp < pow(2, 10)) {
52 tmp = tmp * 2.0f;
53 exp--;
54 }while(tmp < pow(2, 10));
55 } else if(tmp >= pow(2, 11)) {
58 tmp /= 2.0f;
59 exp++;
60 }while(tmp >= pow(2, 11));
63 mantissa = (unsigned int) tmp;
64 if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
66 exp += 10; /* Normalize the mantissa */
67 exp += 15; /* Exponent is encoded with excess 15 */
69 if(exp > 30) { /* too big */
70 ret = 0x7c00; /* INF */
71 } else if(exp <= 0) {
72 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
73 while(exp <= 0) {
74 mantissa = mantissa >> 1;
75 exp++;
77 ret = mantissa & 0x3ff;
78 } else {
79 ret = (exp << 10) | (mantissa & 0x3ff);
82 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
83 return ret;
86 /* *******************************************
87 IWineD3DSurface IUnknown parts follow
88 ******************************************* */
89 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
91 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
92 /* Warn ,but be nice about things */
93 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
95 if (IsEqualGUID(riid, &IID_IUnknown)
96 || IsEqualGUID(riid, &IID_IWineD3DBase)
97 || IsEqualGUID(riid, &IID_IWineD3DResource)
98 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
99 IUnknown_AddRef((IUnknown*)iface);
100 *ppobj = This;
101 return S_OK;
103 *ppobj = NULL;
104 return E_NOINTERFACE;
107 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
108 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
109 ULONG ref = InterlockedIncrement(&This->resource.ref);
110 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
111 return ref;
114 /* ****************************************************
115 IWineD3DSurface IWineD3DResource parts follow
116 **************************************************** */
117 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
118 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
121 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
122 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
125 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
126 return resource_free_private_data((IWineD3DResource *)iface, refguid);
129 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
130 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
133 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
134 return resource_get_priority((IWineD3DResource *)iface);
137 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
138 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
139 return resource_get_type((IWineD3DResource *)iface);
142 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
143 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
144 return resource_get_parent((IWineD3DResource *)iface, pParent);
147 /* ******************************************************
148 IWineD3DSurface IWineD3DSurface parts follow
149 ****************************************************** */
151 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
152 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
153 IWineD3DBase *container = 0;
155 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
157 if (!ppContainer) {
158 ERR("Called without a valid ppContainer.\n");
161 /* Standalone surfaces return the device as container. */
162 if (This->container) container = This->container;
163 else container = (IWineD3DBase *)This->resource.device;
165 TRACE("Relaying to QueryInterface\n");
166 return IUnknown_QueryInterface(container, riid, ppContainer);
169 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
170 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
172 TRACE("(%p) : copying into %p\n", This, pDesc);
174 pDesc->format = This->resource.format_desc->format;
175 pDesc->resource_type = This->resource.resourceType;
176 pDesc->usage = This->resource.usage;
177 pDesc->pool = This->resource.pool;
178 pDesc->size = This->resource.size; /* dx8 only */
179 pDesc->multisample_type = This->currentDesc.MultiSampleType;
180 pDesc->multisample_quality = This->currentDesc.MultiSampleQuality;
181 pDesc->width = This->currentDesc.Width;
182 pDesc->height = This->currentDesc.Height;
184 return WINED3D_OK;
187 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags)
189 TRACE("iface %p, flags %#x.\n", iface, Flags);
191 switch (Flags)
193 case WINEDDGBS_CANBLT:
194 case WINEDDGBS_ISBLTDONE:
195 return WINED3D_OK;
197 default:
198 return WINED3DERR_INVALIDCALL;
202 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
203 /* XXX: DDERR_INVALIDSURFACETYPE */
205 TRACE("(%p)->(%08x)\n",iface,Flags);
206 switch (Flags) {
207 case WINEDDGFS_CANFLIP:
208 case WINEDDGFS_ISFLIPDONE:
209 return WINED3D_OK;
211 default:
212 return WINED3DERR_INVALIDCALL;
216 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
217 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
218 TRACE("(%p)\n", This);
220 /* D3D8 and 9 loose full devices, ddraw only surfaces */
221 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
224 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
225 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
226 TRACE("(%p)\n", This);
228 /* So far we don't lose anything :) */
229 This->Flags &= ~SFLAG_LOST;
230 return WINED3D_OK;
233 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
234 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
235 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
236 TRACE("(%p)->(%p)\n", This, Pal);
238 if(This->palette == PalImpl) {
239 TRACE("Nop palette change\n");
240 return WINED3D_OK;
243 if(This->palette != NULL)
244 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
245 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
247 This->palette = PalImpl;
249 if(PalImpl != NULL) {
250 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
251 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
254 return IWineD3DSurface_RealizePalette(iface);
256 else return WINED3D_OK;
259 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
261 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
262 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
264 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
265 FIXME(" colorkey value not supported (%08x) !\n", Flags);
266 return WINED3DERR_INVALIDCALL;
269 /* Dirtify the surface, but only if a key was changed */
270 if(CKey) {
271 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
272 case WINEDDCKEY_DESTBLT:
273 This->DestBltCKey = *CKey;
274 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
275 break;
277 case WINEDDCKEY_DESTOVERLAY:
278 This->DestOverlayCKey = *CKey;
279 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
280 break;
282 case WINEDDCKEY_SRCOVERLAY:
283 This->SrcOverlayCKey = *CKey;
284 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
285 break;
287 case WINEDDCKEY_SRCBLT:
288 This->SrcBltCKey = *CKey;
289 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
290 break;
293 else {
294 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
295 case WINEDDCKEY_DESTBLT:
296 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
297 break;
299 case WINEDDCKEY_DESTOVERLAY:
300 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
301 break;
303 case WINEDDCKEY_SRCOVERLAY:
304 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
305 break;
307 case WINEDDCKEY_SRCBLT:
308 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
309 break;
313 return WINED3D_OK;
316 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
317 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
318 TRACE("(%p)->(%p)\n", This, Pal);
320 *Pal = (IWineD3DPalette *) This->palette;
321 return WINED3D_OK;
324 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
325 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
326 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
327 DWORD ret;
328 TRACE("(%p)\n", This);
330 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
332 /* Since compressed formats are block based, pitch means the amount of
333 * bytes to the next row of block rather than the next row of pixels. */
334 UINT row_block_count = (This->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
335 ret = row_block_count * format_desc->block_byte_count;
337 else
339 unsigned char alignment = This->resource.device->surface_alignment;
340 ret = This->resource.format_desc->byte_count * This->currentDesc.Width; /* Bytes / row */
341 ret = (ret + alignment - 1) & ~(alignment - 1);
343 TRACE("(%p) Returning %d\n", This, ret);
344 return ret;
347 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
348 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
349 LONG w, h;
351 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
353 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
355 TRACE("(%p): Not an overlay surface\n", This);
356 return WINEDDERR_NOTAOVERLAYSURFACE;
359 w = This->overlay_destrect.right - This->overlay_destrect.left;
360 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
361 This->overlay_destrect.left = X;
362 This->overlay_destrect.top = Y;
363 This->overlay_destrect.right = X + w;
364 This->overlay_destrect.bottom = Y + h;
366 IWineD3DSurface_DrawOverlay(iface);
368 return WINED3D_OK;
371 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
372 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
373 HRESULT hr;
375 TRACE("(%p)->(%p,%p)\n", This, X, Y);
377 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
379 TRACE("(%p): Not an overlay surface\n", This);
380 return WINEDDERR_NOTAOVERLAYSURFACE;
382 if(This->overlay_dest == NULL) {
383 *X = 0; *Y = 0;
384 hr = WINEDDERR_OVERLAYNOTVISIBLE;
385 } else {
386 *X = This->overlay_destrect.left;
387 *Y = This->overlay_destrect.top;
388 hr = WINED3D_OK;
391 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
392 return hr;
395 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
396 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
398 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, Flags, Ref);
400 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
402 TRACE("(%p): Not an overlay surface\n", This);
403 return WINEDDERR_NOTAOVERLAYSURFACE;
406 return WINED3D_OK;
409 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
410 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
412 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
413 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
414 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
416 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
418 WARN("(%p): Not an overlay surface\n", This);
419 return WINEDDERR_NOTAOVERLAYSURFACE;
420 } else if(!DstSurface) {
421 WARN("(%p): Dest surface is NULL\n", This);
422 return WINED3DERR_INVALIDCALL;
425 if(SrcRect) {
426 This->overlay_srcrect = *SrcRect;
427 } else {
428 This->overlay_srcrect.left = 0;
429 This->overlay_srcrect.top = 0;
430 This->overlay_srcrect.right = This->currentDesc.Width;
431 This->overlay_srcrect.bottom = This->currentDesc.Height;
434 if(DstRect) {
435 This->overlay_destrect = *DstRect;
436 } else {
437 This->overlay_destrect.left = 0;
438 This->overlay_destrect.top = 0;
439 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
440 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
443 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
444 list_remove(&This->overlay_entry);
447 if(Flags & WINEDDOVER_SHOW) {
448 if(This->overlay_dest != Dst) {
449 This->overlay_dest = Dst;
450 list_add_tail(&Dst->overlays, &This->overlay_entry);
452 } else if(Flags & WINEDDOVER_HIDE) {
453 /* tests show that the rectangles are erased on hide */
454 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
455 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
456 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
457 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
458 This->overlay_dest = NULL;
461 IWineD3DSurface_DrawOverlay(iface);
463 return WINED3D_OK;
466 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
468 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
469 TRACE("(%p)->(%p)\n", This, clipper);
471 This->clipper = clipper;
472 return WINED3D_OK;
475 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
477 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
478 TRACE("(%p)->(%p)\n", This, clipper);
480 *clipper = This->clipper;
481 if(*clipper) {
482 IWineD3DClipper_AddRef(*clipper);
484 return WINED3D_OK;
487 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
488 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
490 TRACE("This %p, container %p\n", This, container);
492 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
494 TRACE("Setting container to %p from %p\n", container, This->container);
495 This->container = container;
497 return WINED3D_OK;
500 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
501 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
502 const struct wined3d_format_desc *format_desc = getFormatDescEntry(format,
503 &This->resource.device->adapter->gl_info);
505 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
507 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
508 return WINED3DERR_INVALIDCALL;
511 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
513 This->resource.size = surface_calculate_size(format_desc, This->resource.device->surface_alignment,
514 This->pow2Width, This->pow2Height);
516 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
518 This->resource.format_desc = format_desc;
520 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
522 return WINED3D_OK;
525 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
526 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
527 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
528 int extraline = 0;
529 SYSTEM_INFO sysInfo;
530 BITMAPINFO* b_info;
531 HDC ddc;
532 DWORD *masks;
533 UINT usage;
535 if(!(format_desc->Flags & WINED3DFMT_FLAG_GETDC))
537 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format_desc->format));
538 return WINED3DERR_INVALIDCALL;
541 switch (format_desc->byte_count)
543 case 2:
544 case 4:
545 /* Allocate extra space to store the RGB bit masks. */
546 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
547 break;
549 case 3:
550 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
551 break;
553 default:
554 /* Allocate extra space for a palette. */
555 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
556 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
557 break;
560 if (!b_info)
561 return E_OUTOFMEMORY;
563 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
564 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
565 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
566 * add an extra line to the dib section
568 GetSystemInfo(&sysInfo);
569 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
570 extraline = 1;
571 TRACE("Adding an extra line to the dib section\n");
574 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
575 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
576 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
577 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
578 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
579 b_info->bmiHeader.biPlanes = 1;
580 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
582 b_info->bmiHeader.biXPelsPerMeter = 0;
583 b_info->bmiHeader.biYPelsPerMeter = 0;
584 b_info->bmiHeader.biClrUsed = 0;
585 b_info->bmiHeader.biClrImportant = 0;
587 /* Get the bit masks */
588 masks = (DWORD *)b_info->bmiColors;
589 switch (This->resource.format_desc->format)
591 case WINED3DFMT_B8G8R8_UNORM:
592 usage = DIB_RGB_COLORS;
593 b_info->bmiHeader.biCompression = BI_RGB;
594 break;
596 case WINED3DFMT_B5G5R5X1_UNORM:
597 case WINED3DFMT_B5G5R5A1_UNORM:
598 case WINED3DFMT_B4G4R4A4_UNORM:
599 case WINED3DFMT_B4G4R4X4_UNORM:
600 case WINED3DFMT_B2G3R3_UNORM:
601 case WINED3DFMT_B2G3R3A8_UNORM:
602 case WINED3DFMT_R10G10B10A2_UNORM:
603 case WINED3DFMT_R8G8B8A8_UNORM:
604 case WINED3DFMT_R8G8B8X8_UNORM:
605 case WINED3DFMT_B10G10R10A2_UNORM:
606 case WINED3DFMT_B5G6R5_UNORM:
607 case WINED3DFMT_R16G16B16A16_UNORM:
608 usage = 0;
609 b_info->bmiHeader.biCompression = BI_BITFIELDS;
610 masks[0] = format_desc->red_mask;
611 masks[1] = format_desc->green_mask;
612 masks[2] = format_desc->blue_mask;
613 break;
615 default:
616 /* Don't know palette */
617 b_info->bmiHeader.biCompression = BI_RGB;
618 usage = 0;
619 break;
622 ddc = GetDC(0);
623 if (ddc == 0) {
624 HeapFree(GetProcessHeap(), 0, b_info);
625 return HRESULT_FROM_WIN32(GetLastError());
628 TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
629 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
630 ReleaseDC(0, ddc);
632 if (!This->dib.DIBsection) {
633 ERR("CreateDIBSection failed!\n");
634 HeapFree(GetProcessHeap(), 0, b_info);
635 return HRESULT_FROM_WIN32(GetLastError());
638 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
639 /* copy the existing surface to the dib section */
640 if(This->resource.allocatedMemory) {
641 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
642 } else {
643 /* This is to make LockRect read the gl Texture although memory is allocated */
644 This->Flags &= ~SFLAG_INSYSMEM;
646 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
648 HeapFree(GetProcessHeap(), 0, b_info);
650 /* Now allocate a HDC */
651 This->hDC = CreateCompatibleDC(0);
652 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
653 TRACE("using wined3d palette %p\n", This->palette);
654 SelectPalette(This->hDC,
655 This->palette ? This->palette->hpal : 0,
656 FALSE);
658 This->Flags |= SFLAG_DIBSECTION;
660 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
661 This->resource.heapMemory = NULL;
663 return WINED3D_OK;
666 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
667 unsigned int w, unsigned int h)
669 unsigned int x, y;
670 const float *src_f;
671 unsigned short *dst_s;
673 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
674 for(y = 0; y < h; y++) {
675 src_f = (const float *)(src + y * pitch_in);
676 dst_s = (unsigned short *) (dst + y * pitch_out);
677 for(x = 0; x < w; x++) {
678 dst_s[x] = float_32_to_16(src_f + x);
683 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
684 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
686 static const unsigned char convert_5to8[] =
688 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
689 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
690 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
691 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
693 static const unsigned char convert_6to8[] =
695 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
696 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
697 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
698 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
699 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
700 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
701 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
702 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
704 unsigned int x, y;
706 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
708 for (y = 0; y < h; ++y)
710 const WORD *src_line = (const WORD *)(src + y * pitch_in);
711 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
712 for (x = 0; x < w; ++x)
714 WORD pixel = src_line[x];
715 dst_line[x] = 0xff000000
716 | convert_5to8[(pixel & 0xf800) >> 11] << 16
717 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
718 | convert_5to8[(pixel & 0x001f)];
723 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
724 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
726 unsigned int x, y;
728 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
730 for (y = 0; y < h; ++y)
732 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
733 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
735 for (x = 0; x < w; ++x)
737 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
742 static inline BYTE cliptobyte(int x)
744 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
747 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
748 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
750 unsigned int x, y;
751 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
753 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
755 for (y = 0; y < h; ++y)
757 const BYTE *src_line = src + y * pitch_in;
758 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
759 for (x = 0; x < w; ++x)
761 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
762 * C = Y - 16; D = U - 128; E = V - 128;
763 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
764 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
765 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
766 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
767 * U and V are shared between the pixels.
769 if (!(x & 1)) /* for every even pixel, read new U and V */
771 d = (int) src_line[1] - 128;
772 e = (int) src_line[3] - 128;
773 r2 = 409 * e + 128;
774 g2 = - 100 * d - 208 * e + 128;
775 b2 = 516 * d + 128;
777 c2 = 298 * ((int) src_line[0] - 16);
778 dst_line[x] = 0xff000000
779 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
780 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
781 | cliptobyte((c2 + b2) >> 8); /* blue */
782 /* Scale RGB values to 0..255 range,
783 * then clip them if still not in range (may be negative),
784 * then shift them within DWORD if necessary.
786 src_line += 2;
791 struct d3dfmt_convertor_desc {
792 WINED3DFORMAT from, to;
793 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
796 static const struct d3dfmt_convertor_desc convertors[] =
798 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
799 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
800 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
801 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
804 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
806 unsigned int i;
807 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
808 if(convertors[i].from == from && convertors[i].to == to) {
809 return &convertors[i];
812 return NULL;
815 /*****************************************************************************
816 * surface_convert_format
818 * Creates a duplicate of a surface in a different format. Is used by Blt to
819 * blit between surfaces with different formats
821 * Parameters
822 * source: Source surface
823 * fmt: Requested destination format
825 *****************************************************************************/
826 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
827 IWineD3DSurface *ret = NULL;
828 const struct d3dfmt_convertor_desc *conv;
829 WINED3DLOCKED_RECT lock_src, lock_dst;
830 HRESULT hr;
832 conv = find_convertor(source->resource.format_desc->format, to_fmt);
833 if(!conv) {
834 FIXME("Cannot find a conversion function from format %s to %s\n",
835 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
836 return NULL;
839 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
840 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
841 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
842 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
843 NULL /* parent */, &wined3d_null_parent_ops);
844 if(!ret) {
845 ERR("Failed to create a destination surface for conversion\n");
846 return NULL;
849 memset(&lock_src, 0, sizeof(lock_src));
850 memset(&lock_dst, 0, sizeof(lock_dst));
852 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
853 if(FAILED(hr)) {
854 ERR("Failed to lock the source surface\n");
855 IWineD3DSurface_Release(ret);
856 return NULL;
858 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
859 if(FAILED(hr)) {
860 ERR("Failed to lock the dest surface\n");
861 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
862 IWineD3DSurface_Release(ret);
863 return NULL;
866 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
867 source->currentDesc.Width, source->currentDesc.Height);
869 IWineD3DSurface_UnlockRect(ret);
870 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
872 return (IWineD3DSurfaceImpl *) ret;
875 /*****************************************************************************
876 * _Blt_ColorFill
878 * Helper function that fills a memory area with a specific color
880 * Params:
881 * buf: memory address to start filling at
882 * width, height: Dimensions of the area to fill
883 * bpp: Bit depth of the surface
884 * lPitch: pitch of the surface
885 * color: Color to fill with
887 *****************************************************************************/
888 static HRESULT
889 _Blt_ColorFill(BYTE *buf,
890 int width, int height,
891 int bpp, LONG lPitch,
892 DWORD color)
894 int x, y;
895 LPBYTE first;
897 /* Do first row */
899 #define COLORFILL_ROW(type) \
901 type *d = (type *) buf; \
902 for (x = 0; x < width; x++) \
903 d[x] = (type) color; \
904 break; \
906 switch(bpp)
908 case 1: COLORFILL_ROW(BYTE)
909 case 2: COLORFILL_ROW(WORD)
910 case 3:
912 BYTE *d = buf;
913 for (x = 0; x < width; x++,d+=3)
915 d[0] = (color ) & 0xFF;
916 d[1] = (color>> 8) & 0xFF;
917 d[2] = (color>>16) & 0xFF;
919 break;
921 case 4: COLORFILL_ROW(DWORD)
922 default:
923 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
924 return WINED3DERR_NOTAVAILABLE;
927 #undef COLORFILL_ROW
929 /* Now copy first row */
930 first = buf;
931 for (y = 1; y < height; y++)
933 buf += lPitch;
934 memcpy(buf, first, width * bpp);
936 return WINED3D_OK;
939 /*****************************************************************************
940 * IWineD3DSurface::Blt, SW emulation version
942 * Performs a blit to a surface, with or without a source surface.
943 * This is the main functionality of DirectDraw
945 * Params:
946 * DestRect: Destination rectangle to write to
947 * SrcSurface: Source surface, can be NULL
948 * SrcRect: Source rectangle
949 *****************************************************************************/
950 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
951 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
953 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
954 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
955 RECT xdst,xsrc;
956 HRESULT ret = WINED3D_OK;
957 WINED3DLOCKED_RECT dlock, slock;
958 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
959 const struct wined3d_format_desc *sEntry, *dEntry;
960 int x, y;
961 const BYTE *sbuf;
962 BYTE *dbuf;
963 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
965 if (TRACE_ON(d3d_surface))
967 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
968 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
969 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
970 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
973 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
975 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
976 return WINEDDERR_SURFACEBUSY;
979 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
980 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
981 FIXME("Filters not supported in software blit\n");
984 /* First check for the validity of source / destination rectangles.
985 * This was verified using a test application + by MSDN. */
987 if (SrcRect)
989 if (Src)
991 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
992 || SrcRect->left > Src->currentDesc.Width || SrcRect->left < 0
993 || SrcRect->top > Src->currentDesc.Height || SrcRect->top < 0
994 || SrcRect->right > Src->currentDesc.Width || SrcRect->right < 0
995 || SrcRect->bottom > Src->currentDesc.Height || SrcRect->bottom < 0)
997 WARN("Application gave us bad source rectangle for Blt.\n");
998 return WINEDDERR_INVALIDRECT;
1001 if (!SrcRect->right || !SrcRect->bottom
1002 || SrcRect->left == (int)Src->currentDesc.Width
1003 || SrcRect->top == (int)Src->currentDesc.Height)
1005 TRACE("Nothing to be done.\n");
1006 return WINED3D_OK;
1010 xsrc = *SrcRect;
1012 else if (Src)
1014 xsrc.left = 0;
1015 xsrc.top = 0;
1016 xsrc.right = Src->currentDesc.Width;
1017 xsrc.bottom = Src->currentDesc.Height;
1019 else
1021 memset(&xsrc, 0, sizeof(xsrc));
1024 if (DestRect)
1026 /* For the Destination rect, it can be out of bounds on the condition
1027 * that a clipper is set for the given surface. */
1028 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1029 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
1030 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1031 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1032 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1034 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1035 return WINEDDERR_INVALIDRECT;
1038 if (DestRect->right <= 0 || DestRect->bottom <= 0
1039 || DestRect->left >= (int)This->currentDesc.Width
1040 || DestRect->top >= (int)This->currentDesc.Height)
1042 TRACE("Nothing to be done.\n");
1043 return WINED3D_OK;
1046 if (!Src)
1048 RECT full_rect;
1050 full_rect.left = 0;
1051 full_rect.top = 0;
1052 full_rect.right = This->currentDesc.Width;
1053 full_rect.bottom = This->currentDesc.Height;
1054 IntersectRect(&xdst, &full_rect, DestRect);
1056 else
1058 BOOL clip_horiz, clip_vert;
1060 xdst = *DestRect;
1061 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1062 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1064 if (clip_vert || clip_horiz)
1066 /* Now check if this is a special case or not... */
1067 if ((Flags & WINEDDBLT_DDFX)
1068 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1069 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1071 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1072 return WINED3D_OK;
1075 if (clip_horiz)
1077 if (xdst.left < 0)
1079 xsrc.left -= xdst.left;
1080 xdst.left = 0;
1082 if (xdst.right > This->currentDesc.Width)
1084 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1085 xdst.right = (int)This->currentDesc.Width;
1089 if (clip_vert)
1091 if (xdst.top < 0)
1093 xsrc.top -= xdst.top;
1094 xdst.top = 0;
1096 if (xdst.bottom > This->currentDesc.Height)
1098 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1099 xdst.bottom = (int)This->currentDesc.Height;
1103 /* And check if after clipping something is still to be done... */
1104 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1105 || (xdst.left >= (int)This->currentDesc.Width)
1106 || (xdst.top >= (int)This->currentDesc.Height)
1107 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1108 || (xsrc.left >= (int) Src->currentDesc.Width)
1109 || (xsrc.top >= (int)Src->currentDesc.Height))
1111 TRACE("Nothing to be done after clipping.\n");
1112 return WINED3D_OK;
1117 else
1119 xdst.left = 0;
1120 xdst.top = 0;
1121 xdst.right = This->currentDesc.Width;
1122 xdst.bottom = This->currentDesc.Height;
1125 if (Src == This)
1127 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1128 slock = dlock;
1129 sEntry = This->resource.format_desc;
1130 dEntry = sEntry;
1132 else
1134 dEntry = This->resource.format_desc;
1135 if (Src)
1137 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1139 Src = surface_convert_format(Src, dEntry->format);
1140 if(!Src) {
1141 /* The conv function writes a FIXME */
1142 WARN("Cannot convert source surface format to dest format\n");
1143 goto release;
1146 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1147 sEntry = Src->resource.format_desc;
1149 else
1151 sEntry = dEntry;
1153 if (DestRect)
1154 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1155 else
1156 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1159 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1161 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1163 if (!DestRect || Src == This)
1165 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1166 goto release;
1170 bpp = This->resource.format_desc->byte_count;
1171 srcheight = xsrc.bottom - xsrc.top;
1172 srcwidth = xsrc.right - xsrc.left;
1173 dstheight = xdst.bottom - xdst.top;
1174 dstwidth = xdst.right - xdst.left;
1175 width = (xdst.right - xdst.left) * bpp;
1177 if (DestRect && Src != This)
1178 dbuf = dlock.pBits;
1179 else
1180 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1182 if (Flags & WINEDDBLT_WAIT)
1184 Flags &= ~WINEDDBLT_WAIT;
1186 if (Flags & WINEDDBLT_ASYNC)
1188 static BOOL displayed = FALSE;
1189 if (!displayed)
1190 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1191 displayed = TRUE;
1192 Flags &= ~WINEDDBLT_ASYNC;
1194 if (Flags & WINEDDBLT_DONOTWAIT)
1196 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1197 static BOOL displayed = FALSE;
1198 if (!displayed)
1199 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1200 displayed = TRUE;
1201 Flags &= ~WINEDDBLT_DONOTWAIT;
1204 /* First, all the 'source-less' blits */
1205 if (Flags & WINEDDBLT_COLORFILL)
1207 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1208 dlock.Pitch, DDBltFx->u5.dwFillColor);
1209 Flags &= ~WINEDDBLT_COLORFILL;
1212 if (Flags & WINEDDBLT_DEPTHFILL)
1214 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1216 if (Flags & WINEDDBLT_ROP)
1218 /* Catch some degenerate cases here */
1219 switch(DDBltFx->dwROP)
1221 case BLACKNESS:
1222 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1223 break;
1224 case 0xAA0029: /* No-op */
1225 break;
1226 case WHITENESS:
1227 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1228 break;
1229 case SRCCOPY: /* well, we do that below ? */
1230 break;
1231 default:
1232 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1233 goto error;
1235 Flags &= ~WINEDDBLT_ROP;
1237 if (Flags & WINEDDBLT_DDROPS)
1239 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1241 /* Now the 'with source' blits */
1242 if (Src)
1244 const BYTE *sbase;
1245 int sx, xinc, sy, yinc;
1247 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1248 goto release;
1249 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1250 xinc = (srcwidth << 16) / dstwidth;
1251 yinc = (srcheight << 16) / dstheight;
1253 if (!Flags)
1255 /* No effects, we can cheat here */
1256 if (dstwidth == srcwidth)
1258 if (dstheight == srcheight)
1260 /* No stretching in either direction. This needs to be as
1261 * fast as possible */
1262 sbuf = sbase;
1264 /* check for overlapping surfaces */
1265 if (Src != This || xdst.top < xsrc.top ||
1266 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1268 /* no overlap, or dst above src, so copy from top downwards */
1269 for (y = 0; y < dstheight; y++)
1271 memcpy(dbuf, sbuf, width);
1272 sbuf += slock.Pitch;
1273 dbuf += dlock.Pitch;
1276 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1278 sbuf += (slock.Pitch*dstheight);
1279 dbuf += (dlock.Pitch*dstheight);
1280 for (y = 0; y < dstheight; y++)
1282 sbuf -= slock.Pitch;
1283 dbuf -= dlock.Pitch;
1284 memcpy(dbuf, sbuf, width);
1287 else /* src and dst overlapping on the same line, use memmove */
1289 for (y = 0; y < dstheight; y++)
1291 memmove(dbuf, sbuf, width);
1292 sbuf += slock.Pitch;
1293 dbuf += dlock.Pitch;
1296 } else {
1297 /* Stretching in Y direction only */
1298 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1299 sbuf = sbase + (sy >> 16) * slock.Pitch;
1300 memcpy(dbuf, sbuf, width);
1301 dbuf += dlock.Pitch;
1305 else
1307 /* Stretching in X direction */
1308 int last_sy = -1;
1309 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1311 sbuf = sbase + (sy >> 16) * slock.Pitch;
1313 if ((sy >> 16) == (last_sy >> 16))
1315 /* this sourcerow is the same as last sourcerow -
1316 * copy already stretched row
1318 memcpy(dbuf, dbuf - dlock.Pitch, width);
1320 else
1322 #define STRETCH_ROW(type) { \
1323 const type *s = (const type *)sbuf; \
1324 type *d = (type *)dbuf; \
1325 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1326 d[x] = s[sx >> 16]; \
1327 break; }
1329 switch(bpp)
1331 case 1: STRETCH_ROW(BYTE)
1332 case 2: STRETCH_ROW(WORD)
1333 case 4: STRETCH_ROW(DWORD)
1334 case 3:
1336 const BYTE *s;
1337 BYTE *d = dbuf;
1338 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1340 DWORD pixel;
1342 s = sbuf+3*(sx>>16);
1343 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1344 d[0] = (pixel )&0xff;
1345 d[1] = (pixel>> 8)&0xff;
1346 d[2] = (pixel>>16)&0xff;
1347 d+=3;
1349 break;
1351 default:
1352 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1353 ret = WINED3DERR_NOTAVAILABLE;
1354 goto error;
1356 #undef STRETCH_ROW
1358 dbuf += dlock.Pitch;
1359 last_sy = sy;
1363 else
1365 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1366 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1367 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1368 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1370 /* The color keying flags are checked for correctness in ddraw */
1371 if (Flags & WINEDDBLT_KEYSRC)
1373 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1374 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1376 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1378 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1379 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1382 if (Flags & WINEDDBLT_KEYDEST)
1384 /* Destination color keys are taken from the source surface ! */
1385 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1386 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1388 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1390 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1391 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1394 if(bpp == 1)
1396 keymask = 0xff;
1398 else
1400 keymask = sEntry->red_mask
1401 | sEntry->green_mask
1402 | sEntry->blue_mask;
1404 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1407 if (Flags & WINEDDBLT_DDFX)
1409 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1410 LONG tmpxy;
1411 dTopLeft = dbuf;
1412 dTopRight = dbuf+((dstwidth-1)*bpp);
1413 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1414 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1416 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1418 /* I don't think we need to do anything about this flag */
1419 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1421 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1423 tmp = dTopRight;
1424 dTopRight = dTopLeft;
1425 dTopLeft = tmp;
1426 tmp = dBottomRight;
1427 dBottomRight = dBottomLeft;
1428 dBottomLeft = tmp;
1429 dstxinc = dstxinc *-1;
1431 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1433 tmp = dTopLeft;
1434 dTopLeft = dBottomLeft;
1435 dBottomLeft = tmp;
1436 tmp = dTopRight;
1437 dTopRight = dBottomRight;
1438 dBottomRight = tmp;
1439 dstyinc = dstyinc *-1;
1441 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1443 /* I don't think we need to do anything about this flag */
1444 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1446 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1448 tmp = dBottomRight;
1449 dBottomRight = dTopLeft;
1450 dTopLeft = tmp;
1451 tmp = dBottomLeft;
1452 dBottomLeft = dTopRight;
1453 dTopRight = tmp;
1454 dstxinc = dstxinc * -1;
1455 dstyinc = dstyinc * -1;
1457 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1459 tmp = dTopLeft;
1460 dTopLeft = dBottomLeft;
1461 dBottomLeft = dBottomRight;
1462 dBottomRight = dTopRight;
1463 dTopRight = tmp;
1464 tmpxy = dstxinc;
1465 dstxinc = dstyinc;
1466 dstyinc = tmpxy;
1467 dstxinc = dstxinc * -1;
1469 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1471 tmp = dTopLeft;
1472 dTopLeft = dTopRight;
1473 dTopRight = dBottomRight;
1474 dBottomRight = dBottomLeft;
1475 dBottomLeft = tmp;
1476 tmpxy = dstxinc;
1477 dstxinc = dstyinc;
1478 dstyinc = tmpxy;
1479 dstyinc = dstyinc * -1;
1481 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1483 /* I don't think we need to do anything about this flag */
1484 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1486 dbuf = dTopLeft;
1487 Flags &= ~(WINEDDBLT_DDFX);
1490 #define COPY_COLORKEY_FX(type) { \
1491 const type *s; \
1492 type *d = (type *)dbuf, *dx, tmp; \
1493 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1494 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1495 dx = d; \
1496 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1497 tmp = s[sx >> 16]; \
1498 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1499 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1500 dx[0] = tmp; \
1502 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1504 d = (type*)(((LPBYTE)d)+dstyinc); \
1506 break; }
1508 switch (bpp) {
1509 case 1: COPY_COLORKEY_FX(BYTE)
1510 case 2: COPY_COLORKEY_FX(WORD)
1511 case 4: COPY_COLORKEY_FX(DWORD)
1512 case 3:
1514 const BYTE *s;
1515 BYTE *d = dbuf, *dx;
1516 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1518 sbuf = sbase + (sy >> 16) * slock.Pitch;
1519 dx = d;
1520 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1522 DWORD pixel, dpixel = 0;
1523 s = sbuf+3*(sx>>16);
1524 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1525 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1526 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1527 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1529 dx[0] = (pixel )&0xff;
1530 dx[1] = (pixel>> 8)&0xff;
1531 dx[2] = (pixel>>16)&0xff;
1533 dx+= dstxinc;
1535 d += dstyinc;
1537 break;
1539 default:
1540 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1541 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1542 ret = WINED3DERR_NOTAVAILABLE;
1543 goto error;
1544 #undef COPY_COLORKEY_FX
1549 error:
1550 if (Flags && FIXME_ON(d3d_surface))
1552 FIXME("\tUnsupported flags: %08x\n", Flags);
1555 release:
1556 IWineD3DSurface_UnlockRect(iface);
1557 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1558 /* Release the converted surface if any */
1559 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1560 return ret;
1563 /*****************************************************************************
1564 * IWineD3DSurface::BltFast, SW emulation version
1566 * This is the software implementation of BltFast, as used by GDI surfaces
1567 * and as a fallback for OpenGL surfaces. This code is taken from the old
1568 * DirectDraw code, and was originally written by TransGaming.
1570 * Params:
1571 * dstx:
1572 * dsty:
1573 * Source: Source surface to copy from
1574 * rsrc: Source rectangle
1575 * trans: Some Flags
1577 * Returns:
1578 * WINED3D_OK on success
1580 *****************************************************************************/
1581 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1582 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1584 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1585 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1587 int bpp, w, h, x, y;
1588 WINED3DLOCKED_RECT dlock,slock;
1589 HRESULT ret = WINED3D_OK;
1590 RECT rsrc2;
1591 RECT lock_src, lock_dst, lock_union;
1592 const BYTE *sbuf;
1593 BYTE *dbuf;
1594 const struct wined3d_format_desc *sEntry, *dEntry;
1596 if (TRACE_ON(d3d_surface))
1598 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1600 if (rsrc)
1602 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1603 rsrc->right,rsrc->bottom);
1605 else
1607 TRACE(" srcrect: NULL\n");
1611 if ((This->Flags & SFLAG_LOCKED) ||
1612 (Src->Flags & SFLAG_LOCKED))
1614 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1615 return WINEDDERR_SURFACEBUSY;
1618 if (!rsrc)
1620 WARN("rsrc is NULL!\n");
1621 rsrc2.left = 0;
1622 rsrc2.top = 0;
1623 rsrc2.right = Src->currentDesc.Width;
1624 rsrc2.bottom = Src->currentDesc.Height;
1625 rsrc = &rsrc2;
1628 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1629 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1630 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1631 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1632 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1633 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1635 WARN("Application gave us bad source rectangle for BltFast.\n");
1636 return WINEDDERR_INVALIDRECT;
1639 h = rsrc->bottom - rsrc->top;
1640 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1641 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1642 if (h <= 0) return WINEDDERR_INVALIDRECT;
1644 w = rsrc->right - rsrc->left;
1645 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1646 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1647 if (w <= 0) return WINEDDERR_INVALIDRECT;
1649 /* Now compute the locking rectangle... */
1650 lock_src.left = rsrc->left;
1651 lock_src.top = rsrc->top;
1652 lock_src.right = lock_src.left + w;
1653 lock_src.bottom = lock_src.top + h;
1655 lock_dst.left = dstx;
1656 lock_dst.top = dsty;
1657 lock_dst.right = dstx + w;
1658 lock_dst.bottom = dsty + h;
1660 bpp = This->resource.format_desc->byte_count;
1662 /* We need to lock the surfaces, or we won't get refreshes when done. */
1663 if (Src == This)
1665 int pitch;
1667 UnionRect(&lock_union, &lock_src, &lock_dst);
1669 /* Lock the union of the two rectangles */
1670 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1671 if(ret != WINED3D_OK) goto error;
1673 pitch = dlock.Pitch;
1674 slock.Pitch = dlock.Pitch;
1676 /* Since slock was originally copied from this surface's description, we can just reuse it */
1677 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1678 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1679 sEntry = Src->resource.format_desc;
1680 dEntry = sEntry;
1682 else
1684 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1685 if(ret != WINED3D_OK) goto error;
1686 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1687 if(ret != WINED3D_OK) goto error;
1689 sbuf = slock.pBits;
1690 dbuf = dlock.pBits;
1691 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1693 sEntry = Src->resource.format_desc;
1694 dEntry = This->resource.format_desc;
1697 /* Handle compressed surfaces first... */
1698 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1700 UINT row_block_count;
1702 TRACE("compressed -> compressed copy\n");
1703 if (trans)
1704 FIXME("trans arg not supported when a compressed surface is involved\n");
1705 if (dstx || dsty)
1706 FIXME("offset for destination surface is not supported\n");
1707 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1709 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1710 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1711 goto error;
1714 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1715 for (y = 0; y < h; y += dEntry->block_height)
1717 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1718 dbuf += dlock.Pitch;
1719 sbuf += slock.Pitch;
1722 goto error;
1724 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1726 /* TODO: Use the libtxc_dxtn.so shared library to do
1727 * software decompression
1729 ERR("Software decompression not supported.\n");
1730 goto error;
1733 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1735 DWORD keylow, keyhigh;
1736 DWORD mask = Src->resource.format_desc->red_mask |
1737 Src->resource.format_desc->green_mask |
1738 Src->resource.format_desc->blue_mask;
1740 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1741 if(!mask && bpp==1)
1742 mask = 0xff;
1744 TRACE("Color keyed copy\n");
1745 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1747 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1748 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1750 else
1752 /* I'm not sure if this is correct */
1753 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1754 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1755 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1758 #define COPYBOX_COLORKEY(type) { \
1759 const type *s = (const type *)sbuf; \
1760 type *d = (type *)dbuf; \
1761 type tmp; \
1762 for (y = 0; y < h; y++) { \
1763 for (x = 0; x < w; x++) { \
1764 tmp = s[x]; \
1765 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1767 s = (const type *)((const BYTE *)s + slock.Pitch); \
1768 d = (type *)((BYTE *)d + dlock.Pitch); \
1770 break; \
1773 switch (bpp) {
1774 case 1: COPYBOX_COLORKEY(BYTE)
1775 case 2: COPYBOX_COLORKEY(WORD)
1776 case 4: COPYBOX_COLORKEY(DWORD)
1777 case 3:
1779 const BYTE *s;
1780 BYTE *d;
1781 DWORD tmp;
1782 s = sbuf;
1783 d = dbuf;
1784 for (y = 0; y < h; y++)
1786 for (x = 0; x < w * 3; x += 3)
1788 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1789 if (tmp < keylow || tmp > keyhigh)
1791 d[x + 0] = s[x + 0];
1792 d[x + 1] = s[x + 1];
1793 d[x + 2] = s[x + 2];
1796 s += slock.Pitch;
1797 d += dlock.Pitch;
1799 break;
1801 default:
1802 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1803 ret = WINED3DERR_NOTAVAILABLE;
1804 goto error;
1806 #undef COPYBOX_COLORKEY
1807 TRACE("Copy Done\n");
1809 else
1811 int width = w * bpp;
1812 INT sbufpitch, dbufpitch;
1814 TRACE("NO color key copy\n");
1815 /* Handle overlapping surfaces */
1816 if (sbuf < dbuf)
1818 sbuf += (h - 1) * slock.Pitch;
1819 dbuf += (h - 1) * dlock.Pitch;
1820 sbufpitch = -slock.Pitch;
1821 dbufpitch = -dlock.Pitch;
1823 else
1825 sbufpitch = slock.Pitch;
1826 dbufpitch = dlock.Pitch;
1828 for (y = 0; y < h; y++)
1830 /* This is pretty easy, a line for line memcpy */
1831 memmove(dbuf, sbuf, width);
1832 sbuf += sbufpitch;
1833 dbuf += dbufpitch;
1835 TRACE("Copy done\n");
1838 error:
1839 if (Src == This)
1841 IWineD3DSurface_UnlockRect(iface);
1843 else
1845 IWineD3DSurface_UnlockRect(iface);
1846 IWineD3DSurface_UnlockRect(Source);
1849 return ret;
1852 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1854 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1856 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1857 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1859 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1861 if (NULL == pRect)
1863 pLockedRect->pBits = This->resource.allocatedMemory;
1864 This->lockedRect.left = 0;
1865 This->lockedRect.top = 0;
1866 This->lockedRect.right = This->currentDesc.Width;
1867 This->lockedRect.bottom = This->currentDesc.Height;
1869 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1870 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1871 This->lockedRect.right, This->lockedRect.bottom);
1873 else
1875 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
1877 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1878 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1880 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1882 /* Compressed textures are block based, so calculate the offset of
1883 * the block that contains the top-left pixel of the locked rectangle. */
1884 pLockedRect->pBits = This->resource.allocatedMemory
1885 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1886 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1888 else
1890 pLockedRect->pBits = This->resource.allocatedMemory +
1891 (pLockedRect->Pitch * pRect->top) +
1892 (pRect->left * format_desc->byte_count);
1894 This->lockedRect.left = pRect->left;
1895 This->lockedRect.top = pRect->top;
1896 This->lockedRect.right = pRect->right;
1897 This->lockedRect.bottom = pRect->bottom;
1900 /* No dirtifying is needed for this surface implementation */
1901 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1903 return WINED3D_OK;
1906 /* TODO: think about moving this down to resource? */
1907 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1909 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1911 /* This should only be called for sysmem textures, it may be a good idea
1912 * to extend this to all pools at some point in the future */
1913 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1915 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1917 return This->resource.allocatedMemory;