d3d9: Abort the x8l8v8u8 test if the format is not supported.
[wine.git] / dlls / wined3d / surface_base.c
blobca715f50eaba07ecc98718bb13867d29cc38725f
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_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
121 return resource_get_device((IWineD3DResource *)iface, ppDevice);
124 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
125 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
128 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
129 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
132 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
133 return resource_free_private_data((IWineD3DResource *)iface, refguid);
136 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
137 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
140 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
141 return resource_get_priority((IWineD3DResource *)iface);
144 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
145 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
146 return resource_get_type((IWineD3DResource *)iface);
149 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
150 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
151 return resource_get_parent((IWineD3DResource *)iface, pParent);
154 /* ******************************************************
155 IWineD3DSurface IWineD3DSurface parts follow
156 ****************************************************** */
158 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
159 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
160 IWineD3DBase *container = 0;
162 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
164 if (!ppContainer) {
165 ERR("Called without a valid ppContainer.\n");
168 /* Standalone surfaces return the device as container. */
169 if (This->container) {
170 container = This->container;
171 } else {
172 container = (IWineD3DBase *)This->resource.wineD3DDevice;
175 TRACE("Relaying to QueryInterface\n");
176 return IUnknown_QueryInterface(container, riid, ppContainer);
179 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
180 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
182 TRACE("(%p) : copying into %p\n", This, pDesc);
184 pDesc->format = This->resource.format_desc->format;
185 pDesc->resource_type = This->resource.resourceType;
186 pDesc->usage = This->resource.usage;
187 pDesc->pool = This->resource.pool;
188 pDesc->size = This->resource.size; /* dx8 only */
189 pDesc->multisample_type = This->currentDesc.MultiSampleType;
190 pDesc->multisample_quality = This->currentDesc.MultiSampleQuality;
191 pDesc->width = This->currentDesc.Width;
192 pDesc->height = This->currentDesc.Height;
194 return WINED3D_OK;
197 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
198 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
199 TRACE("(%p)->(%x)\n", This, Flags);
201 switch (Flags)
203 case WINEDDGBS_CANBLT:
204 case WINEDDGBS_ISBLTDONE:
205 return WINED3D_OK;
207 default:
208 return WINED3DERR_INVALIDCALL;
212 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
213 /* XXX: DDERR_INVALIDSURFACETYPE */
215 TRACE("(%p)->(%08x)\n",iface,Flags);
216 switch (Flags) {
217 case WINEDDGFS_CANFLIP:
218 case WINEDDGFS_ISFLIPDONE:
219 return WINED3D_OK;
221 default:
222 return WINED3DERR_INVALIDCALL;
226 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
227 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
228 TRACE("(%p)\n", This);
230 /* D3D8 and 9 loose full devices, ddraw only surfaces */
231 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
234 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
235 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
236 TRACE("(%p)\n", This);
238 /* So far we don't lose anything :) */
239 This->Flags &= ~SFLAG_LOST;
240 return WINED3D_OK;
243 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
244 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
245 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
246 TRACE("(%p)->(%p)\n", This, Pal);
248 if(This->palette == PalImpl) {
249 TRACE("Nop palette change\n");
250 return WINED3D_OK;
253 if(This->palette != NULL)
254 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
255 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
257 This->palette = PalImpl;
259 if(PalImpl != NULL) {
260 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
261 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
264 return IWineD3DSurface_RealizePalette(iface);
266 else return WINED3D_OK;
269 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
271 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
272 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
274 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
275 FIXME(" colorkey value not supported (%08x) !\n", Flags);
276 return WINED3DERR_INVALIDCALL;
279 /* Dirtify the surface, but only if a key was changed */
280 if(CKey) {
281 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
282 case WINEDDCKEY_DESTBLT:
283 This->DestBltCKey = *CKey;
284 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
285 break;
287 case WINEDDCKEY_DESTOVERLAY:
288 This->DestOverlayCKey = *CKey;
289 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
290 break;
292 case WINEDDCKEY_SRCOVERLAY:
293 This->SrcOverlayCKey = *CKey;
294 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
295 break;
297 case WINEDDCKEY_SRCBLT:
298 This->SrcBltCKey = *CKey;
299 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
300 break;
303 else {
304 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
305 case WINEDDCKEY_DESTBLT:
306 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
307 break;
309 case WINEDDCKEY_DESTOVERLAY:
310 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
311 break;
313 case WINEDDCKEY_SRCOVERLAY:
314 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
315 break;
317 case WINEDDCKEY_SRCBLT:
318 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
319 break;
323 return WINED3D_OK;
326 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
327 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
328 TRACE("(%p)->(%p)\n", This, Pal);
330 *Pal = (IWineD3DPalette *) This->palette;
331 return WINED3D_OK;
334 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
335 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
336 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
337 DWORD ret;
338 TRACE("(%p)\n", This);
340 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
342 /* Since compressed formats are block based, pitch means the amount of
343 * bytes to the next row of block rather than the next row of pixels. */
344 UINT row_block_count = (This->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
345 ret = row_block_count * format_desc->block_byte_count;
347 else
349 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
350 ret = This->resource.format_desc->byte_count * This->currentDesc.Width; /* Bytes / row */
351 ret = (ret + alignment - 1) & ~(alignment - 1);
353 TRACE("(%p) Returning %d\n", This, ret);
354 return ret;
357 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
358 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
359 LONG w, h;
361 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
363 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
365 TRACE("(%p): Not an overlay surface\n", This);
366 return WINEDDERR_NOTAOVERLAYSURFACE;
369 w = This->overlay_destrect.right - This->overlay_destrect.left;
370 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
371 This->overlay_destrect.left = X;
372 This->overlay_destrect.top = Y;
373 This->overlay_destrect.right = X + w;
374 This->overlay_destrect.bottom = Y + h;
376 IWineD3DSurface_DrawOverlay(iface);
378 return WINED3D_OK;
381 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
382 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
383 HRESULT hr;
385 TRACE("(%p)->(%p,%p)\n", This, X, Y);
387 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
389 TRACE("(%p): Not an overlay surface\n", This);
390 return WINEDDERR_NOTAOVERLAYSURFACE;
392 if(This->overlay_dest == NULL) {
393 *X = 0; *Y = 0;
394 hr = WINEDDERR_OVERLAYNOTVISIBLE;
395 } else {
396 *X = This->overlay_destrect.left;
397 *Y = This->overlay_destrect.top;
398 hr = WINED3D_OK;
401 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
402 return hr;
405 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
406 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
407 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
409 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
411 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
413 TRACE("(%p): Not an overlay surface\n", This);
414 return WINEDDERR_NOTAOVERLAYSURFACE;
417 return WINED3D_OK;
420 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
421 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
423 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
424 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
425 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
427 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
429 WARN("(%p): Not an overlay surface\n", This);
430 return WINEDDERR_NOTAOVERLAYSURFACE;
431 } else if(!DstSurface) {
432 WARN("(%p): Dest surface is NULL\n", This);
433 return WINED3DERR_INVALIDCALL;
436 if(SrcRect) {
437 This->overlay_srcrect = *SrcRect;
438 } else {
439 This->overlay_srcrect.left = 0;
440 This->overlay_srcrect.top = 0;
441 This->overlay_srcrect.right = This->currentDesc.Width;
442 This->overlay_srcrect.bottom = This->currentDesc.Height;
445 if(DstRect) {
446 This->overlay_destrect = *DstRect;
447 } else {
448 This->overlay_destrect.left = 0;
449 This->overlay_destrect.top = 0;
450 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
451 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
454 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
455 list_remove(&This->overlay_entry);
458 if(Flags & WINEDDOVER_SHOW) {
459 if(This->overlay_dest != Dst) {
460 This->overlay_dest = Dst;
461 list_add_tail(&Dst->overlays, &This->overlay_entry);
463 } else if(Flags & WINEDDOVER_HIDE) {
464 /* tests show that the rectangles are erased on hide */
465 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
466 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
467 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
468 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
469 This->overlay_dest = NULL;
472 IWineD3DSurface_DrawOverlay(iface);
474 return WINED3D_OK;
477 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
479 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
480 TRACE("(%p)->(%p)\n", This, clipper);
482 This->clipper = clipper;
483 return WINED3D_OK;
486 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
488 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
489 TRACE("(%p)->(%p)\n", This, clipper);
491 *clipper = This->clipper;
492 if(*clipper) {
493 IWineD3DClipper_AddRef(*clipper);
495 return WINED3D_OK;
498 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
499 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
501 TRACE("This %p, container %p\n", This, container);
503 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
505 TRACE("Setting container to %p from %p\n", container, This->container);
506 This->container = container;
508 return WINED3D_OK;
511 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
512 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
513 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format,
514 &This->resource.wineD3DDevice->adapter->gl_info);
516 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
518 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
519 return WINED3DERR_INVALIDCALL;
522 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
524 This->resource.size = surface_calculate_size(format_desc, This->resource.wineD3DDevice->surface_alignment,
525 This->pow2Width, This->pow2Height);
527 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
529 This->resource.format_desc = format_desc;
531 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
533 return WINED3D_OK;
536 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
537 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
538 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
539 int extraline = 0;
540 SYSTEM_INFO sysInfo;
541 BITMAPINFO* b_info;
542 HDC ddc;
543 DWORD *masks;
544 UINT usage;
546 if(!(format_desc->Flags & WINED3DFMT_FLAG_GETDC))
548 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format_desc->format));
549 return WINED3DERR_INVALIDCALL;
552 switch (format_desc->byte_count)
554 case 2:
555 case 4:
556 /* Allocate extra space to store the RGB bit masks. */
557 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
558 break;
560 case 3:
561 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
562 break;
564 default:
565 /* Allocate extra space for a palette. */
566 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
567 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
568 break;
571 if (!b_info)
572 return E_OUTOFMEMORY;
574 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
575 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
576 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
577 * add an extra line to the dib section
579 GetSystemInfo(&sysInfo);
580 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
581 extraline = 1;
582 TRACE("Adding an extra line to the dib section\n");
585 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
586 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
587 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
588 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
589 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
590 b_info->bmiHeader.biPlanes = 1;
591 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
593 b_info->bmiHeader.biXPelsPerMeter = 0;
594 b_info->bmiHeader.biYPelsPerMeter = 0;
595 b_info->bmiHeader.biClrUsed = 0;
596 b_info->bmiHeader.biClrImportant = 0;
598 /* Get the bit masks */
599 masks = (DWORD *)b_info->bmiColors;
600 switch (This->resource.format_desc->format)
602 case WINED3DFMT_B8G8R8_UNORM:
603 usage = DIB_RGB_COLORS;
604 b_info->bmiHeader.biCompression = BI_RGB;
605 break;
607 case WINED3DFMT_B5G5R5X1_UNORM:
608 case WINED3DFMT_B5G5R5A1_UNORM:
609 case WINED3DFMT_B4G4R4A4_UNORM:
610 case WINED3DFMT_B4G4R4X4_UNORM:
611 case WINED3DFMT_B2G3R3_UNORM:
612 case WINED3DFMT_B2G3R3A8_UNORM:
613 case WINED3DFMT_R10G10B10A2_UNORM:
614 case WINED3DFMT_R8G8B8A8_UNORM:
615 case WINED3DFMT_R8G8B8X8_UNORM:
616 case WINED3DFMT_B10G10R10A2_UNORM:
617 case WINED3DFMT_B5G6R5_UNORM:
618 case WINED3DFMT_R16G16B16A16_UNORM:
619 usage = 0;
620 b_info->bmiHeader.biCompression = BI_BITFIELDS;
621 masks[0] = format_desc->red_mask;
622 masks[1] = format_desc->green_mask;
623 masks[2] = format_desc->blue_mask;
624 break;
626 default:
627 /* Don't know palette */
628 b_info->bmiHeader.biCompression = BI_RGB;
629 usage = 0;
630 break;
633 ddc = GetDC(0);
634 if (ddc == 0) {
635 HeapFree(GetProcessHeap(), 0, b_info);
636 return HRESULT_FROM_WIN32(GetLastError());
639 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);
640 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
641 ReleaseDC(0, ddc);
643 if (!This->dib.DIBsection) {
644 ERR("CreateDIBSection failed!\n");
645 HeapFree(GetProcessHeap(), 0, b_info);
646 return HRESULT_FROM_WIN32(GetLastError());
649 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
650 /* copy the existing surface to the dib section */
651 if(This->resource.allocatedMemory) {
652 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
653 } else {
654 /* This is to make LockRect read the gl Texture although memory is allocated */
655 This->Flags &= ~SFLAG_INSYSMEM;
657 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
659 HeapFree(GetProcessHeap(), 0, b_info);
661 /* Now allocate a HDC */
662 This->hDC = CreateCompatibleDC(0);
663 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
664 TRACE("using wined3d palette %p\n", This->palette);
665 SelectPalette(This->hDC,
666 This->palette ? This->palette->hpal : 0,
667 FALSE);
669 This->Flags |= SFLAG_DIBSECTION;
671 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
672 This->resource.heapMemory = NULL;
674 return WINED3D_OK;
677 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
678 unsigned int w, unsigned int h)
680 unsigned int x, y;
681 const float *src_f;
682 unsigned short *dst_s;
684 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
685 for(y = 0; y < h; y++) {
686 src_f = (const float *)(src + y * pitch_in);
687 dst_s = (unsigned short *) (dst + y * pitch_out);
688 for(x = 0; x < w; x++) {
689 dst_s[x] = float_32_to_16(src_f + x);
694 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
695 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
697 static const unsigned char convert_5to8[] =
699 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
700 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
701 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
702 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
704 static const unsigned char convert_6to8[] =
706 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
707 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
708 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
709 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
710 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
711 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
712 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
713 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
715 unsigned int x, y;
717 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
719 for (y = 0; y < h; ++y)
721 const WORD *src_line = (const WORD *)(src + y * pitch_in);
722 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
723 for (x = 0; x < w; ++x)
725 WORD pixel = src_line[x];
726 dst_line[x] = 0xff000000
727 | convert_5to8[(pixel & 0xf800) >> 11] << 16
728 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
729 | convert_5to8[(pixel & 0x001f)];
734 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
735 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
737 unsigned int x, y;
739 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
741 for (y = 0; y < h; ++y)
743 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
744 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
746 for (x = 0; x < w; ++x)
748 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
753 struct d3dfmt_convertor_desc {
754 WINED3DFORMAT from, to;
755 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
758 static const struct d3dfmt_convertor_desc convertors[] =
760 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
761 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
762 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
765 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
767 unsigned int i;
768 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
769 if(convertors[i].from == from && convertors[i].to == to) {
770 return &convertors[i];
773 return NULL;
776 /*****************************************************************************
777 * surface_convert_format
779 * Creates a duplicate of a surface in a different format. Is used by Blt to
780 * blit between surfaces with different formats
782 * Parameters
783 * source: Source surface
784 * fmt: Requested destination format
786 *****************************************************************************/
787 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
788 IWineD3DSurface *ret = NULL;
789 const struct d3dfmt_convertor_desc *conv;
790 WINED3DLOCKED_RECT lock_src, lock_dst;
791 HRESULT hr;
793 conv = find_convertor(source->resource.format_desc->format, to_fmt);
794 if(!conv) {
795 FIXME("Cannot find a conversion function from format %s to %s\n",
796 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
797 return NULL;
800 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.wineD3DDevice, source->currentDesc.Width,
801 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
802 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
803 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
804 NULL /* parent */, &wined3d_null_parent_ops);
805 if(!ret) {
806 ERR("Failed to create a destination surface for conversion\n");
807 return NULL;
810 memset(&lock_src, 0, sizeof(lock_src));
811 memset(&lock_dst, 0, sizeof(lock_dst));
813 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
814 if(FAILED(hr)) {
815 ERR("Failed to lock the source surface\n");
816 IWineD3DSurface_Release(ret);
817 return NULL;
819 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
820 if(FAILED(hr)) {
821 ERR("Failed to lock the dest surface\n");
822 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
823 IWineD3DSurface_Release(ret);
824 return NULL;
827 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
828 source->currentDesc.Width, source->currentDesc.Height);
830 IWineD3DSurface_UnlockRect(ret);
831 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
833 return (IWineD3DSurfaceImpl *) ret;
836 /*****************************************************************************
837 * _Blt_ColorFill
839 * Helper function that fills a memory area with a specific color
841 * Params:
842 * buf: memory address to start filling at
843 * width, height: Dimensions of the area to fill
844 * bpp: Bit depth of the surface
845 * lPitch: pitch of the surface
846 * color: Color to fill with
848 *****************************************************************************/
849 static HRESULT
850 _Blt_ColorFill(BYTE *buf,
851 int width, int height,
852 int bpp, LONG lPitch,
853 DWORD color)
855 int x, y;
856 LPBYTE first;
858 /* Do first row */
860 #define COLORFILL_ROW(type) \
862 type *d = (type *) buf; \
863 for (x = 0; x < width; x++) \
864 d[x] = (type) color; \
865 break; \
867 switch(bpp)
869 case 1: COLORFILL_ROW(BYTE)
870 case 2: COLORFILL_ROW(WORD)
871 case 3:
873 BYTE *d = buf;
874 for (x = 0; x < width; x++,d+=3)
876 d[0] = (color ) & 0xFF;
877 d[1] = (color>> 8) & 0xFF;
878 d[2] = (color>>16) & 0xFF;
880 break;
882 case 4: COLORFILL_ROW(DWORD)
883 default:
884 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
885 return WINED3DERR_NOTAVAILABLE;
888 #undef COLORFILL_ROW
890 /* Now copy first row */
891 first = buf;
892 for (y = 1; y < height; y++)
894 buf += lPitch;
895 memcpy(buf, first, width * bpp);
897 return WINED3D_OK;
900 /*****************************************************************************
901 * IWineD3DSurface::Blt, SW emulation version
903 * Performs blits to a surface, eigher from a source of source-less blts
904 * This is the main functionality of DirectDraw
906 * Params:
907 * DestRect: Destination rectangle to write to
908 * SrcSurface: Source surface, can be NULL
909 * SrcRect: Source rectangle
910 *****************************************************************************/
911 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
912 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
914 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
915 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
916 RECT xdst,xsrc;
917 HRESULT ret = WINED3D_OK;
918 WINED3DLOCKED_RECT dlock, slock;
919 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
920 const struct GlPixelFormatDesc *sEntry, *dEntry;
921 int x, y;
922 const BYTE *sbuf;
923 BYTE *dbuf;
924 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
926 if (TRACE_ON(d3d_surface))
928 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
929 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
930 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
931 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
932 #if 0
933 TRACE("\tflags: ");
934 DDRAW_dump_DDBLT(Flags);
935 if (Flags & WINEDDBLT_DDFX)
937 TRACE("\tblitfx: ");
938 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
940 #endif
943 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
945 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
946 return WINEDDERR_SURFACEBUSY;
949 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
950 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
951 FIXME("Filters not supported in software blit\n");
954 /* First check for the validity of source / destination rectangles. This was
955 * verified using a test application + by MSDN.
957 if ((Src != NULL) && (SrcRect != NULL) &&
958 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
959 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
960 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
961 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
962 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
964 WARN("Application gave us bad source rectangle for Blt.\n");
965 return WINEDDERR_INVALIDRECT;
967 /* For the Destination rect, it can be out of bounds on the condition that a clipper
968 * is set for the given surface.
970 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
971 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
972 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
973 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
974 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
975 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
977 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
978 return WINEDDERR_INVALIDRECT;
981 /* Now handle negative values in the rectangles. Warning: only supported for now
982 in the 'simple' cases (ie not in any stretching / rotation cases).
984 First, the case where nothing is to be done.
986 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
987 (DestRect->top >= (int) This->currentDesc.Height) ||
988 (DestRect->left >= (int) This->currentDesc.Width))) ||
989 ((Src != NULL) && (SrcRect != NULL) &&
990 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
991 (SrcRect->top >= (int) Src->currentDesc.Height) ||
992 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
994 TRACE("Nothing to be done !\n");
995 return WINED3D_OK;
998 if (DestRect)
1000 xdst = *DestRect;
1002 else
1004 xdst.top = 0;
1005 xdst.bottom = This->currentDesc.Height;
1006 xdst.left = 0;
1007 xdst.right = This->currentDesc.Width;
1010 if (SrcRect)
1012 xsrc = *SrcRect;
1014 else
1016 if (Src)
1018 xsrc.top = 0;
1019 xsrc.bottom = Src->currentDesc.Height;
1020 xsrc.left = 0;
1021 xsrc.right = Src->currentDesc.Width;
1023 else
1025 memset(&xsrc,0,sizeof(xsrc));
1029 /* The easy case : the source-less blits.... */
1030 if (Src == NULL && DestRect)
1032 RECT full_rect;
1033 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1035 full_rect.left = 0;
1036 full_rect.top = 0;
1037 full_rect.right = This->currentDesc.Width;
1038 full_rect.bottom = This->currentDesc.Height;
1039 IntersectRect(&temp_rect, &full_rect, DestRect);
1040 xdst = temp_rect;
1042 else if (DestRect)
1044 /* Only handle clipping on the destination rectangle */
1045 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1046 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1047 if (clip_vert || clip_horiz)
1049 /* Now check if this is a special case or not... */
1050 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1051 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1052 (Flags & WINEDDBLT_DDFX))
1054 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1055 return WINED3D_OK;
1058 if (clip_horiz)
1060 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1061 if (DestRect->right > This->currentDesc.Width)
1063 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1064 xdst.right = (int) This->currentDesc.Width;
1067 if (clip_vert)
1069 if (DestRect->top < 0)
1071 xsrc.top -= DestRect->top;
1072 xdst.top = 0;
1074 if (DestRect->bottom > This->currentDesc.Height)
1076 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1077 xdst.bottom = (int) This->currentDesc.Height;
1080 /* And check if after clipping something is still to be done... */
1081 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1082 (xdst.top >= (int) This->currentDesc.Height) ||
1083 (xdst.left >= (int) This->currentDesc.Width) ||
1084 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1085 (xsrc.top >= (int) Src->currentDesc.Height) ||
1086 (xsrc.left >= (int) Src->currentDesc.Width))
1088 TRACE("Nothing to be done after clipping !\n");
1089 return WINED3D_OK;
1094 if (Src == This)
1096 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1097 slock = dlock;
1098 sEntry = This->resource.format_desc;
1099 dEntry = sEntry;
1101 else
1103 dEntry = This->resource.format_desc;
1104 if (Src)
1106 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1108 Src = surface_convert_format(Src, dEntry->format);
1109 if(!Src) {
1110 /* The conv function writes a FIXME */
1111 WARN("Cannot convert source surface format to dest format\n");
1112 goto release;
1115 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1116 sEntry = Src->resource.format_desc;
1118 else
1120 sEntry = dEntry;
1122 if (DestRect)
1123 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1124 else
1125 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1128 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1130 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1132 if (!DestRect || Src == This)
1134 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1135 goto release;
1139 bpp = This->resource.format_desc->byte_count;
1140 srcheight = xsrc.bottom - xsrc.top;
1141 srcwidth = xsrc.right - xsrc.left;
1142 dstheight = xdst.bottom - xdst.top;
1143 dstwidth = xdst.right - xdst.left;
1144 width = (xdst.right - xdst.left) * bpp;
1146 if (DestRect && Src != This)
1147 dbuf = dlock.pBits;
1148 else
1149 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1151 if (Flags & WINEDDBLT_WAIT)
1153 Flags &= ~WINEDDBLT_WAIT;
1155 if (Flags & WINEDDBLT_ASYNC)
1157 static BOOL displayed = FALSE;
1158 if (!displayed)
1159 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1160 displayed = TRUE;
1161 Flags &= ~WINEDDBLT_ASYNC;
1163 if (Flags & WINEDDBLT_DONOTWAIT)
1165 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1166 static BOOL displayed = FALSE;
1167 if (!displayed)
1168 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1169 displayed = TRUE;
1170 Flags &= ~WINEDDBLT_DONOTWAIT;
1173 /* First, all the 'source-less' blits */
1174 if (Flags & WINEDDBLT_COLORFILL)
1176 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1177 dlock.Pitch, DDBltFx->u5.dwFillColor);
1178 Flags &= ~WINEDDBLT_COLORFILL;
1181 if (Flags & WINEDDBLT_DEPTHFILL)
1183 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1185 if (Flags & WINEDDBLT_ROP)
1187 /* Catch some degenerate cases here */
1188 switch(DDBltFx->dwROP)
1190 case BLACKNESS:
1191 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1192 break;
1193 case 0xAA0029: /* No-op */
1194 break;
1195 case WHITENESS:
1196 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1197 break;
1198 case SRCCOPY: /* well, we do that below ? */
1199 break;
1200 default:
1201 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1202 goto error;
1204 Flags &= ~WINEDDBLT_ROP;
1206 if (Flags & WINEDDBLT_DDROPS)
1208 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1210 /* Now the 'with source' blits */
1211 if (Src)
1213 const BYTE *sbase;
1214 int sx, xinc, sy, yinc;
1216 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1217 goto release;
1218 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1219 xinc = (srcwidth << 16) / dstwidth;
1220 yinc = (srcheight << 16) / dstheight;
1222 if (!Flags)
1224 /* No effects, we can cheat here */
1225 if (dstwidth == srcwidth)
1227 if (dstheight == srcheight)
1229 /* No stretching in either direction. This needs to be as
1230 * fast as possible */
1231 sbuf = sbase;
1233 /* check for overlapping surfaces */
1234 if (Src != This || xdst.top < xsrc.top ||
1235 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1237 /* no overlap, or dst above src, so copy from top downwards */
1238 for (y = 0; y < dstheight; y++)
1240 memcpy(dbuf, sbuf, width);
1241 sbuf += slock.Pitch;
1242 dbuf += dlock.Pitch;
1245 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1247 sbuf += (slock.Pitch*dstheight);
1248 dbuf += (dlock.Pitch*dstheight);
1249 for (y = 0; y < dstheight; y++)
1251 sbuf -= slock.Pitch;
1252 dbuf -= dlock.Pitch;
1253 memcpy(dbuf, sbuf, width);
1256 else /* src and dst overlapping on the same line, use memmove */
1258 for (y = 0; y < dstheight; y++)
1260 memmove(dbuf, sbuf, width);
1261 sbuf += slock.Pitch;
1262 dbuf += dlock.Pitch;
1265 } else {
1266 /* Stretching in Y direction only */
1267 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1268 sbuf = sbase + (sy >> 16) * slock.Pitch;
1269 memcpy(dbuf, sbuf, width);
1270 dbuf += dlock.Pitch;
1274 else
1276 /* Stretching in X direction */
1277 int last_sy = -1;
1278 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1280 sbuf = sbase + (sy >> 16) * slock.Pitch;
1282 if ((sy >> 16) == (last_sy >> 16))
1284 /* this sourcerow is the same as last sourcerow -
1285 * copy already stretched row
1287 memcpy(dbuf, dbuf - dlock.Pitch, width);
1289 else
1291 #define STRETCH_ROW(type) { \
1292 const type *s = (const type *)sbuf; \
1293 type *d = (type *)dbuf; \
1294 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1295 d[x] = s[sx >> 16]; \
1296 break; }
1298 switch(bpp)
1300 case 1: STRETCH_ROW(BYTE)
1301 case 2: STRETCH_ROW(WORD)
1302 case 4: STRETCH_ROW(DWORD)
1303 case 3:
1305 const BYTE *s;
1306 BYTE *d = dbuf;
1307 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1309 DWORD pixel;
1311 s = sbuf+3*(sx>>16);
1312 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1313 d[0] = (pixel )&0xff;
1314 d[1] = (pixel>> 8)&0xff;
1315 d[2] = (pixel>>16)&0xff;
1316 d+=3;
1318 break;
1320 default:
1321 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1322 ret = WINED3DERR_NOTAVAILABLE;
1323 goto error;
1325 #undef STRETCH_ROW
1327 dbuf += dlock.Pitch;
1328 last_sy = sy;
1332 else
1334 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1335 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1336 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1337 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1339 /* The color keying flags are checked for correctness in ddraw */
1340 if (Flags & WINEDDBLT_KEYSRC)
1342 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1343 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1345 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1347 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1348 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1351 if (Flags & WINEDDBLT_KEYDEST)
1353 /* Destination color keys are taken from the source surface ! */
1354 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1355 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1357 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1359 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1360 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1363 if(bpp == 1)
1365 keymask = 0xff;
1367 else
1369 keymask = sEntry->red_mask
1370 | sEntry->green_mask
1371 | sEntry->blue_mask;
1373 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1376 if (Flags & WINEDDBLT_DDFX)
1378 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1379 LONG tmpxy;
1380 dTopLeft = dbuf;
1381 dTopRight = dbuf+((dstwidth-1)*bpp);
1382 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1383 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1385 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1387 /* I don't think we need to do anything about this flag */
1388 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1390 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1392 tmp = dTopRight;
1393 dTopRight = dTopLeft;
1394 dTopLeft = tmp;
1395 tmp = dBottomRight;
1396 dBottomRight = dBottomLeft;
1397 dBottomLeft = tmp;
1398 dstxinc = dstxinc *-1;
1400 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1402 tmp = dTopLeft;
1403 dTopLeft = dBottomLeft;
1404 dBottomLeft = tmp;
1405 tmp = dTopRight;
1406 dTopRight = dBottomRight;
1407 dBottomRight = tmp;
1408 dstyinc = dstyinc *-1;
1410 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1412 /* I don't think we need to do anything about this flag */
1413 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1415 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1417 tmp = dBottomRight;
1418 dBottomRight = dTopLeft;
1419 dTopLeft = tmp;
1420 tmp = dBottomLeft;
1421 dBottomLeft = dTopRight;
1422 dTopRight = tmp;
1423 dstxinc = dstxinc * -1;
1424 dstyinc = dstyinc * -1;
1426 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1428 tmp = dTopLeft;
1429 dTopLeft = dBottomLeft;
1430 dBottomLeft = dBottomRight;
1431 dBottomRight = dTopRight;
1432 dTopRight = tmp;
1433 tmpxy = dstxinc;
1434 dstxinc = dstyinc;
1435 dstyinc = tmpxy;
1436 dstxinc = dstxinc * -1;
1438 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1440 tmp = dTopLeft;
1441 dTopLeft = dTopRight;
1442 dTopRight = dBottomRight;
1443 dBottomRight = dBottomLeft;
1444 dBottomLeft = tmp;
1445 tmpxy = dstxinc;
1446 dstxinc = dstyinc;
1447 dstyinc = tmpxy;
1448 dstyinc = dstyinc * -1;
1450 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1452 /* I don't think we need to do anything about this flag */
1453 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1455 dbuf = dTopLeft;
1456 Flags &= ~(WINEDDBLT_DDFX);
1459 #define COPY_COLORKEY_FX(type) { \
1460 const type *s; \
1461 type *d = (type *)dbuf, *dx, tmp; \
1462 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1463 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1464 dx = d; \
1465 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1466 tmp = s[sx >> 16]; \
1467 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1468 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1469 dx[0] = tmp; \
1471 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1473 d = (type*)(((LPBYTE)d)+dstyinc); \
1475 break; }
1477 switch (bpp) {
1478 case 1: COPY_COLORKEY_FX(BYTE)
1479 case 2: COPY_COLORKEY_FX(WORD)
1480 case 4: COPY_COLORKEY_FX(DWORD)
1481 case 3:
1483 const BYTE *s;
1484 BYTE *d = dbuf, *dx;
1485 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1487 sbuf = sbase + (sy >> 16) * slock.Pitch;
1488 dx = d;
1489 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1491 DWORD pixel, dpixel = 0;
1492 s = sbuf+3*(sx>>16);
1493 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1494 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1495 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1496 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1498 dx[0] = (pixel )&0xff;
1499 dx[1] = (pixel>> 8)&0xff;
1500 dx[2] = (pixel>>16)&0xff;
1502 dx+= dstxinc;
1504 d += dstyinc;
1506 break;
1508 default:
1509 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1510 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1511 ret = WINED3DERR_NOTAVAILABLE;
1512 goto error;
1513 #undef COPY_COLORKEY_FX
1518 error:
1519 if (Flags && FIXME_ON(d3d_surface))
1521 FIXME("\tUnsupported flags: %08x\n", Flags);
1524 release:
1525 IWineD3DSurface_UnlockRect(iface);
1526 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1527 /* Release the converted surface if any */
1528 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1529 return ret;
1532 /*****************************************************************************
1533 * IWineD3DSurface::BltFast, SW emulation version
1535 * This is the software implementation of BltFast, as used by GDI surfaces
1536 * and as a fallback for OpenGL surfaces. This code is taken from the old
1537 * DirectDraw code, and was originally written by TransGaming.
1539 * Params:
1540 * dstx:
1541 * dsty:
1542 * Source: Source surface to copy from
1543 * rsrc: Source rectangle
1544 * trans: Some Flags
1546 * Returns:
1547 * WINED3D_OK on success
1549 *****************************************************************************/
1550 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1551 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1553 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1554 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1556 int bpp, w, h, x, y;
1557 WINED3DLOCKED_RECT dlock,slock;
1558 HRESULT ret = WINED3D_OK;
1559 RECT rsrc2;
1560 RECT lock_src, lock_dst, lock_union;
1561 const BYTE *sbuf;
1562 BYTE *dbuf;
1563 const struct GlPixelFormatDesc *sEntry, *dEntry;
1565 if (TRACE_ON(d3d_surface))
1567 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1569 if (rsrc)
1571 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1572 rsrc->right,rsrc->bottom);
1574 else
1576 TRACE(" srcrect: NULL\n");
1580 if ((This->Flags & SFLAG_LOCKED) ||
1581 (Src->Flags & SFLAG_LOCKED))
1583 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1584 return WINEDDERR_SURFACEBUSY;
1587 if (!rsrc)
1589 WARN("rsrc is NULL!\n");
1590 rsrc2.left = 0;
1591 rsrc2.top = 0;
1592 rsrc2.right = Src->currentDesc.Width;
1593 rsrc2.bottom = Src->currentDesc.Height;
1594 rsrc = &rsrc2;
1597 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1598 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1599 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1600 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1601 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1602 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1604 WARN("Application gave us bad source rectangle for BltFast.\n");
1605 return WINEDDERR_INVALIDRECT;
1608 h = rsrc->bottom - rsrc->top;
1609 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1610 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1611 if (h <= 0) return WINEDDERR_INVALIDRECT;
1613 w = rsrc->right - rsrc->left;
1614 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1615 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1616 if (w <= 0) return WINEDDERR_INVALIDRECT;
1618 /* Now compute the locking rectangle... */
1619 lock_src.left = rsrc->left;
1620 lock_src.top = rsrc->top;
1621 lock_src.right = lock_src.left + w;
1622 lock_src.bottom = lock_src.top + h;
1624 lock_dst.left = dstx;
1625 lock_dst.top = dsty;
1626 lock_dst.right = dstx + w;
1627 lock_dst.bottom = dsty + h;
1629 bpp = This->resource.format_desc->byte_count;
1631 /* We need to lock the surfaces, or we won't get refreshes when done. */
1632 if (Src == This)
1634 int pitch;
1636 UnionRect(&lock_union, &lock_src, &lock_dst);
1638 /* Lock the union of the two rectangles */
1639 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1640 if(ret != WINED3D_OK) goto error;
1642 pitch = dlock.Pitch;
1643 slock.Pitch = dlock.Pitch;
1645 /* Since slock was originally copied from this surface's description, we can just reuse it */
1646 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1647 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1648 sEntry = Src->resource.format_desc;
1649 dEntry = sEntry;
1651 else
1653 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1654 if(ret != WINED3D_OK) goto error;
1655 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1656 if(ret != WINED3D_OK) goto error;
1658 sbuf = slock.pBits;
1659 dbuf = dlock.pBits;
1660 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1662 sEntry = Src->resource.format_desc;
1663 dEntry = This->resource.format_desc;
1666 /* Handle compressed surfaces first... */
1667 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1669 UINT row_block_count;
1671 TRACE("compressed -> compressed copy\n");
1672 if (trans)
1673 FIXME("trans arg not supported when a compressed surface is involved\n");
1674 if (dstx || dsty)
1675 FIXME("offset for destination surface is not supported\n");
1676 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1678 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1679 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1680 goto error;
1683 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1684 for (y = 0; y < h; y += dEntry->block_height)
1686 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1687 dbuf += dlock.Pitch;
1688 sbuf += slock.Pitch;
1691 goto error;
1693 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1695 /* TODO: Use the libtxc_dxtn.so shared library to do
1696 * software decompression
1698 ERR("Software decompression not supported.\n");
1699 goto error;
1702 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1704 DWORD keylow, keyhigh;
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 < keylow || tmp > 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");
1869 return;
1872 /* TODO: think about moving this down to resource? */
1873 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1875 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1877 /* This should only be called for sysmem textures, it may be a good idea
1878 * to extend this to all pools at some point in the future */
1879 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1881 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1883 return This->resource.allocatedMemory;