wined3d: Rename surface_calculate_size() to wined3d_format_calculate_size().
[wine.git] / dlls / wined3d / surface_base.c
blob6c12155908a4e1f3c73f674bc451e9cfdd85fb97
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 < powf(2, 10)) {
52 tmp = tmp * 2.0f;
53 exp--;
54 }while(tmp < powf(2, 10));
55 } else if(tmp >= powf(2, 11)) {
58 tmp /= 2.0f;
59 exp++;
60 }while(tmp >= powf(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 | WINED3DFMT_FLAG_BROKEN_PITCH))
331 == WINED3DFMT_FLAG_COMPRESSED)
333 /* Since compressed formats are block based, pitch means the amount of
334 * bytes to the next row of block rather than the next row of pixels. */
335 UINT row_block_count = (This->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
336 ret = row_block_count * format_desc->block_byte_count;
338 else
340 unsigned char alignment = This->resource.device->surface_alignment;
341 ret = This->resource.format_desc->byte_count * This->currentDesc.Width; /* Bytes / row */
342 ret = (ret + alignment - 1) & ~(alignment - 1);
344 TRACE("(%p) Returning %d\n", This, ret);
345 return ret;
348 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
349 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
350 LONG w, h;
352 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
354 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
356 TRACE("(%p): Not an overlay surface\n", This);
357 return WINEDDERR_NOTAOVERLAYSURFACE;
360 w = This->overlay_destrect.right - This->overlay_destrect.left;
361 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
362 This->overlay_destrect.left = X;
363 This->overlay_destrect.top = Y;
364 This->overlay_destrect.right = X + w;
365 This->overlay_destrect.bottom = Y + h;
367 IWineD3DSurface_DrawOverlay(iface);
369 return WINED3D_OK;
372 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
373 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
374 HRESULT hr;
376 TRACE("(%p)->(%p,%p)\n", This, X, Y);
378 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
380 TRACE("(%p): Not an overlay surface\n", This);
381 return WINEDDERR_NOTAOVERLAYSURFACE;
383 if(This->overlay_dest == NULL) {
384 *X = 0; *Y = 0;
385 hr = WINEDDERR_OVERLAYNOTVISIBLE;
386 } else {
387 *X = This->overlay_destrect.left;
388 *Y = This->overlay_destrect.top;
389 hr = WINED3D_OK;
392 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
393 return hr;
396 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
397 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
399 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, Flags, Ref);
401 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
403 TRACE("(%p): Not an overlay surface\n", This);
404 return WINEDDERR_NOTAOVERLAYSURFACE;
407 return WINED3D_OK;
410 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
411 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
413 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
414 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
415 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
417 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
419 WARN("(%p): Not an overlay surface\n", This);
420 return WINEDDERR_NOTAOVERLAYSURFACE;
421 } else if(!DstSurface) {
422 WARN("(%p): Dest surface is NULL\n", This);
423 return WINED3DERR_INVALIDCALL;
426 if(SrcRect) {
427 This->overlay_srcrect = *SrcRect;
428 } else {
429 This->overlay_srcrect.left = 0;
430 This->overlay_srcrect.top = 0;
431 This->overlay_srcrect.right = This->currentDesc.Width;
432 This->overlay_srcrect.bottom = This->currentDesc.Height;
435 if(DstRect) {
436 This->overlay_destrect = *DstRect;
437 } else {
438 This->overlay_destrect.left = 0;
439 This->overlay_destrect.top = 0;
440 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
441 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
444 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
445 list_remove(&This->overlay_entry);
448 if(Flags & WINEDDOVER_SHOW) {
449 if(This->overlay_dest != Dst) {
450 This->overlay_dest = Dst;
451 list_add_tail(&Dst->overlays, &This->overlay_entry);
453 } else if(Flags & WINEDDOVER_HIDE) {
454 /* tests show that the rectangles are erased on hide */
455 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
456 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
457 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
458 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
459 This->overlay_dest = NULL;
462 IWineD3DSurface_DrawOverlay(iface);
464 return WINED3D_OK;
467 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
469 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
470 TRACE("(%p)->(%p)\n", This, clipper);
472 This->clipper = clipper;
473 return WINED3D_OK;
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
478 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
479 TRACE("(%p)->(%p)\n", This, clipper);
481 *clipper = This->clipper;
482 if(*clipper) {
483 IWineD3DClipper_AddRef(*clipper);
485 return WINED3D_OK;
488 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
489 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
491 TRACE("This %p, container %p\n", This, container);
493 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
495 TRACE("Setting container to %p from %p\n", container, This->container);
496 This->container = container;
498 return WINED3D_OK;
501 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
502 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
503 const struct wined3d_format_desc *format_desc = getFormatDescEntry(format,
504 &This->resource.device->adapter->gl_info);
506 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
508 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
509 return WINED3DERR_INVALIDCALL;
512 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
514 This->resource.size = wined3d_format_calculate_size(format_desc, This->resource.device->surface_alignment,
515 This->pow2Width, This->pow2Height);
517 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
519 This->resource.format_desc = format_desc;
521 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
523 return WINED3D_OK;
526 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
527 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
528 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
529 int extraline = 0;
530 SYSTEM_INFO sysInfo;
531 BITMAPINFO* b_info;
532 HDC ddc;
533 DWORD *masks;
534 UINT usage;
536 if(!(format_desc->Flags & WINED3DFMT_FLAG_GETDC))
538 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format_desc->format));
539 return WINED3DERR_INVALIDCALL;
542 switch (format_desc->byte_count)
544 case 2:
545 case 4:
546 /* Allocate extra space to store the RGB bit masks. */
547 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
548 break;
550 case 3:
551 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
552 break;
554 default:
555 /* Allocate extra space for a palette. */
556 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
557 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
558 break;
561 if (!b_info)
562 return E_OUTOFMEMORY;
564 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
565 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
566 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
567 * add an extra line to the dib section
569 GetSystemInfo(&sysInfo);
570 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
571 extraline = 1;
572 TRACE("Adding an extra line to the dib section\n");
575 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
576 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
577 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
578 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
579 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
580 b_info->bmiHeader.biPlanes = 1;
581 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
583 b_info->bmiHeader.biXPelsPerMeter = 0;
584 b_info->bmiHeader.biYPelsPerMeter = 0;
585 b_info->bmiHeader.biClrUsed = 0;
586 b_info->bmiHeader.biClrImportant = 0;
588 /* Get the bit masks */
589 masks = (DWORD *)b_info->bmiColors;
590 switch (This->resource.format_desc->format)
592 case WINED3DFMT_B8G8R8_UNORM:
593 usage = DIB_RGB_COLORS;
594 b_info->bmiHeader.biCompression = BI_RGB;
595 break;
597 case WINED3DFMT_B5G5R5X1_UNORM:
598 case WINED3DFMT_B5G5R5A1_UNORM:
599 case WINED3DFMT_B4G4R4A4_UNORM:
600 case WINED3DFMT_B4G4R4X4_UNORM:
601 case WINED3DFMT_B2G3R3_UNORM:
602 case WINED3DFMT_B2G3R3A8_UNORM:
603 case WINED3DFMT_R10G10B10A2_UNORM:
604 case WINED3DFMT_R8G8B8A8_UNORM:
605 case WINED3DFMT_R8G8B8X8_UNORM:
606 case WINED3DFMT_B10G10R10A2_UNORM:
607 case WINED3DFMT_B5G6R5_UNORM:
608 case WINED3DFMT_R16G16B16A16_UNORM:
609 usage = 0;
610 b_info->bmiHeader.biCompression = BI_BITFIELDS;
611 masks[0] = format_desc->red_mask;
612 masks[1] = format_desc->green_mask;
613 masks[2] = format_desc->blue_mask;
614 break;
616 default:
617 /* Don't know palette */
618 b_info->bmiHeader.biCompression = BI_RGB;
619 usage = 0;
620 break;
623 ddc = GetDC(0);
624 if (ddc == 0) {
625 HeapFree(GetProcessHeap(), 0, b_info);
626 return HRESULT_FROM_WIN32(GetLastError());
629 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);
630 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
631 ReleaseDC(0, ddc);
633 if (!This->dib.DIBsection) {
634 ERR("CreateDIBSection failed!\n");
635 HeapFree(GetProcessHeap(), 0, b_info);
636 return HRESULT_FROM_WIN32(GetLastError());
639 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
640 /* copy the existing surface to the dib section */
641 if(This->resource.allocatedMemory) {
642 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
643 } else {
644 /* This is to make LockRect read the gl Texture although memory is allocated */
645 This->Flags &= ~SFLAG_INSYSMEM;
647 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
649 HeapFree(GetProcessHeap(), 0, b_info);
651 /* Now allocate a HDC */
652 This->hDC = CreateCompatibleDC(0);
653 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
654 TRACE("using wined3d palette %p\n", This->palette);
655 SelectPalette(This->hDC,
656 This->palette ? This->palette->hpal : 0,
657 FALSE);
659 This->Flags |= SFLAG_DIBSECTION;
661 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
662 This->resource.heapMemory = NULL;
664 return WINED3D_OK;
667 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
668 unsigned int w, unsigned int h)
670 unsigned int x, y;
671 const float *src_f;
672 unsigned short *dst_s;
674 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
675 for(y = 0; y < h; y++) {
676 src_f = (const float *)(src + y * pitch_in);
677 dst_s = (unsigned short *) (dst + y * pitch_out);
678 for(x = 0; x < w; x++) {
679 dst_s[x] = float_32_to_16(src_f + x);
684 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
685 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
687 static const unsigned char convert_5to8[] =
689 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
690 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
691 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
692 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
694 static const unsigned char convert_6to8[] =
696 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
697 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
698 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
699 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
700 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
701 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
702 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
703 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
705 unsigned int x, y;
707 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
709 for (y = 0; y < h; ++y)
711 const WORD *src_line = (const WORD *)(src + y * pitch_in);
712 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
713 for (x = 0; x < w; ++x)
715 WORD pixel = src_line[x];
716 dst_line[x] = 0xff000000
717 | convert_5to8[(pixel & 0xf800) >> 11] << 16
718 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
719 | convert_5to8[(pixel & 0x001f)];
724 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
725 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
727 unsigned int x, y;
729 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
731 for (y = 0; y < h; ++y)
733 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
734 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
736 for (x = 0; x < w; ++x)
738 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
743 static inline BYTE cliptobyte(int x)
745 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
748 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
749 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
751 unsigned int x, y;
752 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
754 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
756 for (y = 0; y < h; ++y)
758 const BYTE *src_line = src + y * pitch_in;
759 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
760 for (x = 0; x < w; ++x)
762 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
763 * C = Y - 16; D = U - 128; E = V - 128;
764 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
765 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
766 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
767 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
768 * U and V are shared between the pixels.
770 if (!(x & 1)) /* for every even pixel, read new U and V */
772 d = (int) src_line[1] - 128;
773 e = (int) src_line[3] - 128;
774 r2 = 409 * e + 128;
775 g2 = - 100 * d - 208 * e + 128;
776 b2 = 516 * d + 128;
778 c2 = 298 * ((int) src_line[0] - 16);
779 dst_line[x] = 0xff000000
780 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
781 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
782 | cliptobyte((c2 + b2) >> 8); /* blue */
783 /* Scale RGB values to 0..255 range,
784 * then clip them if still not in range (may be negative),
785 * then shift them within DWORD if necessary.
787 src_line += 2;
792 struct d3dfmt_convertor_desc {
793 WINED3DFORMAT from, to;
794 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
797 static const struct d3dfmt_convertor_desc convertors[] =
799 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
800 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
801 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
802 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
805 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
807 unsigned int i;
808 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
809 if(convertors[i].from == from && convertors[i].to == to) {
810 return &convertors[i];
813 return NULL;
816 /*****************************************************************************
817 * surface_convert_format
819 * Creates a duplicate of a surface in a different format. Is used by Blt to
820 * blit between surfaces with different formats
822 * Parameters
823 * source: Source surface
824 * fmt: Requested destination format
826 *****************************************************************************/
827 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
828 IWineD3DSurface *ret = NULL;
829 const struct d3dfmt_convertor_desc *conv;
830 WINED3DLOCKED_RECT lock_src, lock_dst;
831 HRESULT hr;
833 conv = find_convertor(source->resource.format_desc->format, to_fmt);
834 if(!conv) {
835 FIXME("Cannot find a conversion function from format %s to %s\n",
836 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
837 return NULL;
840 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
841 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
842 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
843 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
844 NULL /* parent */, &wined3d_null_parent_ops);
845 if(!ret) {
846 ERR("Failed to create a destination surface for conversion\n");
847 return NULL;
850 memset(&lock_src, 0, sizeof(lock_src));
851 memset(&lock_dst, 0, sizeof(lock_dst));
853 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
854 if(FAILED(hr)) {
855 ERR("Failed to lock the source surface\n");
856 IWineD3DSurface_Release(ret);
857 return NULL;
859 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
860 if(FAILED(hr)) {
861 ERR("Failed to lock the dest surface\n");
862 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
863 IWineD3DSurface_Release(ret);
864 return NULL;
867 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
868 source->currentDesc.Width, source->currentDesc.Height);
870 IWineD3DSurface_UnlockRect(ret);
871 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
873 return (IWineD3DSurfaceImpl *) ret;
876 /*****************************************************************************
877 * _Blt_ColorFill
879 * Helper function that fills a memory area with a specific color
881 * Params:
882 * buf: memory address to start filling at
883 * width, height: Dimensions of the area to fill
884 * bpp: Bit depth of the surface
885 * lPitch: pitch of the surface
886 * color: Color to fill with
888 *****************************************************************************/
889 static HRESULT
890 _Blt_ColorFill(BYTE *buf,
891 int width, int height,
892 int bpp, LONG lPitch,
893 DWORD color)
895 int x, y;
896 LPBYTE first;
898 /* Do first row */
900 #define COLORFILL_ROW(type) \
902 type *d = (type *) buf; \
903 for (x = 0; x < width; x++) \
904 d[x] = (type) color; \
905 break; \
907 switch(bpp)
909 case 1: COLORFILL_ROW(BYTE)
910 case 2: COLORFILL_ROW(WORD)
911 case 3:
913 BYTE *d = buf;
914 for (x = 0; x < width; x++,d+=3)
916 d[0] = (color ) & 0xFF;
917 d[1] = (color>> 8) & 0xFF;
918 d[2] = (color>>16) & 0xFF;
920 break;
922 case 4: COLORFILL_ROW(DWORD)
923 default:
924 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
925 return WINED3DERR_NOTAVAILABLE;
928 #undef COLORFILL_ROW
930 /* Now copy first row */
931 first = buf;
932 for (y = 1; y < height; y++)
934 buf += lPitch;
935 memcpy(buf, first, width * bpp);
937 return WINED3D_OK;
940 /*****************************************************************************
941 * IWineD3DSurface::Blt, SW emulation version
943 * Performs a blit to a surface, with or without a source surface.
944 * This is the main functionality of DirectDraw
946 * Params:
947 * DestRect: Destination rectangle to write to
948 * src_surface: Source surface, can be NULL
949 * SrcRect: Source rectangle
950 *****************************************************************************/
951 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
952 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
954 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
955 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
956 RECT xdst,xsrc;
957 HRESULT ret = WINED3D_OK;
958 WINED3DLOCKED_RECT dlock, slock;
959 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
960 const struct wined3d_format_desc *sEntry, *dEntry;
961 int x, y;
962 const BYTE *sbuf;
963 BYTE *dbuf;
965 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
966 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
967 Flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
969 if ((This->Flags & SFLAG_LOCKED) || (src && (src->Flags & SFLAG_LOCKED)))
971 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
972 return WINEDDERR_SURFACEBUSY;
975 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
976 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
977 FIXME("Filters not supported in software blit\n");
980 /* First check for the validity of source / destination rectangles.
981 * This was verified using a test application + by MSDN. */
983 if (SrcRect)
985 if (src)
987 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
988 || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
989 || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
990 || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
991 || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
993 WARN("Application gave us bad source rectangle for Blt.\n");
994 return WINEDDERR_INVALIDRECT;
997 if (!SrcRect->right || !SrcRect->bottom
998 || SrcRect->left == (int)src->currentDesc.Width
999 || SrcRect->top == (int)src->currentDesc.Height)
1001 TRACE("Nothing to be done.\n");
1002 return WINED3D_OK;
1006 xsrc = *SrcRect;
1008 else if (src)
1010 xsrc.left = 0;
1011 xsrc.top = 0;
1012 xsrc.right = src->currentDesc.Width;
1013 xsrc.bottom = src->currentDesc.Height;
1015 else
1017 memset(&xsrc, 0, sizeof(xsrc));
1020 if (DestRect)
1022 /* For the Destination rect, it can be out of bounds on the condition
1023 * that a clipper is set for the given surface. */
1024 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1025 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
1026 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1027 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1028 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1030 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1031 return WINEDDERR_INVALIDRECT;
1034 if (DestRect->right <= 0 || DestRect->bottom <= 0
1035 || DestRect->left >= (int)This->currentDesc.Width
1036 || DestRect->top >= (int)This->currentDesc.Height)
1038 TRACE("Nothing to be done.\n");
1039 return WINED3D_OK;
1042 if (!src)
1044 RECT full_rect;
1046 full_rect.left = 0;
1047 full_rect.top = 0;
1048 full_rect.right = This->currentDesc.Width;
1049 full_rect.bottom = This->currentDesc.Height;
1050 IntersectRect(&xdst, &full_rect, DestRect);
1052 else
1054 BOOL clip_horiz, clip_vert;
1056 xdst = *DestRect;
1057 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1058 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1060 if (clip_vert || clip_horiz)
1062 /* Now check if this is a special case or not... */
1063 if ((Flags & WINEDDBLT_DDFX)
1064 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1065 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1067 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1068 return WINED3D_OK;
1071 if (clip_horiz)
1073 if (xdst.left < 0)
1075 xsrc.left -= xdst.left;
1076 xdst.left = 0;
1078 if (xdst.right > This->currentDesc.Width)
1080 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1081 xdst.right = (int)This->currentDesc.Width;
1085 if (clip_vert)
1087 if (xdst.top < 0)
1089 xsrc.top -= xdst.top;
1090 xdst.top = 0;
1092 if (xdst.bottom > This->currentDesc.Height)
1094 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1095 xdst.bottom = (int)This->currentDesc.Height;
1099 /* And check if after clipping something is still to be done... */
1100 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1101 || (xdst.left >= (int)This->currentDesc.Width)
1102 || (xdst.top >= (int)This->currentDesc.Height)
1103 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1104 || (xsrc.left >= (int)src->currentDesc.Width)
1105 || (xsrc.top >= (int)src->currentDesc.Height))
1107 TRACE("Nothing to be done after clipping.\n");
1108 return WINED3D_OK;
1113 else
1115 xdst.left = 0;
1116 xdst.top = 0;
1117 xdst.right = This->currentDesc.Width;
1118 xdst.bottom = This->currentDesc.Height;
1121 if (src == This)
1123 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1124 slock = dlock;
1125 sEntry = This->resource.format_desc;
1126 dEntry = sEntry;
1128 else
1130 dEntry = This->resource.format_desc;
1131 if (src)
1133 if (This->resource.format_desc->format != src->resource.format_desc->format)
1135 src = surface_convert_format(src, dEntry->format);
1136 if (!src)
1138 /* The conv function writes a FIXME */
1139 WARN("Cannot convert source surface format to dest format\n");
1140 goto release;
1143 IWineD3DSurface_LockRect((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1144 sEntry = src->resource.format_desc;
1146 else
1148 sEntry = dEntry;
1150 if (DestRect)
1151 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1152 else
1153 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1156 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1158 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1160 if (!DestRect || src == This)
1162 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1163 goto release;
1167 bpp = This->resource.format_desc->byte_count;
1168 srcheight = xsrc.bottom - xsrc.top;
1169 srcwidth = xsrc.right - xsrc.left;
1170 dstheight = xdst.bottom - xdst.top;
1171 dstwidth = xdst.right - xdst.left;
1172 width = (xdst.right - xdst.left) * bpp;
1174 if (DestRect && src != This)
1175 dbuf = dlock.pBits;
1176 else
1177 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1179 if (Flags & WINEDDBLT_WAIT)
1181 Flags &= ~WINEDDBLT_WAIT;
1183 if (Flags & WINEDDBLT_ASYNC)
1185 static BOOL displayed = FALSE;
1186 if (!displayed)
1187 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1188 displayed = TRUE;
1189 Flags &= ~WINEDDBLT_ASYNC;
1191 if (Flags & WINEDDBLT_DONOTWAIT)
1193 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1194 static BOOL displayed = FALSE;
1195 if (!displayed)
1196 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1197 displayed = TRUE;
1198 Flags &= ~WINEDDBLT_DONOTWAIT;
1201 /* First, all the 'source-less' blits */
1202 if (Flags & WINEDDBLT_COLORFILL)
1204 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1205 dlock.Pitch, DDBltFx->u5.dwFillColor);
1206 Flags &= ~WINEDDBLT_COLORFILL;
1209 if (Flags & WINEDDBLT_DEPTHFILL)
1211 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1213 if (Flags & WINEDDBLT_ROP)
1215 /* Catch some degenerate cases here */
1216 switch(DDBltFx->dwROP)
1218 case BLACKNESS:
1219 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1220 break;
1221 case 0xAA0029: /* No-op */
1222 break;
1223 case WHITENESS:
1224 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1225 break;
1226 case SRCCOPY: /* well, we do that below ? */
1227 break;
1228 default:
1229 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1230 goto error;
1232 Flags &= ~WINEDDBLT_ROP;
1234 if (Flags & WINEDDBLT_DDROPS)
1236 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1238 /* Now the 'with source' blits */
1239 if (src)
1241 const BYTE *sbase;
1242 int sx, xinc, sy, yinc;
1244 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1245 goto release;
1246 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1247 xinc = (srcwidth << 16) / dstwidth;
1248 yinc = (srcheight << 16) / dstheight;
1250 if (!Flags)
1252 /* No effects, we can cheat here */
1253 if (dstwidth == srcwidth)
1255 if (dstheight == srcheight)
1257 /* No stretching in either direction. This needs to be as
1258 * fast as possible */
1259 sbuf = sbase;
1261 /* check for overlapping surfaces */
1262 if (src != This || xdst.top < xsrc.top ||
1263 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1265 /* no overlap, or dst above src, so copy from top downwards */
1266 for (y = 0; y < dstheight; y++)
1268 memcpy(dbuf, sbuf, width);
1269 sbuf += slock.Pitch;
1270 dbuf += dlock.Pitch;
1273 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1275 sbuf += (slock.Pitch*dstheight);
1276 dbuf += (dlock.Pitch*dstheight);
1277 for (y = 0; y < dstheight; y++)
1279 sbuf -= slock.Pitch;
1280 dbuf -= dlock.Pitch;
1281 memcpy(dbuf, sbuf, width);
1284 else /* src and dst overlapping on the same line, use memmove */
1286 for (y = 0; y < dstheight; y++)
1288 memmove(dbuf, sbuf, width);
1289 sbuf += slock.Pitch;
1290 dbuf += dlock.Pitch;
1293 } else {
1294 /* Stretching in Y direction only */
1295 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1296 sbuf = sbase + (sy >> 16) * slock.Pitch;
1297 memcpy(dbuf, sbuf, width);
1298 dbuf += dlock.Pitch;
1302 else
1304 /* Stretching in X direction */
1305 int last_sy = -1;
1306 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1308 sbuf = sbase + (sy >> 16) * slock.Pitch;
1310 if ((sy >> 16) == (last_sy >> 16))
1312 /* this sourcerow is the same as last sourcerow -
1313 * copy already stretched row
1315 memcpy(dbuf, dbuf - dlock.Pitch, width);
1317 else
1319 #define STRETCH_ROW(type) { \
1320 const type *s = (const type *)sbuf; \
1321 type *d = (type *)dbuf; \
1322 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1323 d[x] = s[sx >> 16]; \
1324 break; }
1326 switch(bpp)
1328 case 1: STRETCH_ROW(BYTE)
1329 case 2: STRETCH_ROW(WORD)
1330 case 4: STRETCH_ROW(DWORD)
1331 case 3:
1333 const BYTE *s;
1334 BYTE *d = dbuf;
1335 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1337 DWORD pixel;
1339 s = sbuf+3*(sx>>16);
1340 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1341 d[0] = (pixel )&0xff;
1342 d[1] = (pixel>> 8)&0xff;
1343 d[2] = (pixel>>16)&0xff;
1344 d+=3;
1346 break;
1348 default:
1349 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1350 ret = WINED3DERR_NOTAVAILABLE;
1351 goto error;
1353 #undef STRETCH_ROW
1355 dbuf += dlock.Pitch;
1356 last_sy = sy;
1360 else
1362 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1363 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1364 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1365 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1367 /* The color keying flags are checked for correctness in ddraw */
1368 if (Flags & WINEDDBLT_KEYSRC)
1370 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1371 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1373 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1375 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1376 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1379 if (Flags & WINEDDBLT_KEYDEST)
1381 /* Destination color keys are taken from the source surface ! */
1382 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1383 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1385 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1387 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1388 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1391 if(bpp == 1)
1393 keymask = 0xff;
1395 else
1397 keymask = sEntry->red_mask
1398 | sEntry->green_mask
1399 | sEntry->blue_mask;
1401 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1404 if (Flags & WINEDDBLT_DDFX)
1406 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1407 LONG tmpxy;
1408 dTopLeft = dbuf;
1409 dTopRight = dbuf+((dstwidth-1)*bpp);
1410 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1411 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1413 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1415 /* I don't think we need to do anything about this flag */
1416 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1418 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1420 tmp = dTopRight;
1421 dTopRight = dTopLeft;
1422 dTopLeft = tmp;
1423 tmp = dBottomRight;
1424 dBottomRight = dBottomLeft;
1425 dBottomLeft = tmp;
1426 dstxinc = dstxinc *-1;
1428 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1430 tmp = dTopLeft;
1431 dTopLeft = dBottomLeft;
1432 dBottomLeft = tmp;
1433 tmp = dTopRight;
1434 dTopRight = dBottomRight;
1435 dBottomRight = tmp;
1436 dstyinc = dstyinc *-1;
1438 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1440 /* I don't think we need to do anything about this flag */
1441 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1443 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1445 tmp = dBottomRight;
1446 dBottomRight = dTopLeft;
1447 dTopLeft = tmp;
1448 tmp = dBottomLeft;
1449 dBottomLeft = dTopRight;
1450 dTopRight = tmp;
1451 dstxinc = dstxinc * -1;
1452 dstyinc = dstyinc * -1;
1454 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1456 tmp = dTopLeft;
1457 dTopLeft = dBottomLeft;
1458 dBottomLeft = dBottomRight;
1459 dBottomRight = dTopRight;
1460 dTopRight = tmp;
1461 tmpxy = dstxinc;
1462 dstxinc = dstyinc;
1463 dstyinc = tmpxy;
1464 dstxinc = dstxinc * -1;
1466 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1468 tmp = dTopLeft;
1469 dTopLeft = dTopRight;
1470 dTopRight = dBottomRight;
1471 dBottomRight = dBottomLeft;
1472 dBottomLeft = tmp;
1473 tmpxy = dstxinc;
1474 dstxinc = dstyinc;
1475 dstyinc = tmpxy;
1476 dstyinc = dstyinc * -1;
1478 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1480 /* I don't think we need to do anything about this flag */
1481 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1483 dbuf = dTopLeft;
1484 Flags &= ~(WINEDDBLT_DDFX);
1487 #define COPY_COLORKEY_FX(type) { \
1488 const type *s; \
1489 type *d = (type *)dbuf, *dx, tmp; \
1490 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1491 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1492 dx = d; \
1493 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1494 tmp = s[sx >> 16]; \
1495 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1496 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1497 dx[0] = tmp; \
1499 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1501 d = (type*)(((LPBYTE)d)+dstyinc); \
1503 break; }
1505 switch (bpp) {
1506 case 1: COPY_COLORKEY_FX(BYTE)
1507 case 2: COPY_COLORKEY_FX(WORD)
1508 case 4: COPY_COLORKEY_FX(DWORD)
1509 case 3:
1511 const BYTE *s;
1512 BYTE *d = dbuf, *dx;
1513 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1515 sbuf = sbase + (sy >> 16) * slock.Pitch;
1516 dx = d;
1517 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1519 DWORD pixel, dpixel = 0;
1520 s = sbuf+3*(sx>>16);
1521 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1522 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1523 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1524 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1526 dx[0] = (pixel )&0xff;
1527 dx[1] = (pixel>> 8)&0xff;
1528 dx[2] = (pixel>>16)&0xff;
1530 dx+= dstxinc;
1532 d += dstyinc;
1534 break;
1536 default:
1537 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1538 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1539 ret = WINED3DERR_NOTAVAILABLE;
1540 goto error;
1541 #undef COPY_COLORKEY_FX
1546 error:
1547 if (Flags && FIXME_ON(d3d_surface))
1549 FIXME("\tUnsupported flags: %08x\n", Flags);
1552 release:
1553 IWineD3DSurface_UnlockRect(iface);
1554 if (src && src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *)src);
1555 /* Release the converted surface if any */
1556 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1557 return ret;
1560 /*****************************************************************************
1561 * IWineD3DSurface::BltFast, SW emulation version
1563 * This is the software implementation of BltFast, as used by GDI surfaces
1564 * and as a fallback for OpenGL surfaces. This code is taken from the old
1565 * DirectDraw code, and was originally written by TransGaming.
1567 * Params:
1568 * dstx:
1569 * dsty:
1570 * src_surface: Source surface to copy from
1571 * rsrc: Source rectangle
1572 * trans: Some Flags
1574 * Returns:
1575 * WINED3D_OK on success
1577 *****************************************************************************/
1578 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1579 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1581 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1582 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1584 int bpp, w, h, x, y;
1585 WINED3DLOCKED_RECT dlock,slock;
1586 HRESULT ret = WINED3D_OK;
1587 RECT rsrc2;
1588 RECT lock_src, lock_dst, lock_union;
1589 const BYTE *sbuf;
1590 BYTE *dbuf;
1591 const struct wined3d_format_desc *sEntry, *dEntry;
1593 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1594 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1596 if ((This->Flags & SFLAG_LOCKED) || (src->Flags & SFLAG_LOCKED))
1598 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1599 return WINEDDERR_SURFACEBUSY;
1602 if (!rsrc)
1604 WARN("rsrc is NULL!\n");
1605 rsrc2.left = 0;
1606 rsrc2.top = 0;
1607 rsrc2.right = src->currentDesc.Width;
1608 rsrc2.bottom = src->currentDesc.Height;
1609 rsrc = &rsrc2;
1612 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1613 if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1614 || (rsrc->top > src->currentDesc.Height) || (rsrc->top < 0)
1615 || (rsrc->left > src->currentDesc.Width) || (rsrc->left < 0)
1616 || (rsrc->right > src->currentDesc.Width) || (rsrc->right < 0)
1617 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1619 WARN("Application gave us bad source rectangle for BltFast.\n");
1620 return WINEDDERR_INVALIDRECT;
1623 h = rsrc->bottom - rsrc->top;
1624 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1625 if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1626 if (h <= 0) return WINEDDERR_INVALIDRECT;
1628 w = rsrc->right - rsrc->left;
1629 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1630 if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1631 if (w <= 0) return WINEDDERR_INVALIDRECT;
1633 /* Now compute the locking rectangle... */
1634 lock_src.left = rsrc->left;
1635 lock_src.top = rsrc->top;
1636 lock_src.right = lock_src.left + w;
1637 lock_src.bottom = lock_src.top + h;
1639 lock_dst.left = dstx;
1640 lock_dst.top = dsty;
1641 lock_dst.right = dstx + w;
1642 lock_dst.bottom = dsty + h;
1644 bpp = This->resource.format_desc->byte_count;
1646 /* We need to lock the surfaces, or we won't get refreshes when done. */
1647 if (src == This)
1649 int pitch;
1651 UnionRect(&lock_union, &lock_src, &lock_dst);
1653 /* Lock the union of the two rectangles */
1654 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1655 if(ret != WINED3D_OK) goto error;
1657 pitch = dlock.Pitch;
1658 slock.Pitch = dlock.Pitch;
1660 /* Since slock was originally copied from this surface's description, we can just reuse it */
1661 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1662 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1663 sEntry = src->resource.format_desc;
1664 dEntry = sEntry;
1666 else
1668 ret = IWineD3DSurface_LockRect(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1669 if(ret != WINED3D_OK) goto error;
1670 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1671 if(ret != WINED3D_OK) goto error;
1673 sbuf = slock.pBits;
1674 dbuf = dlock.pBits;
1675 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1677 sEntry = src->resource.format_desc;
1678 dEntry = This->resource.format_desc;
1681 /* Handle compressed surfaces first... */
1682 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1684 UINT row_block_count;
1686 TRACE("compressed -> compressed copy\n");
1687 if (trans)
1688 FIXME("trans arg not supported when a compressed surface is involved\n");
1689 if (dstx || dsty)
1690 FIXME("offset for destination surface is not supported\n");
1691 if (src->resource.format_desc->format != This->resource.format_desc->format)
1693 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1694 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1695 goto error;
1698 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1699 for (y = 0; y < h; y += dEntry->block_height)
1701 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1702 dbuf += dlock.Pitch;
1703 sbuf += slock.Pitch;
1706 goto error;
1708 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1710 /* TODO: Use the libtxc_dxtn.so shared library to do
1711 * software decompression
1713 ERR("Software decompression not supported.\n");
1714 goto error;
1717 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1719 DWORD keylow, keyhigh;
1720 DWORD mask = src->resource.format_desc->red_mask
1721 | src->resource.format_desc->green_mask
1722 | src->resource.format_desc->blue_mask;
1724 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1725 if(!mask && bpp==1)
1726 mask = 0xff;
1728 TRACE("Color keyed copy\n");
1729 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1731 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1732 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1734 else
1736 /* I'm not sure if this is correct */
1737 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1738 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1739 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1742 #define COPYBOX_COLORKEY(type) { \
1743 const type *s = (const type *)sbuf; \
1744 type *d = (type *)dbuf; \
1745 type tmp; \
1746 for (y = 0; y < h; y++) { \
1747 for (x = 0; x < w; x++) { \
1748 tmp = s[x]; \
1749 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1751 s = (const type *)((const BYTE *)s + slock.Pitch); \
1752 d = (type *)((BYTE *)d + dlock.Pitch); \
1754 break; \
1757 switch (bpp) {
1758 case 1: COPYBOX_COLORKEY(BYTE)
1759 case 2: COPYBOX_COLORKEY(WORD)
1760 case 4: COPYBOX_COLORKEY(DWORD)
1761 case 3:
1763 const BYTE *s;
1764 BYTE *d;
1765 DWORD tmp;
1766 s = sbuf;
1767 d = dbuf;
1768 for (y = 0; y < h; y++)
1770 for (x = 0; x < w * 3; x += 3)
1772 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1773 if (tmp < keylow || tmp > keyhigh)
1775 d[x + 0] = s[x + 0];
1776 d[x + 1] = s[x + 1];
1777 d[x + 2] = s[x + 2];
1780 s += slock.Pitch;
1781 d += dlock.Pitch;
1783 break;
1785 default:
1786 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1787 ret = WINED3DERR_NOTAVAILABLE;
1788 goto error;
1790 #undef COPYBOX_COLORKEY
1791 TRACE("Copy Done\n");
1793 else
1795 int width = w * bpp;
1796 INT sbufpitch, dbufpitch;
1798 TRACE("NO color key copy\n");
1799 /* Handle overlapping surfaces */
1800 if (sbuf < dbuf)
1802 sbuf += (h - 1) * slock.Pitch;
1803 dbuf += (h - 1) * dlock.Pitch;
1804 sbufpitch = -slock.Pitch;
1805 dbufpitch = -dlock.Pitch;
1807 else
1809 sbufpitch = slock.Pitch;
1810 dbufpitch = dlock.Pitch;
1812 for (y = 0; y < h; y++)
1814 /* This is pretty easy, a line for line memcpy */
1815 memmove(dbuf, sbuf, width);
1816 sbuf += sbufpitch;
1817 dbuf += dbufpitch;
1819 TRACE("Copy done\n");
1822 error:
1823 if (src == This)
1825 IWineD3DSurface_UnlockRect(iface);
1827 else
1829 IWineD3DSurface_UnlockRect(iface);
1830 IWineD3DSurface_UnlockRect(src_surface);
1833 return ret;
1836 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1838 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1840 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1841 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1843 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1845 if (NULL == pRect)
1847 pLockedRect->pBits = This->resource.allocatedMemory;
1848 This->lockedRect.left = 0;
1849 This->lockedRect.top = 0;
1850 This->lockedRect.right = This->currentDesc.Width;
1851 This->lockedRect.bottom = This->currentDesc.Height;
1853 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1854 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1855 This->lockedRect.right, This->lockedRect.bottom);
1857 else
1859 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
1861 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1862 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1864 if ((format_desc->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH))
1865 == WINED3DFMT_FLAG_COMPRESSED)
1867 /* Compressed textures are block based, so calculate the offset of
1868 * the block that contains the top-left pixel of the locked rectangle. */
1869 pLockedRect->pBits = This->resource.allocatedMemory
1870 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1871 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1873 else
1875 pLockedRect->pBits = This->resource.allocatedMemory +
1876 (pLockedRect->Pitch * pRect->top) +
1877 (pRect->left * format_desc->byte_count);
1879 This->lockedRect.left = pRect->left;
1880 This->lockedRect.top = pRect->top;
1881 This->lockedRect.right = pRect->right;
1882 This->lockedRect.bottom = pRect->bottom;
1885 /* No dirtifying is needed for this surface implementation */
1886 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1888 return WINED3D_OK;
1891 /* TODO: think about moving this down to resource? */
1892 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1894 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1896 /* This should only be called for sysmem textures, it may be a good idea
1897 * to extend this to all pools at some point in the future */
1898 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1900 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1902 return This->resource.allocatedMemory;