wined3d: Store an IWineD3DClipperImpl pointer in IWineD3DSurfaceImpl.
[wine.git] / dlls / wined3d / surface_base.c
blob4449bf03d738c396e00476d141bcd096e0e40c4a
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, IWineD3DPalette *Pal) {
220 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
221 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
222 TRACE("(%p)->(%p)\n", This, Pal);
224 if(This->palette == PalImpl) {
225 TRACE("Nop palette change\n");
226 return WINED3D_OK;
229 if (This->palette)
230 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
231 This->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
233 This->palette = PalImpl;
235 if (PalImpl)
237 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
238 PalImpl->flags |= WINEDDPCAPS_PRIMARYSURFACE;
240 return IWineD3DSurface_RealizePalette(iface);
242 else return WINED3D_OK;
245 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD flags, const WINEDDCOLORKEY *CKey)
247 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
249 TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, CKey);
251 if (flags & WINEDDCKEY_COLORSPACE)
253 FIXME(" colorkey value not supported (%08x) !\n", flags);
254 return WINED3DERR_INVALIDCALL;
257 /* Dirtify the surface, but only if a key was changed */
258 if (CKey)
260 switch (flags & ~WINEDDCKEY_COLORSPACE)
262 case WINEDDCKEY_DESTBLT:
263 This->DestBltCKey = *CKey;
264 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
265 break;
267 case WINEDDCKEY_DESTOVERLAY:
268 This->DestOverlayCKey = *CKey;
269 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
270 break;
272 case WINEDDCKEY_SRCOVERLAY:
273 This->SrcOverlayCKey = *CKey;
274 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
275 break;
277 case WINEDDCKEY_SRCBLT:
278 This->SrcBltCKey = *CKey;
279 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
280 break;
283 else
285 switch (flags & ~WINEDDCKEY_COLORSPACE)
287 case WINEDDCKEY_DESTBLT:
288 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
289 break;
291 case WINEDDCKEY_DESTOVERLAY:
292 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
293 break;
295 case WINEDDCKEY_SRCOVERLAY:
296 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
297 break;
299 case WINEDDCKEY_SRCBLT:
300 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
301 break;
305 return WINED3D_OK;
308 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
309 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
310 TRACE("(%p)->(%p)\n", This, Pal);
312 *Pal = (IWineD3DPalette *) This->palette;
313 return WINED3D_OK;
316 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
318 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
319 const struct wined3d_format *format = This->resource.format;
320 DWORD ret;
321 TRACE("(%p)\n", This);
323 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
325 /* Since compressed formats are block based, pitch means the amount of
326 * bytes to the next row of block rather than the next row of pixels. */
327 UINT row_block_count = (This->currentDesc.Width + format->block_width - 1) / format->block_width;
328 ret = row_block_count * format->block_byte_count;
330 else
332 unsigned char alignment = This->resource.device->surface_alignment;
333 ret = This->resource.format->byte_count * This->currentDesc.Width; /* Bytes / row */
334 ret = (ret + alignment - 1) & ~(alignment - 1);
336 TRACE("(%p) Returning %d\n", This, ret);
337 return ret;
340 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
341 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
342 LONG w, h;
344 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
346 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
348 TRACE("(%p): Not an overlay surface\n", This);
349 return WINEDDERR_NOTAOVERLAYSURFACE;
352 w = This->overlay_destrect.right - This->overlay_destrect.left;
353 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
354 This->overlay_destrect.left = X;
355 This->overlay_destrect.top = Y;
356 This->overlay_destrect.right = X + w;
357 This->overlay_destrect.bottom = Y + h;
359 IWineD3DSurface_DrawOverlay(iface);
361 return WINED3D_OK;
364 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
365 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
366 HRESULT hr;
368 TRACE("(%p)->(%p,%p)\n", This, X, Y);
370 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
372 TRACE("(%p): Not an overlay surface\n", This);
373 return WINEDDERR_NOTAOVERLAYSURFACE;
376 if (!This->overlay_dest)
378 *X = 0; *Y = 0;
379 hr = WINEDDERR_OVERLAYNOTVISIBLE;
380 } else {
381 *X = This->overlay_destrect.left;
382 *Y = This->overlay_destrect.top;
383 hr = WINED3D_OK;
386 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
387 return hr;
390 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD flags, IWineD3DSurface *Ref)
392 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
394 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, flags, Ref);
396 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
398 TRACE("(%p): Not an overlay surface\n", This);
399 return WINEDDERR_NOTAOVERLAYSURFACE;
402 return WINED3D_OK;
405 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
406 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD flags, const WINEDDOVERLAYFX *FX)
408 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
409 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
411 TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
412 iface, wine_dbgstr_rect(SrcRect), DstSurface, wine_dbgstr_rect(DstRect), flags, FX);
414 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
416 WARN("(%p): Not an overlay surface\n", This);
417 return WINEDDERR_NOTAOVERLAYSURFACE;
418 } else if(!DstSurface) {
419 WARN("(%p): Dest surface is NULL\n", This);
420 return WINED3DERR_INVALIDCALL;
423 if(SrcRect) {
424 This->overlay_srcrect = *SrcRect;
425 } else {
426 This->overlay_srcrect.left = 0;
427 This->overlay_srcrect.top = 0;
428 This->overlay_srcrect.right = This->currentDesc.Width;
429 This->overlay_srcrect.bottom = This->currentDesc.Height;
432 if(DstRect) {
433 This->overlay_destrect = *DstRect;
434 } else {
435 This->overlay_destrect.left = 0;
436 This->overlay_destrect.top = 0;
437 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
438 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
441 if (This->overlay_dest && (This->overlay_dest != Dst || flags & WINEDDOVER_HIDE))
443 list_remove(&This->overlay_entry);
446 if (flags & WINEDDOVER_SHOW)
448 if (This->overlay_dest != Dst)
450 This->overlay_dest = Dst;
451 list_add_tail(&Dst->overlays, &This->overlay_entry);
454 else if (flags & WINEDDOVER_HIDE)
456 /* tests show that the rectangles are erased on hide */
457 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
458 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
459 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
460 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
461 This->overlay_dest = NULL;
464 IWineD3DSurface_DrawOverlay(iface);
466 return WINED3D_OK;
469 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
471 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
472 TRACE("(%p)->(%p)\n", This, clipper);
474 This->clipper = (IWineD3DClipperImpl *)clipper;
475 return WINED3D_OK;
478 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
480 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
481 TRACE("(%p)->(%p)\n", This, clipper);
483 *clipper = (IWineD3DClipper *)This->clipper;
484 if (*clipper)
485 IWineD3DClipper_AddRef(*clipper);
487 return WINED3D_OK;
490 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
492 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
493 const struct wined3d_format *format = wined3d_get_format(&This->resource.device->adapter->gl_info, format_id);
495 if (This->resource.format->id != WINED3DFMT_UNKNOWN)
497 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
498 return WINED3DERR_INVALIDCALL;
501 TRACE("(%p) : Setting texture format to %s (%#x).\n", This, debug_d3dformat(format_id), format_id);
503 This->resource.size = wined3d_format_calculate_size(format, This->resource.device->surface_alignment,
504 This->pow2Width, This->pow2Height);
506 This->flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
508 This->resource.format = format;
510 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format->byte_count);
512 return WINED3D_OK;
515 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface)
517 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
518 const struct wined3d_format *format = This->resource.format;
519 int extraline = 0;
520 SYSTEM_INFO sysInfo;
521 BITMAPINFO* b_info;
522 HDC ddc;
523 DWORD *masks;
524 UINT usage;
526 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
528 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format->id));
529 return WINED3DERR_INVALIDCALL;
532 switch (format->byte_count)
534 case 2:
535 case 4:
536 /* Allocate extra space to store the RGB bit masks. */
537 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
538 break;
540 case 3:
541 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
542 break;
544 default:
545 /* Allocate extra space for a palette. */
546 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
547 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
548 break;
551 if (!b_info)
552 return E_OUTOFMEMORY;
554 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
555 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
556 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
557 * add an extra line to the dib section
559 GetSystemInfo(&sysInfo);
560 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
561 extraline = 1;
562 TRACE("Adding an extra line to the dib section\n");
565 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
566 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
567 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format->byte_count;
568 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
569 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
570 b_info->bmiHeader.biPlanes = 1;
571 b_info->bmiHeader.biBitCount = format->byte_count * 8;
573 b_info->bmiHeader.biXPelsPerMeter = 0;
574 b_info->bmiHeader.biYPelsPerMeter = 0;
575 b_info->bmiHeader.biClrUsed = 0;
576 b_info->bmiHeader.biClrImportant = 0;
578 /* Get the bit masks */
579 masks = (DWORD *)b_info->bmiColors;
580 switch (This->resource.format->id)
582 case WINED3DFMT_B8G8R8_UNORM:
583 usage = DIB_RGB_COLORS;
584 b_info->bmiHeader.biCompression = BI_RGB;
585 break;
587 case WINED3DFMT_B5G5R5X1_UNORM:
588 case WINED3DFMT_B5G5R5A1_UNORM:
589 case WINED3DFMT_B4G4R4A4_UNORM:
590 case WINED3DFMT_B4G4R4X4_UNORM:
591 case WINED3DFMT_B2G3R3_UNORM:
592 case WINED3DFMT_B2G3R3A8_UNORM:
593 case WINED3DFMT_R10G10B10A2_UNORM:
594 case WINED3DFMT_R8G8B8A8_UNORM:
595 case WINED3DFMT_R8G8B8X8_UNORM:
596 case WINED3DFMT_B10G10R10A2_UNORM:
597 case WINED3DFMT_B5G6R5_UNORM:
598 case WINED3DFMT_R16G16B16A16_UNORM:
599 usage = 0;
600 b_info->bmiHeader.biCompression = BI_BITFIELDS;
601 masks[0] = format->red_mask;
602 masks[1] = format->green_mask;
603 masks[2] = format->blue_mask;
604 break;
606 default:
607 /* Don't know palette */
608 b_info->bmiHeader.biCompression = BI_RGB;
609 usage = 0;
610 break;
613 if (!(ddc = GetDC(0)))
615 HeapFree(GetProcessHeap(), 0, b_info);
616 return HRESULT_FROM_WIN32(GetLastError());
619 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);
620 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
621 ReleaseDC(0, ddc);
623 if (!This->dib.DIBsection) {
624 ERR("CreateDIBSection failed!\n");
625 HeapFree(GetProcessHeap(), 0, b_info);
626 return HRESULT_FROM_WIN32(GetLastError());
629 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
630 /* copy the existing surface to the dib section */
631 if(This->resource.allocatedMemory) {
632 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
633 } else {
634 /* This is to make LockRect read the gl Texture although memory is allocated */
635 This->flags &= ~SFLAG_INSYSMEM;
637 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
639 HeapFree(GetProcessHeap(), 0, b_info);
641 /* Now allocate a HDC */
642 This->hDC = CreateCompatibleDC(0);
643 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
644 TRACE("using wined3d palette %p\n", This->palette);
645 SelectPalette(This->hDC,
646 This->palette ? This->palette->hpal : 0,
647 FALSE);
649 This->flags |= SFLAG_DIBSECTION;
651 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
652 This->resource.heapMemory = NULL;
654 return WINED3D_OK;
657 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
658 unsigned int w, unsigned int h)
660 unsigned int x, y;
661 const float *src_f;
662 unsigned short *dst_s;
664 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
665 for(y = 0; y < h; y++) {
666 src_f = (const float *)(src + y * pitch_in);
667 dst_s = (unsigned short *) (dst + y * pitch_out);
668 for(x = 0; x < w; x++) {
669 dst_s[x] = float_32_to_16(src_f + x);
674 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
675 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
677 static const unsigned char convert_5to8[] =
679 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
680 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
681 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
682 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
684 static const unsigned char convert_6to8[] =
686 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
687 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
688 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
689 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
690 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
691 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
692 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
693 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
695 unsigned int x, y;
697 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
699 for (y = 0; y < h; ++y)
701 const WORD *src_line = (const WORD *)(src + y * pitch_in);
702 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
703 for (x = 0; x < w; ++x)
705 WORD pixel = src_line[x];
706 dst_line[x] = 0xff000000
707 | convert_5to8[(pixel & 0xf800) >> 11] << 16
708 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
709 | convert_5to8[(pixel & 0x001f)];
714 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
715 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
717 unsigned int x, y;
719 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
721 for (y = 0; y < h; ++y)
723 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
724 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
726 for (x = 0; x < w; ++x)
728 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
733 static inline BYTE cliptobyte(int x)
735 return (BYTE) ((x < 0) ? 0 : ((x > 255) ? 255 : x));
738 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
739 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
741 unsigned int x, y;
742 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
744 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
746 for (y = 0; y < h; ++y)
748 const BYTE *src_line = src + y * pitch_in;
749 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
750 for (x = 0; x < w; ++x)
752 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
753 * C = Y - 16; D = U - 128; E = V - 128;
754 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
755 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
756 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
757 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
758 * U and V are shared between the pixels.
760 if (!(x & 1)) /* for every even pixel, read new U and V */
762 d = (int) src_line[1] - 128;
763 e = (int) src_line[3] - 128;
764 r2 = 409 * e + 128;
765 g2 = - 100 * d - 208 * e + 128;
766 b2 = 516 * d + 128;
768 c2 = 298 * ((int) src_line[0] - 16);
769 dst_line[x] = 0xff000000
770 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
771 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
772 | cliptobyte((c2 + b2) >> 8); /* blue */
773 /* Scale RGB values to 0..255 range,
774 * then clip them if still not in range (may be negative),
775 * then shift them within DWORD if necessary.
777 src_line += 2;
782 struct d3dfmt_convertor_desc
784 enum wined3d_format_id from, to;
785 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
788 static const struct d3dfmt_convertor_desc convertors[] =
790 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
791 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
792 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
793 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
796 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from, enum wined3d_format_id to)
798 unsigned int i;
799 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
800 if(convertors[i].from == from && convertors[i].to == to) {
801 return &convertors[i];
804 return NULL;
807 /*****************************************************************************
808 * surface_convert_format
810 * Creates a duplicate of a surface in a different format. Is used by Blt to
811 * blit between surfaces with different formats
813 * Parameters
814 * source: Source surface
815 * fmt: Requested destination format
817 *****************************************************************************/
818 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
820 IWineD3DSurface *ret = NULL;
821 const struct d3dfmt_convertor_desc *conv;
822 WINED3DLOCKED_RECT lock_src, lock_dst;
823 HRESULT hr;
825 conv = find_convertor(source->resource.format->id, to_fmt);
826 if (!conv)
828 FIXME("Cannot find a conversion function from format %s to %s.\n",
829 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
830 return NULL;
833 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
834 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
835 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
836 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
837 NULL /* parent */, &wined3d_null_parent_ops, &ret);
838 if(!ret) {
839 ERR("Failed to create a destination surface for conversion\n");
840 return NULL;
843 memset(&lock_src, 0, sizeof(lock_src));
844 memset(&lock_dst, 0, sizeof(lock_dst));
846 hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
847 if (FAILED(hr))
849 ERR("Failed to lock the source surface.\n");
850 IWineD3DSurface_Release(ret);
851 return NULL;
853 hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
854 if (FAILED(hr))
856 ERR("Failed to lock the dest surface\n");
857 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
858 IWineD3DSurface_Release(ret);
859 return NULL;
862 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
863 source->currentDesc.Width, source->currentDesc.Height);
865 IWineD3DSurface_Unmap(ret);
866 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
868 return (IWineD3DSurfaceImpl *) ret;
871 /*****************************************************************************
872 * _Blt_ColorFill
874 * Helper function that fills a memory area with a specific color
876 * Params:
877 * buf: memory address to start filling at
878 * width, height: Dimensions of the area to fill
879 * bpp: Bit depth of the surface
880 * lPitch: pitch of the surface
881 * color: Color to fill with
883 *****************************************************************************/
884 static HRESULT
885 _Blt_ColorFill(BYTE *buf,
886 int width, int height,
887 int bpp, LONG lPitch,
888 DWORD color)
890 int x, y;
891 LPBYTE first;
893 /* Do first row */
895 #define COLORFILL_ROW(type) \
897 type *d = (type *) buf; \
898 for (x = 0; x < width; x++) \
899 d[x] = (type) color; \
900 break; \
902 switch(bpp)
904 case 1: COLORFILL_ROW(BYTE)
905 case 2: COLORFILL_ROW(WORD)
906 case 3:
908 BYTE *d = buf;
909 for (x = 0; x < width; x++,d+=3)
911 d[0] = (color ) & 0xFF;
912 d[1] = (color>> 8) & 0xFF;
913 d[2] = (color>>16) & 0xFF;
915 break;
917 case 4: COLORFILL_ROW(DWORD)
918 default:
919 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
920 return WINED3DERR_NOTAVAILABLE;
923 #undef COLORFILL_ROW
925 /* Now copy first row */
926 first = buf;
927 for (y = 1; y < height; y++)
929 buf += lPitch;
930 memcpy(buf, first, width * bpp);
932 return WINED3D_OK;
935 /*****************************************************************************
936 * IWineD3DSurface::Blt, SW emulation version
938 * Performs a blit to a surface, with or without a source surface.
939 * This is the main functionality of DirectDraw
941 * Params:
942 * DestRect: Destination rectangle to write to
943 * src_surface: Source surface, can be NULL
944 * SrcRect: Source rectangle
945 *****************************************************************************/
946 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
947 const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
949 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
950 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
951 RECT xdst,xsrc;
952 HRESULT ret = WINED3D_OK;
953 WINED3DLOCKED_RECT dlock, slock;
954 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
955 const struct wined3d_format *sEntry, *dEntry;
956 int x, y;
957 const BYTE *sbuf;
958 BYTE *dbuf;
960 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
961 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
962 flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
964 if ((This->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
966 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
967 return WINEDDERR_SURFACEBUSY;
970 /* First check for the validity of source / destination rectangles.
971 * This was verified using a test application + by MSDN. */
973 if (SrcRect)
975 if (src)
977 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
978 || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
979 || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
980 || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
981 || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
983 WARN("Application gave us bad source rectangle for Blt.\n");
984 return WINEDDERR_INVALIDRECT;
987 if (!SrcRect->right || !SrcRect->bottom
988 || SrcRect->left == (int)src->currentDesc.Width
989 || SrcRect->top == (int)src->currentDesc.Height)
991 TRACE("Nothing to be done.\n");
992 return WINED3D_OK;
996 xsrc = *SrcRect;
998 else if (src)
1000 xsrc.left = 0;
1001 xsrc.top = 0;
1002 xsrc.right = src->currentDesc.Width;
1003 xsrc.bottom = src->currentDesc.Height;
1005 else
1007 memset(&xsrc, 0, sizeof(xsrc));
1010 if (DestRect)
1012 /* For the Destination rect, it can be out of bounds on the condition
1013 * that a clipper is set for the given surface. */
1014 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
1015 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
1016 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1017 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1018 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1020 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1021 return WINEDDERR_INVALIDRECT;
1024 if (DestRect->right <= 0 || DestRect->bottom <= 0
1025 || DestRect->left >= (int)This->currentDesc.Width
1026 || DestRect->top >= (int)This->currentDesc.Height)
1028 TRACE("Nothing to be done.\n");
1029 return WINED3D_OK;
1032 if (!src)
1034 RECT full_rect;
1036 full_rect.left = 0;
1037 full_rect.top = 0;
1038 full_rect.right = This->currentDesc.Width;
1039 full_rect.bottom = This->currentDesc.Height;
1040 IntersectRect(&xdst, &full_rect, DestRect);
1042 else
1044 BOOL clip_horiz, clip_vert;
1046 xdst = *DestRect;
1047 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1048 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1050 if (clip_vert || clip_horiz)
1052 /* Now check if this is a special case or not... */
1053 if ((flags & WINEDDBLT_DDFX)
1054 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1055 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1057 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1058 return WINED3D_OK;
1061 if (clip_horiz)
1063 if (xdst.left < 0)
1065 xsrc.left -= xdst.left;
1066 xdst.left = 0;
1068 if (xdst.right > This->currentDesc.Width)
1070 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1071 xdst.right = (int)This->currentDesc.Width;
1075 if (clip_vert)
1077 if (xdst.top < 0)
1079 xsrc.top -= xdst.top;
1080 xdst.top = 0;
1082 if (xdst.bottom > This->currentDesc.Height)
1084 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1085 xdst.bottom = (int)This->currentDesc.Height;
1089 /* And check if after clipping something is still to be done... */
1090 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1091 || (xdst.left >= (int)This->currentDesc.Width)
1092 || (xdst.top >= (int)This->currentDesc.Height)
1093 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1094 || (xsrc.left >= (int)src->currentDesc.Width)
1095 || (xsrc.top >= (int)src->currentDesc.Height))
1097 TRACE("Nothing to be done after clipping.\n");
1098 return WINED3D_OK;
1103 else
1105 xdst.left = 0;
1106 xdst.top = 0;
1107 xdst.right = This->currentDesc.Width;
1108 xdst.bottom = This->currentDesc.Height;
1111 if (src == This)
1113 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1114 slock = dlock;
1115 sEntry = This->resource.format;
1116 dEntry = sEntry;
1118 else
1120 dEntry = This->resource.format;
1121 if (src)
1123 if (This->resource.format->id != src->resource.format->id)
1125 src = surface_convert_format(src, dEntry->id);
1126 if (!src)
1128 /* The conv function writes a FIXME */
1129 WARN("Cannot convert source surface format to dest format\n");
1130 goto release;
1133 IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1134 sEntry = src->resource.format;
1136 else
1138 sEntry = dEntry;
1140 if (DestRect)
1141 IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
1142 else
1143 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
1146 if (!DDBltFx || !(DDBltFx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
1148 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_FOURCC)
1150 if (!DestRect || src == This)
1152 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1153 goto release;
1157 bpp = This->resource.format->byte_count;
1158 srcheight = xsrc.bottom - xsrc.top;
1159 srcwidth = xsrc.right - xsrc.left;
1160 dstheight = xdst.bottom - xdst.top;
1161 dstwidth = xdst.right - xdst.left;
1162 width = (xdst.right - xdst.left) * bpp;
1164 if (DestRect && src != This)
1165 dbuf = dlock.pBits;
1166 else
1167 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1169 if (flags & WINEDDBLT_WAIT)
1171 flags &= ~WINEDDBLT_WAIT;
1173 if (flags & WINEDDBLT_ASYNC)
1175 static BOOL displayed = FALSE;
1176 if (!displayed)
1177 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1178 displayed = TRUE;
1179 flags &= ~WINEDDBLT_ASYNC;
1181 if (flags & WINEDDBLT_DONOTWAIT)
1183 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1184 static BOOL displayed = FALSE;
1185 if (!displayed)
1186 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1187 displayed = TRUE;
1188 flags &= ~WINEDDBLT_DONOTWAIT;
1191 /* First, all the 'source-less' blits */
1192 if (flags & WINEDDBLT_COLORFILL)
1194 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1195 dlock.Pitch, DDBltFx->u5.dwFillColor);
1196 flags &= ~WINEDDBLT_COLORFILL;
1199 if (flags & WINEDDBLT_DEPTHFILL)
1201 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1203 if (flags & WINEDDBLT_ROP)
1205 /* Catch some degenerate cases here */
1206 switch(DDBltFx->dwROP)
1208 case BLACKNESS:
1209 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1210 break;
1211 case 0xAA0029: /* No-op */
1212 break;
1213 case WHITENESS:
1214 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1215 break;
1216 case SRCCOPY: /* well, we do that below ? */
1217 break;
1218 default:
1219 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1220 goto error;
1222 flags &= ~WINEDDBLT_ROP;
1224 if (flags & WINEDDBLT_DDROPS)
1226 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1228 /* Now the 'with source' blits */
1229 if (src)
1231 const BYTE *sbase;
1232 int sx, xinc, sy, yinc;
1234 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1235 goto release;
1237 if (Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT
1238 && (srcwidth != dstwidth || srcheight != dstheight))
1240 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
1241 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(Filter));
1244 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1245 xinc = (srcwidth << 16) / dstwidth;
1246 yinc = (srcheight << 16) / dstheight;
1248 if (!flags)
1250 /* No effects, we can cheat here */
1251 if (dstwidth == srcwidth)
1253 if (dstheight == srcheight)
1255 /* No stretching in either direction. This needs to be as
1256 * fast as possible */
1257 sbuf = sbase;
1259 /* check for overlapping surfaces */
1260 if (src != This || xdst.top < xsrc.top ||
1261 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1263 /* no overlap, or dst above src, so copy from top downwards */
1264 for (y = 0; y < dstheight; y++)
1266 memcpy(dbuf, sbuf, width);
1267 sbuf += slock.Pitch;
1268 dbuf += dlock.Pitch;
1271 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1273 sbuf += (slock.Pitch*dstheight);
1274 dbuf += (dlock.Pitch*dstheight);
1275 for (y = 0; y < dstheight; y++)
1277 sbuf -= slock.Pitch;
1278 dbuf -= dlock.Pitch;
1279 memcpy(dbuf, sbuf, width);
1282 else /* src and dst overlapping on the same line, use memmove */
1284 for (y = 0; y < dstheight; y++)
1286 memmove(dbuf, sbuf, width);
1287 sbuf += slock.Pitch;
1288 dbuf += dlock.Pitch;
1291 } else {
1292 /* Stretching in Y direction only */
1293 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1294 sbuf = sbase + (sy >> 16) * slock.Pitch;
1295 memcpy(dbuf, sbuf, width);
1296 dbuf += dlock.Pitch;
1300 else
1302 /* Stretching in X direction */
1303 int last_sy = -1;
1304 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1306 sbuf = sbase + (sy >> 16) * slock.Pitch;
1308 if ((sy >> 16) == (last_sy >> 16))
1310 /* this sourcerow is the same as last sourcerow -
1311 * copy already stretched row
1313 memcpy(dbuf, dbuf - dlock.Pitch, width);
1315 else
1317 #define STRETCH_ROW(type) { \
1318 const type *s = (const type *)sbuf; \
1319 type *d = (type *)dbuf; \
1320 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1321 d[x] = s[sx >> 16]; \
1322 break; }
1324 switch(bpp)
1326 case 1: STRETCH_ROW(BYTE)
1327 case 2: STRETCH_ROW(WORD)
1328 case 4: STRETCH_ROW(DWORD)
1329 case 3:
1331 const BYTE *s;
1332 BYTE *d = dbuf;
1333 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1335 DWORD pixel;
1337 s = sbuf+3*(sx>>16);
1338 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1339 d[0] = (pixel )&0xff;
1340 d[1] = (pixel>> 8)&0xff;
1341 d[2] = (pixel>>16)&0xff;
1342 d+=3;
1344 break;
1346 default:
1347 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1348 ret = WINED3DERR_NOTAVAILABLE;
1349 goto error;
1351 #undef STRETCH_ROW
1353 dbuf += dlock.Pitch;
1354 last_sy = sy;
1358 else
1360 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1361 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1362 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1363 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1365 /* The color keying flags are checked for correctness in ddraw */
1366 if (flags & WINEDDBLT_KEYSRC)
1368 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1369 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1371 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
1373 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1374 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1377 if (flags & WINEDDBLT_KEYDEST)
1379 /* Destination color keys are taken from the source surface ! */
1380 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1381 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1383 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
1385 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1386 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1389 if(bpp == 1)
1391 keymask = 0xff;
1393 else
1395 keymask = sEntry->red_mask
1396 | sEntry->green_mask
1397 | sEntry->blue_mask;
1399 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1402 if (flags & WINEDDBLT_DDFX)
1404 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1405 LONG tmpxy;
1406 dTopLeft = dbuf;
1407 dTopRight = dbuf+((dstwidth-1)*bpp);
1408 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1409 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1411 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1413 /* I don't think we need to do anything about this flag */
1414 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1416 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1418 tmp = dTopRight;
1419 dTopRight = dTopLeft;
1420 dTopLeft = tmp;
1421 tmp = dBottomRight;
1422 dBottomRight = dBottomLeft;
1423 dBottomLeft = tmp;
1424 dstxinc = dstxinc *-1;
1426 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1428 tmp = dTopLeft;
1429 dTopLeft = dBottomLeft;
1430 dBottomLeft = tmp;
1431 tmp = dTopRight;
1432 dTopRight = dBottomRight;
1433 dBottomRight = tmp;
1434 dstyinc = dstyinc *-1;
1436 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1438 /* I don't think we need to do anything about this flag */
1439 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1441 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1443 tmp = dBottomRight;
1444 dBottomRight = dTopLeft;
1445 dTopLeft = tmp;
1446 tmp = dBottomLeft;
1447 dBottomLeft = dTopRight;
1448 dTopRight = tmp;
1449 dstxinc = dstxinc * -1;
1450 dstyinc = dstyinc * -1;
1452 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1454 tmp = dTopLeft;
1455 dTopLeft = dBottomLeft;
1456 dBottomLeft = dBottomRight;
1457 dBottomRight = dTopRight;
1458 dTopRight = tmp;
1459 tmpxy = dstxinc;
1460 dstxinc = dstyinc;
1461 dstyinc = tmpxy;
1462 dstxinc = dstxinc * -1;
1464 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1466 tmp = dTopLeft;
1467 dTopLeft = dTopRight;
1468 dTopRight = dBottomRight;
1469 dBottomRight = dBottomLeft;
1470 dBottomLeft = tmp;
1471 tmpxy = dstxinc;
1472 dstxinc = dstyinc;
1473 dstyinc = tmpxy;
1474 dstyinc = dstyinc * -1;
1476 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1478 /* I don't think we need to do anything about this flag */
1479 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1481 dbuf = dTopLeft;
1482 flags &= ~(WINEDDBLT_DDFX);
1485 #define COPY_COLORKEY_FX(type) { \
1486 const type *s; \
1487 type *d = (type *)dbuf, *dx, tmp; \
1488 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1489 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1490 dx = d; \
1491 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1492 tmp = s[sx >> 16]; \
1493 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1494 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1495 dx[0] = tmp; \
1497 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1499 d = (type*)(((LPBYTE)d)+dstyinc); \
1501 break; }
1503 switch (bpp) {
1504 case 1: COPY_COLORKEY_FX(BYTE)
1505 case 2: COPY_COLORKEY_FX(WORD)
1506 case 4: COPY_COLORKEY_FX(DWORD)
1507 case 3:
1509 const BYTE *s;
1510 BYTE *d = dbuf, *dx;
1511 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1513 sbuf = sbase + (sy >> 16) * slock.Pitch;
1514 dx = d;
1515 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1517 DWORD pixel, dpixel = 0;
1518 s = sbuf+3*(sx>>16);
1519 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1520 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1521 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1522 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1524 dx[0] = (pixel )&0xff;
1525 dx[1] = (pixel>> 8)&0xff;
1526 dx[2] = (pixel>>16)&0xff;
1528 dx+= dstxinc;
1530 d += dstyinc;
1532 break;
1534 default:
1535 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1536 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1537 ret = WINED3DERR_NOTAVAILABLE;
1538 goto error;
1539 #undef COPY_COLORKEY_FX
1544 error:
1545 if (flags && FIXME_ON(d3d_surface))
1547 FIXME("\tUnsupported flags: %#x.\n", flags);
1550 release:
1551 IWineD3DSurface_Unmap(iface);
1552 if (src && src != This) IWineD3DSurface_Unmap((IWineD3DSurface *)src);
1553 /* Release the converted surface if any */
1554 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1555 return ret;
1558 /*****************************************************************************
1559 * IWineD3DSurface::BltFast, SW emulation version
1561 * This is the software implementation of BltFast, as used by GDI surfaces
1562 * and as a fallback for OpenGL surfaces. This code is taken from the old
1563 * DirectDraw code, and was originally written by TransGaming.
1565 * Params:
1566 * dstx:
1567 * dsty:
1568 * src_surface: Source surface to copy from
1569 * rsrc: Source rectangle
1570 * trans: Some flags
1572 * Returns:
1573 * WINED3D_OK on success
1575 *****************************************************************************/
1576 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1577 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1579 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1580 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1582 int bpp, w, h, x, y;
1583 WINED3DLOCKED_RECT dlock,slock;
1584 HRESULT ret = WINED3D_OK;
1585 RECT rsrc2;
1586 RECT lock_src, lock_dst, lock_union;
1587 const BYTE *sbuf;
1588 BYTE *dbuf;
1589 const struct wined3d_format *sEntry, *dEntry;
1591 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1592 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1594 if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
1596 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1597 return WINEDDERR_SURFACEBUSY;
1600 if (!rsrc)
1602 WARN("rsrc is NULL!\n");
1603 rsrc2.left = 0;
1604 rsrc2.top = 0;
1605 rsrc2.right = src->currentDesc.Width;
1606 rsrc2.bottom = src->currentDesc.Height;
1607 rsrc = &rsrc2;
1610 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1611 if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1612 || (rsrc->top > src->currentDesc.Height) || (rsrc->top < 0)
1613 || (rsrc->left > src->currentDesc.Width) || (rsrc->left < 0)
1614 || (rsrc->right > src->currentDesc.Width) || (rsrc->right < 0)
1615 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1617 WARN("Application gave us bad source rectangle for BltFast.\n");
1618 return WINEDDERR_INVALIDRECT;
1621 h = rsrc->bottom - rsrc->top;
1622 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1623 if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1624 if (h <= 0) return WINEDDERR_INVALIDRECT;
1626 w = rsrc->right - rsrc->left;
1627 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1628 if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1629 if (w <= 0) return WINEDDERR_INVALIDRECT;
1631 /* Now compute the locking rectangle... */
1632 lock_src.left = rsrc->left;
1633 lock_src.top = rsrc->top;
1634 lock_src.right = lock_src.left + w;
1635 lock_src.bottom = lock_src.top + h;
1637 lock_dst.left = dstx;
1638 lock_dst.top = dsty;
1639 lock_dst.right = dstx + w;
1640 lock_dst.bottom = dsty + h;
1642 bpp = This->resource.format->byte_count;
1644 /* We need to lock the surfaces, or we won't get refreshes when done. */
1645 if (src == This)
1647 int pitch;
1649 UnionRect(&lock_union, &lock_src, &lock_dst);
1651 /* Lock the union of the two rectangles */
1652 ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
1653 if (FAILED(ret)) goto error;
1655 pitch = dlock.Pitch;
1656 slock.Pitch = dlock.Pitch;
1658 /* Since slock was originally copied from this surface's description, we can just reuse it */
1659 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1660 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1661 sEntry = src->resource.format;
1662 dEntry = sEntry;
1664 else
1666 ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1667 if (FAILED(ret)) goto error;
1668 ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
1669 if (FAILED(ret)) goto error;
1671 sbuf = slock.pBits;
1672 dbuf = dlock.pBits;
1673 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1675 sEntry = src->resource.format;
1676 dEntry = This->resource.format;
1679 /* Handle compressed surfaces first... */
1680 if (sEntry->flags & dEntry->flags & WINED3DFMT_FLAG_COMPRESSED)
1682 UINT row_block_count;
1684 TRACE("compressed -> compressed copy\n");
1685 if (trans)
1686 FIXME("trans arg not supported when a compressed surface is involved\n");
1687 if (dstx || dsty)
1688 FIXME("offset for destination surface is not supported\n");
1689 if (src->resource.format->id != This->resource.format->id)
1691 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1692 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1693 goto error;
1696 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1697 for (y = 0; y < h; y += dEntry->block_height)
1699 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1700 dbuf += dlock.Pitch;
1701 sbuf += slock.Pitch;
1704 goto error;
1706 if ((sEntry->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->flags & WINED3DFMT_FLAG_COMPRESSED))
1708 /* TODO: Use the libtxc_dxtn.so shared library to do
1709 * software decompression
1711 ERR("Software decompression not supported.\n");
1712 goto error;
1715 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1717 DWORD keylow, keyhigh;
1718 DWORD mask = src->resource.format->red_mask
1719 | src->resource.format->green_mask
1720 | src->resource.format->blue_mask;
1722 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1723 if(!mask && bpp==1)
1724 mask = 0xff;
1726 TRACE("Color keyed copy\n");
1727 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1729 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1730 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1732 else
1734 /* I'm not sure if this is correct */
1735 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1736 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1737 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1740 #define COPYBOX_COLORKEY(type) { \
1741 const type *s = (const type *)sbuf; \
1742 type *d = (type *)dbuf; \
1743 type tmp; \
1744 for (y = 0; y < h; y++) { \
1745 for (x = 0; x < w; x++) { \
1746 tmp = s[x]; \
1747 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1749 s = (const type *)((const BYTE *)s + slock.Pitch); \
1750 d = (type *)((BYTE *)d + dlock.Pitch); \
1752 break; \
1755 switch (bpp) {
1756 case 1: COPYBOX_COLORKEY(BYTE)
1757 case 2: COPYBOX_COLORKEY(WORD)
1758 case 4: COPYBOX_COLORKEY(DWORD)
1759 case 3:
1761 const BYTE *s;
1762 BYTE *d;
1763 DWORD tmp;
1764 s = sbuf;
1765 d = dbuf;
1766 for (y = 0; y < h; y++)
1768 for (x = 0; x < w * 3; x += 3)
1770 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1771 if (tmp < keylow || tmp > keyhigh)
1773 d[x + 0] = s[x + 0];
1774 d[x + 1] = s[x + 1];
1775 d[x + 2] = s[x + 2];
1778 s += slock.Pitch;
1779 d += dlock.Pitch;
1781 break;
1783 default:
1784 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1785 ret = WINED3DERR_NOTAVAILABLE;
1786 goto error;
1788 #undef COPYBOX_COLORKEY
1789 TRACE("Copy Done\n");
1791 else
1793 int width = w * bpp;
1794 INT sbufpitch, dbufpitch;
1796 TRACE("NO color key copy\n");
1797 /* Handle overlapping surfaces */
1798 if (sbuf < dbuf)
1800 sbuf += (h - 1) * slock.Pitch;
1801 dbuf += (h - 1) * dlock.Pitch;
1802 sbufpitch = -slock.Pitch;
1803 dbufpitch = -dlock.Pitch;
1805 else
1807 sbufpitch = slock.Pitch;
1808 dbufpitch = dlock.Pitch;
1810 for (y = 0; y < h; y++)
1812 /* This is pretty easy, a line for line memcpy */
1813 memmove(dbuf, sbuf, width);
1814 sbuf += sbufpitch;
1815 dbuf += dbufpitch;
1817 TRACE("Copy done\n");
1820 error:
1821 if (src == This)
1823 IWineD3DSurface_Unmap(iface);
1825 else
1827 IWineD3DSurface_Unmap(iface);
1828 IWineD3DSurface_Unmap(src_surface);
1831 return ret;
1834 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
1835 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
1837 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1839 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
1840 iface, pLockedRect, wine_dbgstr_rect(pRect), flags);
1842 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1844 if (!pRect)
1846 pLockedRect->pBits = This->resource.allocatedMemory;
1847 This->lockedRect.left = 0;
1848 This->lockedRect.top = 0;
1849 This->lockedRect.right = This->currentDesc.Width;
1850 This->lockedRect.bottom = This->currentDesc.Height;
1852 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1853 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1854 This->lockedRect.right, This->lockedRect.bottom);
1856 else
1858 const struct wined3d_format *format = This->resource.format;
1860 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1861 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1863 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1865 /* Compressed textures are block based, so calculate the offset of
1866 * the block that contains the top-left pixel of the locked rectangle. */
1867 pLockedRect->pBits = This->resource.allocatedMemory
1868 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1869 + ((pRect->left / format->block_width) * format->block_byte_count);
1871 else
1873 pLockedRect->pBits = This->resource.allocatedMemory +
1874 (pLockedRect->Pitch * pRect->top) +
1875 (pRect->left * format->byte_count);
1877 This->lockedRect.left = pRect->left;
1878 This->lockedRect.top = pRect->top;
1879 This->lockedRect.right = pRect->right;
1880 This->lockedRect.bottom = pRect->bottom;
1883 /* No dirtifying is needed for this surface implementation */
1884 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1886 return WINED3D_OK;
1889 /* TODO: think about moving this down to resource? */
1890 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1892 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1894 /* This should only be called for sysmem textures, it may be a good idea
1895 * to extend this to all pools at some point in the future */
1896 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1898 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1900 return This->resource.allocatedMemory;