urlmon: Fixed a race in tests causing unexpected Switch call failures.
[wine/wine-gecko.git] / dlls / wined3d / surface_base.c
blobf32836684d3b6e9d885077c8be8f13fa864367d8
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-2010 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 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface,
115 REFGUID riid, const void *data, DWORD data_size, DWORD flags)
117 return resource_set_private_data((IWineD3DResource *)iface, riid, data, data_size, flags);
120 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
121 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
124 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
125 return resource_free_private_data((IWineD3DResource *)iface, refguid);
128 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
129 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
132 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
133 return resource_get_priority((IWineD3DResource *)iface);
136 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
137 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
138 return resource_get_type((IWineD3DResource *)iface);
141 void * WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface)
143 TRACE("iface %p.\n", iface);
145 return ((IWineD3DSurfaceImpl *)iface)->resource.parent;
148 void WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *desc)
150 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
152 TRACE("iface %p, desc %p.\n", iface, desc);
154 desc->format = surface->resource.format->id;
155 desc->resource_type = surface->resource.resourceType;
156 desc->usage = surface->resource.usage;
157 desc->pool = surface->resource.pool;
158 desc->size = surface->resource.size; /* dx8 only */
159 desc->multisample_type = surface->currentDesc.MultiSampleType;
160 desc->multisample_quality = surface->currentDesc.MultiSampleQuality;
161 desc->width = surface->currentDesc.Width;
162 desc->height = surface->currentDesc.Height;
165 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD flags)
167 TRACE("iface %p, flags %#x.\n", iface, flags);
169 switch (flags)
171 case WINEDDGBS_CANBLT:
172 case WINEDDGBS_ISBLTDONE:
173 return WINED3D_OK;
175 default:
176 return WINED3DERR_INVALIDCALL;
180 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD flags)
182 /* XXX: DDERR_INVALIDSURFACETYPE */
184 TRACE("iface %p, flags %#x.\n", iface, flags);
186 switch (flags)
188 case WINEDDGFS_CANFLIP:
189 case WINEDDGFS_ISFLIPDONE:
190 return WINED3D_OK;
192 default:
193 return WINED3DERR_INVALIDCALL;
197 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
198 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
199 TRACE("(%p)\n", This);
201 /* D3D8 and 9 loose full devices, ddraw only surfaces */
202 return This->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
205 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
206 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
207 TRACE("(%p)\n", This);
209 /* So far we don't lose anything :) */
210 This->flags &= ~SFLAG_LOST;
211 return WINED3D_OK;
214 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
215 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
216 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
217 TRACE("(%p)->(%p)\n", This, Pal);
219 if(This->palette == PalImpl) {
220 TRACE("Nop palette change\n");
221 return WINED3D_OK;
224 if (This->palette)
225 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
226 This->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
228 This->palette = PalImpl;
230 if (PalImpl)
232 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
233 PalImpl->flags |= WINEDDPCAPS_PRIMARYSURFACE;
235 return IWineD3DSurface_RealizePalette(iface);
237 else return WINED3D_OK;
240 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD flags, const WINEDDCOLORKEY *CKey)
242 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
244 TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, CKey);
246 if (flags & WINEDDCKEY_COLORSPACE)
248 FIXME(" colorkey value not supported (%08x) !\n", flags);
249 return WINED3DERR_INVALIDCALL;
252 /* Dirtify the surface, but only if a key was changed */
253 if (CKey)
255 switch (flags & ~WINEDDCKEY_COLORSPACE)
257 case WINEDDCKEY_DESTBLT:
258 This->DestBltCKey = *CKey;
259 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
260 break;
262 case WINEDDCKEY_DESTOVERLAY:
263 This->DestOverlayCKey = *CKey;
264 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
265 break;
267 case WINEDDCKEY_SRCOVERLAY:
268 This->SrcOverlayCKey = *CKey;
269 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
270 break;
272 case WINEDDCKEY_SRCBLT:
273 This->SrcBltCKey = *CKey;
274 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
275 break;
278 else
280 switch (flags & ~WINEDDCKEY_COLORSPACE)
282 case WINEDDCKEY_DESTBLT:
283 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
284 break;
286 case WINEDDCKEY_DESTOVERLAY:
287 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
288 break;
290 case WINEDDCKEY_SRCOVERLAY:
291 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
292 break;
294 case WINEDDCKEY_SRCBLT:
295 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
296 break;
300 return WINED3D_OK;
303 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
304 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
305 TRACE("(%p)->(%p)\n", This, Pal);
307 *Pal = (IWineD3DPalette *) This->palette;
308 return WINED3D_OK;
311 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
313 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
314 const struct wined3d_format *format = This->resource.format;
315 DWORD ret;
316 TRACE("(%p)\n", This);
318 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
320 /* Since compressed formats are block based, pitch means the amount of
321 * bytes to the next row of block rather than the next row of pixels. */
322 UINT row_block_count = (This->currentDesc.Width + format->block_width - 1) / format->block_width;
323 ret = row_block_count * format->block_byte_count;
325 else
327 unsigned char alignment = This->resource.device->surface_alignment;
328 ret = This->resource.format->byte_count * This->currentDesc.Width; /* Bytes / row */
329 ret = (ret + alignment - 1) & ~(alignment - 1);
331 TRACE("(%p) Returning %d\n", This, ret);
332 return ret;
335 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
336 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
337 LONG w, h;
339 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
341 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
343 TRACE("(%p): Not an overlay surface\n", This);
344 return WINEDDERR_NOTAOVERLAYSURFACE;
347 w = This->overlay_destrect.right - This->overlay_destrect.left;
348 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
349 This->overlay_destrect.left = X;
350 This->overlay_destrect.top = Y;
351 This->overlay_destrect.right = X + w;
352 This->overlay_destrect.bottom = Y + h;
354 IWineD3DSurface_DrawOverlay(iface);
356 return WINED3D_OK;
359 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
360 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
361 HRESULT hr;
363 TRACE("(%p)->(%p,%p)\n", This, X, Y);
365 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
367 TRACE("(%p): Not an overlay surface\n", This);
368 return WINEDDERR_NOTAOVERLAYSURFACE;
371 if (!This->overlay_dest)
373 *X = 0; *Y = 0;
374 hr = WINEDDERR_OVERLAYNOTVISIBLE;
375 } else {
376 *X = This->overlay_destrect.left;
377 *Y = This->overlay_destrect.top;
378 hr = WINED3D_OK;
381 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
382 return hr;
385 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD flags, IWineD3DSurface *Ref)
387 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
389 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, flags, Ref);
391 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
393 TRACE("(%p): Not an overlay surface\n", This);
394 return WINEDDERR_NOTAOVERLAYSURFACE;
397 return WINED3D_OK;
400 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
401 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD flags, const WINEDDOVERLAYFX *FX)
403 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
404 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
406 TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
407 iface, wine_dbgstr_rect(SrcRect), DstSurface, wine_dbgstr_rect(DstRect), flags, FX);
409 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
411 WARN("(%p): Not an overlay surface\n", This);
412 return WINEDDERR_NOTAOVERLAYSURFACE;
413 } else if(!DstSurface) {
414 WARN("(%p): Dest surface is NULL\n", This);
415 return WINED3DERR_INVALIDCALL;
418 if(SrcRect) {
419 This->overlay_srcrect = *SrcRect;
420 } else {
421 This->overlay_srcrect.left = 0;
422 This->overlay_srcrect.top = 0;
423 This->overlay_srcrect.right = This->currentDesc.Width;
424 This->overlay_srcrect.bottom = This->currentDesc.Height;
427 if(DstRect) {
428 This->overlay_destrect = *DstRect;
429 } else {
430 This->overlay_destrect.left = 0;
431 This->overlay_destrect.top = 0;
432 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
433 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
436 if (This->overlay_dest && (This->overlay_dest != Dst || flags & WINEDDOVER_HIDE))
438 list_remove(&This->overlay_entry);
441 if (flags & WINEDDOVER_SHOW)
443 if (This->overlay_dest != Dst)
445 This->overlay_dest = Dst;
446 list_add_tail(&Dst->overlays, &This->overlay_entry);
449 else if (flags & WINEDDOVER_HIDE)
451 /* tests show that the rectangles are erased on hide */
452 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
453 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
454 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
455 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
456 This->overlay_dest = NULL;
459 IWineD3DSurface_DrawOverlay(iface);
461 return WINED3D_OK;
464 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
466 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
467 TRACE("(%p)->(%p)\n", This, clipper);
469 This->clipper = clipper;
470 return WINED3D_OK;
473 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
475 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
476 TRACE("(%p)->(%p)\n", This, clipper);
478 *clipper = This->clipper;
479 if(*clipper) {
480 IWineD3DClipper_AddRef(*clipper);
482 return WINED3D_OK;
485 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
487 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
488 const struct wined3d_format *format = wined3d_get_format(&This->resource.device->adapter->gl_info, format_id);
490 if (This->resource.format->id != WINED3DFMT_UNKNOWN)
492 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
493 return WINED3DERR_INVALIDCALL;
496 TRACE("(%p) : Setting texture format to %s (%#x).\n", This, debug_d3dformat(format_id), format_id);
498 This->resource.size = wined3d_format_calculate_size(format, This->resource.device->surface_alignment,
499 This->pow2Width, This->pow2Height);
501 This->flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
503 This->resource.format = format;
505 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format->byte_count);
507 return WINED3D_OK;
510 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface)
512 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
513 const struct wined3d_format *format = This->resource.format;
514 int extraline = 0;
515 SYSTEM_INFO sysInfo;
516 BITMAPINFO* b_info;
517 HDC ddc;
518 DWORD *masks;
519 UINT usage;
521 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
523 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format->id));
524 return WINED3DERR_INVALIDCALL;
527 switch (format->byte_count)
529 case 2:
530 case 4:
531 /* Allocate extra space to store the RGB bit masks. */
532 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
533 break;
535 case 3:
536 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
537 break;
539 default:
540 /* Allocate extra space for a palette. */
541 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
542 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
543 break;
546 if (!b_info)
547 return E_OUTOFMEMORY;
549 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
550 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
551 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
552 * add an extra line to the dib section
554 GetSystemInfo(&sysInfo);
555 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
556 extraline = 1;
557 TRACE("Adding an extra line to the dib section\n");
560 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
561 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
562 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format->byte_count;
563 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
564 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
565 b_info->bmiHeader.biPlanes = 1;
566 b_info->bmiHeader.biBitCount = format->byte_count * 8;
568 b_info->bmiHeader.biXPelsPerMeter = 0;
569 b_info->bmiHeader.biYPelsPerMeter = 0;
570 b_info->bmiHeader.biClrUsed = 0;
571 b_info->bmiHeader.biClrImportant = 0;
573 /* Get the bit masks */
574 masks = (DWORD *)b_info->bmiColors;
575 switch (This->resource.format->id)
577 case WINED3DFMT_B8G8R8_UNORM:
578 usage = DIB_RGB_COLORS;
579 b_info->bmiHeader.biCompression = BI_RGB;
580 break;
582 case WINED3DFMT_B5G5R5X1_UNORM:
583 case WINED3DFMT_B5G5R5A1_UNORM:
584 case WINED3DFMT_B4G4R4A4_UNORM:
585 case WINED3DFMT_B4G4R4X4_UNORM:
586 case WINED3DFMT_B2G3R3_UNORM:
587 case WINED3DFMT_B2G3R3A8_UNORM:
588 case WINED3DFMT_R10G10B10A2_UNORM:
589 case WINED3DFMT_R8G8B8A8_UNORM:
590 case WINED3DFMT_R8G8B8X8_UNORM:
591 case WINED3DFMT_B10G10R10A2_UNORM:
592 case WINED3DFMT_B5G6R5_UNORM:
593 case WINED3DFMT_R16G16B16A16_UNORM:
594 usage = 0;
595 b_info->bmiHeader.biCompression = BI_BITFIELDS;
596 masks[0] = format->red_mask;
597 masks[1] = format->green_mask;
598 masks[2] = format->blue_mask;
599 break;
601 default:
602 /* Don't know palette */
603 b_info->bmiHeader.biCompression = BI_RGB;
604 usage = 0;
605 break;
608 if (!(ddc = GetDC(0)))
610 HeapFree(GetProcessHeap(), 0, b_info);
611 return HRESULT_FROM_WIN32(GetLastError());
614 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);
615 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
616 ReleaseDC(0, ddc);
618 if (!This->dib.DIBsection) {
619 ERR("CreateDIBSection failed!\n");
620 HeapFree(GetProcessHeap(), 0, b_info);
621 return HRESULT_FROM_WIN32(GetLastError());
624 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
625 /* copy the existing surface to the dib section */
626 if(This->resource.allocatedMemory) {
627 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
628 } else {
629 /* This is to make LockRect read the gl Texture although memory is allocated */
630 This->flags &= ~SFLAG_INSYSMEM;
632 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
634 HeapFree(GetProcessHeap(), 0, b_info);
636 /* Now allocate a HDC */
637 This->hDC = CreateCompatibleDC(0);
638 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
639 TRACE("using wined3d palette %p\n", This->palette);
640 SelectPalette(This->hDC,
641 This->palette ? This->palette->hpal : 0,
642 FALSE);
644 This->flags |= SFLAG_DIBSECTION;
646 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
647 This->resource.heapMemory = NULL;
649 return WINED3D_OK;
652 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
653 unsigned int w, unsigned int h)
655 unsigned int x, y;
656 const float *src_f;
657 unsigned short *dst_s;
659 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
660 for(y = 0; y < h; y++) {
661 src_f = (const float *)(src + y * pitch_in);
662 dst_s = (unsigned short *) (dst + y * pitch_out);
663 for(x = 0; x < w; x++) {
664 dst_s[x] = float_32_to_16(src_f + x);
669 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
670 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
672 static const unsigned char convert_5to8[] =
674 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
675 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
676 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
677 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
679 static const unsigned char convert_6to8[] =
681 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
682 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
683 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
684 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
685 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
686 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
687 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
688 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
690 unsigned int x, y;
692 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
694 for (y = 0; y < h; ++y)
696 const WORD *src_line = (const WORD *)(src + y * pitch_in);
697 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
698 for (x = 0; x < w; ++x)
700 WORD pixel = src_line[x];
701 dst_line[x] = 0xff000000
702 | convert_5to8[(pixel & 0xf800) >> 11] << 16
703 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
704 | convert_5to8[(pixel & 0x001f)];
709 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
710 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
712 unsigned int x, y;
714 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
716 for (y = 0; y < h; ++y)
718 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
719 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
721 for (x = 0; x < w; ++x)
723 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
728 static inline BYTE cliptobyte(int x)
730 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
733 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
734 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
736 unsigned int x, y;
737 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
739 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
741 for (y = 0; y < h; ++y)
743 const BYTE *src_line = src + y * pitch_in;
744 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
745 for (x = 0; x < w; ++x)
747 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
748 * C = Y - 16; D = U - 128; E = V - 128;
749 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
750 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
751 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
752 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
753 * U and V are shared between the pixels.
755 if (!(x & 1)) /* for every even pixel, read new U and V */
757 d = (int) src_line[1] - 128;
758 e = (int) src_line[3] - 128;
759 r2 = 409 * e + 128;
760 g2 = - 100 * d - 208 * e + 128;
761 b2 = 516 * d + 128;
763 c2 = 298 * ((int) src_line[0] - 16);
764 dst_line[x] = 0xff000000
765 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
766 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
767 | cliptobyte((c2 + b2) >> 8); /* blue */
768 /* Scale RGB values to 0..255 range,
769 * then clip them if still not in range (may be negative),
770 * then shift them within DWORD if necessary.
772 src_line += 2;
777 struct d3dfmt_convertor_desc
779 enum wined3d_format_id from, to;
780 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
783 static const struct d3dfmt_convertor_desc convertors[] =
785 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
786 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
787 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
788 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
791 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
793 unsigned int i;
794 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
795 if(convertors[i].from == from && convertors[i].to == to) {
796 return &convertors[i];
799 return NULL;
802 /*****************************************************************************
803 * surface_convert_format
805 * Creates a duplicate of a surface in a different format. Is used by Blt to
806 * blit between surfaces with different formats
808 * Parameters
809 * source: Source surface
810 * fmt: Requested destination format
812 *****************************************************************************/
813 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
815 IWineD3DSurface *ret = NULL;
816 const struct d3dfmt_convertor_desc *conv;
817 WINED3DLOCKED_RECT lock_src, lock_dst;
818 HRESULT hr;
820 conv = find_convertor(source->resource.format->id, to_fmt);
821 if (!conv)
823 FIXME("Cannot find a conversion function from format %s to %s.\n",
824 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
825 return NULL;
828 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
829 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
830 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
831 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
832 NULL /* parent */, &wined3d_null_parent_ops, &ret);
833 if(!ret) {
834 ERR("Failed to create a destination surface for conversion\n");
835 return NULL;
838 memset(&lock_src, 0, sizeof(lock_src));
839 memset(&lock_dst, 0, sizeof(lock_dst));
841 hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
842 if (FAILED(hr))
844 ERR("Failed to lock the source surface.\n");
845 IWineD3DSurface_Release(ret);
846 return NULL;
848 hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
849 if (FAILED(hr))
851 ERR("Failed to lock the dest surface\n");
852 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
853 IWineD3DSurface_Release(ret);
854 return NULL;
857 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
858 source->currentDesc.Width, source->currentDesc.Height);
860 IWineD3DSurface_Unmap(ret);
861 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
863 return (IWineD3DSurfaceImpl *) ret;
866 /*****************************************************************************
867 * _Blt_ColorFill
869 * Helper function that fills a memory area with a specific color
871 * Params:
872 * buf: memory address to start filling at
873 * width, height: Dimensions of the area to fill
874 * bpp: Bit depth of the surface
875 * lPitch: pitch of the surface
876 * color: Color to fill with
878 *****************************************************************************/
879 static HRESULT
880 _Blt_ColorFill(BYTE *buf,
881 int width, int height,
882 int bpp, LONG lPitch,
883 DWORD color)
885 int x, y;
886 LPBYTE first;
888 /* Do first row */
890 #define COLORFILL_ROW(type) \
892 type *d = (type *) buf; \
893 for (x = 0; x < width; x++) \
894 d[x] = (type) color; \
895 break; \
897 switch(bpp)
899 case 1: COLORFILL_ROW(BYTE)
900 case 2: COLORFILL_ROW(WORD)
901 case 3:
903 BYTE *d = buf;
904 for (x = 0; x < width; x++,d+=3)
906 d[0] = (color ) & 0xFF;
907 d[1] = (color>> 8) & 0xFF;
908 d[2] = (color>>16) & 0xFF;
910 break;
912 case 4: COLORFILL_ROW(DWORD)
913 default:
914 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
915 return WINED3DERR_NOTAVAILABLE;
918 #undef COLORFILL_ROW
920 /* Now copy first row */
921 first = buf;
922 for (y = 1; y < height; y++)
924 buf += lPitch;
925 memcpy(buf, first, width * bpp);
927 return WINED3D_OK;
930 /*****************************************************************************
931 * IWineD3DSurface::Blt, SW emulation version
933 * Performs a blit to a surface, with or without a source surface.
934 * This is the main functionality of DirectDraw
936 * Params:
937 * DestRect: Destination rectangle to write to
938 * src_surface: Source surface, can be NULL
939 * SrcRect: Source rectangle
940 *****************************************************************************/
941 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
942 const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
944 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
945 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
946 RECT xdst,xsrc;
947 HRESULT ret = WINED3D_OK;
948 WINED3DLOCKED_RECT dlock, slock;
949 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
950 const struct wined3d_format *sEntry, *dEntry;
951 int x, y;
952 const BYTE *sbuf;
953 BYTE *dbuf;
955 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
956 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
957 flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
959 if ((This->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
961 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
962 return WINEDDERR_SURFACEBUSY;
965 /* First check for the validity of source / destination rectangles.
966 * This was verified using a test application + by MSDN. */
968 if (SrcRect)
970 if (src)
972 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
973 || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
974 || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
975 || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
976 || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
978 WARN("Application gave us bad source rectangle for Blt.\n");
979 return WINEDDERR_INVALIDRECT;
982 if (!SrcRect->right || !SrcRect->bottom
983 || SrcRect->left == (int)src->currentDesc.Width
984 || SrcRect->top == (int)src->currentDesc.Height)
986 TRACE("Nothing to be done.\n");
987 return WINED3D_OK;
991 xsrc = *SrcRect;
993 else if (src)
995 xsrc.left = 0;
996 xsrc.top = 0;
997 xsrc.right = src->currentDesc.Width;
998 xsrc.bottom = src->currentDesc.Height;
1000 else
1002 memset(&xsrc, 0, sizeof(xsrc));
1005 if (DestRect)
1007 /* For the Destination rect, it can be out of bounds on the condition
1008 * that a clipper is set for the given surface. */
1009 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1010 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
1011 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1012 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1013 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1015 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1016 return WINEDDERR_INVALIDRECT;
1019 if (DestRect->right <= 0 || DestRect->bottom <= 0
1020 || DestRect->left >= (int)This->currentDesc.Width
1021 || DestRect->top >= (int)This->currentDesc.Height)
1023 TRACE("Nothing to be done.\n");
1024 return WINED3D_OK;
1027 if (!src)
1029 RECT full_rect;
1031 full_rect.left = 0;
1032 full_rect.top = 0;
1033 full_rect.right = This->currentDesc.Width;
1034 full_rect.bottom = This->currentDesc.Height;
1035 IntersectRect(&xdst, &full_rect, DestRect);
1037 else
1039 BOOL clip_horiz, clip_vert;
1041 xdst = *DestRect;
1042 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1043 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1045 if (clip_vert || clip_horiz)
1047 /* Now check if this is a special case or not... */
1048 if ((flags & WINEDDBLT_DDFX)
1049 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1050 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1052 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1053 return WINED3D_OK;
1056 if (clip_horiz)
1058 if (xdst.left < 0)
1060 xsrc.left -= xdst.left;
1061 xdst.left = 0;
1063 if (xdst.right > This->currentDesc.Width)
1065 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1066 xdst.right = (int)This->currentDesc.Width;
1070 if (clip_vert)
1072 if (xdst.top < 0)
1074 xsrc.top -= xdst.top;
1075 xdst.top = 0;
1077 if (xdst.bottom > This->currentDesc.Height)
1079 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1080 xdst.bottom = (int)This->currentDesc.Height;
1084 /* And check if after clipping something is still to be done... */
1085 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1086 || (xdst.left >= (int)This->currentDesc.Width)
1087 || (xdst.top >= (int)This->currentDesc.Height)
1088 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1089 || (xsrc.left >= (int)src->currentDesc.Width)
1090 || (xsrc.top >= (int)src->currentDesc.Height))
1092 TRACE("Nothing to be done after clipping.\n");
1093 return WINED3D_OK;
1098 else
1100 xdst.left = 0;
1101 xdst.top = 0;
1102 xdst.right = This->currentDesc.Width;
1103 xdst.bottom = This->currentDesc.Height;
1106 if (src == This)
1108 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1109 slock = dlock;
1110 sEntry = This->resource.format;
1111 dEntry = sEntry;
1113 else
1115 dEntry = This->resource.format;
1116 if (src)
1118 if (This->resource.format->id != src->resource.format->id)
1120 src = surface_convert_format(src, dEntry->id);
1121 if (!src)
1123 /* The conv function writes a FIXME */
1124 WARN("Cannot convert source surface format to dest format\n");
1125 goto release;
1128 IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1129 sEntry = src->resource.format;
1131 else
1133 sEntry = dEntry;
1135 if (DestRect)
1136 IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
1137 else
1138 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1141 if (!DDBltFx || !(DDBltFx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
1143 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_FOURCC)
1145 if (!DestRect || src == This)
1147 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1148 goto release;
1152 bpp = This->resource.format->byte_count;
1153 srcheight = xsrc.bottom - xsrc.top;
1154 srcwidth = xsrc.right - xsrc.left;
1155 dstheight = xdst.bottom - xdst.top;
1156 dstwidth = xdst.right - xdst.left;
1157 width = (xdst.right - xdst.left) * bpp;
1159 if (DestRect && src != This)
1160 dbuf = dlock.pBits;
1161 else
1162 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1164 if (flags & WINEDDBLT_WAIT)
1166 flags &= ~WINEDDBLT_WAIT;
1168 if (flags & WINEDDBLT_ASYNC)
1170 static BOOL displayed = FALSE;
1171 if (!displayed)
1172 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1173 displayed = TRUE;
1174 flags &= ~WINEDDBLT_ASYNC;
1176 if (flags & WINEDDBLT_DONOTWAIT)
1178 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1179 static BOOL displayed = FALSE;
1180 if (!displayed)
1181 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1182 displayed = TRUE;
1183 flags &= ~WINEDDBLT_DONOTWAIT;
1186 /* First, all the 'source-less' blits */
1187 if (flags & WINEDDBLT_COLORFILL)
1189 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1190 dlock.Pitch, DDBltFx->u5.dwFillColor);
1191 flags &= ~WINEDDBLT_COLORFILL;
1194 if (flags & WINEDDBLT_DEPTHFILL)
1196 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1198 if (flags & WINEDDBLT_ROP)
1200 /* Catch some degenerate cases here */
1201 switch(DDBltFx->dwROP)
1203 case BLACKNESS:
1204 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1205 break;
1206 case 0xAA0029: /* No-op */
1207 break;
1208 case WHITENESS:
1209 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1210 break;
1211 case SRCCOPY: /* well, we do that below ? */
1212 break;
1213 default:
1214 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1215 goto error;
1217 flags &= ~WINEDDBLT_ROP;
1219 if (flags & WINEDDBLT_DDROPS)
1221 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1223 /* Now the 'with source' blits */
1224 if (src)
1226 const BYTE *sbase;
1227 int sx, xinc, sy, yinc;
1229 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1230 goto release;
1232 if (Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT
1233 && (srcwidth != dstwidth || srcheight != dstheight))
1235 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1236 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter));
1239 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1240 xinc = (srcwidth << 16) / dstwidth;
1241 yinc = (srcheight << 16) / dstheight;
1243 if (!flags)
1245 /* No effects, we can cheat here */
1246 if (dstwidth == srcwidth)
1248 if (dstheight == srcheight)
1250 /* No stretching in either direction. This needs to be as
1251 * fast as possible */
1252 sbuf = sbase;
1254 /* check for overlapping surfaces */
1255 if (src != This || xdst.top < xsrc.top ||
1256 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1258 /* no overlap, or dst above src, so copy from top downwards */
1259 for (y = 0; y < dstheight; y++)
1261 memcpy(dbuf, sbuf, width);
1262 sbuf += slock.Pitch;
1263 dbuf += dlock.Pitch;
1266 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1268 sbuf += (slock.Pitch*dstheight);
1269 dbuf += (dlock.Pitch*dstheight);
1270 for (y = 0; y < dstheight; y++)
1272 sbuf -= slock.Pitch;
1273 dbuf -= dlock.Pitch;
1274 memcpy(dbuf, sbuf, width);
1277 else /* src and dst overlapping on the same line, use memmove */
1279 for (y = 0; y < dstheight; y++)
1281 memmove(dbuf, sbuf, width);
1282 sbuf += slock.Pitch;
1283 dbuf += dlock.Pitch;
1286 } else {
1287 /* Stretching in Y direction only */
1288 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1289 sbuf = sbase + (sy >> 16) * slock.Pitch;
1290 memcpy(dbuf, sbuf, width);
1291 dbuf += dlock.Pitch;
1295 else
1297 /* Stretching in X direction */
1298 int last_sy = -1;
1299 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1301 sbuf = sbase + (sy >> 16) * slock.Pitch;
1303 if ((sy >> 16) == (last_sy >> 16))
1305 /* this sourcerow is the same as last sourcerow -
1306 * copy already stretched row
1308 memcpy(dbuf, dbuf - dlock.Pitch, width);
1310 else
1312 #define STRETCH_ROW(type) { \
1313 const type *s = (const type *)sbuf; \
1314 type *d = (type *)dbuf; \
1315 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1316 d[x] = s[sx >> 16]; \
1317 break; }
1319 switch(bpp)
1321 case 1: STRETCH_ROW(BYTE)
1322 case 2: STRETCH_ROW(WORD)
1323 case 4: STRETCH_ROW(DWORD)
1324 case 3:
1326 const BYTE *s;
1327 BYTE *d = dbuf;
1328 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1330 DWORD pixel;
1332 s = sbuf+3*(sx>>16);
1333 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1334 d[0] = (pixel )&0xff;
1335 d[1] = (pixel>> 8)&0xff;
1336 d[2] = (pixel>>16)&0xff;
1337 d+=3;
1339 break;
1341 default:
1342 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1343 ret = WINED3DERR_NOTAVAILABLE;
1344 goto error;
1346 #undef STRETCH_ROW
1348 dbuf += dlock.Pitch;
1349 last_sy = sy;
1353 else
1355 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1356 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1357 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1358 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1360 /* The color keying flags are checked for correctness in ddraw */
1361 if (flags & WINEDDBLT_KEYSRC)
1363 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1364 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1366 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
1368 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1369 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1372 if (flags & WINEDDBLT_KEYDEST)
1374 /* Destination color keys are taken from the source surface ! */
1375 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1376 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1378 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
1380 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1381 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1384 if(bpp == 1)
1386 keymask = 0xff;
1388 else
1390 keymask = sEntry->red_mask
1391 | sEntry->green_mask
1392 | sEntry->blue_mask;
1394 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1397 if (flags & WINEDDBLT_DDFX)
1399 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1400 LONG tmpxy;
1401 dTopLeft = dbuf;
1402 dTopRight = dbuf+((dstwidth-1)*bpp);
1403 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1404 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1406 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1408 /* I don't think we need to do anything about this flag */
1409 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1411 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1413 tmp = dTopRight;
1414 dTopRight = dTopLeft;
1415 dTopLeft = tmp;
1416 tmp = dBottomRight;
1417 dBottomRight = dBottomLeft;
1418 dBottomLeft = tmp;
1419 dstxinc = dstxinc *-1;
1421 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1423 tmp = dTopLeft;
1424 dTopLeft = dBottomLeft;
1425 dBottomLeft = tmp;
1426 tmp = dTopRight;
1427 dTopRight = dBottomRight;
1428 dBottomRight = tmp;
1429 dstyinc = dstyinc *-1;
1431 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1433 /* I don't think we need to do anything about this flag */
1434 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1436 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1438 tmp = dBottomRight;
1439 dBottomRight = dTopLeft;
1440 dTopLeft = tmp;
1441 tmp = dBottomLeft;
1442 dBottomLeft = dTopRight;
1443 dTopRight = tmp;
1444 dstxinc = dstxinc * -1;
1445 dstyinc = dstyinc * -1;
1447 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1449 tmp = dTopLeft;
1450 dTopLeft = dBottomLeft;
1451 dBottomLeft = dBottomRight;
1452 dBottomRight = dTopRight;
1453 dTopRight = tmp;
1454 tmpxy = dstxinc;
1455 dstxinc = dstyinc;
1456 dstyinc = tmpxy;
1457 dstxinc = dstxinc * -1;
1459 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1461 tmp = dTopLeft;
1462 dTopLeft = dTopRight;
1463 dTopRight = dBottomRight;
1464 dBottomRight = dBottomLeft;
1465 dBottomLeft = tmp;
1466 tmpxy = dstxinc;
1467 dstxinc = dstyinc;
1468 dstyinc = tmpxy;
1469 dstyinc = dstyinc * -1;
1471 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1473 /* I don't think we need to do anything about this flag */
1474 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1476 dbuf = dTopLeft;
1477 flags &= ~(WINEDDBLT_DDFX);
1480 #define COPY_COLORKEY_FX(type) { \
1481 const type *s; \
1482 type *d = (type *)dbuf, *dx, tmp; \
1483 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1484 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1485 dx = d; \
1486 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1487 tmp = s[sx >> 16]; \
1488 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1489 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1490 dx[0] = tmp; \
1492 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1494 d = (type*)(((LPBYTE)d)+dstyinc); \
1496 break; }
1498 switch (bpp) {
1499 case 1: COPY_COLORKEY_FX(BYTE)
1500 case 2: COPY_COLORKEY_FX(WORD)
1501 case 4: COPY_COLORKEY_FX(DWORD)
1502 case 3:
1504 const BYTE *s;
1505 BYTE *d = dbuf, *dx;
1506 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1508 sbuf = sbase + (sy >> 16) * slock.Pitch;
1509 dx = d;
1510 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1512 DWORD pixel, dpixel = 0;
1513 s = sbuf+3*(sx>>16);
1514 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1515 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1516 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1517 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1519 dx[0] = (pixel )&0xff;
1520 dx[1] = (pixel>> 8)&0xff;
1521 dx[2] = (pixel>>16)&0xff;
1523 dx+= dstxinc;
1525 d += dstyinc;
1527 break;
1529 default:
1530 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1531 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1532 ret = WINED3DERR_NOTAVAILABLE;
1533 goto error;
1534 #undef COPY_COLORKEY_FX
1539 error:
1540 if (flags && FIXME_ON(d3d_surface))
1542 FIXME("\tUnsupported flags: %#x.\n", flags);
1545 release:
1546 IWineD3DSurface_Unmap(iface);
1547 if (src && src != This) IWineD3DSurface_Unmap((IWineD3DSurface *)src);
1548 /* Release the converted surface if any */
1549 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1550 return ret;
1553 /*****************************************************************************
1554 * IWineD3DSurface::BltFast, SW emulation version
1556 * This is the software implementation of BltFast, as used by GDI surfaces
1557 * and as a fallback for OpenGL surfaces. This code is taken from the old
1558 * DirectDraw code, and was originally written by TransGaming.
1560 * Params:
1561 * dstx:
1562 * dsty:
1563 * src_surface: Source surface to copy from
1564 * rsrc: Source rectangle
1565 * trans: Some flags
1567 * Returns:
1568 * WINED3D_OK on success
1570 *****************************************************************************/
1571 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1572 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1574 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1575 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1577 int bpp, w, h, x, y;
1578 WINED3DLOCKED_RECT dlock,slock;
1579 HRESULT ret = WINED3D_OK;
1580 RECT rsrc2;
1581 RECT lock_src, lock_dst, lock_union;
1582 const BYTE *sbuf;
1583 BYTE *dbuf;
1584 const struct wined3d_format *sEntry, *dEntry;
1586 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1587 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1589 if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
1591 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1592 return WINEDDERR_SURFACEBUSY;
1595 if (!rsrc)
1597 WARN("rsrc is NULL!\n");
1598 rsrc2.left = 0;
1599 rsrc2.top = 0;
1600 rsrc2.right = src->currentDesc.Width;
1601 rsrc2.bottom = src->currentDesc.Height;
1602 rsrc = &rsrc2;
1605 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1606 if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1607 || (rsrc->top > src->currentDesc.Height) || (rsrc->top < 0)
1608 || (rsrc->left > src->currentDesc.Width) || (rsrc->left < 0)
1609 || (rsrc->right > src->currentDesc.Width) || (rsrc->right < 0)
1610 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1612 WARN("Application gave us bad source rectangle for BltFast.\n");
1613 return WINEDDERR_INVALIDRECT;
1616 h = rsrc->bottom - rsrc->top;
1617 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1618 if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1619 if (h <= 0) return WINEDDERR_INVALIDRECT;
1621 w = rsrc->right - rsrc->left;
1622 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1623 if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1624 if (w <= 0) return WINEDDERR_INVALIDRECT;
1626 /* Now compute the locking rectangle... */
1627 lock_src.left = rsrc->left;
1628 lock_src.top = rsrc->top;
1629 lock_src.right = lock_src.left + w;
1630 lock_src.bottom = lock_src.top + h;
1632 lock_dst.left = dstx;
1633 lock_dst.top = dsty;
1634 lock_dst.right = dstx + w;
1635 lock_dst.bottom = dsty + h;
1637 bpp = This->resource.format->byte_count;
1639 /* We need to lock the surfaces, or we won't get refreshes when done. */
1640 if (src == This)
1642 int pitch;
1644 UnionRect(&lock_union, &lock_src, &lock_dst);
1646 /* Lock the union of the two rectangles */
1647 ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
1648 if (FAILED(ret)) goto error;
1650 pitch = dlock.Pitch;
1651 slock.Pitch = dlock.Pitch;
1653 /* Since slock was originally copied from this surface's description, we can just reuse it */
1654 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1655 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1656 sEntry = src->resource.format;
1657 dEntry = sEntry;
1659 else
1661 ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1662 if (FAILED(ret)) goto error;
1663 ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
1664 if (FAILED(ret)) goto error;
1666 sbuf = slock.pBits;
1667 dbuf = dlock.pBits;
1668 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1670 sEntry = src->resource.format;
1671 dEntry = This->resource.format;
1674 /* Handle compressed surfaces first... */
1675 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_COMPRESSED)
1677 UINT row_block_count;
1679 TRACE("compressed -> compressed copy\n");
1680 if (trans)
1681 FIXME("trans arg not supported when a compressed surface is involved\n");
1682 if (dstx || dsty)
1683 FIXME("offset for destination surface is not supported\n");
1684 if (src->resource.format->id != This->resource.format->id)
1686 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1687 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1688 goto error;
1691 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1692 for (y = 0; y < h; y += dEntry->block_height)
1694 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1695 dbuf += dlock.Pitch;
1696 sbuf += slock.Pitch;
1699 goto error;
1701 if ((sEntry->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->flags & WINED3DFMT_FLAG_COMPRESSED))
1703 /* TODO: Use the libtxc_dxtn.so shared library to do
1704 * software decompression
1706 ERR("Software decompression not supported.\n");
1707 goto error;
1710 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1712 DWORD keylow, keyhigh;
1713 DWORD mask = src->resource.format->red_mask
1714 | src->resource.format->green_mask
1715 | src->resource.format->blue_mask;
1717 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1718 if(!mask && bpp==1)
1719 mask = 0xff;
1721 TRACE("Color keyed copy\n");
1722 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1724 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1725 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1727 else
1729 /* I'm not sure if this is correct */
1730 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1731 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1732 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1735 #define COPYBOX_COLORKEY(type) { \
1736 const type *s = (const type *)sbuf; \
1737 type *d = (type *)dbuf; \
1738 type tmp; \
1739 for (y = 0; y < h; y++) { \
1740 for (x = 0; x < w; x++) { \
1741 tmp = s[x]; \
1742 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1744 s = (const type *)((const BYTE *)s + slock.Pitch); \
1745 d = (type *)((BYTE *)d + dlock.Pitch); \
1747 break; \
1750 switch (bpp) {
1751 case 1: COPYBOX_COLORKEY(BYTE)
1752 case 2: COPYBOX_COLORKEY(WORD)
1753 case 4: COPYBOX_COLORKEY(DWORD)
1754 case 3:
1756 const BYTE *s;
1757 BYTE *d;
1758 DWORD tmp;
1759 s = sbuf;
1760 d = dbuf;
1761 for (y = 0; y < h; y++)
1763 for (x = 0; x < w * 3; x += 3)
1765 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1766 if (tmp < keylow || tmp > keyhigh)
1768 d[x + 0] = s[x + 0];
1769 d[x + 1] = s[x + 1];
1770 d[x + 2] = s[x + 2];
1773 s += slock.Pitch;
1774 d += dlock.Pitch;
1776 break;
1778 default:
1779 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1780 ret = WINED3DERR_NOTAVAILABLE;
1781 goto error;
1783 #undef COPYBOX_COLORKEY
1784 TRACE("Copy Done\n");
1786 else
1788 int width = w * bpp;
1789 INT sbufpitch, dbufpitch;
1791 TRACE("NO color key copy\n");
1792 /* Handle overlapping surfaces */
1793 if (sbuf < dbuf)
1795 sbuf += (h - 1) * slock.Pitch;
1796 dbuf += (h - 1) * dlock.Pitch;
1797 sbufpitch = -slock.Pitch;
1798 dbufpitch = -dlock.Pitch;
1800 else
1802 sbufpitch = slock.Pitch;
1803 dbufpitch = dlock.Pitch;
1805 for (y = 0; y < h; y++)
1807 /* This is pretty easy, a line for line memcpy */
1808 memmove(dbuf, sbuf, width);
1809 sbuf += sbufpitch;
1810 dbuf += dbufpitch;
1812 TRACE("Copy done\n");
1815 error:
1816 if (src == This)
1818 IWineD3DSurface_Unmap(iface);
1820 else
1822 IWineD3DSurface_Unmap(iface);
1823 IWineD3DSurface_Unmap(src_surface);
1826 return ret;
1829 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
1830 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
1832 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1834 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
1835 iface, pLockedRect, wine_dbgstr_rect(pRect), flags);
1837 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1839 if (!pRect)
1841 pLockedRect->pBits = This->resource.allocatedMemory;
1842 This->lockedRect.left = 0;
1843 This->lockedRect.top = 0;
1844 This->lockedRect.right = This->currentDesc.Width;
1845 This->lockedRect.bottom = This->currentDesc.Height;
1847 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1848 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1849 This->lockedRect.right, This->lockedRect.bottom);
1851 else
1853 const struct wined3d_format *format = This->resource.format;
1855 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1856 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1858 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1860 /* Compressed textures are block based, so calculate the offset of
1861 * the block that contains the top-left pixel of the locked rectangle. */
1862 pLockedRect->pBits = This->resource.allocatedMemory
1863 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1864 + ((pRect->left / format->block_width) * format->block_byte_count);
1866 else
1868 pLockedRect->pBits = This->resource.allocatedMemory +
1869 (pLockedRect->Pitch * pRect->top) +
1870 (pRect->left * format->byte_count);
1872 This->lockedRect.left = pRect->left;
1873 This->lockedRect.top = pRect->top;
1874 This->lockedRect.right = pRect->right;
1875 This->lockedRect.bottom = pRect->bottom;
1878 /* No dirtifying is needed for this surface implementation */
1879 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1881 return WINED3D_OK;
1884 /* TODO: think about moving this down to resource? */
1885 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1887 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1889 /* This should only be called for sysmem textures, it may be a good idea
1890 * to extend this to all pools at some point in the future */
1891 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1893 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1895 return This->resource.allocatedMemory;