msxml3: Add IObjectSafety support to IXMLHTTPRequest.
[wine.git] / dlls / wined3d / surface_base.c
blob65d632751e87a748df131e21a0732f1a01784e8b
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((IWineD3DResourceImpl *)iface, riid, data, data_size, flags);
120 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface,
121 REFGUID guid, void *data, DWORD *data_size)
123 return resource_get_private_data((IWineD3DResourceImpl *)iface, guid, data, data_size);
126 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid)
128 return resource_free_private_data((IWineD3DResourceImpl *)iface, refguid);
131 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD priority)
133 return resource_set_priority((IWineD3DResourceImpl *)iface, priority);
136 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface)
138 return resource_get_priority((IWineD3DResourceImpl *)iface);
141 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface)
143 return resource_get_type((IWineD3DResourceImpl *)iface);
146 void * WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface)
148 TRACE("iface %p.\n", iface);
150 return ((IWineD3DSurfaceImpl *)iface)->resource.parent;
153 void WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *desc)
155 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
157 TRACE("iface %p, desc %p.\n", iface, desc);
159 desc->format = surface->resource.format->id;
160 desc->resource_type = surface->resource.resourceType;
161 desc->usage = surface->resource.usage;
162 desc->pool = surface->resource.pool;
163 desc->size = surface->resource.size; /* dx8 only */
164 desc->multisample_type = surface->currentDesc.MultiSampleType;
165 desc->multisample_quality = surface->currentDesc.MultiSampleQuality;
166 desc->width = surface->currentDesc.Width;
167 desc->height = surface->currentDesc.Height;
170 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD flags)
172 TRACE("iface %p, flags %#x.\n", iface, flags);
174 switch (flags)
176 case WINEDDGBS_CANBLT:
177 case WINEDDGBS_ISBLTDONE:
178 return WINED3D_OK;
180 default:
181 return WINED3DERR_INVALIDCALL;
185 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD flags)
187 /* XXX: DDERR_INVALIDSURFACETYPE */
189 TRACE("iface %p, flags %#x.\n", iface, flags);
191 switch (flags)
193 case WINEDDGFS_CANFLIP:
194 case WINEDDGFS_ISFLIPDONE:
195 return WINED3D_OK;
197 default:
198 return WINED3DERR_INVALIDCALL;
202 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
203 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
204 TRACE("(%p)\n", This);
206 /* D3D8 and 9 loose full devices, ddraw only surfaces */
207 return This->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
210 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
211 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
212 TRACE("(%p)\n", This);
214 /* So far we don't lose anything :) */
215 This->flags &= ~SFLAG_LOST;
216 return WINED3D_OK;
219 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, struct wined3d_palette *palette)
221 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
223 TRACE("iface %p, palette %p.\n", iface, palette);
225 if (This->palette == palette)
227 TRACE("Nop palette change\n");
228 return WINED3D_OK;
231 if (This->palette)
232 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
233 This->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
235 This->palette = palette;
237 if (palette)
239 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
240 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
242 This->surface_ops->surface_realize_palette(This);
245 return WINED3D_OK;
248 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD flags, const WINEDDCOLORKEY *CKey)
250 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
252 TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, CKey);
254 if (flags & WINEDDCKEY_COLORSPACE)
256 FIXME(" colorkey value not supported (%08x) !\n", flags);
257 return WINED3DERR_INVALIDCALL;
260 /* Dirtify the surface, but only if a key was changed */
261 if (CKey)
263 switch (flags & ~WINEDDCKEY_COLORSPACE)
265 case WINEDDCKEY_DESTBLT:
266 This->DestBltCKey = *CKey;
267 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
268 break;
270 case WINEDDCKEY_DESTOVERLAY:
271 This->DestOverlayCKey = *CKey;
272 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
273 break;
275 case WINEDDCKEY_SRCOVERLAY:
276 This->SrcOverlayCKey = *CKey;
277 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
278 break;
280 case WINEDDCKEY_SRCBLT:
281 This->SrcBltCKey = *CKey;
282 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
283 break;
286 else
288 switch (flags & ~WINEDDCKEY_COLORSPACE)
290 case WINEDDCKEY_DESTBLT:
291 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
292 break;
294 case WINEDDCKEY_DESTOVERLAY:
295 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
296 break;
298 case WINEDDCKEY_SRCOVERLAY:
299 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
300 break;
302 case WINEDDCKEY_SRCBLT:
303 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
304 break;
308 return WINED3D_OK;
311 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, struct wined3d_palette **palette)
313 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
315 TRACE("iface %p, palette %p.\n", iface, palette);
317 *palette = This->palette;
319 return WINED3D_OK;
322 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
324 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
325 const struct wined3d_format *format = This->resource.format;
326 DWORD ret;
327 TRACE("(%p)\n", This);
329 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
331 /* Since compressed formats are block based, pitch means the amount of
332 * bytes to the next row of block rather than the next row of pixels. */
333 UINT row_block_count = (This->currentDesc.Width + format->block_width - 1) / format->block_width;
334 ret = row_block_count * format->block_byte_count;
336 else
338 unsigned char alignment = This->resource.device->surface_alignment;
339 ret = This->resource.format->byte_count * This->currentDesc.Width; /* Bytes / row */
340 ret = (ret + alignment - 1) & ~(alignment - 1);
342 TRACE("(%p) Returning %d\n", This, ret);
343 return ret;
346 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
347 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
348 LONG w, h;
350 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
352 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
354 TRACE("(%p): Not an overlay surface\n", This);
355 return WINEDDERR_NOTAOVERLAYSURFACE;
358 w = This->overlay_destrect.right - This->overlay_destrect.left;
359 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
360 This->overlay_destrect.left = X;
361 This->overlay_destrect.top = Y;
362 This->overlay_destrect.right = X + w;
363 This->overlay_destrect.bottom = Y + h;
365 This->surface_ops->surface_draw_overlay(This);
367 return WINED3D_OK;
370 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
371 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
372 HRESULT hr;
374 TRACE("(%p)->(%p,%p)\n", This, X, Y);
376 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
378 TRACE("(%p): Not an overlay surface\n", This);
379 return WINEDDERR_NOTAOVERLAYSURFACE;
382 if (!This->overlay_dest)
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)
398 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
400 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, flags, Ref);
402 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
404 TRACE("(%p): Not an overlay surface\n", This);
405 return WINEDDERR_NOTAOVERLAYSURFACE;
408 return WINED3D_OK;
411 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
412 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD flags, const WINEDDOVERLAYFX *FX)
414 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
415 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
417 TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
418 iface, wine_dbgstr_rect(SrcRect), DstSurface, wine_dbgstr_rect(DstRect), flags, FX);
420 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
422 WARN("(%p): Not an overlay surface\n", This);
423 return WINEDDERR_NOTAOVERLAYSURFACE;
424 } else if(!DstSurface) {
425 WARN("(%p): Dest surface is NULL\n", This);
426 return WINED3DERR_INVALIDCALL;
429 if(SrcRect) {
430 This->overlay_srcrect = *SrcRect;
431 } else {
432 This->overlay_srcrect.left = 0;
433 This->overlay_srcrect.top = 0;
434 This->overlay_srcrect.right = This->currentDesc.Width;
435 This->overlay_srcrect.bottom = This->currentDesc.Height;
438 if(DstRect) {
439 This->overlay_destrect = *DstRect;
440 } else {
441 This->overlay_destrect.left = 0;
442 This->overlay_destrect.top = 0;
443 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
444 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
447 if (This->overlay_dest && (This->overlay_dest != Dst || flags & WINEDDOVER_HIDE))
449 list_remove(&This->overlay_entry);
452 if (flags & WINEDDOVER_SHOW)
454 if (This->overlay_dest != Dst)
456 This->overlay_dest = Dst;
457 list_add_tail(&Dst->overlays, &This->overlay_entry);
460 else if (flags & WINEDDOVER_HIDE)
462 /* tests show that the rectangles are erased on hide */
463 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
464 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
465 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
466 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
467 This->overlay_dest = NULL;
470 This->surface_ops->surface_draw_overlay(This);
472 return WINED3D_OK;
475 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, struct wined3d_clipper *clipper)
477 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
479 TRACE("iface %p, clipper %p.\n", iface, clipper);
481 This->clipper = clipper;
483 return WINED3D_OK;
486 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, struct wined3d_clipper **clipper)
488 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
490 TRACE("iface %p, clipper %p.\n", iface, clipper);
492 *clipper = This->clipper;
493 if (*clipper)
494 wined3d_clipper_incref(*clipper);
496 return WINED3D_OK;
499 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
501 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
502 const struct wined3d_format *format = wined3d_get_format(&This->resource.device->adapter->gl_info, format_id);
504 if (This->resource.format->id != WINED3DFMT_UNKNOWN)
506 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
507 return WINED3DERR_INVALIDCALL;
510 TRACE("(%p) : Setting texture format to %s (%#x).\n", This, debug_d3dformat(format_id), format_id);
512 This->resource.size = wined3d_format_calculate_size(format, This->resource.device->surface_alignment,
513 This->pow2Width, This->pow2Height);
515 This->flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
517 This->resource.format = format;
519 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format->byte_count);
521 return WINED3D_OK;
524 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface)
526 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
527 const struct wined3d_format *format = This->resource.format;
528 int extraline = 0;
529 SYSTEM_INFO sysInfo;
530 BITMAPINFO* b_info;
531 HDC ddc;
532 DWORD *masks;
533 UINT usage;
535 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
537 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format->id));
538 return WINED3DERR_INVALIDCALL;
541 switch (format->byte_count)
543 case 2:
544 case 4:
545 /* Allocate extra space to store the RGB bit masks. */
546 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
547 break;
549 case 3:
550 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
551 break;
553 default:
554 /* Allocate extra space for a palette. */
555 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
556 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
557 break;
560 if (!b_info)
561 return E_OUTOFMEMORY;
563 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
564 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
565 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
566 * add an extra line to the dib section
568 GetSystemInfo(&sysInfo);
569 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
570 extraline = 1;
571 TRACE("Adding an extra line to the dib section\n");
574 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
575 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
576 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format->byte_count;
577 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
578 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
579 b_info->bmiHeader.biPlanes = 1;
580 b_info->bmiHeader.biBitCount = format->byte_count * 8;
582 b_info->bmiHeader.biXPelsPerMeter = 0;
583 b_info->bmiHeader.biYPelsPerMeter = 0;
584 b_info->bmiHeader.biClrUsed = 0;
585 b_info->bmiHeader.biClrImportant = 0;
587 /* Get the bit masks */
588 masks = (DWORD *)b_info->bmiColors;
589 switch (This->resource.format->id)
591 case WINED3DFMT_B8G8R8_UNORM:
592 usage = DIB_RGB_COLORS;
593 b_info->bmiHeader.biCompression = BI_RGB;
594 break;
596 case WINED3DFMT_B5G5R5X1_UNORM:
597 case WINED3DFMT_B5G5R5A1_UNORM:
598 case WINED3DFMT_B4G4R4A4_UNORM:
599 case WINED3DFMT_B4G4R4X4_UNORM:
600 case WINED3DFMT_B2G3R3_UNORM:
601 case WINED3DFMT_B2G3R3A8_UNORM:
602 case WINED3DFMT_R10G10B10A2_UNORM:
603 case WINED3DFMT_R8G8B8A8_UNORM:
604 case WINED3DFMT_R8G8B8X8_UNORM:
605 case WINED3DFMT_B10G10R10A2_UNORM:
606 case WINED3DFMT_B5G6R5_UNORM:
607 case WINED3DFMT_R16G16B16A16_UNORM:
608 usage = 0;
609 b_info->bmiHeader.biCompression = BI_BITFIELDS;
610 masks[0] = format->red_mask;
611 masks[1] = format->green_mask;
612 masks[2] = format->blue_mask;
613 break;
615 default:
616 /* Don't know palette */
617 b_info->bmiHeader.biCompression = BI_RGB;
618 usage = 0;
619 break;
622 if (!(ddc = GetDC(0)))
624 HeapFree(GetProcessHeap(), 0, b_info);
625 return HRESULT_FROM_WIN32(GetLastError());
628 TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
629 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
630 ReleaseDC(0, ddc);
632 if (!This->dib.DIBsection) {
633 ERR("CreateDIBSection failed!\n");
634 HeapFree(GetProcessHeap(), 0, b_info);
635 return HRESULT_FROM_WIN32(GetLastError());
638 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
639 /* copy the existing surface to the dib section */
640 if(This->resource.allocatedMemory) {
641 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
642 } else {
643 /* This is to make LockRect read the gl Texture although memory is allocated */
644 This->flags &= ~SFLAG_INSYSMEM;
646 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
648 HeapFree(GetProcessHeap(), 0, b_info);
650 /* Now allocate a HDC */
651 This->hDC = CreateCompatibleDC(0);
652 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
653 TRACE("using wined3d palette %p\n", This->palette);
654 SelectPalette(This->hDC,
655 This->palette ? This->palette->hpal : 0,
656 FALSE);
658 This->flags |= SFLAG_DIBSECTION;
660 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
661 This->resource.heapMemory = NULL;
663 return WINED3D_OK;
666 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
667 unsigned int w, unsigned int h)
669 unsigned int x, y;
670 const float *src_f;
671 unsigned short *dst_s;
673 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
674 for(y = 0; y < h; y++) {
675 src_f = (const float *)(src + y * pitch_in);
676 dst_s = (unsigned short *) (dst + y * pitch_out);
677 for(x = 0; x < w; x++) {
678 dst_s[x] = float_32_to_16(src_f + x);
683 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
684 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
686 static const unsigned char convert_5to8[] =
688 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
689 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
690 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
691 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
693 static const unsigned char convert_6to8[] =
695 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
696 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
697 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
698 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
699 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
700 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
701 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
702 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
704 unsigned int x, y;
706 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
708 for (y = 0; y < h; ++y)
710 const WORD *src_line = (const WORD *)(src + y * pitch_in);
711 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
712 for (x = 0; x < w; ++x)
714 WORD pixel = src_line[x];
715 dst_line[x] = 0xff000000
716 | convert_5to8[(pixel & 0xf800) >> 11] << 16
717 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
718 | convert_5to8[(pixel & 0x001f)];
723 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
724 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
726 unsigned int x, y;
728 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
730 for (y = 0; y < h; ++y)
732 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
733 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
735 for (x = 0; x < w; ++x)
737 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
742 static inline BYTE cliptobyte(int x)
744 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
747 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
748 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
750 unsigned int x, y;
751 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
753 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
755 for (y = 0; y < h; ++y)
757 const BYTE *src_line = src + y * pitch_in;
758 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
759 for (x = 0; x < w; ++x)
761 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
762 * C = Y - 16; D = U - 128; E = V - 128;
763 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
764 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
765 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
766 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
767 * U and V are shared between the pixels.
769 if (!(x & 1)) /* for every even pixel, read new U and V */
771 d = (int) src_line[1] - 128;
772 e = (int) src_line[3] - 128;
773 r2 = 409 * e + 128;
774 g2 = - 100 * d - 208 * e + 128;
775 b2 = 516 * d + 128;
777 c2 = 298 * ((int) src_line[0] - 16);
778 dst_line[x] = 0xff000000
779 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
780 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
781 | cliptobyte((c2 + b2) >> 8); /* blue */
782 /* Scale RGB values to 0..255 range,
783 * then clip them if still not in range (may be negative),
784 * then shift them within DWORD if necessary.
786 src_line += 2;
791 struct d3dfmt_convertor_desc
793 enum wined3d_format_id 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(enum wined3d_format_id from, enum wined3d_format_id 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, enum wined3d_format_id to_fmt)
829 IWineD3DSurface *ret = NULL;
830 const struct d3dfmt_convertor_desc *conv;
831 WINED3DLOCKED_RECT lock_src, lock_dst;
832 HRESULT hr;
834 conv = find_convertor(source->resource.format->id, to_fmt);
835 if (!conv)
837 FIXME("Cannot find a conversion function from format %s to %s.\n",
838 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
839 return NULL;
842 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
843 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
844 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
845 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
846 NULL /* parent */, &wined3d_null_parent_ops, &ret);
847 if(!ret) {
848 ERR("Failed to create a destination surface for conversion\n");
849 return NULL;
852 memset(&lock_src, 0, sizeof(lock_src));
853 memset(&lock_dst, 0, sizeof(lock_dst));
855 hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
856 if (FAILED(hr))
858 ERR("Failed to lock the source surface.\n");
859 IWineD3DSurface_Release(ret);
860 return NULL;
862 hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
863 if (FAILED(hr))
865 ERR("Failed to lock the dest surface\n");
866 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
867 IWineD3DSurface_Release(ret);
868 return NULL;
871 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
872 source->currentDesc.Width, source->currentDesc.Height);
874 IWineD3DSurface_Unmap(ret);
875 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
877 return (IWineD3DSurfaceImpl *) ret;
880 /*****************************************************************************
881 * _Blt_ColorFill
883 * Helper function that fills a memory area with a specific color
885 * Params:
886 * buf: memory address to start filling at
887 * width, height: Dimensions of the area to fill
888 * bpp: Bit depth of the surface
889 * lPitch: pitch of the surface
890 * color: Color to fill with
892 *****************************************************************************/
893 static HRESULT
894 _Blt_ColorFill(BYTE *buf,
895 int width, int height,
896 int bpp, LONG lPitch,
897 DWORD color)
899 int x, y;
900 LPBYTE first;
902 /* Do first row */
904 #define COLORFILL_ROW(type) \
906 type *d = (type *) buf; \
907 for (x = 0; x < width; x++) \
908 d[x] = (type) color; \
909 break; \
911 switch(bpp)
913 case 1: COLORFILL_ROW(BYTE)
914 case 2: COLORFILL_ROW(WORD)
915 case 3:
917 BYTE *d = buf;
918 for (x = 0; x < width; x++,d+=3)
920 d[0] = (color ) & 0xFF;
921 d[1] = (color>> 8) & 0xFF;
922 d[2] = (color>>16) & 0xFF;
924 break;
926 case 4: COLORFILL_ROW(DWORD)
927 default:
928 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
929 return WINED3DERR_NOTAVAILABLE;
932 #undef COLORFILL_ROW
934 /* Now copy first row */
935 first = buf;
936 for (y = 1; y < height; y++)
938 buf += lPitch;
939 memcpy(buf, first, width * bpp);
941 return WINED3D_OK;
944 /*****************************************************************************
945 * IWineD3DSurface::Blt, SW emulation version
947 * Performs a blit to a surface, with or without a source surface.
948 * This is the main functionality of DirectDraw
950 * Params:
951 * DestRect: Destination rectangle to write to
952 * src_surface: Source surface, can be NULL
953 * SrcRect: Source rectangle
954 *****************************************************************************/
955 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
956 const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
958 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
959 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
960 RECT xdst,xsrc;
961 HRESULT ret = WINED3D_OK;
962 WINED3DLOCKED_RECT dlock, slock;
963 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
964 const struct wined3d_format *sEntry, *dEntry;
965 int x, y;
966 const BYTE *sbuf;
967 BYTE *dbuf;
969 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
970 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
971 flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
973 if ((This->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
975 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
976 return WINEDDERR_SURFACEBUSY;
979 /* First check for the validity of source / destination rectangles.
980 * This was verified using a test application + by MSDN. */
982 if (SrcRect)
984 if (src)
986 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
987 || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
988 || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
989 || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
990 || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
992 WARN("Application gave us bad source rectangle for Blt.\n");
993 return WINEDDERR_INVALIDRECT;
996 if (!SrcRect->right || !SrcRect->bottom
997 || SrcRect->left == (int)src->currentDesc.Width
998 || SrcRect->top == (int)src->currentDesc.Height)
1000 TRACE("Nothing to be done.\n");
1001 return WINED3D_OK;
1005 xsrc = *SrcRect;
1007 else if (src)
1009 xsrc.left = 0;
1010 xsrc.top = 0;
1011 xsrc.right = src->currentDesc.Width;
1012 xsrc.bottom = src->currentDesc.Height;
1014 else
1016 memset(&xsrc, 0, sizeof(xsrc));
1019 if (DestRect)
1021 /* For the Destination rect, it can be out of bounds on the condition
1022 * that a clipper is set for the given surface. */
1023 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1024 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
1025 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1026 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1027 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1029 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1030 return WINEDDERR_INVALIDRECT;
1033 if (DestRect->right <= 0 || DestRect->bottom <= 0
1034 || DestRect->left >= (int)This->currentDesc.Width
1035 || DestRect->top >= (int)This->currentDesc.Height)
1037 TRACE("Nothing to be done.\n");
1038 return WINED3D_OK;
1041 if (!src)
1043 RECT full_rect;
1045 full_rect.left = 0;
1046 full_rect.top = 0;
1047 full_rect.right = This->currentDesc.Width;
1048 full_rect.bottom = This->currentDesc.Height;
1049 IntersectRect(&xdst, &full_rect, DestRect);
1051 else
1053 BOOL clip_horiz, clip_vert;
1055 xdst = *DestRect;
1056 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1057 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1059 if (clip_vert || clip_horiz)
1061 /* Now check if this is a special case or not... */
1062 if ((flags & WINEDDBLT_DDFX)
1063 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1064 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1066 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1067 return WINED3D_OK;
1070 if (clip_horiz)
1072 if (xdst.left < 0)
1074 xsrc.left -= xdst.left;
1075 xdst.left = 0;
1077 if (xdst.right > This->currentDesc.Width)
1079 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1080 xdst.right = (int)This->currentDesc.Width;
1084 if (clip_vert)
1086 if (xdst.top < 0)
1088 xsrc.top -= xdst.top;
1089 xdst.top = 0;
1091 if (xdst.bottom > This->currentDesc.Height)
1093 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1094 xdst.bottom = (int)This->currentDesc.Height;
1098 /* And check if after clipping something is still to be done... */
1099 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1100 || (xdst.left >= (int)This->currentDesc.Width)
1101 || (xdst.top >= (int)This->currentDesc.Height)
1102 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1103 || (xsrc.left >= (int)src->currentDesc.Width)
1104 || (xsrc.top >= (int)src->currentDesc.Height))
1106 TRACE("Nothing to be done after clipping.\n");
1107 return WINED3D_OK;
1112 else
1114 xdst.left = 0;
1115 xdst.top = 0;
1116 xdst.right = This->currentDesc.Width;
1117 xdst.bottom = This->currentDesc.Height;
1120 if (src == This)
1122 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1123 slock = dlock;
1124 sEntry = This->resource.format;
1125 dEntry = sEntry;
1127 else
1129 dEntry = This->resource.format;
1130 if (src)
1132 if (This->resource.format->id != src->resource.format->id)
1134 src = surface_convert_format(src, dEntry->id);
1135 if (!src)
1137 /* The conv function writes a FIXME */
1138 WARN("Cannot convert source surface format to dest format\n");
1139 goto release;
1142 IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1143 sEntry = src->resource.format;
1145 else
1147 sEntry = dEntry;
1149 if (DestRect)
1150 IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
1151 else
1152 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1155 if (!DDBltFx || !(DDBltFx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
1157 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_FOURCC)
1159 if (!DestRect || src == This)
1161 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1162 goto release;
1166 bpp = This->resource.format->byte_count;
1167 srcheight = xsrc.bottom - xsrc.top;
1168 srcwidth = xsrc.right - xsrc.left;
1169 dstheight = xdst.bottom - xdst.top;
1170 dstwidth = xdst.right - xdst.left;
1171 width = (xdst.right - xdst.left) * bpp;
1173 if (DestRect && src != This)
1174 dbuf = dlock.pBits;
1175 else
1176 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1178 if (flags & WINEDDBLT_WAIT)
1180 flags &= ~WINEDDBLT_WAIT;
1182 if (flags & WINEDDBLT_ASYNC)
1184 static BOOL displayed = FALSE;
1185 if (!displayed)
1186 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1187 displayed = TRUE;
1188 flags &= ~WINEDDBLT_ASYNC;
1190 if (flags & WINEDDBLT_DONOTWAIT)
1192 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1193 static BOOL displayed = FALSE;
1194 if (!displayed)
1195 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1196 displayed = TRUE;
1197 flags &= ~WINEDDBLT_DONOTWAIT;
1200 /* First, all the 'source-less' blits */
1201 if (flags & WINEDDBLT_COLORFILL)
1203 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1204 dlock.Pitch, DDBltFx->u5.dwFillColor);
1205 flags &= ~WINEDDBLT_COLORFILL;
1208 if (flags & WINEDDBLT_DEPTHFILL)
1210 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1212 if (flags & WINEDDBLT_ROP)
1214 /* Catch some degenerate cases here */
1215 switch(DDBltFx->dwROP)
1217 case BLACKNESS:
1218 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1219 break;
1220 case 0xAA0029: /* No-op */
1221 break;
1222 case WHITENESS:
1223 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1224 break;
1225 case SRCCOPY: /* well, we do that below ? */
1226 break;
1227 default:
1228 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1229 goto error;
1231 flags &= ~WINEDDBLT_ROP;
1233 if (flags & WINEDDBLT_DDROPS)
1235 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1237 /* Now the 'with source' blits */
1238 if (src)
1240 const BYTE *sbase;
1241 int sx, xinc, sy, yinc;
1243 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1244 goto release;
1246 if (Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT
1247 && (srcwidth != dstwidth || srcheight != dstheight))
1249 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1250 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter));
1253 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1254 xinc = (srcwidth << 16) / dstwidth;
1255 yinc = (srcheight << 16) / dstheight;
1257 if (!flags)
1259 /* No effects, we can cheat here */
1260 if (dstwidth == srcwidth)
1262 if (dstheight == srcheight)
1264 /* No stretching in either direction. This needs to be as
1265 * fast as possible */
1266 sbuf = sbase;
1268 /* check for overlapping surfaces */
1269 if (src != This || xdst.top < xsrc.top ||
1270 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1272 /* no overlap, or dst above src, so copy from top downwards */
1273 for (y = 0; y < dstheight; y++)
1275 memcpy(dbuf, sbuf, width);
1276 sbuf += slock.Pitch;
1277 dbuf += dlock.Pitch;
1280 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1282 sbuf += (slock.Pitch*dstheight);
1283 dbuf += (dlock.Pitch*dstheight);
1284 for (y = 0; y < dstheight; y++)
1286 sbuf -= slock.Pitch;
1287 dbuf -= dlock.Pitch;
1288 memcpy(dbuf, sbuf, width);
1291 else /* src and dst overlapping on the same line, use memmove */
1293 for (y = 0; y < dstheight; y++)
1295 memmove(dbuf, sbuf, width);
1296 sbuf += slock.Pitch;
1297 dbuf += dlock.Pitch;
1300 } else {
1301 /* Stretching in Y direction only */
1302 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1303 sbuf = sbase + (sy >> 16) * slock.Pitch;
1304 memcpy(dbuf, sbuf, width);
1305 dbuf += dlock.Pitch;
1309 else
1311 /* Stretching in X direction */
1312 int last_sy = -1;
1313 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1315 sbuf = sbase + (sy >> 16) * slock.Pitch;
1317 if ((sy >> 16) == (last_sy >> 16))
1319 /* this sourcerow is the same as last sourcerow -
1320 * copy already stretched row
1322 memcpy(dbuf, dbuf - dlock.Pitch, width);
1324 else
1326 #define STRETCH_ROW(type) { \
1327 const type *s = (const type *)sbuf; \
1328 type *d = (type *)dbuf; \
1329 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1330 d[x] = s[sx >> 16]; \
1331 break; }
1333 switch(bpp)
1335 case 1: STRETCH_ROW(BYTE)
1336 case 2: STRETCH_ROW(WORD)
1337 case 4: STRETCH_ROW(DWORD)
1338 case 3:
1340 const BYTE *s;
1341 BYTE *d = dbuf;
1342 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1344 DWORD pixel;
1346 s = sbuf+3*(sx>>16);
1347 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1348 d[0] = (pixel )&0xff;
1349 d[1] = (pixel>> 8)&0xff;
1350 d[2] = (pixel>>16)&0xff;
1351 d+=3;
1353 break;
1355 default:
1356 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1357 ret = WINED3DERR_NOTAVAILABLE;
1358 goto error;
1360 #undef STRETCH_ROW
1362 dbuf += dlock.Pitch;
1363 last_sy = sy;
1367 else
1369 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1370 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1371 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1372 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1374 /* The color keying flags are checked for correctness in ddraw */
1375 if (flags & WINEDDBLT_KEYSRC)
1377 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1378 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1380 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
1382 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1383 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1386 if (flags & WINEDDBLT_KEYDEST)
1388 /* Destination color keys are taken from the source surface ! */
1389 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1390 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1392 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
1394 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1395 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1398 if(bpp == 1)
1400 keymask = 0xff;
1402 else
1404 keymask = sEntry->red_mask
1405 | sEntry->green_mask
1406 | sEntry->blue_mask;
1408 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1411 if (flags & WINEDDBLT_DDFX)
1413 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1414 LONG tmpxy;
1415 dTopLeft = dbuf;
1416 dTopRight = dbuf+((dstwidth-1)*bpp);
1417 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1418 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1420 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1422 /* I don't think we need to do anything about this flag */
1423 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1425 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1427 tmp = dTopRight;
1428 dTopRight = dTopLeft;
1429 dTopLeft = tmp;
1430 tmp = dBottomRight;
1431 dBottomRight = dBottomLeft;
1432 dBottomLeft = tmp;
1433 dstxinc = dstxinc *-1;
1435 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1437 tmp = dTopLeft;
1438 dTopLeft = dBottomLeft;
1439 dBottomLeft = tmp;
1440 tmp = dTopRight;
1441 dTopRight = dBottomRight;
1442 dBottomRight = tmp;
1443 dstyinc = dstyinc *-1;
1445 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1447 /* I don't think we need to do anything about this flag */
1448 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1450 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1452 tmp = dBottomRight;
1453 dBottomRight = dTopLeft;
1454 dTopLeft = tmp;
1455 tmp = dBottomLeft;
1456 dBottomLeft = dTopRight;
1457 dTopRight = tmp;
1458 dstxinc = dstxinc * -1;
1459 dstyinc = dstyinc * -1;
1461 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1463 tmp = dTopLeft;
1464 dTopLeft = dBottomLeft;
1465 dBottomLeft = dBottomRight;
1466 dBottomRight = dTopRight;
1467 dTopRight = tmp;
1468 tmpxy = dstxinc;
1469 dstxinc = dstyinc;
1470 dstyinc = tmpxy;
1471 dstxinc = dstxinc * -1;
1473 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1475 tmp = dTopLeft;
1476 dTopLeft = dTopRight;
1477 dTopRight = dBottomRight;
1478 dBottomRight = dBottomLeft;
1479 dBottomLeft = tmp;
1480 tmpxy = dstxinc;
1481 dstxinc = dstyinc;
1482 dstyinc = tmpxy;
1483 dstyinc = dstyinc * -1;
1485 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1487 /* I don't think we need to do anything about this flag */
1488 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1490 dbuf = dTopLeft;
1491 flags &= ~(WINEDDBLT_DDFX);
1494 #define COPY_COLORKEY_FX(type) { \
1495 const type *s; \
1496 type *d = (type *)dbuf, *dx, tmp; \
1497 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1498 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1499 dx = d; \
1500 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1501 tmp = s[sx >> 16]; \
1502 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1503 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1504 dx[0] = tmp; \
1506 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1508 d = (type*)(((LPBYTE)d)+dstyinc); \
1510 break; }
1512 switch (bpp) {
1513 case 1: COPY_COLORKEY_FX(BYTE)
1514 case 2: COPY_COLORKEY_FX(WORD)
1515 case 4: COPY_COLORKEY_FX(DWORD)
1516 case 3:
1518 const BYTE *s;
1519 BYTE *d = dbuf, *dx;
1520 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1522 sbuf = sbase + (sy >> 16) * slock.Pitch;
1523 dx = d;
1524 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1526 DWORD pixel, dpixel = 0;
1527 s = sbuf+3*(sx>>16);
1528 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1529 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1530 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1531 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1533 dx[0] = (pixel )&0xff;
1534 dx[1] = (pixel>> 8)&0xff;
1535 dx[2] = (pixel>>16)&0xff;
1537 dx+= dstxinc;
1539 d += dstyinc;
1541 break;
1543 default:
1544 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1545 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1546 ret = WINED3DERR_NOTAVAILABLE;
1547 goto error;
1548 #undef COPY_COLORKEY_FX
1553 error:
1554 if (flags && FIXME_ON(d3d_surface))
1556 FIXME("\tUnsupported flags: %#x.\n", flags);
1559 release:
1560 IWineD3DSurface_Unmap(iface);
1561 if (src && src != This) IWineD3DSurface_Unmap((IWineD3DSurface *)src);
1562 /* Release the converted surface if any */
1563 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1564 return ret;
1567 /*****************************************************************************
1568 * IWineD3DSurface::BltFast, SW emulation version
1570 * This is the software implementation of BltFast, as used by GDI surfaces
1571 * and as a fallback for OpenGL surfaces. This code is taken from the old
1572 * DirectDraw code, and was originally written by TransGaming.
1574 * Params:
1575 * dstx:
1576 * dsty:
1577 * src_surface: Source surface to copy from
1578 * rsrc: Source rectangle
1579 * trans: Some flags
1581 * Returns:
1582 * WINED3D_OK on success
1584 *****************************************************************************/
1585 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1586 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1588 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1589 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1591 int bpp, w, h, x, y;
1592 WINED3DLOCKED_RECT dlock,slock;
1593 HRESULT ret = WINED3D_OK;
1594 RECT rsrc2;
1595 RECT lock_src, lock_dst, lock_union;
1596 const BYTE *sbuf;
1597 BYTE *dbuf;
1598 const struct wined3d_format *sEntry, *dEntry;
1600 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1601 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1603 if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
1605 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1606 return WINEDDERR_SURFACEBUSY;
1609 if (!rsrc)
1611 WARN("rsrc is NULL!\n");
1612 rsrc2.left = 0;
1613 rsrc2.top = 0;
1614 rsrc2.right = src->currentDesc.Width;
1615 rsrc2.bottom = src->currentDesc.Height;
1616 rsrc = &rsrc2;
1619 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1620 if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1621 || (rsrc->top > src->currentDesc.Height) || (rsrc->top < 0)
1622 || (rsrc->left > src->currentDesc.Width) || (rsrc->left < 0)
1623 || (rsrc->right > src->currentDesc.Width) || (rsrc->right < 0)
1624 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1626 WARN("Application gave us bad source rectangle for BltFast.\n");
1627 return WINEDDERR_INVALIDRECT;
1630 h = rsrc->bottom - rsrc->top;
1631 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1632 if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1633 if (h <= 0) return WINEDDERR_INVALIDRECT;
1635 w = rsrc->right - rsrc->left;
1636 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1637 if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1638 if (w <= 0) return WINEDDERR_INVALIDRECT;
1640 /* Now compute the locking rectangle... */
1641 lock_src.left = rsrc->left;
1642 lock_src.top = rsrc->top;
1643 lock_src.right = lock_src.left + w;
1644 lock_src.bottom = lock_src.top + h;
1646 lock_dst.left = dstx;
1647 lock_dst.top = dsty;
1648 lock_dst.right = dstx + w;
1649 lock_dst.bottom = dsty + h;
1651 bpp = This->resource.format->byte_count;
1653 /* We need to lock the surfaces, or we won't get refreshes when done. */
1654 if (src == This)
1656 int pitch;
1658 UnionRect(&lock_union, &lock_src, &lock_dst);
1660 /* Lock the union of the two rectangles */
1661 ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
1662 if (FAILED(ret)) goto error;
1664 pitch = dlock.Pitch;
1665 slock.Pitch = dlock.Pitch;
1667 /* Since slock was originally copied from this surface's description, we can just reuse it */
1668 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1669 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1670 sEntry = src->resource.format;
1671 dEntry = sEntry;
1673 else
1675 ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1676 if (FAILED(ret)) goto error;
1677 ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
1678 if (FAILED(ret)) goto error;
1680 sbuf = slock.pBits;
1681 dbuf = dlock.pBits;
1682 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1684 sEntry = src->resource.format;
1685 dEntry = This->resource.format;
1688 /* Handle compressed surfaces first... */
1689 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_COMPRESSED)
1691 UINT row_block_count;
1693 TRACE("compressed -> compressed copy\n");
1694 if (trans)
1695 FIXME("trans arg not supported when a compressed surface is involved\n");
1696 if (dstx || dsty)
1697 FIXME("offset for destination surface is not supported\n");
1698 if (src->resource.format->id != This->resource.format->id)
1700 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1701 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1702 goto error;
1705 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1706 for (y = 0; y < h; y += dEntry->block_height)
1708 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1709 dbuf += dlock.Pitch;
1710 sbuf += slock.Pitch;
1713 goto error;
1715 if ((sEntry->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->flags & WINED3DFMT_FLAG_COMPRESSED))
1717 /* TODO: Use the libtxc_dxtn.so shared library to do
1718 * software decompression
1720 ERR("Software decompression not supported.\n");
1721 goto error;
1724 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1726 DWORD keylow, keyhigh;
1727 DWORD mask = src->resource.format->red_mask
1728 | src->resource.format->green_mask
1729 | src->resource.format->blue_mask;
1731 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1732 if(!mask && bpp==1)
1733 mask = 0xff;
1735 TRACE("Color keyed copy\n");
1736 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1738 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1739 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1741 else
1743 /* I'm not sure if this is correct */
1744 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1745 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1746 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1749 #define COPYBOX_COLORKEY(type) { \
1750 const type *s = (const type *)sbuf; \
1751 type *d = (type *)dbuf; \
1752 type tmp; \
1753 for (y = 0; y < h; y++) { \
1754 for (x = 0; x < w; x++) { \
1755 tmp = s[x]; \
1756 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1758 s = (const type *)((const BYTE *)s + slock.Pitch); \
1759 d = (type *)((BYTE *)d + dlock.Pitch); \
1761 break; \
1764 switch (bpp) {
1765 case 1: COPYBOX_COLORKEY(BYTE)
1766 case 2: COPYBOX_COLORKEY(WORD)
1767 case 4: COPYBOX_COLORKEY(DWORD)
1768 case 3:
1770 const BYTE *s;
1771 BYTE *d;
1772 DWORD tmp;
1773 s = sbuf;
1774 d = dbuf;
1775 for (y = 0; y < h; y++)
1777 for (x = 0; x < w * 3; x += 3)
1779 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1780 if (tmp < keylow || tmp > keyhigh)
1782 d[x + 0] = s[x + 0];
1783 d[x + 1] = s[x + 1];
1784 d[x + 2] = s[x + 2];
1787 s += slock.Pitch;
1788 d += dlock.Pitch;
1790 break;
1792 default:
1793 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1794 ret = WINED3DERR_NOTAVAILABLE;
1795 goto error;
1797 #undef COPYBOX_COLORKEY
1798 TRACE("Copy Done\n");
1800 else
1802 int width = w * bpp;
1803 INT sbufpitch, dbufpitch;
1805 TRACE("NO color key copy\n");
1806 /* Handle overlapping surfaces */
1807 if (sbuf < dbuf)
1809 sbuf += (h - 1) * slock.Pitch;
1810 dbuf += (h - 1) * dlock.Pitch;
1811 sbufpitch = -slock.Pitch;
1812 dbufpitch = -dlock.Pitch;
1814 else
1816 sbufpitch = slock.Pitch;
1817 dbufpitch = dlock.Pitch;
1819 for (y = 0; y < h; y++)
1821 /* This is pretty easy, a line for line memcpy */
1822 memmove(dbuf, sbuf, width);
1823 sbuf += sbufpitch;
1824 dbuf += dbufpitch;
1826 TRACE("Copy done\n");
1829 error:
1830 if (src == This)
1832 IWineD3DSurface_Unmap(iface);
1834 else
1836 IWineD3DSurface_Unmap(iface);
1837 IWineD3DSurface_Unmap(src_surface);
1840 return ret;
1843 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
1844 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
1846 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1848 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
1849 iface, pLockedRect, wine_dbgstr_rect(pRect), flags);
1851 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1853 if (!pRect)
1855 pLockedRect->pBits = This->resource.allocatedMemory;
1856 This->lockedRect.left = 0;
1857 This->lockedRect.top = 0;
1858 This->lockedRect.right = This->currentDesc.Width;
1859 This->lockedRect.bottom = This->currentDesc.Height;
1861 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1862 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1863 This->lockedRect.right, This->lockedRect.bottom);
1865 else
1867 const struct wined3d_format *format = This->resource.format;
1869 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1870 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1872 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1874 /* Compressed textures are block based, so calculate the offset of
1875 * the block that contains the top-left pixel of the locked rectangle. */
1876 pLockedRect->pBits = This->resource.allocatedMemory
1877 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1878 + ((pRect->left / format->block_width) * format->block_byte_count);
1880 else
1882 pLockedRect->pBits = This->resource.allocatedMemory +
1883 (pLockedRect->Pitch * pRect->top) +
1884 (pRect->left * format->byte_count);
1886 This->lockedRect.left = pRect->left;
1887 This->lockedRect.top = pRect->top;
1888 This->lockedRect.right = pRect->right;
1889 This->lockedRect.bottom = pRect->bottom;
1892 /* No dirtifying is needed for this surface implementation */
1893 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1895 return WINED3D_OK;