wined3d: Recognize the SM4 sampler register type.
[wine.git] / dlls / wined3d / surface_base.c
blobe4dd853b0b3a5566285c0105e66eda156bf45ca2
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_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
827 if(FAILED(hr)) {
828 ERR("Failed to lock the source surface\n");
829 IWineD3DSurface_Release(ret);
830 return NULL;
832 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
833 if(FAILED(hr)) {
834 ERR("Failed to lock the dest surface\n");
835 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
836 IWineD3DSurface_Release(ret);
837 return NULL;
840 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
841 source->currentDesc.Width, source->currentDesc.Height);
843 IWineD3DSurface_UnlockRect(ret);
844 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
846 return (IWineD3DSurfaceImpl *) ret;
849 /*****************************************************************************
850 * _Blt_ColorFill
852 * Helper function that fills a memory area with a specific color
854 * Params:
855 * buf: memory address to start filling at
856 * width, height: Dimensions of the area to fill
857 * bpp: Bit depth of the surface
858 * lPitch: pitch of the surface
859 * color: Color to fill with
861 *****************************************************************************/
862 static HRESULT
863 _Blt_ColorFill(BYTE *buf,
864 int width, int height,
865 int bpp, LONG lPitch,
866 DWORD color)
868 int x, y;
869 LPBYTE first;
871 /* Do first row */
873 #define COLORFILL_ROW(type) \
875 type *d = (type *) buf; \
876 for (x = 0; x < width; x++) \
877 d[x] = (type) color; \
878 break; \
880 switch(bpp)
882 case 1: COLORFILL_ROW(BYTE)
883 case 2: COLORFILL_ROW(WORD)
884 case 3:
886 BYTE *d = buf;
887 for (x = 0; x < width; x++,d+=3)
889 d[0] = (color ) & 0xFF;
890 d[1] = (color>> 8) & 0xFF;
891 d[2] = (color>>16) & 0xFF;
893 break;
895 case 4: COLORFILL_ROW(DWORD)
896 default:
897 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
898 return WINED3DERR_NOTAVAILABLE;
901 #undef COLORFILL_ROW
903 /* Now copy first row */
904 first = buf;
905 for (y = 1; y < height; y++)
907 buf += lPitch;
908 memcpy(buf, first, width * bpp);
910 return WINED3D_OK;
913 /*****************************************************************************
914 * IWineD3DSurface::Blt, SW emulation version
916 * Performs a blit to a surface, with or without a source surface.
917 * This is the main functionality of DirectDraw
919 * Params:
920 * DestRect: Destination rectangle to write to
921 * src_surface: Source surface, can be NULL
922 * SrcRect: Source rectangle
923 *****************************************************************************/
924 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *src_surface,
925 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
927 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
928 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
929 RECT xdst,xsrc;
930 HRESULT ret = WINED3D_OK;
931 WINED3DLOCKED_RECT dlock, slock;
932 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
933 const struct wined3d_format *sEntry, *dEntry;
934 int x, y;
935 const BYTE *sbuf;
936 BYTE *dbuf;
938 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
939 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
940 Flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
942 if ((This->Flags & SFLAG_LOCKED) || (src && (src->Flags & SFLAG_LOCKED)))
944 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
945 return WINEDDERR_SURFACEBUSY;
948 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
949 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
950 FIXME("Filters not supported in software blit\n");
953 /* First check for the validity of source / destination rectangles.
954 * This was verified using a test application + by MSDN. */
956 if (SrcRect)
958 if (src)
960 if (SrcRect->right < SrcRect->left || SrcRect->bottom < SrcRect->top
961 || SrcRect->left > src->currentDesc.Width || SrcRect->left < 0
962 || SrcRect->top > src->currentDesc.Height || SrcRect->top < 0
963 || SrcRect->right > src->currentDesc.Width || SrcRect->right < 0
964 || SrcRect->bottom > src->currentDesc.Height || SrcRect->bottom < 0)
966 WARN("Application gave us bad source rectangle for Blt.\n");
967 return WINEDDERR_INVALIDRECT;
970 if (!SrcRect->right || !SrcRect->bottom
971 || SrcRect->left == (int)src->currentDesc.Width
972 || SrcRect->top == (int)src->currentDesc.Height)
974 TRACE("Nothing to be done.\n");
975 return WINED3D_OK;
979 xsrc = *SrcRect;
981 else if (src)
983 xsrc.left = 0;
984 xsrc.top = 0;
985 xsrc.right = src->currentDesc.Width;
986 xsrc.bottom = src->currentDesc.Height;
988 else
990 memset(&xsrc, 0, sizeof(xsrc));
993 if (DestRect)
995 /* For the Destination rect, it can be out of bounds on the condition
996 * that a clipper is set for the given surface. */
997 if (!This->clipper && (DestRect->right < DestRect->left || DestRect->bottom < DestRect->top
998 || DestRect->left > This->currentDesc.Width || DestRect->left < 0
999 || DestRect->top > This->currentDesc.Height || DestRect->top < 0
1000 || DestRect->right > This->currentDesc.Width || DestRect->right < 0
1001 || DestRect->bottom > This->currentDesc.Height || DestRect->bottom < 0))
1003 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
1004 return WINEDDERR_INVALIDRECT;
1007 if (DestRect->right <= 0 || DestRect->bottom <= 0
1008 || DestRect->left >= (int)This->currentDesc.Width
1009 || DestRect->top >= (int)This->currentDesc.Height)
1011 TRACE("Nothing to be done.\n");
1012 return WINED3D_OK;
1015 if (!src)
1017 RECT full_rect;
1019 full_rect.left = 0;
1020 full_rect.top = 0;
1021 full_rect.right = This->currentDesc.Width;
1022 full_rect.bottom = This->currentDesc.Height;
1023 IntersectRect(&xdst, &full_rect, DestRect);
1025 else
1027 BOOL clip_horiz, clip_vert;
1029 xdst = *DestRect;
1030 clip_horiz = xdst.left < 0 || xdst.right > (int)This->currentDesc.Width;
1031 clip_vert = xdst.top < 0 || xdst.bottom > (int)This->currentDesc.Height;
1033 if (clip_vert || clip_horiz)
1035 /* Now check if this is a special case or not... */
1036 if ((Flags & WINEDDBLT_DDFX)
1037 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
1038 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
1040 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1041 return WINED3D_OK;
1044 if (clip_horiz)
1046 if (xdst.left < 0)
1048 xsrc.left -= xdst.left;
1049 xdst.left = 0;
1051 if (xdst.right > This->currentDesc.Width)
1053 xsrc.right -= (xdst.right - (int)This->currentDesc.Width);
1054 xdst.right = (int)This->currentDesc.Width;
1058 if (clip_vert)
1060 if (xdst.top < 0)
1062 xsrc.top -= xdst.top;
1063 xdst.top = 0;
1065 if (xdst.bottom > This->currentDesc.Height)
1067 xsrc.bottom -= (xdst.bottom - (int)This->currentDesc.Height);
1068 xdst.bottom = (int)This->currentDesc.Height;
1072 /* And check if after clipping something is still to be done... */
1073 if ((xdst.right <= 0) || (xdst.bottom <= 0)
1074 || (xdst.left >= (int)This->currentDesc.Width)
1075 || (xdst.top >= (int)This->currentDesc.Height)
1076 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
1077 || (xsrc.left >= (int)src->currentDesc.Width)
1078 || (xsrc.top >= (int)src->currentDesc.Height))
1080 TRACE("Nothing to be done after clipping.\n");
1081 return WINED3D_OK;
1086 else
1088 xdst.left = 0;
1089 xdst.top = 0;
1090 xdst.right = This->currentDesc.Width;
1091 xdst.bottom = This->currentDesc.Height;
1094 if (src == This)
1096 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1097 slock = dlock;
1098 sEntry = This->resource.format;
1099 dEntry = sEntry;
1101 else
1103 dEntry = This->resource.format;
1104 if (src)
1106 if (This->resource.format->id != src->resource.format->id)
1108 src = surface_convert_format(src, dEntry->id);
1109 if (!src)
1111 /* The conv function writes a FIXME */
1112 WARN("Cannot convert source surface format to dest format\n");
1113 goto release;
1116 IWineD3DSurface_LockRect((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
1117 sEntry = src->resource.format;
1119 else
1121 sEntry = dEntry;
1123 if (DestRect)
1124 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1125 else
1126 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1129 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1131 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1133 if (!DestRect || src == This)
1135 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1136 goto release;
1140 bpp = This->resource.format->byte_count;
1141 srcheight = xsrc.bottom - xsrc.top;
1142 srcwidth = xsrc.right - xsrc.left;
1143 dstheight = xdst.bottom - xdst.top;
1144 dstwidth = xdst.right - xdst.left;
1145 width = (xdst.right - xdst.left) * bpp;
1147 if (DestRect && src != This)
1148 dbuf = dlock.pBits;
1149 else
1150 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1152 if (Flags & WINEDDBLT_WAIT)
1154 Flags &= ~WINEDDBLT_WAIT;
1156 if (Flags & WINEDDBLT_ASYNC)
1158 static BOOL displayed = FALSE;
1159 if (!displayed)
1160 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1161 displayed = TRUE;
1162 Flags &= ~WINEDDBLT_ASYNC;
1164 if (Flags & WINEDDBLT_DONOTWAIT)
1166 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1167 static BOOL displayed = FALSE;
1168 if (!displayed)
1169 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1170 displayed = TRUE;
1171 Flags &= ~WINEDDBLT_DONOTWAIT;
1174 /* First, all the 'source-less' blits */
1175 if (Flags & WINEDDBLT_COLORFILL)
1177 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1178 dlock.Pitch, DDBltFx->u5.dwFillColor);
1179 Flags &= ~WINEDDBLT_COLORFILL;
1182 if (Flags & WINEDDBLT_DEPTHFILL)
1184 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1186 if (Flags & WINEDDBLT_ROP)
1188 /* Catch some degenerate cases here */
1189 switch(DDBltFx->dwROP)
1191 case BLACKNESS:
1192 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1193 break;
1194 case 0xAA0029: /* No-op */
1195 break;
1196 case WHITENESS:
1197 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1198 break;
1199 case SRCCOPY: /* well, we do that below ? */
1200 break;
1201 default:
1202 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1203 goto error;
1205 Flags &= ~WINEDDBLT_ROP;
1207 if (Flags & WINEDDBLT_DDROPS)
1209 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1211 /* Now the 'with source' blits */
1212 if (src)
1214 const BYTE *sbase;
1215 int sx, xinc, sy, yinc;
1217 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1218 goto release;
1219 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1220 xinc = (srcwidth << 16) / dstwidth;
1221 yinc = (srcheight << 16) / dstheight;
1223 if (!Flags)
1225 /* No effects, we can cheat here */
1226 if (dstwidth == srcwidth)
1228 if (dstheight == srcheight)
1230 /* No stretching in either direction. This needs to be as
1231 * fast as possible */
1232 sbuf = sbase;
1234 /* check for overlapping surfaces */
1235 if (src != This || xdst.top < xsrc.top ||
1236 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1238 /* no overlap, or dst above src, so copy from top downwards */
1239 for (y = 0; y < dstheight; y++)
1241 memcpy(dbuf, sbuf, width);
1242 sbuf += slock.Pitch;
1243 dbuf += dlock.Pitch;
1246 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1248 sbuf += (slock.Pitch*dstheight);
1249 dbuf += (dlock.Pitch*dstheight);
1250 for (y = 0; y < dstheight; y++)
1252 sbuf -= slock.Pitch;
1253 dbuf -= dlock.Pitch;
1254 memcpy(dbuf, sbuf, width);
1257 else /* src and dst overlapping on the same line, use memmove */
1259 for (y = 0; y < dstheight; y++)
1261 memmove(dbuf, sbuf, width);
1262 sbuf += slock.Pitch;
1263 dbuf += dlock.Pitch;
1266 } else {
1267 /* Stretching in Y direction only */
1268 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1269 sbuf = sbase + (sy >> 16) * slock.Pitch;
1270 memcpy(dbuf, sbuf, width);
1271 dbuf += dlock.Pitch;
1275 else
1277 /* Stretching in X direction */
1278 int last_sy = -1;
1279 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1281 sbuf = sbase + (sy >> 16) * slock.Pitch;
1283 if ((sy >> 16) == (last_sy >> 16))
1285 /* this sourcerow is the same as last sourcerow -
1286 * copy already stretched row
1288 memcpy(dbuf, dbuf - dlock.Pitch, width);
1290 else
1292 #define STRETCH_ROW(type) { \
1293 const type *s = (const type *)sbuf; \
1294 type *d = (type *)dbuf; \
1295 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1296 d[x] = s[sx >> 16]; \
1297 break; }
1299 switch(bpp)
1301 case 1: STRETCH_ROW(BYTE)
1302 case 2: STRETCH_ROW(WORD)
1303 case 4: STRETCH_ROW(DWORD)
1304 case 3:
1306 const BYTE *s;
1307 BYTE *d = dbuf;
1308 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1310 DWORD pixel;
1312 s = sbuf+3*(sx>>16);
1313 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1314 d[0] = (pixel )&0xff;
1315 d[1] = (pixel>> 8)&0xff;
1316 d[2] = (pixel>>16)&0xff;
1317 d+=3;
1319 break;
1321 default:
1322 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1323 ret = WINED3DERR_NOTAVAILABLE;
1324 goto error;
1326 #undef STRETCH_ROW
1328 dbuf += dlock.Pitch;
1329 last_sy = sy;
1333 else
1335 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1336 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1337 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1338 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1340 /* The color keying flags are checked for correctness in ddraw */
1341 if (Flags & WINEDDBLT_KEYSRC)
1343 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1344 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1346 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1348 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1349 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1352 if (Flags & WINEDDBLT_KEYDEST)
1354 /* Destination color keys are taken from the source surface ! */
1355 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
1356 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
1358 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1360 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1361 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1364 if(bpp == 1)
1366 keymask = 0xff;
1368 else
1370 keymask = sEntry->red_mask
1371 | sEntry->green_mask
1372 | sEntry->blue_mask;
1374 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1377 if (Flags & WINEDDBLT_DDFX)
1379 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1380 LONG tmpxy;
1381 dTopLeft = dbuf;
1382 dTopRight = dbuf+((dstwidth-1)*bpp);
1383 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1384 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1386 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1388 /* I don't think we need to do anything about this flag */
1389 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1391 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1393 tmp = dTopRight;
1394 dTopRight = dTopLeft;
1395 dTopLeft = tmp;
1396 tmp = dBottomRight;
1397 dBottomRight = dBottomLeft;
1398 dBottomLeft = tmp;
1399 dstxinc = dstxinc *-1;
1401 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1403 tmp = dTopLeft;
1404 dTopLeft = dBottomLeft;
1405 dBottomLeft = tmp;
1406 tmp = dTopRight;
1407 dTopRight = dBottomRight;
1408 dBottomRight = tmp;
1409 dstyinc = dstyinc *-1;
1411 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1413 /* I don't think we need to do anything about this flag */
1414 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1416 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1418 tmp = dBottomRight;
1419 dBottomRight = dTopLeft;
1420 dTopLeft = tmp;
1421 tmp = dBottomLeft;
1422 dBottomLeft = dTopRight;
1423 dTopRight = tmp;
1424 dstxinc = dstxinc * -1;
1425 dstyinc = dstyinc * -1;
1427 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1429 tmp = dTopLeft;
1430 dTopLeft = dBottomLeft;
1431 dBottomLeft = dBottomRight;
1432 dBottomRight = dTopRight;
1433 dTopRight = tmp;
1434 tmpxy = dstxinc;
1435 dstxinc = dstyinc;
1436 dstyinc = tmpxy;
1437 dstxinc = dstxinc * -1;
1439 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1441 tmp = dTopLeft;
1442 dTopLeft = dTopRight;
1443 dTopRight = dBottomRight;
1444 dBottomRight = dBottomLeft;
1445 dBottomLeft = tmp;
1446 tmpxy = dstxinc;
1447 dstxinc = dstyinc;
1448 dstyinc = tmpxy;
1449 dstyinc = dstyinc * -1;
1451 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1453 /* I don't think we need to do anything about this flag */
1454 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1456 dbuf = dTopLeft;
1457 Flags &= ~(WINEDDBLT_DDFX);
1460 #define COPY_COLORKEY_FX(type) { \
1461 const type *s; \
1462 type *d = (type *)dbuf, *dx, tmp; \
1463 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1464 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1465 dx = d; \
1466 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1467 tmp = s[sx >> 16]; \
1468 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1469 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1470 dx[0] = tmp; \
1472 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1474 d = (type*)(((LPBYTE)d)+dstyinc); \
1476 break; }
1478 switch (bpp) {
1479 case 1: COPY_COLORKEY_FX(BYTE)
1480 case 2: COPY_COLORKEY_FX(WORD)
1481 case 4: COPY_COLORKEY_FX(DWORD)
1482 case 3:
1484 const BYTE *s;
1485 BYTE *d = dbuf, *dx;
1486 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1488 sbuf = sbase + (sy >> 16) * slock.Pitch;
1489 dx = d;
1490 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1492 DWORD pixel, dpixel = 0;
1493 s = sbuf+3*(sx>>16);
1494 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1495 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1496 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1497 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1499 dx[0] = (pixel )&0xff;
1500 dx[1] = (pixel>> 8)&0xff;
1501 dx[2] = (pixel>>16)&0xff;
1503 dx+= dstxinc;
1505 d += dstyinc;
1507 break;
1509 default:
1510 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1511 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1512 ret = WINED3DERR_NOTAVAILABLE;
1513 goto error;
1514 #undef COPY_COLORKEY_FX
1519 error:
1520 if (Flags && FIXME_ON(d3d_surface))
1522 FIXME("\tUnsupported flags: %08x\n", Flags);
1525 release:
1526 IWineD3DSurface_UnlockRect(iface);
1527 if (src && src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *)src);
1528 /* Release the converted surface if any */
1529 if (src && src_surface != (IWineD3DSurface *)src) IWineD3DSurface_Release((IWineD3DSurface *)src);
1530 return ret;
1533 /*****************************************************************************
1534 * IWineD3DSurface::BltFast, SW emulation version
1536 * This is the software implementation of BltFast, as used by GDI surfaces
1537 * and as a fallback for OpenGL surfaces. This code is taken from the old
1538 * DirectDraw code, and was originally written by TransGaming.
1540 * Params:
1541 * dstx:
1542 * dsty:
1543 * src_surface: Source surface to copy from
1544 * rsrc: Source rectangle
1545 * trans: Some Flags
1547 * Returns:
1548 * WINED3D_OK on success
1550 *****************************************************************************/
1551 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1552 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
1554 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1555 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
1557 int bpp, w, h, x, y;
1558 WINED3DLOCKED_RECT dlock,slock;
1559 HRESULT ret = WINED3D_OK;
1560 RECT rsrc2;
1561 RECT lock_src, lock_dst, lock_union;
1562 const BYTE *sbuf;
1563 BYTE *dbuf;
1564 const struct wined3d_format *sEntry, *dEntry;
1566 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1567 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
1569 if ((This->Flags & SFLAG_LOCKED) || (src->Flags & SFLAG_LOCKED))
1571 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1572 return WINEDDERR_SURFACEBUSY;
1575 if (!rsrc)
1577 WARN("rsrc is NULL!\n");
1578 rsrc2.left = 0;
1579 rsrc2.top = 0;
1580 rsrc2.right = src->currentDesc.Width;
1581 rsrc2.bottom = src->currentDesc.Height;
1582 rsrc = &rsrc2;
1585 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1586 if ((rsrc->bottom > src->currentDesc.Height) || (rsrc->bottom < 0)
1587 || (rsrc->top > src->currentDesc.Height) || (rsrc->top < 0)
1588 || (rsrc->left > src->currentDesc.Width) || (rsrc->left < 0)
1589 || (rsrc->right > src->currentDesc.Width) || (rsrc->right < 0)
1590 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1592 WARN("Application gave us bad source rectangle for BltFast.\n");
1593 return WINEDDERR_INVALIDRECT;
1596 h = rsrc->bottom - rsrc->top;
1597 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1598 if (h > src->currentDesc.Height-rsrc->top) h = src->currentDesc.Height-rsrc->top;
1599 if (h <= 0) return WINEDDERR_INVALIDRECT;
1601 w = rsrc->right - rsrc->left;
1602 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1603 if (w > src->currentDesc.Width-rsrc->left) w = src->currentDesc.Width-rsrc->left;
1604 if (w <= 0) return WINEDDERR_INVALIDRECT;
1606 /* Now compute the locking rectangle... */
1607 lock_src.left = rsrc->left;
1608 lock_src.top = rsrc->top;
1609 lock_src.right = lock_src.left + w;
1610 lock_src.bottom = lock_src.top + h;
1612 lock_dst.left = dstx;
1613 lock_dst.top = dsty;
1614 lock_dst.right = dstx + w;
1615 lock_dst.bottom = dsty + h;
1617 bpp = This->resource.format->byte_count;
1619 /* We need to lock the surfaces, or we won't get refreshes when done. */
1620 if (src == This)
1622 int pitch;
1624 UnionRect(&lock_union, &lock_src, &lock_dst);
1626 /* Lock the union of the two rectangles */
1627 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1628 if(ret != WINED3D_OK) goto error;
1630 pitch = dlock.Pitch;
1631 slock.Pitch = dlock.Pitch;
1633 /* Since slock was originally copied from this surface's description, we can just reuse it */
1634 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1635 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1636 sEntry = src->resource.format;
1637 dEntry = sEntry;
1639 else
1641 ret = IWineD3DSurface_LockRect(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
1642 if(ret != WINED3D_OK) goto error;
1643 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1644 if(ret != WINED3D_OK) goto error;
1646 sbuf = slock.pBits;
1647 dbuf = dlock.pBits;
1648 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1650 sEntry = src->resource.format;
1651 dEntry = This->resource.format;
1654 /* Handle compressed surfaces first... */
1655 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1657 UINT row_block_count;
1659 TRACE("compressed -> compressed copy\n");
1660 if (trans)
1661 FIXME("trans arg not supported when a compressed surface is involved\n");
1662 if (dstx || dsty)
1663 FIXME("offset for destination surface is not supported\n");
1664 if (src->resource.format->id != This->resource.format->id)
1666 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1667 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1668 goto error;
1671 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1672 for (y = 0; y < h; y += dEntry->block_height)
1674 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1675 dbuf += dlock.Pitch;
1676 sbuf += slock.Pitch;
1679 goto error;
1681 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1683 /* TODO: Use the libtxc_dxtn.so shared library to do
1684 * software decompression
1686 ERR("Software decompression not supported.\n");
1687 goto error;
1690 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1692 DWORD keylow, keyhigh;
1693 DWORD mask = src->resource.format->red_mask
1694 | src->resource.format->green_mask
1695 | src->resource.format->blue_mask;
1697 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1698 if(!mask && bpp==1)
1699 mask = 0xff;
1701 TRACE("Color keyed copy\n");
1702 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1704 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
1705 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
1707 else
1709 /* I'm not sure if this is correct */
1710 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1711 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1712 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1715 #define COPYBOX_COLORKEY(type) { \
1716 const type *s = (const type *)sbuf; \
1717 type *d = (type *)dbuf; \
1718 type tmp; \
1719 for (y = 0; y < h; y++) { \
1720 for (x = 0; x < w; x++) { \
1721 tmp = s[x]; \
1722 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1724 s = (const type *)((const BYTE *)s + slock.Pitch); \
1725 d = (type *)((BYTE *)d + dlock.Pitch); \
1727 break; \
1730 switch (bpp) {
1731 case 1: COPYBOX_COLORKEY(BYTE)
1732 case 2: COPYBOX_COLORKEY(WORD)
1733 case 4: COPYBOX_COLORKEY(DWORD)
1734 case 3:
1736 const BYTE *s;
1737 BYTE *d;
1738 DWORD tmp;
1739 s = sbuf;
1740 d = dbuf;
1741 for (y = 0; y < h; y++)
1743 for (x = 0; x < w * 3; x += 3)
1745 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1746 if (tmp < keylow || tmp > keyhigh)
1748 d[x + 0] = s[x + 0];
1749 d[x + 1] = s[x + 1];
1750 d[x + 2] = s[x + 2];
1753 s += slock.Pitch;
1754 d += dlock.Pitch;
1756 break;
1758 default:
1759 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1760 ret = WINED3DERR_NOTAVAILABLE;
1761 goto error;
1763 #undef COPYBOX_COLORKEY
1764 TRACE("Copy Done\n");
1766 else
1768 int width = w * bpp;
1769 INT sbufpitch, dbufpitch;
1771 TRACE("NO color key copy\n");
1772 /* Handle overlapping surfaces */
1773 if (sbuf < dbuf)
1775 sbuf += (h - 1) * slock.Pitch;
1776 dbuf += (h - 1) * dlock.Pitch;
1777 sbufpitch = -slock.Pitch;
1778 dbufpitch = -dlock.Pitch;
1780 else
1782 sbufpitch = slock.Pitch;
1783 dbufpitch = dlock.Pitch;
1785 for (y = 0; y < h; y++)
1787 /* This is pretty easy, a line for line memcpy */
1788 memmove(dbuf, sbuf, width);
1789 sbuf += sbufpitch;
1790 dbuf += dbufpitch;
1792 TRACE("Copy done\n");
1795 error:
1796 if (src == This)
1798 IWineD3DSurface_UnlockRect(iface);
1800 else
1802 IWineD3DSurface_UnlockRect(iface);
1803 IWineD3DSurface_UnlockRect(src_surface);
1806 return ret;
1809 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1811 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1813 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1814 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1816 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1818 if (!pRect)
1820 pLockedRect->pBits = This->resource.allocatedMemory;
1821 This->lockedRect.left = 0;
1822 This->lockedRect.top = 0;
1823 This->lockedRect.right = This->currentDesc.Width;
1824 This->lockedRect.bottom = This->currentDesc.Height;
1826 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1827 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1828 This->lockedRect.right, This->lockedRect.bottom);
1830 else
1832 const struct wined3d_format *format = This->resource.format;
1834 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1835 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1837 if ((format->Flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1839 /* Compressed textures are block based, so calculate the offset of
1840 * the block that contains the top-left pixel of the locked rectangle. */
1841 pLockedRect->pBits = This->resource.allocatedMemory
1842 + ((pRect->top / format->block_height) * pLockedRect->Pitch)
1843 + ((pRect->left / format->block_width) * format->block_byte_count);
1845 else
1847 pLockedRect->pBits = This->resource.allocatedMemory +
1848 (pLockedRect->Pitch * pRect->top) +
1849 (pRect->left * format->byte_count);
1851 This->lockedRect.left = pRect->left;
1852 This->lockedRect.top = pRect->top;
1853 This->lockedRect.right = pRect->right;
1854 This->lockedRect.bottom = pRect->bottom;
1857 /* No dirtifying is needed for this surface implementation */
1858 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1860 return WINED3D_OK;
1863 /* TODO: think about moving this down to resource? */
1864 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1866 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1868 /* This should only be called for sysmem textures, it may be a good idea
1869 * to extend this to all pools at some point in the future */
1870 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1872 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1874 return This->resource.allocatedMemory;