Release 1.1.37.
[wine/gsoc-2012-control.git] / dlls / wined3d / surface_base.c
blob33e3d3ed885e3b6fea00eb713195e9d1f0af06a8
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 < pow(2, 10)) {
52 tmp = tmp * 2.0f;
53 exp--;
54 }while(tmp < pow(2, 10));
55 } else if(tmp >= pow(2, 11)) {
58 tmp /= 2.0f;
59 exp++;
60 }while(tmp >= pow(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;
87 /* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
89 /* *******************************************
90 IWineD3DSurface IUnknown parts follow
91 ******************************************* */
92 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
94 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
95 /* Warn ,but be nice about things */
96 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
98 if (IsEqualGUID(riid, &IID_IUnknown)
99 || IsEqualGUID(riid, &IID_IWineD3DBase)
100 || IsEqualGUID(riid, &IID_IWineD3DResource)
101 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
102 IUnknown_AddRef((IUnknown*)iface);
103 *ppobj = This;
104 return S_OK;
106 *ppobj = NULL;
107 return E_NOINTERFACE;
110 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
111 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
112 ULONG ref = InterlockedIncrement(&This->resource.ref);
113 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
114 return ref;
117 /* ****************************************************
118 IWineD3DSurface IWineD3DResource parts follow
119 **************************************************** */
120 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
121 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
124 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
125 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
128 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
129 return resource_free_private_data((IWineD3DResource *)iface, refguid);
132 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
133 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
136 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
137 return resource_get_priority((IWineD3DResource *)iface);
140 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
141 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
142 return resource_get_type((IWineD3DResource *)iface);
145 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
146 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
147 return resource_get_parent((IWineD3DResource *)iface, pParent);
150 /* ******************************************************
151 IWineD3DSurface IWineD3DSurface parts follow
152 ****************************************************** */
154 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
155 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
156 IWineD3DBase *container = 0;
158 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
160 if (!ppContainer) {
161 ERR("Called without a valid ppContainer.\n");
164 /* Standalone surfaces return the device as container. */
165 if (This->container) container = This->container;
166 else container = (IWineD3DBase *)This->resource.device;
168 TRACE("Relaying to QueryInterface\n");
169 return IUnknown_QueryInterface(container, riid, ppContainer);
172 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
173 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
175 TRACE("(%p) : copying into %p\n", This, pDesc);
177 pDesc->format = This->resource.format_desc->format;
178 pDesc->resource_type = This->resource.resourceType;
179 pDesc->usage = This->resource.usage;
180 pDesc->pool = This->resource.pool;
181 pDesc->size = This->resource.size; /* dx8 only */
182 pDesc->multisample_type = This->currentDesc.MultiSampleType;
183 pDesc->multisample_quality = This->currentDesc.MultiSampleQuality;
184 pDesc->width = This->currentDesc.Width;
185 pDesc->height = This->currentDesc.Height;
187 return WINED3D_OK;
190 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags)
192 TRACE("iface %p, flags %#x.\n", iface, Flags);
194 switch (Flags)
196 case WINEDDGBS_CANBLT:
197 case WINEDDGBS_ISBLTDONE:
198 return WINED3D_OK;
200 default:
201 return WINED3DERR_INVALIDCALL;
205 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
206 /* XXX: DDERR_INVALIDSURFACETYPE */
208 TRACE("(%p)->(%08x)\n",iface,Flags);
209 switch (Flags) {
210 case WINEDDGFS_CANFLIP:
211 case WINEDDGFS_ISFLIPDONE:
212 return WINED3D_OK;
214 default:
215 return WINED3DERR_INVALIDCALL;
219 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
220 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
221 TRACE("(%p)\n", This);
223 /* D3D8 and 9 loose full devices, ddraw only surfaces */
224 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
227 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
228 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
229 TRACE("(%p)\n", This);
231 /* So far we don't lose anything :) */
232 This->Flags &= ~SFLAG_LOST;
233 return WINED3D_OK;
236 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
237 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
238 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
239 TRACE("(%p)->(%p)\n", This, Pal);
241 if(This->palette == PalImpl) {
242 TRACE("Nop palette change\n");
243 return WINED3D_OK;
246 if(This->palette != NULL)
247 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
248 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
250 This->palette = PalImpl;
252 if(PalImpl != NULL) {
253 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
254 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
257 return IWineD3DSurface_RealizePalette(iface);
259 else return WINED3D_OK;
262 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
264 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
265 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
267 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
268 FIXME(" colorkey value not supported (%08x) !\n", Flags);
269 return WINED3DERR_INVALIDCALL;
272 /* Dirtify the surface, but only if a key was changed */
273 if(CKey) {
274 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
275 case WINEDDCKEY_DESTBLT:
276 This->DestBltCKey = *CKey;
277 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
278 break;
280 case WINEDDCKEY_DESTOVERLAY:
281 This->DestOverlayCKey = *CKey;
282 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
283 break;
285 case WINEDDCKEY_SRCOVERLAY:
286 This->SrcOverlayCKey = *CKey;
287 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
288 break;
290 case WINEDDCKEY_SRCBLT:
291 This->SrcBltCKey = *CKey;
292 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
293 break;
296 else {
297 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
298 case WINEDDCKEY_DESTBLT:
299 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
300 break;
302 case WINEDDCKEY_DESTOVERLAY:
303 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
304 break;
306 case WINEDDCKEY_SRCOVERLAY:
307 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
308 break;
310 case WINEDDCKEY_SRCBLT:
311 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
312 break;
316 return WINED3D_OK;
319 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
320 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
321 TRACE("(%p)->(%p)\n", This, Pal);
323 *Pal = (IWineD3DPalette *) This->palette;
324 return WINED3D_OK;
327 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
328 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
329 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
330 DWORD ret;
331 TRACE("(%p)\n", This);
333 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
335 /* Since compressed formats are block based, pitch means the amount of
336 * bytes to the next row of block rather than the next row of pixels. */
337 UINT row_block_count = (This->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
338 ret = row_block_count * format_desc->block_byte_count;
340 else
342 unsigned char alignment = This->resource.device->surface_alignment;
343 ret = This->resource.format_desc->byte_count * This->currentDesc.Width; /* Bytes / row */
344 ret = (ret + alignment - 1) & ~(alignment - 1);
346 TRACE("(%p) Returning %d\n", This, ret);
347 return ret;
350 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
351 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
352 LONG w, h;
354 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
356 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
358 TRACE("(%p): Not an overlay surface\n", This);
359 return WINEDDERR_NOTAOVERLAYSURFACE;
362 w = This->overlay_destrect.right - This->overlay_destrect.left;
363 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
364 This->overlay_destrect.left = X;
365 This->overlay_destrect.top = Y;
366 This->overlay_destrect.right = X + w;
367 This->overlay_destrect.bottom = Y + h;
369 IWineD3DSurface_DrawOverlay(iface);
371 return WINED3D_OK;
374 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
375 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
376 HRESULT hr;
378 TRACE("(%p)->(%p,%p)\n", This, X, Y);
380 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
382 TRACE("(%p): Not an overlay surface\n", This);
383 return WINEDDERR_NOTAOVERLAYSURFACE;
385 if(This->overlay_dest == NULL) {
386 *X = 0; *Y = 0;
387 hr = WINEDDERR_OVERLAYNOTVISIBLE;
388 } else {
389 *X = This->overlay_destrect.left;
390 *Y = This->overlay_destrect.top;
391 hr = WINED3D_OK;
394 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
395 return hr;
398 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
399 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
401 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, Flags, Ref);
403 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
405 TRACE("(%p): Not an overlay surface\n", This);
406 return WINEDDERR_NOTAOVERLAYSURFACE;
409 return WINED3D_OK;
412 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
413 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
415 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
416 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
417 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
419 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
421 WARN("(%p): Not an overlay surface\n", This);
422 return WINEDDERR_NOTAOVERLAYSURFACE;
423 } else if(!DstSurface) {
424 WARN("(%p): Dest surface is NULL\n", This);
425 return WINED3DERR_INVALIDCALL;
428 if(SrcRect) {
429 This->overlay_srcrect = *SrcRect;
430 } else {
431 This->overlay_srcrect.left = 0;
432 This->overlay_srcrect.top = 0;
433 This->overlay_srcrect.right = This->currentDesc.Width;
434 This->overlay_srcrect.bottom = This->currentDesc.Height;
437 if(DstRect) {
438 This->overlay_destrect = *DstRect;
439 } else {
440 This->overlay_destrect.left = 0;
441 This->overlay_destrect.top = 0;
442 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
443 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
446 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
447 list_remove(&This->overlay_entry);
450 if(Flags & WINEDDOVER_SHOW) {
451 if(This->overlay_dest != Dst) {
452 This->overlay_dest = Dst;
453 list_add_tail(&Dst->overlays, &This->overlay_entry);
455 } 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 = 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 = This->clipper;
484 if(*clipper) {
485 IWineD3DClipper_AddRef(*clipper);
487 return WINED3D_OK;
490 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
491 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
493 TRACE("This %p, container %p\n", This, container);
495 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
497 TRACE("Setting container to %p from %p\n", container, This->container);
498 This->container = container;
500 return WINED3D_OK;
503 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
504 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
505 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format,
506 &This->resource.device->adapter->gl_info);
508 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
510 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
511 return WINED3DERR_INVALIDCALL;
514 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
516 This->resource.size = surface_calculate_size(format_desc, This->resource.device->surface_alignment,
517 This->pow2Width, This->pow2Height);
519 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
521 This->resource.format_desc = format_desc;
523 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
525 return WINED3D_OK;
528 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
529 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
530 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
531 int extraline = 0;
532 SYSTEM_INFO sysInfo;
533 BITMAPINFO* b_info;
534 HDC ddc;
535 DWORD *masks;
536 UINT usage;
538 if(!(format_desc->Flags & WINED3DFMT_FLAG_GETDC))
540 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format_desc->format));
541 return WINED3DERR_INVALIDCALL;
544 switch (format_desc->byte_count)
546 case 2:
547 case 4:
548 /* Allocate extra space to store the RGB bit masks. */
549 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
550 break;
552 case 3:
553 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
554 break;
556 default:
557 /* Allocate extra space for a palette. */
558 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
559 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
560 break;
563 if (!b_info)
564 return E_OUTOFMEMORY;
566 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
567 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
568 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
569 * add an extra line to the dib section
571 GetSystemInfo(&sysInfo);
572 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
573 extraline = 1;
574 TRACE("Adding an extra line to the dib section\n");
577 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
578 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
579 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
580 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
581 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
582 b_info->bmiHeader.biPlanes = 1;
583 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
585 b_info->bmiHeader.biXPelsPerMeter = 0;
586 b_info->bmiHeader.biYPelsPerMeter = 0;
587 b_info->bmiHeader.biClrUsed = 0;
588 b_info->bmiHeader.biClrImportant = 0;
590 /* Get the bit masks */
591 masks = (DWORD *)b_info->bmiColors;
592 switch (This->resource.format_desc->format)
594 case WINED3DFMT_B8G8R8_UNORM:
595 usage = DIB_RGB_COLORS;
596 b_info->bmiHeader.biCompression = BI_RGB;
597 break;
599 case WINED3DFMT_B5G5R5X1_UNORM:
600 case WINED3DFMT_B5G5R5A1_UNORM:
601 case WINED3DFMT_B4G4R4A4_UNORM:
602 case WINED3DFMT_B4G4R4X4_UNORM:
603 case WINED3DFMT_B2G3R3_UNORM:
604 case WINED3DFMT_B2G3R3A8_UNORM:
605 case WINED3DFMT_R10G10B10A2_UNORM:
606 case WINED3DFMT_R8G8B8A8_UNORM:
607 case WINED3DFMT_R8G8B8X8_UNORM:
608 case WINED3DFMT_B10G10R10A2_UNORM:
609 case WINED3DFMT_B5G6R5_UNORM:
610 case WINED3DFMT_R16G16B16A16_UNORM:
611 usage = 0;
612 b_info->bmiHeader.biCompression = BI_BITFIELDS;
613 masks[0] = format_desc->red_mask;
614 masks[1] = format_desc->green_mask;
615 masks[2] = format_desc->blue_mask;
616 break;
618 default:
619 /* Don't know palette */
620 b_info->bmiHeader.biCompression = BI_RGB;
621 usage = 0;
622 break;
625 ddc = GetDC(0);
626 if (ddc == 0) {
627 HeapFree(GetProcessHeap(), 0, b_info);
628 return HRESULT_FROM_WIN32(GetLastError());
631 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);
632 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
633 ReleaseDC(0, ddc);
635 if (!This->dib.DIBsection) {
636 ERR("CreateDIBSection failed!\n");
637 HeapFree(GetProcessHeap(), 0, b_info);
638 return HRESULT_FROM_WIN32(GetLastError());
641 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
642 /* copy the existing surface to the dib section */
643 if(This->resource.allocatedMemory) {
644 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
645 } else {
646 /* This is to make LockRect read the gl Texture although memory is allocated */
647 This->Flags &= ~SFLAG_INSYSMEM;
649 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
651 HeapFree(GetProcessHeap(), 0, b_info);
653 /* Now allocate a HDC */
654 This->hDC = CreateCompatibleDC(0);
655 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
656 TRACE("using wined3d palette %p\n", This->palette);
657 SelectPalette(This->hDC,
658 This->palette ? This->palette->hpal : 0,
659 FALSE);
661 This->Flags |= SFLAG_DIBSECTION;
663 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
664 This->resource.heapMemory = NULL;
666 return WINED3D_OK;
669 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
670 unsigned int w, unsigned int h)
672 unsigned int x, y;
673 const float *src_f;
674 unsigned short *dst_s;
676 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
677 for(y = 0; y < h; y++) {
678 src_f = (const float *)(src + y * pitch_in);
679 dst_s = (unsigned short *) (dst + y * pitch_out);
680 for(x = 0; x < w; x++) {
681 dst_s[x] = float_32_to_16(src_f + x);
686 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
687 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
689 static const unsigned char convert_5to8[] =
691 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
692 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
693 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
694 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
696 static const unsigned char convert_6to8[] =
698 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
699 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
700 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
701 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
702 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
703 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
704 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
705 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
707 unsigned int x, y;
709 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
711 for (y = 0; y < h; ++y)
713 const WORD *src_line = (const WORD *)(src + y * pitch_in);
714 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
715 for (x = 0; x < w; ++x)
717 WORD pixel = src_line[x];
718 dst_line[x] = 0xff000000
719 | convert_5to8[(pixel & 0xf800) >> 11] << 16
720 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
721 | convert_5to8[(pixel & 0x001f)];
726 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
727 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
729 unsigned int x, y;
731 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
733 for (y = 0; y < h; ++y)
735 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
736 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
738 for (x = 0; x < w; ++x)
740 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
745 struct d3dfmt_convertor_desc {
746 WINED3DFORMAT from, to;
747 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
750 static const struct d3dfmt_convertor_desc convertors[] =
752 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
753 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
754 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
757 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
759 unsigned int i;
760 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
761 if(convertors[i].from == from && convertors[i].to == to) {
762 return &convertors[i];
765 return NULL;
768 /*****************************************************************************
769 * surface_convert_format
771 * Creates a duplicate of a surface in a different format. Is used by Blt to
772 * blit between surfaces with different formats
774 * Parameters
775 * source: Source surface
776 * fmt: Requested destination format
778 *****************************************************************************/
779 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
780 IWineD3DSurface *ret = NULL;
781 const struct d3dfmt_convertor_desc *conv;
782 WINED3DLOCKED_RECT lock_src, lock_dst;
783 HRESULT hr;
785 conv = find_convertor(source->resource.format_desc->format, to_fmt);
786 if(!conv) {
787 FIXME("Cannot find a conversion function from format %s to %s\n",
788 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
789 return NULL;
792 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
793 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
794 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
795 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
796 NULL /* parent */, &wined3d_null_parent_ops);
797 if(!ret) {
798 ERR("Failed to create a destination surface for conversion\n");
799 return NULL;
802 memset(&lock_src, 0, sizeof(lock_src));
803 memset(&lock_dst, 0, sizeof(lock_dst));
805 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
806 if(FAILED(hr)) {
807 ERR("Failed to lock the source surface\n");
808 IWineD3DSurface_Release(ret);
809 return NULL;
811 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
812 if(FAILED(hr)) {
813 ERR("Failed to lock the dest surface\n");
814 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
815 IWineD3DSurface_Release(ret);
816 return NULL;
819 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
820 source->currentDesc.Width, source->currentDesc.Height);
822 IWineD3DSurface_UnlockRect(ret);
823 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
825 return (IWineD3DSurfaceImpl *) ret;
828 /*****************************************************************************
829 * _Blt_ColorFill
831 * Helper function that fills a memory area with a specific color
833 * Params:
834 * buf: memory address to start filling at
835 * width, height: Dimensions of the area to fill
836 * bpp: Bit depth of the surface
837 * lPitch: pitch of the surface
838 * color: Color to fill with
840 *****************************************************************************/
841 static HRESULT
842 _Blt_ColorFill(BYTE *buf,
843 int width, int height,
844 int bpp, LONG lPitch,
845 DWORD color)
847 int x, y;
848 LPBYTE first;
850 /* Do first row */
852 #define COLORFILL_ROW(type) \
854 type *d = (type *) buf; \
855 for (x = 0; x < width; x++) \
856 d[x] = (type) color; \
857 break; \
859 switch(bpp)
861 case 1: COLORFILL_ROW(BYTE)
862 case 2: COLORFILL_ROW(WORD)
863 case 3:
865 BYTE *d = buf;
866 for (x = 0; x < width; x++,d+=3)
868 d[0] = (color ) & 0xFF;
869 d[1] = (color>> 8) & 0xFF;
870 d[2] = (color>>16) & 0xFF;
872 break;
874 case 4: COLORFILL_ROW(DWORD)
875 default:
876 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
877 return WINED3DERR_NOTAVAILABLE;
880 #undef COLORFILL_ROW
882 /* Now copy first row */
883 first = buf;
884 for (y = 1; y < height; y++)
886 buf += lPitch;
887 memcpy(buf, first, width * bpp);
889 return WINED3D_OK;
892 /*****************************************************************************
893 * IWineD3DSurface::Blt, SW emulation version
895 * Performs blits to a surface, eigher from a source of source-less blts
896 * This is the main functionality of DirectDraw
898 * Params:
899 * DestRect: Destination rectangle to write to
900 * SrcSurface: Source surface, can be NULL
901 * SrcRect: Source rectangle
902 *****************************************************************************/
903 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
904 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
906 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
907 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
908 RECT xdst,xsrc;
909 HRESULT ret = WINED3D_OK;
910 WINED3DLOCKED_RECT dlock, slock;
911 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
912 const struct GlPixelFormatDesc *sEntry, *dEntry;
913 int x, y;
914 const BYTE *sbuf;
915 BYTE *dbuf;
916 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
918 if (TRACE_ON(d3d_surface))
920 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
921 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
922 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
923 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
924 #if 0
925 TRACE("\tflags: ");
926 DDRAW_dump_DDBLT(Flags);
927 if (Flags & WINEDDBLT_DDFX)
929 TRACE("\tblitfx: ");
930 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
932 #endif
935 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
937 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
938 return WINEDDERR_SURFACEBUSY;
941 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
942 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
943 FIXME("Filters not supported in software blit\n");
946 /* First check for the validity of source / destination rectangles. This was
947 * verified using a test application + by MSDN.
949 if ((Src != NULL) && (SrcRect != NULL) &&
950 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
951 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
952 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
953 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
954 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
956 WARN("Application gave us bad source rectangle for Blt.\n");
957 return WINEDDERR_INVALIDRECT;
959 /* For the Destination rect, it can be out of bounds on the condition that a clipper
960 * is set for the given surface.
962 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
963 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
964 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
965 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
966 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
967 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
969 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
970 return WINEDDERR_INVALIDRECT;
973 /* Now handle negative values in the rectangles. Warning: only supported for now
974 in the 'simple' cases (ie not in any stretching / rotation cases).
976 First, the case where nothing is to be done.
978 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
979 (DestRect->top >= (int) This->currentDesc.Height) ||
980 (DestRect->left >= (int) This->currentDesc.Width))) ||
981 ((Src != NULL) && (SrcRect != NULL) &&
982 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
983 (SrcRect->top >= (int) Src->currentDesc.Height) ||
984 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
986 TRACE("Nothing to be done !\n");
987 return WINED3D_OK;
990 if (DestRect)
992 xdst = *DestRect;
994 else
996 xdst.top = 0;
997 xdst.bottom = This->currentDesc.Height;
998 xdst.left = 0;
999 xdst.right = This->currentDesc.Width;
1002 if (SrcRect)
1004 xsrc = *SrcRect;
1006 else
1008 if (Src)
1010 xsrc.top = 0;
1011 xsrc.bottom = Src->currentDesc.Height;
1012 xsrc.left = 0;
1013 xsrc.right = Src->currentDesc.Width;
1015 else
1017 memset(&xsrc,0,sizeof(xsrc));
1021 /* The easy case : the source-less blits.... */
1022 if (Src == NULL && DestRect)
1024 RECT full_rect;
1025 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1027 full_rect.left = 0;
1028 full_rect.top = 0;
1029 full_rect.right = This->currentDesc.Width;
1030 full_rect.bottom = This->currentDesc.Height;
1031 IntersectRect(&temp_rect, &full_rect, DestRect);
1032 xdst = temp_rect;
1034 else if (DestRect)
1036 /* Only handle clipping on the destination rectangle */
1037 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1038 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1039 if (clip_vert || clip_horiz)
1041 /* Now check if this is a special case or not... */
1042 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1043 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1044 (Flags & WINEDDBLT_DDFX))
1046 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1047 return WINED3D_OK;
1050 if (clip_horiz)
1052 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1053 if (DestRect->right > This->currentDesc.Width)
1055 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1056 xdst.right = (int) This->currentDesc.Width;
1059 if (clip_vert)
1061 if (DestRect->top < 0)
1063 xsrc.top -= DestRect->top;
1064 xdst.top = 0;
1066 if (DestRect->bottom > This->currentDesc.Height)
1068 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1069 xdst.bottom = (int) This->currentDesc.Height;
1072 /* And check if after clipping something is still to be done... */
1073 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1074 (xdst.top >= (int) This->currentDesc.Height) ||
1075 (xdst.left >= (int) This->currentDesc.Width) ||
1076 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1077 (xsrc.top >= (int) Src->currentDesc.Height) ||
1078 (xsrc.left >= (int) Src->currentDesc.Width))
1080 TRACE("Nothing to be done after clipping !\n");
1081 return WINED3D_OK;
1086 if (Src == This)
1088 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1089 slock = dlock;
1090 sEntry = This->resource.format_desc;
1091 dEntry = sEntry;
1093 else
1095 dEntry = This->resource.format_desc;
1096 if (Src)
1098 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1100 Src = surface_convert_format(Src, dEntry->format);
1101 if(!Src) {
1102 /* The conv function writes a FIXME */
1103 WARN("Cannot convert source surface format to dest format\n");
1104 goto release;
1107 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1108 sEntry = Src->resource.format_desc;
1110 else
1112 sEntry = dEntry;
1114 if (DestRect)
1115 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1116 else
1117 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1120 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1122 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1124 if (!DestRect || Src == This)
1126 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1127 goto release;
1131 bpp = This->resource.format_desc->byte_count;
1132 srcheight = xsrc.bottom - xsrc.top;
1133 srcwidth = xsrc.right - xsrc.left;
1134 dstheight = xdst.bottom - xdst.top;
1135 dstwidth = xdst.right - xdst.left;
1136 width = (xdst.right - xdst.left) * bpp;
1138 if (DestRect && Src != This)
1139 dbuf = dlock.pBits;
1140 else
1141 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1143 if (Flags & WINEDDBLT_WAIT)
1145 Flags &= ~WINEDDBLT_WAIT;
1147 if (Flags & WINEDDBLT_ASYNC)
1149 static BOOL displayed = FALSE;
1150 if (!displayed)
1151 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1152 displayed = TRUE;
1153 Flags &= ~WINEDDBLT_ASYNC;
1155 if (Flags & WINEDDBLT_DONOTWAIT)
1157 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1158 static BOOL displayed = FALSE;
1159 if (!displayed)
1160 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1161 displayed = TRUE;
1162 Flags &= ~WINEDDBLT_DONOTWAIT;
1165 /* First, all the 'source-less' blits */
1166 if (Flags & WINEDDBLT_COLORFILL)
1168 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1169 dlock.Pitch, DDBltFx->u5.dwFillColor);
1170 Flags &= ~WINEDDBLT_COLORFILL;
1173 if (Flags & WINEDDBLT_DEPTHFILL)
1175 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1177 if (Flags & WINEDDBLT_ROP)
1179 /* Catch some degenerate cases here */
1180 switch(DDBltFx->dwROP)
1182 case BLACKNESS:
1183 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1184 break;
1185 case 0xAA0029: /* No-op */
1186 break;
1187 case WHITENESS:
1188 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1189 break;
1190 case SRCCOPY: /* well, we do that below ? */
1191 break;
1192 default:
1193 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1194 goto error;
1196 Flags &= ~WINEDDBLT_ROP;
1198 if (Flags & WINEDDBLT_DDROPS)
1200 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1202 /* Now the 'with source' blits */
1203 if (Src)
1205 const BYTE *sbase;
1206 int sx, xinc, sy, yinc;
1208 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1209 goto release;
1210 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1211 xinc = (srcwidth << 16) / dstwidth;
1212 yinc = (srcheight << 16) / dstheight;
1214 if (!Flags)
1216 /* No effects, we can cheat here */
1217 if (dstwidth == srcwidth)
1219 if (dstheight == srcheight)
1221 /* No stretching in either direction. This needs to be as
1222 * fast as possible */
1223 sbuf = sbase;
1225 /* check for overlapping surfaces */
1226 if (Src != This || xdst.top < xsrc.top ||
1227 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1229 /* no overlap, or dst above src, so copy from top downwards */
1230 for (y = 0; y < dstheight; y++)
1232 memcpy(dbuf, sbuf, width);
1233 sbuf += slock.Pitch;
1234 dbuf += dlock.Pitch;
1237 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1239 sbuf += (slock.Pitch*dstheight);
1240 dbuf += (dlock.Pitch*dstheight);
1241 for (y = 0; y < dstheight; y++)
1243 sbuf -= slock.Pitch;
1244 dbuf -= dlock.Pitch;
1245 memcpy(dbuf, sbuf, width);
1248 else /* src and dst overlapping on the same line, use memmove */
1250 for (y = 0; y < dstheight; y++)
1252 memmove(dbuf, sbuf, width);
1253 sbuf += slock.Pitch;
1254 dbuf += dlock.Pitch;
1257 } else {
1258 /* Stretching in Y direction only */
1259 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1260 sbuf = sbase + (sy >> 16) * slock.Pitch;
1261 memcpy(dbuf, sbuf, width);
1262 dbuf += dlock.Pitch;
1266 else
1268 /* Stretching in X direction */
1269 int last_sy = -1;
1270 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1272 sbuf = sbase + (sy >> 16) * slock.Pitch;
1274 if ((sy >> 16) == (last_sy >> 16))
1276 /* this sourcerow is the same as last sourcerow -
1277 * copy already stretched row
1279 memcpy(dbuf, dbuf - dlock.Pitch, width);
1281 else
1283 #define STRETCH_ROW(type) { \
1284 const type *s = (const type *)sbuf; \
1285 type *d = (type *)dbuf; \
1286 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1287 d[x] = s[sx >> 16]; \
1288 break; }
1290 switch(bpp)
1292 case 1: STRETCH_ROW(BYTE)
1293 case 2: STRETCH_ROW(WORD)
1294 case 4: STRETCH_ROW(DWORD)
1295 case 3:
1297 const BYTE *s;
1298 BYTE *d = dbuf;
1299 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1301 DWORD pixel;
1303 s = sbuf+3*(sx>>16);
1304 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1305 d[0] = (pixel )&0xff;
1306 d[1] = (pixel>> 8)&0xff;
1307 d[2] = (pixel>>16)&0xff;
1308 d+=3;
1310 break;
1312 default:
1313 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1314 ret = WINED3DERR_NOTAVAILABLE;
1315 goto error;
1317 #undef STRETCH_ROW
1319 dbuf += dlock.Pitch;
1320 last_sy = sy;
1324 else
1326 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1327 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1328 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1329 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1331 /* The color keying flags are checked for correctness in ddraw */
1332 if (Flags & WINEDDBLT_KEYSRC)
1334 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1335 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1337 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1339 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1340 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1343 if (Flags & WINEDDBLT_KEYDEST)
1345 /* Destination color keys are taken from the source surface ! */
1346 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1347 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1349 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1351 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1352 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1355 if(bpp == 1)
1357 keymask = 0xff;
1359 else
1361 keymask = sEntry->red_mask
1362 | sEntry->green_mask
1363 | sEntry->blue_mask;
1365 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1368 if (Flags & WINEDDBLT_DDFX)
1370 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1371 LONG tmpxy;
1372 dTopLeft = dbuf;
1373 dTopRight = dbuf+((dstwidth-1)*bpp);
1374 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1375 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1377 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1379 /* I don't think we need to do anything about this flag */
1380 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1382 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1384 tmp = dTopRight;
1385 dTopRight = dTopLeft;
1386 dTopLeft = tmp;
1387 tmp = dBottomRight;
1388 dBottomRight = dBottomLeft;
1389 dBottomLeft = tmp;
1390 dstxinc = dstxinc *-1;
1392 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1394 tmp = dTopLeft;
1395 dTopLeft = dBottomLeft;
1396 dBottomLeft = tmp;
1397 tmp = dTopRight;
1398 dTopRight = dBottomRight;
1399 dBottomRight = tmp;
1400 dstyinc = dstyinc *-1;
1402 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1404 /* I don't think we need to do anything about this flag */
1405 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1407 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1409 tmp = dBottomRight;
1410 dBottomRight = dTopLeft;
1411 dTopLeft = tmp;
1412 tmp = dBottomLeft;
1413 dBottomLeft = dTopRight;
1414 dTopRight = tmp;
1415 dstxinc = dstxinc * -1;
1416 dstyinc = dstyinc * -1;
1418 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1420 tmp = dTopLeft;
1421 dTopLeft = dBottomLeft;
1422 dBottomLeft = dBottomRight;
1423 dBottomRight = dTopRight;
1424 dTopRight = tmp;
1425 tmpxy = dstxinc;
1426 dstxinc = dstyinc;
1427 dstyinc = tmpxy;
1428 dstxinc = dstxinc * -1;
1430 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1432 tmp = dTopLeft;
1433 dTopLeft = dTopRight;
1434 dTopRight = dBottomRight;
1435 dBottomRight = dBottomLeft;
1436 dBottomLeft = tmp;
1437 tmpxy = dstxinc;
1438 dstxinc = dstyinc;
1439 dstyinc = tmpxy;
1440 dstyinc = dstyinc * -1;
1442 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1444 /* I don't think we need to do anything about this flag */
1445 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1447 dbuf = dTopLeft;
1448 Flags &= ~(WINEDDBLT_DDFX);
1451 #define COPY_COLORKEY_FX(type) { \
1452 const type *s; \
1453 type *d = (type *)dbuf, *dx, tmp; \
1454 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1455 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1456 dx = d; \
1457 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1458 tmp = s[sx >> 16]; \
1459 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1460 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1461 dx[0] = tmp; \
1463 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1465 d = (type*)(((LPBYTE)d)+dstyinc); \
1467 break; }
1469 switch (bpp) {
1470 case 1: COPY_COLORKEY_FX(BYTE)
1471 case 2: COPY_COLORKEY_FX(WORD)
1472 case 4: COPY_COLORKEY_FX(DWORD)
1473 case 3:
1475 const BYTE *s;
1476 BYTE *d = dbuf, *dx;
1477 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1479 sbuf = sbase + (sy >> 16) * slock.Pitch;
1480 dx = d;
1481 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1483 DWORD pixel, dpixel = 0;
1484 s = sbuf+3*(sx>>16);
1485 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1486 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1487 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1488 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1490 dx[0] = (pixel )&0xff;
1491 dx[1] = (pixel>> 8)&0xff;
1492 dx[2] = (pixel>>16)&0xff;
1494 dx+= dstxinc;
1496 d += dstyinc;
1498 break;
1500 default:
1501 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1502 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1503 ret = WINED3DERR_NOTAVAILABLE;
1504 goto error;
1505 #undef COPY_COLORKEY_FX
1510 error:
1511 if (Flags && FIXME_ON(d3d_surface))
1513 FIXME("\tUnsupported flags: %08x\n", Flags);
1516 release:
1517 IWineD3DSurface_UnlockRect(iface);
1518 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1519 /* Release the converted surface if any */
1520 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1521 return ret;
1524 /*****************************************************************************
1525 * IWineD3DSurface::BltFast, SW emulation version
1527 * This is the software implementation of BltFast, as used by GDI surfaces
1528 * and as a fallback for OpenGL surfaces. This code is taken from the old
1529 * DirectDraw code, and was originally written by TransGaming.
1531 * Params:
1532 * dstx:
1533 * dsty:
1534 * Source: Source surface to copy from
1535 * rsrc: Source rectangle
1536 * trans: Some Flags
1538 * Returns:
1539 * WINED3D_OK on success
1541 *****************************************************************************/
1542 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1543 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1545 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1546 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1548 int bpp, w, h, x, y;
1549 WINED3DLOCKED_RECT dlock,slock;
1550 HRESULT ret = WINED3D_OK;
1551 RECT rsrc2;
1552 RECT lock_src, lock_dst, lock_union;
1553 const BYTE *sbuf;
1554 BYTE *dbuf;
1555 const struct GlPixelFormatDesc *sEntry, *dEntry;
1557 if (TRACE_ON(d3d_surface))
1559 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1561 if (rsrc)
1563 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1564 rsrc->right,rsrc->bottom);
1566 else
1568 TRACE(" srcrect: NULL\n");
1572 if ((This->Flags & SFLAG_LOCKED) ||
1573 (Src->Flags & SFLAG_LOCKED))
1575 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1576 return WINEDDERR_SURFACEBUSY;
1579 if (!rsrc)
1581 WARN("rsrc is NULL!\n");
1582 rsrc2.left = 0;
1583 rsrc2.top = 0;
1584 rsrc2.right = Src->currentDesc.Width;
1585 rsrc2.bottom = Src->currentDesc.Height;
1586 rsrc = &rsrc2;
1589 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1590 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1591 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1592 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1593 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1594 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1596 WARN("Application gave us bad source rectangle for BltFast.\n");
1597 return WINEDDERR_INVALIDRECT;
1600 h = rsrc->bottom - rsrc->top;
1601 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1602 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1603 if (h <= 0) return WINEDDERR_INVALIDRECT;
1605 w = rsrc->right - rsrc->left;
1606 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1607 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1608 if (w <= 0) return WINEDDERR_INVALIDRECT;
1610 /* Now compute the locking rectangle... */
1611 lock_src.left = rsrc->left;
1612 lock_src.top = rsrc->top;
1613 lock_src.right = lock_src.left + w;
1614 lock_src.bottom = lock_src.top + h;
1616 lock_dst.left = dstx;
1617 lock_dst.top = dsty;
1618 lock_dst.right = dstx + w;
1619 lock_dst.bottom = dsty + h;
1621 bpp = This->resource.format_desc->byte_count;
1623 /* We need to lock the surfaces, or we won't get refreshes when done. */
1624 if (Src == This)
1626 int pitch;
1628 UnionRect(&lock_union, &lock_src, &lock_dst);
1630 /* Lock the union of the two rectangles */
1631 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1632 if(ret != WINED3D_OK) goto error;
1634 pitch = dlock.Pitch;
1635 slock.Pitch = dlock.Pitch;
1637 /* Since slock was originally copied from this surface's description, we can just reuse it */
1638 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1639 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1640 sEntry = Src->resource.format_desc;
1641 dEntry = sEntry;
1643 else
1645 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1646 if(ret != WINED3D_OK) goto error;
1647 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1648 if(ret != WINED3D_OK) goto error;
1650 sbuf = slock.pBits;
1651 dbuf = dlock.pBits;
1652 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1654 sEntry = Src->resource.format_desc;
1655 dEntry = This->resource.format_desc;
1658 /* Handle compressed surfaces first... */
1659 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1661 UINT row_block_count;
1663 TRACE("compressed -> compressed copy\n");
1664 if (trans)
1665 FIXME("trans arg not supported when a compressed surface is involved\n");
1666 if (dstx || dsty)
1667 FIXME("offset for destination surface is not supported\n");
1668 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1670 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1671 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1672 goto error;
1675 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1676 for (y = 0; y < h; y += dEntry->block_height)
1678 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1679 dbuf += dlock.Pitch;
1680 sbuf += slock.Pitch;
1683 goto error;
1685 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1687 /* TODO: Use the libtxc_dxtn.so shared library to do
1688 * software decompression
1690 ERR("Software decompression not supported.\n");
1691 goto error;
1694 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1696 DWORD keylow, keyhigh;
1697 DWORD mask = Src->resource.format_desc->red_mask |
1698 Src->resource.format_desc->green_mask |
1699 Src->resource.format_desc->blue_mask;
1701 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1702 if(!mask && bpp==1)
1703 mask = 0xff;
1705 TRACE("Color keyed copy\n");
1706 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1708 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1709 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1711 else
1713 /* I'm not sure if this is correct */
1714 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1715 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1716 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1719 #define COPYBOX_COLORKEY(type) { \
1720 const type *s = (const type *)sbuf; \
1721 type *d = (type *)dbuf; \
1722 type tmp; \
1723 for (y = 0; y < h; y++) { \
1724 for (x = 0; x < w; x++) { \
1725 tmp = s[x]; \
1726 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1728 s = (const type *)((const BYTE *)s + slock.Pitch); \
1729 d = (type *)((BYTE *)d + dlock.Pitch); \
1731 break; \
1734 switch (bpp) {
1735 case 1: COPYBOX_COLORKEY(BYTE)
1736 case 2: COPYBOX_COLORKEY(WORD)
1737 case 4: COPYBOX_COLORKEY(DWORD)
1738 case 3:
1740 const BYTE *s;
1741 BYTE *d;
1742 DWORD tmp;
1743 s = sbuf;
1744 d = dbuf;
1745 for (y = 0; y < h; y++)
1747 for (x = 0; x < w * 3; x += 3)
1749 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1750 if (tmp < keylow || tmp > keyhigh)
1752 d[x + 0] = s[x + 0];
1753 d[x + 1] = s[x + 1];
1754 d[x + 2] = s[x + 2];
1757 s += slock.Pitch;
1758 d += dlock.Pitch;
1760 break;
1762 default:
1763 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1764 ret = WINED3DERR_NOTAVAILABLE;
1765 goto error;
1767 #undef COPYBOX_COLORKEY
1768 TRACE("Copy Done\n");
1770 else
1772 int width = w * bpp;
1773 INT sbufpitch, dbufpitch;
1775 TRACE("NO color key copy\n");
1776 /* Handle overlapping surfaces */
1777 if (sbuf < dbuf)
1779 sbuf += (h - 1) * slock.Pitch;
1780 dbuf += (h - 1) * dlock.Pitch;
1781 sbufpitch = -slock.Pitch;
1782 dbufpitch = -dlock.Pitch;
1784 else
1786 sbufpitch = slock.Pitch;
1787 dbufpitch = dlock.Pitch;
1789 for (y = 0; y < h; y++)
1791 /* This is pretty easy, a line for line memcpy */
1792 memmove(dbuf, sbuf, width);
1793 sbuf += sbufpitch;
1794 dbuf += dbufpitch;
1796 TRACE("Copy done\n");
1799 error:
1800 if (Src == This)
1802 IWineD3DSurface_UnlockRect(iface);
1804 else
1806 IWineD3DSurface_UnlockRect(iface);
1807 IWineD3DSurface_UnlockRect(Source);
1810 return ret;
1813 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1815 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1817 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1818 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1820 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1822 if (NULL == pRect)
1824 pLockedRect->pBits = This->resource.allocatedMemory;
1825 This->lockedRect.left = 0;
1826 This->lockedRect.top = 0;
1827 This->lockedRect.right = This->currentDesc.Width;
1828 This->lockedRect.bottom = This->currentDesc.Height;
1830 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1831 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1832 This->lockedRect.right, This->lockedRect.bottom);
1834 else
1836 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
1838 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1839 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1841 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1843 /* Compressed textures are block based, so calculate the offset of
1844 * the block that contains the top-left pixel of the locked rectangle. */
1845 pLockedRect->pBits = This->resource.allocatedMemory
1846 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1847 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1849 else
1851 pLockedRect->pBits = This->resource.allocatedMemory +
1852 (pLockedRect->Pitch * pRect->top) +
1853 (pRect->left * format_desc->byte_count);
1855 This->lockedRect.left = pRect->left;
1856 This->lockedRect.top = pRect->top;
1857 This->lockedRect.right = pRect->right;
1858 This->lockedRect.bottom = pRect->bottom;
1861 /* No dirtifying is needed for this surface implementation */
1862 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1864 return WINED3D_OK;
1867 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1868 ERR("Should not be called on base texture\n");
1871 /* TODO: think about moving this down to resource? */
1872 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1874 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1876 /* This should only be called for sysmem textures, it may be a good idea
1877 * to extend this to all pools at some point in the future */
1878 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1880 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1882 return This->resource.allocatedMemory;