wined3d: Consistently use Map/Unmap for mapping resources.
[wine/wine-gecko.git] / dlls / wined3d / surface_base.c
blob1324acfddd730e31ec70fc10a37ae7980e798daa
1 /*
2 * IWineD3DSurface Implementation of management(non-rendering) functions
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11 * Copyright 2007 Henri Verbeet
12 * Copyright 2006-2007 Roderick Colenbrander
13 * Copyright 2009 Henri Verbeet for CodeWeavers
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "config.h"
31 #include "wine/port.h"
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
36 /* See also float_16_to_32() in wined3d_private.h */
37 static inline unsigned short float_32_to_16(const float *in)
39 int exp = 0;
40 float tmp = fabs(*in);
41 unsigned int mantissa;
42 unsigned short ret;
44 /* Deal with special numbers */
45 if (*in == 0.0f) return 0x0000;
46 if(isnan(*in)) return 0x7C01;
47 if (isinf(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
49 if(tmp < powf(2, 10)) {
52 tmp = tmp * 2.0f;
53 exp--;
54 }while(tmp < powf(2, 10));
55 } else if(tmp >= powf(2, 11)) {
58 tmp /= 2.0f;
59 exp++;
60 }while(tmp >= powf(2, 11));
63 mantissa = (unsigned int) tmp;
64 if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
66 exp += 10; /* Normalize the mantissa */
67 exp += 15; /* Exponent is encoded with excess 15 */
69 if(exp > 30) { /* too big */
70 ret = 0x7c00; /* INF */
71 } else if(exp <= 0) {
72 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
73 while(exp <= 0) {
74 mantissa = mantissa >> 1;
75 exp++;
77 ret = mantissa & 0x3ff;
78 } else {
79 ret = (exp << 10) | (mantissa & 0x3ff);
82 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
83 return ret;
86 /* *******************************************
87 IWineD3DSurface IUnknown parts follow
88 ******************************************* */
89 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
91 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
92 /* Warn ,but be nice about things */
93 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
95 if (IsEqualGUID(riid, &IID_IUnknown)
96 || IsEqualGUID(riid, &IID_IWineD3DBase)
97 || IsEqualGUID(riid, &IID_IWineD3DResource)
98 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
99 IUnknown_AddRef((IUnknown*)iface);
100 *ppobj = This;
101 return S_OK;
103 *ppobj = NULL;
104 return E_NOINTERFACE;
107 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
108 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
109 ULONG ref = InterlockedIncrement(&This->resource.ref);
110 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
111 return ref;
114 /* ****************************************************
115 IWineD3DSurface IWineD3DResource parts follow
116 **************************************************** */
117 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
118 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
121 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
122 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
125 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
126 return resource_free_private_data((IWineD3DResource *)iface, refguid);
129 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
130 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
133 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
134 return resource_get_priority((IWineD3DResource *)iface);
137 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
138 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
139 return resource_get_type((IWineD3DResource *)iface);
142 void * WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface)
144 TRACE("iface %p.\n", iface);
146 return ((IWineD3DSurfaceImpl *)iface)->resource.parent;
149 void WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *desc)
151 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
153 TRACE("iface %p, desc %p.\n", iface, desc);
155 desc->format = surface->resource.format->id;
156 desc->resource_type = surface->resource.resourceType;
157 desc->usage = surface->resource.usage;
158 desc->pool = surface->resource.pool;
159 desc->size = surface->resource.size; /* dx8 only */
160 desc->multisample_type = surface->currentDesc.MultiSampleType;
161 desc->multisample_quality = surface->currentDesc.MultiSampleQuality;
162 desc->width = surface->currentDesc.Width;
163 desc->height = surface->currentDesc.Height;
166 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags)
168 TRACE("iface %p, flags %#x.\n", iface, Flags);
170 switch (Flags)
172 case WINEDDGBS_CANBLT:
173 case WINEDDGBS_ISBLTDONE:
174 return WINED3D_OK;
176 default:
177 return WINED3DERR_INVALIDCALL;
181 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
182 /* XXX: DDERR_INVALIDSURFACETYPE */
184 TRACE("(%p)->(%08x)\n",iface,Flags);
185 switch (Flags) {
186 case WINEDDGFS_CANFLIP:
187 case WINEDDGFS_ISFLIPDONE:
188 return WINED3D_OK;
190 default:
191 return WINED3DERR_INVALIDCALL;
195 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
196 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
197 TRACE("(%p)\n", This);
199 /* D3D8 and 9 loose full devices, ddraw only surfaces */
200 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
203 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
204 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
205 TRACE("(%p)\n", This);
207 /* So far we don't lose anything :) */
208 This->Flags &= ~SFLAG_LOST;
209 return WINED3D_OK;
212 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
213 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
214 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
215 TRACE("(%p)->(%p)\n", This, Pal);
217 if(This->palette == PalImpl) {
218 TRACE("Nop palette change\n");
219 return WINED3D_OK;
222 if (This->palette)
223 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
224 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
226 This->palette = PalImpl;
228 if (PalImpl)
230 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
231 PalImpl->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
233 return IWineD3DSurface_RealizePalette(iface);
235 else return WINED3D_OK;
238 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
240 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
241 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
243 if (Flags & WINEDDCKEY_COLORSPACE)
245 FIXME(" colorkey value not supported (%08x) !\n", Flags);
246 return WINED3DERR_INVALIDCALL;
249 /* Dirtify the surface, but only if a key was changed */
250 if(CKey) {
251 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
252 case WINEDDCKEY_DESTBLT:
253 This->DestBltCKey = *CKey;
254 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
255 break;
257 case WINEDDCKEY_DESTOVERLAY:
258 This->DestOverlayCKey = *CKey;
259 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
260 break;
262 case WINEDDCKEY_SRCOVERLAY:
263 This->SrcOverlayCKey = *CKey;
264 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
265 break;
267 case WINEDDCKEY_SRCBLT:
268 This->SrcBltCKey = *CKey;
269 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
270 break;
273 else {
274 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
275 case WINEDDCKEY_DESTBLT:
276 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
277 break;
279 case WINEDDCKEY_DESTOVERLAY:
280 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
281 break;
283 case WINEDDCKEY_SRCOVERLAY:
284 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
285 break;
287 case WINEDDCKEY_SRCBLT:
288 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
289 break;
293 return WINED3D_OK;
296 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
297 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
298 TRACE("(%p)->(%p)\n", This, Pal);
300 *Pal = (IWineD3DPalette *) This->palette;
301 return WINED3D_OK;
304 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
306 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
307 const struct wined3d_format *format = This->resource.format;
308 DWORD ret;
309 TRACE("(%p)\n", This);
311 if ((format->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
313 /* Since compressed formats are block based, pitch means the amount of
314 * bytes to the next row of block rather than the next row of pixels. */
315 UINT row_block_count = (This->currentDesc.Width + format->block_width - 1) / format->block_width;
316 ret = row_block_count * format->block_byte_count;
318 else
320 unsigned char alignment = This->resource.device->surface_alignment;
321 ret = This->resource.format->byte_count * This->currentDesc.Width; /* Bytes / row */
322 ret = (ret + alignment - 1) & ~(alignment - 1);
324 TRACE("(%p) Returning %d\n", This, ret);
325 return ret;
328 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
329 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
330 LONG w, h;
332 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
334 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
336 TRACE("(%p): Not an overlay surface\n", This);
337 return WINEDDERR_NOTAOVERLAYSURFACE;
340 w = This->overlay_destrect.right - This->overlay_destrect.left;
341 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
342 This->overlay_destrect.left = X;
343 This->overlay_destrect.top = Y;
344 This->overlay_destrect.right = X + w;
345 This->overlay_destrect.bottom = Y + h;
347 IWineD3DSurface_DrawOverlay(iface);
349 return WINED3D_OK;
352 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
353 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
354 HRESULT hr;
356 TRACE("(%p)->(%p,%p)\n", This, X, Y);
358 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
360 TRACE("(%p): Not an overlay surface\n", This);
361 return WINEDDERR_NOTAOVERLAYSURFACE;
364 if (!This->overlay_dest)
366 *X = 0; *Y = 0;
367 hr = WINEDDERR_OVERLAYNOTVISIBLE;
368 } else {
369 *X = This->overlay_destrect.left;
370 *Y = This->overlay_destrect.top;
371 hr = WINED3D_OK;
374 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
375 return hr;
378 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
379 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
381 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, Flags, Ref);
383 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
385 TRACE("(%p): Not an overlay surface\n", This);
386 return WINEDDERR_NOTAOVERLAYSURFACE;
389 return WINED3D_OK;
392 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
393 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
395 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
396 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
397 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
399 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
401 WARN("(%p): Not an overlay surface\n", This);
402 return WINEDDERR_NOTAOVERLAYSURFACE;
403 } else if(!DstSurface) {
404 WARN("(%p): Dest surface is NULL\n", This);
405 return WINED3DERR_INVALIDCALL;
408 if(SrcRect) {
409 This->overlay_srcrect = *SrcRect;
410 } else {
411 This->overlay_srcrect.left = 0;
412 This->overlay_srcrect.top = 0;
413 This->overlay_srcrect.right = This->currentDesc.Width;
414 This->overlay_srcrect.bottom = This->currentDesc.Height;
417 if(DstRect) {
418 This->overlay_destrect = *DstRect;
419 } else {
420 This->overlay_destrect.left = 0;
421 This->overlay_destrect.top = 0;
422 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
423 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
426 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
427 list_remove(&This->overlay_entry);
430 if(Flags & WINEDDOVER_SHOW) {
431 if(This->overlay_dest != Dst) {
432 This->overlay_dest = Dst;
433 list_add_tail(&Dst->overlays, &This->overlay_entry);
435 } else if(Flags & WINEDDOVER_HIDE) {
436 /* tests show that the rectangles are erased on hide */
437 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
438 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
439 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
440 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
441 This->overlay_dest = NULL;
444 IWineD3DSurface_DrawOverlay(iface);
446 return WINED3D_OK;
449 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
451 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
452 TRACE("(%p)->(%p)\n", This, clipper);
454 This->clipper = clipper;
455 return WINED3D_OK;
458 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
460 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
461 TRACE("(%p)->(%p)\n", This, clipper);
463 *clipper = This->clipper;
464 if(*clipper) {
465 IWineD3DClipper_AddRef(*clipper);
467 return WINED3D_OK;
470 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
472 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
473 const struct wined3d_format *format = wined3d_get_format(&This->resource.device->adapter->gl_info, format_id);
475 if (This->resource.format->id != WINED3DFMT_UNKNOWN)
477 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
478 return WINED3DERR_INVALIDCALL;
481 TRACE("(%p) : Setting texture format to %s (%#x).\n", This, debug_d3dformat(format_id), format_id);
483 This->resource.size = wined3d_format_calculate_size(format, This->resource.device->surface_alignment,
484 This->pow2Width, This->pow2Height);
486 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
488 This->resource.format = format;
490 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format->byte_count);
492 return WINED3D_OK;
495 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface)
497 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
498 const struct wined3d_format *format = This->resource.format;
499 int extraline = 0;
500 SYSTEM_INFO sysInfo;
501 BITMAPINFO* b_info;
502 HDC ddc;
503 DWORD *masks;
504 UINT usage;
506 if (!(format->Flags & WINED3DFMT_FLAG_GETDC))
508 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format->id));
509 return WINED3DERR_INVALIDCALL;
512 switch (format->byte_count)
514 case 2:
515 case 4:
516 /* Allocate extra space to store the RGB bit masks. */
517 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
518 break;
520 case 3:
521 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
522 break;
524 default:
525 /* Allocate extra space for a palette. */
526 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
527 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
528 break;
531 if (!b_info)
532 return E_OUTOFMEMORY;
534 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
535 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
536 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
537 * add an extra line to the dib section
539 GetSystemInfo(&sysInfo);
540 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
541 extraline = 1;
542 TRACE("Adding an extra line to the dib section\n");
545 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
546 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
547 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format->byte_count;
548 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
549 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
550 b_info->bmiHeader.biPlanes = 1;
551 b_info->bmiHeader.biBitCount = format->byte_count * 8;
553 b_info->bmiHeader.biXPelsPerMeter = 0;
554 b_info->bmiHeader.biYPelsPerMeter = 0;
555 b_info->bmiHeader.biClrUsed = 0;
556 b_info->bmiHeader.biClrImportant = 0;
558 /* Get the bit masks */
559 masks = (DWORD *)b_info->bmiColors;
560 switch (This->resource.format->id)
562 case WINED3DFMT_B8G8R8_UNORM:
563 usage = DIB_RGB_COLORS;
564 b_info->bmiHeader.biCompression = BI_RGB;
565 break;
567 case WINED3DFMT_B5G5R5X1_UNORM:
568 case WINED3DFMT_B5G5R5A1_UNORM:
569 case WINED3DFMT_B4G4R4A4_UNORM:
570 case WINED3DFMT_B4G4R4X4_UNORM:
571 case WINED3DFMT_B2G3R3_UNORM:
572 case WINED3DFMT_B2G3R3A8_UNORM:
573 case WINED3DFMT_R10G10B10A2_UNORM:
574 case WINED3DFMT_R8G8B8A8_UNORM:
575 case WINED3DFMT_R8G8B8X8_UNORM:
576 case WINED3DFMT_B10G10R10A2_UNORM:
577 case WINED3DFMT_B5G6R5_UNORM:
578 case WINED3DFMT_R16G16B16A16_UNORM:
579 usage = 0;
580 b_info->bmiHeader.biCompression = BI_BITFIELDS;
581 masks[0] = format->red_mask;
582 masks[1] = format->green_mask;
583 masks[2] = format->blue_mask;
584 break;
586 default:
587 /* Don't know palette */
588 b_info->bmiHeader.biCompression = BI_RGB;
589 usage = 0;
590 break;
593 if (!(ddc = GetDC(0)))
595 HeapFree(GetProcessHeap(), 0, b_info);
596 return HRESULT_FROM_WIN32(GetLastError());
599 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);
600 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
601 ReleaseDC(0, ddc);
603 if (!This->dib.DIBsection) {
604 ERR("CreateDIBSection failed!\n");
605 HeapFree(GetProcessHeap(), 0, b_info);
606 return HRESULT_FROM_WIN32(GetLastError());
609 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
610 /* copy the existing surface to the dib section */
611 if(This->resource.allocatedMemory) {
612 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
613 } else {
614 /* This is to make LockRect read the gl Texture although memory is allocated */
615 This->Flags &= ~SFLAG_INSYSMEM;
617 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
619 HeapFree(GetProcessHeap(), 0, b_info);
621 /* Now allocate a HDC */
622 This->hDC = CreateCompatibleDC(0);
623 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
624 TRACE("using wined3d palette %p\n", This->palette);
625 SelectPalette(This->hDC,
626 This->palette ? This->palette->hpal : 0,
627 FALSE);
629 This->Flags |= SFLAG_DIBSECTION;
631 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
632 This->resource.heapMemory = NULL;
634 return WINED3D_OK;
637 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
638 unsigned int w, unsigned int h)
640 unsigned int x, y;
641 const float *src_f;
642 unsigned short *dst_s;
644 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
645 for(y = 0; y < h; y++) {
646 src_f = (const float *)(src + y * pitch_in);
647 dst_s = (unsigned short *) (dst + y * pitch_out);
648 for(x = 0; x < w; x++) {
649 dst_s[x] = float_32_to_16(src_f + x);
654 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
655 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
657 static const unsigned char convert_5to8[] =
659 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
660 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
661 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
662 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
664 static const unsigned char convert_6to8[] =
666 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
667 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
668 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
669 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
670 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
671 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
672 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
673 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
675 unsigned int x, y;
677 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
679 for (y = 0; y < h; ++y)
681 const WORD *src_line = (const WORD *)(src + y * pitch_in);
682 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
683 for (x = 0; x < w; ++x)
685 WORD pixel = src_line[x];
686 dst_line[x] = 0xff000000
687 | convert_5to8[(pixel & 0xf800) >> 11] << 16
688 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
689 | convert_5to8[(pixel & 0x001f)];
694 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
695 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
697 unsigned int x, y;
699 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
701 for (y = 0; y < h; ++y)
703 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
704 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
706 for (x = 0; x < w; ++x)
708 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
713 static inline BYTE cliptobyte(int x)
715 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
718 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
719 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
721 unsigned int x, y;
722 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
724 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
726 for (y = 0; y < h; ++y)
728 const BYTE *src_line = src + y * pitch_in;
729 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
730 for (x = 0; x < w; ++x)
732 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
733 * C = Y - 16; D = U - 128; E = V - 128;
734 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
735 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
736 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
737 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
738 * U and V are shared between the pixels.
740 if (!(x & 1)) /* for every even pixel, read new U and V */
742 d = (int) src_line[1] - 128;
743 e = (int) src_line[3] - 128;
744 r2 = 409 * e + 128;
745 g2 = - 100 * d - 208 * e + 128;
746 b2 = 516 * d + 128;
748 c2 = 298 * ((int) src_line[0] - 16);
749 dst_line[x] = 0xff000000
750 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
751 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
752 | cliptobyte((c2 + b2) >> 8); /* blue */
753 /* Scale RGB values to 0..255 range,
754 * then clip them if still not in range (may be negative),
755 * then shift them within DWORD if necessary.
757 src_line += 2;
762 struct d3dfmt_convertor_desc
764 enum wined3d_format_id from, to;
765 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
768 static const struct d3dfmt_convertor_desc convertors[] =
770 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
771 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
772 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
773 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
776 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
778 unsigned int i;
779 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
780 if(convertors[i].from == from && convertors[i].to == to) {
781 return &convertors[i];
784 return NULL;
787 /*****************************************************************************
788 * surface_convert_format
790 * Creates a duplicate of a surface in a different format. Is used by Blt to
791 * blit between surfaces with different formats
793 * Parameters
794 * source: Source surface
795 * fmt: Requested destination format
797 *****************************************************************************/
798 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
800 IWineD3DSurface *ret = NULL;
801 const struct d3dfmt_convertor_desc *conv;
802 WINED3DLOCKED_RECT lock_src, lock_dst;
803 HRESULT hr;
805 conv = find_convertor(source->resource.format->id, to_fmt);
806 if (!conv)
808 FIXME("Cannot find a conversion function from format %s to %s.\n",
809 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
810 return NULL;
813 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
814 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
815 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
816 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
817 NULL /* parent */, &wined3d_null_parent_ops, &ret);
818 if(!ret) {
819 ERR("Failed to create a destination surface for conversion\n");
820 return NULL;
823 memset(&lock_src, 0, sizeof(lock_src));
824 memset(&lock_dst, 0, sizeof(lock_dst));
826 hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
827 if (FAILED(hr))
829 ERR("Failed to lock the source surface.\n");
830 IWineD3DSurface_Release(ret);
831 return NULL;
833 hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
834 if (FAILED(hr))
836 ERR("Failed to lock the dest surface\n");
837 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
838 IWineD3DSurface_Release(ret);
839 return NULL;
842 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
843 source->currentDesc.Width, source->currentDesc.Height);
845 IWineD3DSurface_Unmap(ret);
846 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
848 return (IWineD3DSurfaceImpl *) ret;
851 /*****************************************************************************
852 * _Blt_ColorFill
854 * Helper function that fills a memory area with a specific color
856 * Params:
857 * buf: memory address to start filling at
858 * width, height: Dimensions of the area to fill
859 * bpp: Bit depth of the surface
860 * lPitch: pitch of the surface
861 * color: Color to fill with
863 *****************************************************************************/
864 static HRESULT
865 _Blt_ColorFill(BYTE *buf,
866 int width, int height,
867 int bpp, LONG lPitch,
868 DWORD color)
870 int x, y;
871 LPBYTE first;
873 /* Do first row */
875 #define COLORFILL_ROW(type) \
877 type *d = (type *) buf; \
878 for (x = 0; x < width; x++) \
879 d[x] = (type) color; \
880 break; \
882 switch(bpp)
884 case 1: COLORFILL_ROW(BYTE)
885 case 2: COLORFILL_ROW(WORD)
886 case 3:
888 BYTE *d = buf;
889 for (x = 0; x < width; x++,d+=3)
891 d[0] = (color ) & 0xFF;
892 d[1] = (color>> 8) & 0xFF;
893 d[2] = (color>>16) & 0xFF;
895 break;
897 case 4: COLORFILL_ROW(DWORD)
898 default:
899 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
900 return WINED3DERR_NOTAVAILABLE;
903 #undef COLORFILL_ROW
905 /* Now copy first row */
906 first = buf;
907 for (y = 1; y < height; y++)
909 buf += lPitch;
910 memcpy(buf, first, width * bpp);
912 return WINED3D_OK;
915 /*****************************************************************************
916 * IWineD3DSurface::Blt, SW emulation version
918 * Performs a blit to a surface, with or without a source surface.
919 * This is the main functionality of DirectDraw
921 * Params:
922 * DestRect: Destination rectangle to write to
923 * src_surface: Source surface, can be NULL
924 * SrcRect: Source rectangle
925 *****************************************************************************/
926 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
927 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
929 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
930 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
931 RECT xdst,xsrc;
932 HRESULT ret = WINED3D_OK;
933 WINED3DLOCKED_RECT dlock, slock;
934 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
935 const struct wined3d_format *sEntry, *dEntry;
936 int x, y;
937 const BYTE *sbuf;
938 BYTE *dbuf;
940 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
941 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
942 Flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
944 if ((This->Flags & SFLAG_LOCKED) || (src && (src->Flags & SFLAG_LOCKED)))
946 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
947 return WINEDDERR_SURFACEBUSY;
950 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
951 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
952 FIXME("Filters not supported in software blit\n");
955 /* First check for the validity of source / destination rectangles.
956 * This was verified using a test application + by MSDN. */
958 if (SrcRect)
960 if (src)
962 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
963 || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
964 || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
965 || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
966 || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
968 WARN("Application gave us bad source rectangle for Blt.\n");
969 return WINEDDERR_INVALIDRECT;
972 if (!SrcRect->right || !SrcRect->bottom
973 || SrcRect->left == (int)src->currentDesc.Width
974 || SrcRect->top == (int)src->currentDesc.Height)
976 TRACE("Nothing to be done.\n");
977 return WINED3D_OK;
981 xsrc = *SrcRect;
983 else if (src)
985 xsrc.left = 0;
986 xsrc.top = 0;
987 xsrc.right = src->currentDesc.Width;
988 xsrc.bottom = src->currentDesc.Height;
990 else
992 memset(&xsrc, 0, sizeof(xsrc));
995 if (DestRect)
997 /* For the Destination rect, it can be out of bounds on the condition
998 * that a clipper is set for the given surface. */
999 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1000 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
1001 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1002 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1003 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1005 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1006 return WINEDDERR_INVALIDRECT;
1009 if (DestRect->right <= 0 || DestRect->bottom <= 0
1010 || DestRect->left >= (int)This->currentDesc.Width
1011 || DestRect->top >= (int)This->currentDesc.Height)
1013 TRACE("Nothing to be done.\n");
1014 return WINED3D_OK;
1017 if (!src)
1019 RECT full_rect;
1021 full_rect.left = 0;
1022 full_rect.top = 0;
1023 full_rect.right = This->currentDesc.Width;
1024 full_rect.bottom = This->currentDesc.Height;
1025 IntersectRect(&xdst, &full_rect, DestRect);
1027 else
1029 BOOL clip_horiz, clip_vert;
1031 xdst = *DestRect;
1032 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1033 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1035 if (clip_vert || clip_horiz)
1037 /* Now check if this is a special case or not... */
1038 if ((Flags & WINEDDBLT_DDFX)
1039 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1040 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1042 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1043 return WINED3D_OK;
1046 if (clip_horiz)
1048 if (xdst.left < 0)
1050 xsrc.left -= xdst.left;
1051 xdst.left = 0;
1053 if (xdst.right > This->currentDesc.Width)
1055 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1056 xdst.right = (int)This->currentDesc.Width;
1060 if (clip_vert)
1062 if (xdst.top < 0)
1064 xsrc.top -= xdst.top;
1065 xdst.top = 0;
1067 if (xdst.bottom > This->currentDesc.Height)
1069 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1070 xdst.bottom = (int)This->currentDesc.Height;
1074 /* And check if after clipping something is still to be done... */
1075 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1076 || (xdst.left >= (int)This->currentDesc.Width)
1077 || (xdst.top >= (int)This->currentDesc.Height)
1078 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1079 || (xsrc.left >= (int)src->currentDesc.Width)
1080 || (xsrc.top >= (int)src->currentDesc.Height))
1082 TRACE("Nothing to be done after clipping.\n");
1083 return WINED3D_OK;
1088 else
1090 xdst.left = 0;
1091 xdst.top = 0;
1092 xdst.right = This->currentDesc.Width;
1093 xdst.bottom = This->currentDesc.Height;
1096 if (src == This)
1098 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1099 slock = dlock;
1100 sEntry = This->resource.format;
1101 dEntry = sEntry;
1103 else
1105 dEntry = This->resource.format;
1106 if (src)
1108 if (This->resource.format->id != src->resource.format->id)
1110 src = surface_convert_format(src, dEntry->id);
1111 if (!src)
1113 /* The conv function writes a FIXME */
1114 WARN("Cannot convert source surface format to dest format\n");
1115 goto release;
1118 IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1119 sEntry = src->resource.format;
1121 else
1123 sEntry = dEntry;
1125 if (DestRect)
1126 IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
1127 else
1128 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1131 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1133 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1135 if (!DestRect || src == This)
1137 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1138 goto release;
1142 bpp = This->resource.format->byte_count;
1143 srcheight = xsrc.bottom - xsrc.top;
1144 srcwidth = xsrc.right - xsrc.left;
1145 dstheight = xdst.bottom - xdst.top;
1146 dstwidth = xdst.right - xdst.left;
1147 width = (xdst.right - xdst.left) * bpp;
1149 if (DestRect && src != This)
1150 dbuf = dlock.pBits;
1151 else
1152 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1154 if (Flags & WINEDDBLT_WAIT)
1156 Flags &= ~WINEDDBLT_WAIT;
1158 if (Flags & WINEDDBLT_ASYNC)
1160 static BOOL displayed = FALSE;
1161 if (!displayed)
1162 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1163 displayed = TRUE;
1164 Flags &= ~WINEDDBLT_ASYNC;
1166 if (Flags & WINEDDBLT_DONOTWAIT)
1168 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1169 static BOOL displayed = FALSE;
1170 if (!displayed)
1171 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1172 displayed = TRUE;
1173 Flags &= ~WINEDDBLT_DONOTWAIT;
1176 /* First, all the 'source-less' blits */
1177 if (Flags & WINEDDBLT_COLORFILL)
1179 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1180 dlock.Pitch, DDBltFx->u5.dwFillColor);
1181 Flags &= ~WINEDDBLT_COLORFILL;
1184 if (Flags & WINEDDBLT_DEPTHFILL)
1186 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1188 if (Flags & WINEDDBLT_ROP)
1190 /* Catch some degenerate cases here */
1191 switch(DDBltFx->dwROP)
1193 case BLACKNESS:
1194 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1195 break;
1196 case 0xAA0029: /* No-op */
1197 break;
1198 case WHITENESS:
1199 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1200 break;
1201 case SRCCOPY: /* well, we do that below ? */
1202 break;
1203 default:
1204 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1205 goto error;
1207 Flags &= ~WINEDDBLT_ROP;
1209 if (Flags & WINEDDBLT_DDROPS)
1211 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1213 /* Now the 'with source' blits */
1214 if (src)
1216 const BYTE *sbase;
1217 int sx, xinc, sy, yinc;
1219 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1220 goto release;
1221 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1222 xinc = (srcwidth << 16) / dstwidth;
1223 yinc = (srcheight << 16) / dstheight;
1225 if (!Flags)
1227 /* No effects, we can cheat here */
1228 if (dstwidth == srcwidth)
1230 if (dstheight == srcheight)
1232 /* No stretching in either direction. This needs to be as
1233 * fast as possible */
1234 sbuf = sbase;
1236 /* check for overlapping surfaces */
1237 if (src != This || xdst.top < xsrc.top ||
1238 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1240 /* no overlap, or dst above src, so copy from top downwards */
1241 for (y = 0; y < dstheight; y++)
1243 memcpy(dbuf, sbuf, width);
1244 sbuf += slock.Pitch;
1245 dbuf += dlock.Pitch;
1248 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1250 sbuf += (slock.Pitch*dstheight);
1251 dbuf += (dlock.Pitch*dstheight);
1252 for (y = 0; y < dstheight; y++)
1254 sbuf -= slock.Pitch;
1255 dbuf -= dlock.Pitch;
1256 memcpy(dbuf, sbuf, width);
1259 else /* src and dst overlapping on the same line, use memmove */
1261 for (y = 0; y < dstheight; y++)
1263 memmove(dbuf, sbuf, width);
1264 sbuf += slock.Pitch;
1265 dbuf += dlock.Pitch;
1268 } else {
1269 /* Stretching in Y direction only */
1270 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1271 sbuf = sbase + (sy >> 16) * slock.Pitch;
1272 memcpy(dbuf, sbuf, width);
1273 dbuf += dlock.Pitch;
1277 else
1279 /* Stretching in X direction */
1280 int last_sy = -1;
1281 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1283 sbuf = sbase + (sy >> 16) * slock.Pitch;
1285 if ((sy >> 16) == (last_sy >> 16))
1287 /* this sourcerow is the same as last sourcerow -
1288 * copy already stretched row
1290 memcpy(dbuf, dbuf - dlock.Pitch, width);
1292 else
1294 #define STRETCH_ROW(type) { \
1295 const type *s = (const type *)sbuf; \
1296 type *d = (type *)dbuf; \
1297 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1298 d[x] = s[sx >> 16]; \
1299 break; }
1301 switch(bpp)
1303 case 1: STRETCH_ROW(BYTE)
1304 case 2: STRETCH_ROW(WORD)
1305 case 4: STRETCH_ROW(DWORD)
1306 case 3:
1308 const BYTE *s;
1309 BYTE *d = dbuf;
1310 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1312 DWORD pixel;
1314 s = sbuf+3*(sx>>16);
1315 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1316 d[0] = (pixel )&0xff;
1317 d[1] = (pixel>> 8)&0xff;
1318 d[2] = (pixel>>16)&0xff;
1319 d+=3;
1321 break;
1323 default:
1324 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1325 ret = WINED3DERR_NOTAVAILABLE;
1326 goto error;
1328 #undef STRETCH_ROW
1330 dbuf += dlock.Pitch;
1331 last_sy = sy;
1335 else
1337 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1338 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1339 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1340 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1342 /* The color keying flags are checked for correctness in ddraw */
1343 if (Flags & WINEDDBLT_KEYSRC)
1345 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1346 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1348 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1350 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1351 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1354 if (Flags & WINEDDBLT_KEYDEST)
1356 /* Destination color keys are taken from the source surface ! */
1357 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1358 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1360 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1362 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1363 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1366 if(bpp == 1)
1368 keymask = 0xff;
1370 else
1372 keymask = sEntry->red_mask
1373 | sEntry->green_mask
1374 | sEntry->blue_mask;
1376 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1379 if (Flags & WINEDDBLT_DDFX)
1381 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1382 LONG tmpxy;
1383 dTopLeft = dbuf;
1384 dTopRight = dbuf+((dstwidth-1)*bpp);
1385 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1386 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1388 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1390 /* I don't think we need to do anything about this flag */
1391 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1393 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1395 tmp = dTopRight;
1396 dTopRight = dTopLeft;
1397 dTopLeft = tmp;
1398 tmp = dBottomRight;
1399 dBottomRight = dBottomLeft;
1400 dBottomLeft = tmp;
1401 dstxinc = dstxinc *-1;
1403 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1405 tmp = dTopLeft;
1406 dTopLeft = dBottomLeft;
1407 dBottomLeft = tmp;
1408 tmp = dTopRight;
1409 dTopRight = dBottomRight;
1410 dBottomRight = tmp;
1411 dstyinc = dstyinc *-1;
1413 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1415 /* I don't think we need to do anything about this flag */
1416 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1418 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1420 tmp = dBottomRight;
1421 dBottomRight = dTopLeft;
1422 dTopLeft = tmp;
1423 tmp = dBottomLeft;
1424 dBottomLeft = dTopRight;
1425 dTopRight = tmp;
1426 dstxinc = dstxinc * -1;
1427 dstyinc = dstyinc * -1;
1429 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1431 tmp = dTopLeft;
1432 dTopLeft = dBottomLeft;
1433 dBottomLeft = dBottomRight;
1434 dBottomRight = dTopRight;
1435 dTopRight = tmp;
1436 tmpxy = dstxinc;
1437 dstxinc = dstyinc;
1438 dstyinc = tmpxy;
1439 dstxinc = dstxinc * -1;
1441 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1443 tmp = dTopLeft;
1444 dTopLeft = dTopRight;
1445 dTopRight = dBottomRight;
1446 dBottomRight = dBottomLeft;
1447 dBottomLeft = tmp;
1448 tmpxy = dstxinc;
1449 dstxinc = dstyinc;
1450 dstyinc = tmpxy;
1451 dstyinc = dstyinc * -1;
1453 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1455 /* I don't think we need to do anything about this flag */
1456 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1458 dbuf = dTopLeft;
1459 Flags &= ~(WINEDDBLT_DDFX);
1462 #define COPY_COLORKEY_FX(type) { \
1463 const type *s; \
1464 type *d = (type *)dbuf, *dx, tmp; \
1465 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1466 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1467 dx = d; \
1468 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1469 tmp = s[sx >> 16]; \
1470 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1471 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1472 dx[0] = tmp; \
1474 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1476 d = (type*)(((LPBYTE)d)+dstyinc); \
1478 break; }
1480 switch (bpp) {
1481 case 1: COPY_COLORKEY_FX(BYTE)
1482 case 2: COPY_COLORKEY_FX(WORD)
1483 case 4: COPY_COLORKEY_FX(DWORD)
1484 case 3:
1486 const BYTE *s;
1487 BYTE *d = dbuf, *dx;
1488 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1490 sbuf = sbase + (sy >> 16) * slock.Pitch;
1491 dx = d;
1492 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1494 DWORD pixel, dpixel = 0;
1495 s = sbuf+3*(sx>>16);
1496 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1497 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1498 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1499 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1501 dx[0] = (pixel )&0xff;
1502 dx[1] = (pixel>> 8)&0xff;
1503 dx[2] = (pixel>>16)&0xff;
1505 dx+= dstxinc;
1507 d += dstyinc;
1509 break;
1511 default:
1512 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1513 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1514 ret = WINED3DERR_NOTAVAILABLE;
1515 goto error;
1516 #undef COPY_COLORKEY_FX
1521 error:
1522 if (Flags && FIXME_ON(d3d_surface))
1524 FIXME("\tUnsupported flags: %08x\n", Flags);
1527 release:
1528 IWineD3DSurface_Unmap(iface);
1529 if (src && src != This) IWineD3DSurface_Unmap((IWineD3DSurface *)src);
1530 /* Release the converted surface if any */
1531 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1532 return ret;
1535 /*****************************************************************************
1536 * IWineD3DSurface::BltFast, SW emulation version
1538 * This is the software implementation of BltFast, as used by GDI surfaces
1539 * and as a fallback for OpenGL surfaces. This code is taken from the old
1540 * DirectDraw code, and was originally written by TransGaming.
1542 * Params:
1543 * dstx:
1544 * dsty:
1545 * src_surface: Source surface to copy from
1546 * rsrc: Source rectangle
1547 * trans: Some Flags
1549 * Returns:
1550 * WINED3D_OK on success
1552 *****************************************************************************/
1553 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1554 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1556 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1557 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1559 int bpp, w, h, x, y;
1560 WINED3DLOCKED_RECT dlock,slock;
1561 HRESULT ret = WINED3D_OK;
1562 RECT rsrc2;
1563 RECT lock_src, lock_dst, lock_union;
1564 const BYTE *sbuf;
1565 BYTE *dbuf;
1566 const struct wined3d_format *sEntry, *dEntry;
1568 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1569 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1571 if ((This->Flags & SFLAG_LOCKED) || (src->Flags & SFLAG_LOCKED))
1573 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1574 return WINEDDERR_SURFACEBUSY;
1577 if (!rsrc)
1579 WARN("rsrc is NULL!\n");
1580 rsrc2.left = 0;
1581 rsrc2.top = 0;
1582 rsrc2.right = src->currentDesc.Width;
1583 rsrc2.bottom = src->currentDesc.Height;
1584 rsrc = &rsrc2;
1587 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1588 if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1589 || (rsrc->top > src->currentDesc.Height) || (rsrc->top < 0)
1590 || (rsrc->left > src->currentDesc.Width) || (rsrc->left < 0)
1591 || (rsrc->right > src->currentDesc.Width) || (rsrc->right < 0)
1592 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1594 WARN("Application gave us bad source rectangle for BltFast.\n");
1595 return WINEDDERR_INVALIDRECT;
1598 h = rsrc->bottom - rsrc->top;
1599 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1600 if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1601 if (h <= 0) return WINEDDERR_INVALIDRECT;
1603 w = rsrc->right - rsrc->left;
1604 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1605 if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1606 if (w <= 0) return WINEDDERR_INVALIDRECT;
1608 /* Now compute the locking rectangle... */
1609 lock_src.left = rsrc->left;
1610 lock_src.top = rsrc->top;
1611 lock_src.right = lock_src.left + w;
1612 lock_src.bottom = lock_src.top + h;
1614 lock_dst.left = dstx;
1615 lock_dst.top = dsty;
1616 lock_dst.right = dstx + w;
1617 lock_dst.bottom = dsty + h;
1619 bpp = This->resource.format->byte_count;
1621 /* We need to lock the surfaces, or we won't get refreshes when done. */
1622 if (src == This)
1624 int pitch;
1626 UnionRect(&lock_union, &lock_src, &lock_dst);
1628 /* Lock the union of the two rectangles */
1629 ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
1630 if (FAILED(ret)) goto error;
1632 pitch = dlock.Pitch;
1633 slock.Pitch = dlock.Pitch;
1635 /* Since slock was originally copied from this surface's description, we can just reuse it */
1636 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1637 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1638 sEntry = src->resource.format;
1639 dEntry = sEntry;
1641 else
1643 ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1644 if (FAILED(ret)) goto error;
1645 ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
1646 if (FAILED(ret)) goto error;
1648 sbuf = slock.pBits;
1649 dbuf = dlock.pBits;
1650 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1652 sEntry = src->resource.format;
1653 dEntry = This->resource.format;
1656 /* Handle compressed surfaces first... */
1657 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1659 UINT row_block_count;
1661 TRACE("compressed -> compressed copy\n");
1662 if (trans)
1663 FIXME("trans arg not supported when a compressed surface is involved\n");
1664 if (dstx || dsty)
1665 FIXME("offset for destination surface is not supported\n");
1666 if (src->resource.format->id != This->resource.format->id)
1668 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1669 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1670 goto error;
1673 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1674 for (y = 0; y < h; y += dEntry->block_height)
1676 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1677 dbuf += dlock.Pitch;
1678 sbuf += slock.Pitch;
1681 goto error;
1683 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1685 /* TODO: Use the libtxc_dxtn.so shared library to do
1686 * software decompression
1688 ERR("Software decompression not supported.\n");
1689 goto error;
1692 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1694 DWORD keylow, keyhigh;
1695 DWORD mask = src->resource.format->red_mask
1696 | src->resource.format->green_mask
1697 | src->resource.format->blue_mask;
1699 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1700 if(!mask && bpp==1)
1701 mask = 0xff;
1703 TRACE("Color keyed copy\n");
1704 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1706 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1707 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1709 else
1711 /* I'm not sure if this is correct */
1712 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1713 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1714 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1717 #define COPYBOX_COLORKEY(type) { \
1718 const type *s = (const type *)sbuf; \
1719 type *d = (type *)dbuf; \
1720 type tmp; \
1721 for (y = 0; y < h; y++) { \
1722 for (x = 0; x < w; x++) { \
1723 tmp = s[x]; \
1724 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1726 s = (const type *)((const BYTE *)s + slock.Pitch); \
1727 d = (type *)((BYTE *)d + dlock.Pitch); \
1729 break; \
1732 switch (bpp) {
1733 case 1: COPYBOX_COLORKEY(BYTE)
1734 case 2: COPYBOX_COLORKEY(WORD)
1735 case 4: COPYBOX_COLORKEY(DWORD)
1736 case 3:
1738 const BYTE *s;
1739 BYTE *d;
1740 DWORD tmp;
1741 s = sbuf;
1742 d = dbuf;
1743 for (y = 0; y < h; y++)
1745 for (x = 0; x < w * 3; x += 3)
1747 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1748 if (tmp < keylow || tmp > keyhigh)
1750 d[x + 0] = s[x + 0];
1751 d[x + 1] = s[x + 1];
1752 d[x + 2] = s[x + 2];
1755 s += slock.Pitch;
1756 d += dlock.Pitch;
1758 break;
1760 default:
1761 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1762 ret = WINED3DERR_NOTAVAILABLE;
1763 goto error;
1765 #undef COPYBOX_COLORKEY
1766 TRACE("Copy Done\n");
1768 else
1770 int width = w * bpp;
1771 INT sbufpitch, dbufpitch;
1773 TRACE("NO color key copy\n");
1774 /* Handle overlapping surfaces */
1775 if (sbuf < dbuf)
1777 sbuf += (h - 1) * slock.Pitch;
1778 dbuf += (h - 1) * dlock.Pitch;
1779 sbufpitch = -slock.Pitch;
1780 dbufpitch = -dlock.Pitch;
1782 else
1784 sbufpitch = slock.Pitch;
1785 dbufpitch = dlock.Pitch;
1787 for (y = 0; y < h; y++)
1789 /* This is pretty easy, a line for line memcpy */
1790 memmove(dbuf, sbuf, width);
1791 sbuf += sbufpitch;
1792 dbuf += dbufpitch;
1794 TRACE("Copy done\n");
1797 error:
1798 if (src == This)
1800 IWineD3DSurface_Unmap(iface);
1802 else
1804 IWineD3DSurface_Unmap(iface);
1805 IWineD3DSurface_Unmap(src_surface);
1808 return ret;
1811 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
1812 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags)
1814 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1816 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1817 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1819 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1821 if (!pRect)
1823 pLockedRect->pBits = This->resource.allocatedMemory;
1824 This->lockedRect.left = 0;
1825 This->lockedRect.top = 0;
1826 This->lockedRect.right = This->currentDesc.Width;
1827 This->lockedRect.bottom = This->currentDesc.Height;
1829 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1830 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1831 This->lockedRect.right, This->lockedRect.bottom);
1833 else
1835 const struct wined3d_format *format = This->resource.format;
1837 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1838 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1840 if ((format->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1842 /* Compressed textures are block based, so calculate the offset of
1843 * the block that contains the top-left pixel of the locked rectangle. */
1844 pLockedRect->pBits = This->resource.allocatedMemory
1845 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1846 + ((pRect->left / format->block_width) * format->block_byte_count);
1848 else
1850 pLockedRect->pBits = This->resource.allocatedMemory +
1851 (pLockedRect->Pitch * pRect->top) +
1852 (pRect->left * format->byte_count);
1854 This->lockedRect.left = pRect->left;
1855 This->lockedRect.top = pRect->top;
1856 This->lockedRect.right = pRect->right;
1857 This->lockedRect.bottom = pRect->bottom;
1860 /* No dirtifying is needed for this surface implementation */
1861 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1863 return WINED3D_OK;
1866 /* TODO: think about moving this down to resource? */
1867 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1869 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1871 /* This should only be called for sysmem textures, it may be a good idea
1872 * to extend this to all pools at some point in the future */
1873 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1875 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1877 return This->resource.allocatedMemory;