wined3d: Remove the format field from IWineD3DResourceClass.
[wine/multimedia.git] / dlls / wined3d / surface_base.c
blob941d5379dc8cad24e64cc7ce911e5eedc6917fc8
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
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 #include <assert.h>
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
37 /* See also float_16_to_32() in wined3d_private.h */
38 static inline unsigned short float_32_to_16(const float *in)
40 int exp = 0;
41 float tmp = fabs(*in);
42 unsigned int mantissa;
43 unsigned short ret;
45 /* Deal with special numbers */
46 if(*in == 0.0) return 0x0000;
47 if(isnan(*in)) return 0x7C01;
48 if(isinf(*in)) return (*in < 0.0 ? 0xFC00 : 0x7c00);
50 if(tmp < pow(2, 10)) {
53 tmp = tmp * 2.0;
54 exp--;
55 }while(tmp < pow(2, 10));
56 } else if(tmp >= pow(2, 11)) {
59 tmp /= 2.0;
60 exp++;
61 }while(tmp >= pow(2, 11));
64 mantissa = (unsigned int) tmp;
65 if(tmp - mantissa >= 0.5) mantissa++; /* round to nearest, away from zero */
67 exp += 10; /* Normalize the mantissa */
68 exp += 15; /* Exponent is encoded with excess 15 */
70 if(exp > 30) { /* too big */
71 ret = 0x7c00; /* INF */
72 } else if(exp <= 0) {
73 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
74 while(exp <= 0) {
75 mantissa = mantissa >> 1;
76 exp++;
78 ret = mantissa & 0x3ff;
79 } else {
80 ret = (exp << 10) | (mantissa & 0x3ff);
83 ret |= ((*in < 0.0 ? 1 : 0) << 15); /* Add the sign */
84 return ret;
88 /* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
90 /* *******************************************
91 IWineD3DSurface IUnknown parts follow
92 ******************************************* */
93 HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
95 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
96 /* Warn ,but be nice about things */
97 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
99 if (IsEqualGUID(riid, &IID_IUnknown)
100 || IsEqualGUID(riid, &IID_IWineD3DBase)
101 || IsEqualGUID(riid, &IID_IWineD3DResource)
102 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
103 IUnknown_AddRef((IUnknown*)iface);
104 *ppobj = This;
105 return S_OK;
107 *ppobj = NULL;
108 return E_NOINTERFACE;
111 ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
112 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
113 ULONG ref = InterlockedIncrement(&This->resource.ref);
114 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
115 return ref;
118 /* ****************************************************
119 IWineD3DSurface IWineD3DResource parts follow
120 **************************************************** */
121 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
122 return resource_get_device((IWineD3DResource *)iface, ppDevice);
125 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
126 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
129 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
130 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
133 HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
134 return resource_free_private_data((IWineD3DResource *)iface, refguid);
137 DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
138 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
141 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
142 return resource_get_priority((IWineD3DResource *)iface);
145 WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
146 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
147 return resource_get_type((IWineD3DResource *)iface);
150 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
151 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
152 return resource_get_parent((IWineD3DResource *)iface, pParent);
155 /* ******************************************************
156 IWineD3DSurface IWineD3DSurface parts follow
157 ****************************************************** */
159 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
160 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
161 IWineD3DBase *container = 0;
163 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
165 if (!ppContainer) {
166 ERR("Called without a valid ppContainer.\n");
169 /* Standalone surfaces return the device as container. */
170 if (This->container) {
171 container = This->container;
172 } else {
173 container = (IWineD3DBase *)This->resource.wineD3DDevice;
176 TRACE("Relaying to QueryInterface\n");
177 return IUnknown_QueryInterface(container, riid, ppContainer);
180 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
181 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
183 TRACE("(%p) : copying into %p\n", This, pDesc);
184 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format_desc->format;
185 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
186 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
187 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
188 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
189 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
190 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
191 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
192 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
193 return WINED3D_OK;
196 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
197 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
198 TRACE("(%p)->(%x)\n", This, Flags);
200 switch (Flags)
202 case WINEDDGBS_CANBLT:
203 case WINEDDGBS_ISBLTDONE:
204 return WINED3D_OK;
206 default:
207 return WINED3DERR_INVALIDCALL;
211 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
212 /* XXX: DDERR_INVALIDSURFACETYPE */
214 TRACE("(%p)->(%08x)\n",iface,Flags);
215 switch (Flags) {
216 case WINEDDGFS_CANFLIP:
217 case WINEDDGFS_ISFLIPDONE:
218 return WINED3D_OK;
220 default:
221 return WINED3DERR_INVALIDCALL;
225 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
226 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
227 TRACE("(%p)\n", This);
229 /* D3D8 and 9 loose full devices, ddraw only surfaces */
230 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
233 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
234 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
235 TRACE("(%p)\n", This);
237 /* So far we don't lose anything :) */
238 This->Flags &= ~SFLAG_LOST;
239 return WINED3D_OK;
242 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
243 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
244 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
245 TRACE("(%p)->(%p)\n", This, Pal);
247 if(This->palette == PalImpl) {
248 TRACE("Nop palette change\n");
249 return WINED3D_OK;
252 if(This->palette != NULL)
253 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
254 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
256 This->palette = PalImpl;
258 if(PalImpl != NULL) {
259 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
260 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
263 return IWineD3DSurface_RealizePalette(iface);
265 else return WINED3D_OK;
268 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
270 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
271 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
273 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
274 FIXME(" colorkey value not supported (%08x) !\n", Flags);
275 return WINED3DERR_INVALIDCALL;
278 /* Dirtify the surface, but only if a key was changed */
279 if(CKey) {
280 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
281 case WINEDDCKEY_DESTBLT:
282 This->DestBltCKey = *CKey;
283 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
284 break;
286 case WINEDDCKEY_DESTOVERLAY:
287 This->DestOverlayCKey = *CKey;
288 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
289 break;
291 case WINEDDCKEY_SRCOVERLAY:
292 This->SrcOverlayCKey = *CKey;
293 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
294 break;
296 case WINEDDCKEY_SRCBLT:
297 This->SrcBltCKey = *CKey;
298 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
299 break;
302 else {
303 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
304 case WINEDDCKEY_DESTBLT:
305 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
306 break;
308 case WINEDDCKEY_DESTOVERLAY:
309 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
310 break;
312 case WINEDDCKEY_SRCOVERLAY:
313 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
314 break;
316 case WINEDDCKEY_SRCBLT:
317 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
318 break;
322 return WINED3D_OK;
325 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
326 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
327 TRACE("(%p)->(%p)\n", This, Pal);
329 *Pal = (IWineD3DPalette *) This->palette;
330 return WINED3D_OK;
333 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
334 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
335 WINED3DFORMAT format = This->resource.format_desc->format;
336 DWORD ret;
337 TRACE("(%p)\n", This);
339 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
340 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
341 ie pitch = (width/4) * bytes per block */
342 if (format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
343 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
344 else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
345 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
346 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
347 else {
348 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
349 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
350 ret = (ret + alignment - 1) & ~(alignment - 1);
352 TRACE("(%p) Returning %d\n", This, ret);
353 return ret;
356 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
357 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
358 LONG w, h;
360 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
362 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
364 TRACE("(%p): Not an overlay surface\n", This);
365 return WINEDDERR_NOTAOVERLAYSURFACE;
368 w = This->overlay_destrect.right - This->overlay_destrect.left;
369 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
370 This->overlay_destrect.left = X;
371 This->overlay_destrect.top = Y;
372 This->overlay_destrect.right = X + w;
373 This->overlay_destrect.bottom = Y + h;
375 IWineD3DSurface_DrawOverlay(iface);
377 return WINED3D_OK;
380 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
381 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
382 HRESULT hr;
384 TRACE("(%p)->(%p,%p)\n", This, X, Y);
386 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
388 TRACE("(%p): Not an overlay surface\n", This);
389 return WINEDDERR_NOTAOVERLAYSURFACE;
391 if(This->overlay_dest == NULL) {
392 *X = 0; *Y = 0;
393 hr = WINEDDERR_OVERLAYNOTVISIBLE;
394 } else {
395 *X = This->overlay_destrect.left;
396 *Y = This->overlay_destrect.top;
397 hr = WINED3D_OK;
400 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
401 return hr;
404 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
405 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
406 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
408 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
410 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
412 TRACE("(%p): Not an overlay surface\n", This);
413 return WINEDDERR_NOTAOVERLAYSURFACE;
416 return WINED3D_OK;
419 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
420 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
422 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
423 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
424 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
426 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
428 WARN("(%p): Not an overlay surface\n", This);
429 return WINEDDERR_NOTAOVERLAYSURFACE;
430 } else if(!DstSurface) {
431 WARN("(%p): Dest surface is NULL\n", This);
432 return WINED3DERR_INVALIDCALL;
435 if(SrcRect) {
436 This->overlay_srcrect = *SrcRect;
437 } else {
438 This->overlay_srcrect.left = 0;
439 This->overlay_srcrect.top = 0;
440 This->overlay_srcrect.right = This->currentDesc.Width;
441 This->overlay_srcrect.bottom = This->currentDesc.Height;
444 if(DstRect) {
445 This->overlay_destrect = *DstRect;
446 } else {
447 This->overlay_destrect.left = 0;
448 This->overlay_destrect.top = 0;
449 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
450 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
453 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
454 list_remove(&This->overlay_entry);
457 if(Flags & WINEDDOVER_SHOW) {
458 if(This->overlay_dest != Dst) {
459 This->overlay_dest = Dst;
460 list_add_tail(&Dst->overlays, &This->overlay_entry);
462 } else if(Flags & WINEDDOVER_HIDE) {
463 /* tests show that the rectangles are erased on hide */
464 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
465 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
466 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
467 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
468 This->overlay_dest = NULL;
471 IWineD3DSurface_DrawOverlay(iface);
473 return WINED3D_OK;
476 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
478 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
479 TRACE("(%p)->(%p)\n", This, clipper);
481 This->clipper = clipper;
482 return WINED3D_OK;
485 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
487 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
488 TRACE("(%p)->(%p)\n", This, clipper);
490 *clipper = This->clipper;
491 if(*clipper) {
492 IWineD3DClipper_AddRef(*clipper);
494 return WINED3D_OK;
497 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
498 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
500 TRACE("This %p, container %p\n", This, container);
502 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
504 TRACE("Setting container to %p from %p\n", container, This->container);
505 This->container = container;
507 return WINED3D_OK;
510 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
511 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
512 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format,
513 &This->resource.wineD3DDevice->adapter->gl_info);
515 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
517 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
518 return WINED3DERR_INVALIDCALL;
521 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
522 if (format == WINED3DFMT_UNKNOWN) {
523 This->resource.size = 0;
524 } else if (format == WINED3DFMT_DXT1) {
525 /* DXT1 is half byte per pixel */
526 This->resource.size = ((max(This->pow2Width, 4) * format_desc->byte_count) * max(This->pow2Height, 4)) >> 1;
528 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
529 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
530 This->resource.size = ((max(This->pow2Width, 4) * format_desc->byte_count) * max(This->pow2Height, 4));
531 } else {
532 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
533 This->resource.size = ((This->pow2Width * format_desc->byte_count) + alignment - 1) & ~(alignment - 1);
534 This->resource.size *= This->pow2Height;
537 if (format != WINED3DFMT_UNKNOWN) {
538 This->bytesPerPixel = format_desc->byte_count;
539 } else {
540 This->bytesPerPixel = 0;
543 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
545 This->resource.format_desc = format_desc;
547 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, This->bytesPerPixel);
549 return WINED3D_OK;
552 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
553 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
554 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
555 int extraline = 0;
556 SYSTEM_INFO sysInfo;
557 BITMAPINFO* b_info;
558 HDC ddc;
559 DWORD *masks;
560 UINT usage;
562 switch (This->bytesPerPixel) {
563 case 2:
564 case 4:
565 /* Allocate extra space to store the RGB bit masks. */
566 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
567 break;
569 case 3:
570 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
571 break;
573 default:
574 /* Allocate extra space for a palette. */
575 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
576 sizeof(BITMAPINFOHEADER)
577 + sizeof(RGBQUAD)
578 * (1 << (This->bytesPerPixel * 8)));
579 break;
582 if (!b_info)
583 return E_OUTOFMEMORY;
585 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
586 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
587 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
588 * add an extra line to the dib section
590 GetSystemInfo(&sysInfo);
591 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
592 extraline = 1;
593 TRACE("Adding an extra line to the dib section\n");
596 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
597 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
598 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / This->bytesPerPixel;
599 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
600 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
601 b_info->bmiHeader.biPlanes = 1;
602 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
604 b_info->bmiHeader.biXPelsPerMeter = 0;
605 b_info->bmiHeader.biYPelsPerMeter = 0;
606 b_info->bmiHeader.biClrUsed = 0;
607 b_info->bmiHeader.biClrImportant = 0;
609 /* Get the bit masks */
610 masks = (DWORD *)b_info->bmiColors;
611 switch (This->resource.format_desc->format)
613 case WINED3DFMT_R8G8B8:
614 usage = DIB_RGB_COLORS;
615 b_info->bmiHeader.biCompression = BI_RGB;
616 break;
618 case WINED3DFMT_X1R5G5B5:
619 case WINED3DFMT_A1R5G5B5:
620 case WINED3DFMT_A4R4G4B4:
621 case WINED3DFMT_X4R4G4B4:
622 case WINED3DFMT_R3G3B2:
623 case WINED3DFMT_A8R3G3B2:
624 case WINED3DFMT_R10G10B10A2_UNORM:
625 case WINED3DFMT_R8G8B8A8_UNORM:
626 case WINED3DFMT_X8B8G8R8:
627 case WINED3DFMT_A2R10G10B10:
628 case WINED3DFMT_R5G6B5:
629 case WINED3DFMT_R16G16B16A16_UNORM:
630 usage = 0;
631 b_info->bmiHeader.biCompression = BI_BITFIELDS;
632 masks[0] = format_desc->red_mask;
633 masks[1] = format_desc->green_mask;
634 masks[2] = format_desc->blue_mask;
635 break;
637 default:
638 /* Don't know palette */
639 b_info->bmiHeader.biCompression = BI_RGB;
640 usage = 0;
641 break;
644 ddc = GetDC(0);
645 if (ddc == 0) {
646 HeapFree(GetProcessHeap(), 0, b_info);
647 return HRESULT_FROM_WIN32(GetLastError());
650 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);
651 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
652 ReleaseDC(0, ddc);
654 if (!This->dib.DIBsection) {
655 ERR("CreateDIBSection failed!\n");
656 HeapFree(GetProcessHeap(), 0, b_info);
657 return HRESULT_FROM_WIN32(GetLastError());
660 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
661 /* copy the existing surface to the dib section */
662 if(This->resource.allocatedMemory) {
663 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
664 } else {
665 /* This is to make LockRect read the gl Texture although memory is allocated */
666 This->Flags &= ~SFLAG_INSYSMEM;
668 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
670 HeapFree(GetProcessHeap(), 0, b_info);
672 /* Now allocate a HDC */
673 This->hDC = CreateCompatibleDC(0);
674 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
675 TRACE("using wined3d palette %p\n", This->palette);
676 SelectPalette(This->hDC,
677 This->palette ? This->palette->hpal : 0,
678 FALSE);
680 This->Flags |= SFLAG_DIBSECTION;
682 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
683 This->resource.heapMemory = NULL;
685 return WINED3D_OK;
688 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
689 unsigned int w, unsigned int h)
691 unsigned int x, y;
692 const float *src_f;
693 unsigned short *dst_s;
695 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
696 for(y = 0; y < h; y++) {
697 src_f = (const float *)(src + y * pitch_in);
698 dst_s = (unsigned short *) (dst + y * pitch_out);
699 for(x = 0; x < w; x++) {
700 dst_s[x] = float_32_to_16(src_f + x);
705 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
706 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
708 static const unsigned char convert_5to8[] =
710 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
711 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
712 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
713 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
715 static const unsigned char convert_6to8[] =
717 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
718 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
719 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
720 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
721 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
722 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
723 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
724 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
726 unsigned int x, y;
728 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
730 for (y = 0; y < h; ++y)
732 const WORD *src_line = (const WORD *)(src + y * pitch_in);
733 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
734 for (x = 0; x < w; ++x)
736 WORD pixel = src_line[x];
737 dst_line[x] = 0xff000000
738 | convert_5to8[(pixel & 0xf800) >> 11] << 16
739 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
740 | convert_5to8[(pixel & 0x001f)];
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_R5G6B5, WINED3DFMT_X8R8G8B8, convert_r5g6b5_x8r8g8b8},
756 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
758 unsigned int i;
759 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
760 if(convertors[i].from == from && convertors[i].to == to) {
761 return &convertors[i];
764 return NULL;
767 /*****************************************************************************
768 * surface_convert_format
770 * Creates a duplicate of a surface in a different format. Is used by Blt to
771 * blit between surfaces with different formats
773 * Parameters
774 * source: Source surface
775 * fmt: Requested destination format
777 *****************************************************************************/
778 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
779 IWineD3DSurface *ret = NULL;
780 const struct d3dfmt_convertor_desc *conv;
781 WINED3DLOCKED_RECT lock_src, lock_dst;
782 HRESULT hr;
784 conv = find_convertor(source->resource.format_desc->format, to_fmt);
785 if(!conv) {
786 FIXME("Cannot find a conversion function from format %s to %s\n",
787 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
788 return NULL;
791 IWineD3DDevice_CreateSurface((IWineD3DDevice *) source->resource.wineD3DDevice,
792 source->currentDesc.Width,
793 source->currentDesc.Height,
794 to_fmt,
795 TRUE, /* lockable */
796 TRUE, /* discard */
797 0, /* level */
798 &ret,
799 WINED3DRTYPE_SURFACE,
800 0, /* usage */
801 WINED3DPOOL_SCRATCH,
802 WINED3DMULTISAMPLE_NONE, /* TODO: Multisampled conversion */
803 0, /* MultiSampleQuality */
804 NULL, /* SharedHandle */
805 IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
806 NULL); /* parent */
807 if(!ret) {
808 ERR("Failed to create a destination surface for conversion\n");
809 return NULL;
812 memset(&lock_src, 0, sizeof(lock_src));
813 memset(&lock_dst, 0, sizeof(lock_dst));
815 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
816 if(FAILED(hr)) {
817 ERR("Failed to lock the source surface\n");
818 IWineD3DSurface_Release(ret);
819 return NULL;
821 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
822 if(FAILED(hr)) {
823 ERR("Failed to lock the dest surface\n");
824 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
825 IWineD3DSurface_Release(ret);
826 return NULL;
829 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
830 source->currentDesc.Width, source->currentDesc.Height);
832 IWineD3DSurface_UnlockRect(ret);
833 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
835 return (IWineD3DSurfaceImpl *) ret;
838 /*****************************************************************************
839 * _Blt_ColorFill
841 * Helper function that fills a memory area with a specific color
843 * Params:
844 * buf: memory address to start filling at
845 * width, height: Dimensions of the area to fill
846 * bpp: Bit depth of the surface
847 * lPitch: pitch of the surface
848 * color: Color to fill with
850 *****************************************************************************/
851 static HRESULT
852 _Blt_ColorFill(BYTE *buf,
853 int width, int height,
854 int bpp, LONG lPitch,
855 DWORD color)
857 int x, y;
858 LPBYTE first;
860 /* Do first row */
862 #define COLORFILL_ROW(type) \
864 type *d = (type *) buf; \
865 for (x = 0; x < width; x++) \
866 d[x] = (type) color; \
867 break; \
869 switch(bpp)
871 case 1: COLORFILL_ROW(BYTE)
872 case 2: COLORFILL_ROW(WORD)
873 case 3:
875 BYTE *d = buf;
876 for (x = 0; x < width; x++,d+=3)
878 d[0] = (color ) & 0xFF;
879 d[1] = (color>> 8) & 0xFF;
880 d[2] = (color>>16) & 0xFF;
882 break;
884 case 4: COLORFILL_ROW(DWORD)
885 default:
886 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
887 return WINED3DERR_NOTAVAILABLE;
890 #undef COLORFILL_ROW
892 /* Now copy first row */
893 first = buf;
894 for (y = 1; y < height; y++)
896 buf += lPitch;
897 memcpy(buf, first, width * bpp);
899 return WINED3D_OK;
902 /*****************************************************************************
903 * IWineD3DSurface::Blt, SW emulation version
905 * Performs blits to a surface, eigher from a source of source-less blts
906 * This is the main functionality of DirectDraw
908 * Params:
909 * DestRect: Destination rectangle to write to
910 * SrcSurface: Source surface, can be NULL
911 * SrcRect: Source rectangle
912 *****************************************************************************/
913 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
914 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
916 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
917 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
918 RECT xdst,xsrc;
919 HRESULT ret = WINED3D_OK;
920 WINED3DLOCKED_RECT dlock, slock;
921 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
922 const struct GlPixelFormatDesc *sEntry, *dEntry;
923 int x, y;
924 const BYTE *sbuf;
925 BYTE *dbuf;
926 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
928 if (TRACE_ON(d3d_surface))
930 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
931 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
932 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
933 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
934 #if 0
935 TRACE("\tflags: ");
936 DDRAW_dump_DDBLT(Flags);
937 if (Flags & WINEDDBLT_DDFX)
939 TRACE("\tblitfx: ");
940 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
942 #endif
945 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
947 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
948 return WINEDDERR_SURFACEBUSY;
951 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
952 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
953 FIXME("Filters not supported in software blit\n");
956 /* First check for the validity of source / destination rectangles. This was
957 * verified using a test application + by MSDN.
959 if ((Src != NULL) && (SrcRect != NULL) &&
960 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
961 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
962 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
963 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
964 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
966 WARN("Application gave us bad source rectangle for Blt.\n");
967 return WINEDDERR_INVALIDRECT;
969 /* For the Destination rect, it can be out of bounds on the condition that a clipper
970 * is set for the given surface.
972 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
973 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
974 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
975 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
976 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
977 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
979 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
980 return WINEDDERR_INVALIDRECT;
983 /* Now handle negative values in the rectangles. Warning: only supported for now
984 in the 'simple' cases (ie not in any stretching / rotation cases).
986 First, the case where nothing is to be done.
988 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
989 (DestRect->top >= (int) This->currentDesc.Height) ||
990 (DestRect->left >= (int) This->currentDesc.Width))) ||
991 ((Src != NULL) && (SrcRect != NULL) &&
992 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
993 (SrcRect->top >= (int) Src->currentDesc.Height) ||
994 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
996 TRACE("Nothing to be done !\n");
997 return WINED3D_OK;
1000 if (DestRect)
1002 xdst = *DestRect;
1004 else
1006 xdst.top = 0;
1007 xdst.bottom = This->currentDesc.Height;
1008 xdst.left = 0;
1009 xdst.right = This->currentDesc.Width;
1012 if (SrcRect)
1014 xsrc = *SrcRect;
1016 else
1018 if (Src)
1020 xsrc.top = 0;
1021 xsrc.bottom = Src->currentDesc.Height;
1022 xsrc.left = 0;
1023 xsrc.right = Src->currentDesc.Width;
1025 else
1027 memset(&xsrc,0,sizeof(xsrc));
1031 /* The easy case : the source-less blits.... */
1032 if (Src == NULL && DestRect)
1034 RECT full_rect;
1035 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1037 full_rect.left = 0;
1038 full_rect.top = 0;
1039 full_rect.right = This->currentDesc.Width;
1040 full_rect.bottom = This->currentDesc.Height;
1041 IntersectRect(&temp_rect, &full_rect, DestRect);
1042 xdst = temp_rect;
1044 else if (DestRect)
1046 /* Only handle clipping on the destination rectangle */
1047 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1048 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1049 if (clip_vert || clip_horiz)
1051 /* Now check if this is a special case or not... */
1052 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1053 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1054 (Flags & WINEDDBLT_DDFX))
1056 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1057 return WINED3D_OK;
1060 if (clip_horiz)
1062 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1063 if (DestRect->right > This->currentDesc.Width)
1065 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1066 xdst.right = (int) This->currentDesc.Width;
1069 if (clip_vert)
1071 if (DestRect->top < 0)
1073 xsrc.top -= DestRect->top;
1074 xdst.top = 0;
1076 if (DestRect->bottom > This->currentDesc.Height)
1078 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1079 xdst.bottom = (int) This->currentDesc.Height;
1082 /* And check if after clipping something is still to be done... */
1083 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1084 (xdst.top >= (int) This->currentDesc.Height) ||
1085 (xdst.left >= (int) This->currentDesc.Width) ||
1086 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1087 (xsrc.top >= (int) Src->currentDesc.Height) ||
1088 (xsrc.left >= (int) Src->currentDesc.Width))
1090 TRACE("Nothing to be done after clipping !\n");
1091 return WINED3D_OK;
1096 if (Src == This)
1098 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1099 slock = dlock;
1100 sEntry = This->resource.format_desc;
1101 dEntry = sEntry;
1103 else
1105 dEntry = This->resource.format_desc;
1106 if (Src)
1108 if(This->resource.format_desc != Src->resource.format_desc)
1110 Src = surface_convert_format(Src, dEntry->format);
1111 if(!Src) {
1112 /* The conv function writes a FIXME */
1113 WARN("Cannot convert source surface format to dest format\n");
1114 goto release;
1117 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1118 sEntry = Src->resource.format_desc;
1120 else
1122 sEntry = dEntry;
1124 if (DestRect)
1125 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1126 else
1127 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1130 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1132 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1134 if (!DestRect || Src == This)
1136 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1137 goto release;
1141 bpp = This->bytesPerPixel;
1142 srcheight = xsrc.bottom - xsrc.top;
1143 srcwidth = xsrc.right - xsrc.left;
1144 dstheight = xdst.bottom - xdst.top;
1145 dstwidth = xdst.right - xdst.left;
1146 width = (xdst.right - xdst.left) * bpp;
1148 assert(width <= dlock.Pitch);
1150 if (DestRect && Src != This)
1151 dbuf = dlock.pBits;
1152 else
1153 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1155 if (Flags & WINEDDBLT_WAIT)
1157 Flags &= ~WINEDDBLT_WAIT;
1159 if (Flags & WINEDDBLT_ASYNC)
1161 static BOOL displayed = FALSE;
1162 if (!displayed)
1163 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1164 displayed = TRUE;
1165 Flags &= ~WINEDDBLT_ASYNC;
1167 if (Flags & WINEDDBLT_DONOTWAIT)
1169 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1170 static BOOL displayed = FALSE;
1171 if (!displayed)
1172 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1173 displayed = TRUE;
1174 Flags &= ~WINEDDBLT_DONOTWAIT;
1177 /* First, all the 'source-less' blits */
1178 if (Flags & WINEDDBLT_COLORFILL)
1180 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1181 dlock.Pitch, DDBltFx->u5.dwFillColor);
1182 Flags &= ~WINEDDBLT_COLORFILL;
1185 if (Flags & WINEDDBLT_DEPTHFILL)
1187 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1189 if (Flags & WINEDDBLT_ROP)
1191 /* Catch some degenerate cases here */
1192 switch(DDBltFx->dwROP)
1194 case BLACKNESS:
1195 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1196 break;
1197 case 0xAA0029: /* No-op */
1198 break;
1199 case WHITENESS:
1200 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1201 break;
1202 case SRCCOPY: /* well, we do that below ? */
1203 break;
1204 default:
1205 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1206 goto error;
1208 Flags &= ~WINEDDBLT_ROP;
1210 if (Flags & WINEDDBLT_DDROPS)
1212 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1214 /* Now the 'with source' blits */
1215 if (Src)
1217 const BYTE *sbase;
1218 int sx, xinc, sy, yinc;
1220 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1221 goto release;
1222 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1223 xinc = (srcwidth << 16) / dstwidth;
1224 yinc = (srcheight << 16) / dstheight;
1226 if (!Flags)
1228 /* No effects, we can cheat here */
1229 if (dstwidth == srcwidth)
1231 if (dstheight == srcheight)
1233 /* No stretching in either direction. This needs to be as
1234 * fast as possible */
1235 sbuf = sbase;
1237 /* check for overlapping surfaces */
1238 if (Src != This || xdst.top < xsrc.top ||
1239 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1241 /* no overlap, or dst above src, so copy from top downwards */
1242 for (y = 0; y < dstheight; y++)
1244 memcpy(dbuf, sbuf, width);
1245 sbuf += slock.Pitch;
1246 dbuf += dlock.Pitch;
1249 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1251 sbuf += (slock.Pitch*dstheight);
1252 dbuf += (dlock.Pitch*dstheight);
1253 for (y = 0; y < dstheight; y++)
1255 sbuf -= slock.Pitch;
1256 dbuf -= dlock.Pitch;
1257 memcpy(dbuf, sbuf, width);
1260 else /* src and dst overlapping on the same line, use memmove */
1262 for (y = 0; y < dstheight; y++)
1264 memmove(dbuf, sbuf, width);
1265 sbuf += slock.Pitch;
1266 dbuf += dlock.Pitch;
1269 } else {
1270 /* Stretching in Y direction only */
1271 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1272 sbuf = sbase + (sy >> 16) * slock.Pitch;
1273 memcpy(dbuf, sbuf, width);
1274 dbuf += dlock.Pitch;
1278 else
1280 /* Stretching in X direction */
1281 int last_sy = -1;
1282 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1284 sbuf = sbase + (sy >> 16) * slock.Pitch;
1286 if ((sy >> 16) == (last_sy >> 16))
1288 /* this sourcerow is the same as last sourcerow -
1289 * copy already stretched row
1291 memcpy(dbuf, dbuf - dlock.Pitch, width);
1293 else
1295 #define STRETCH_ROW(type) { \
1296 const type *s = (const type *)sbuf; \
1297 type *d = (type *)dbuf; \
1298 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1299 d[x] = s[sx >> 16]; \
1300 break; }
1302 switch(bpp)
1304 case 1: STRETCH_ROW(BYTE)
1305 case 2: STRETCH_ROW(WORD)
1306 case 4: STRETCH_ROW(DWORD)
1307 case 3:
1309 const BYTE *s;
1310 BYTE *d = dbuf;
1311 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1313 DWORD pixel;
1315 s = sbuf+3*(sx>>16);
1316 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1317 d[0] = (pixel )&0xff;
1318 d[1] = (pixel>> 8)&0xff;
1319 d[2] = (pixel>>16)&0xff;
1320 d+=3;
1322 break;
1324 default:
1325 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1326 ret = WINED3DERR_NOTAVAILABLE;
1327 goto error;
1329 #undef STRETCH_ROW
1331 dbuf += dlock.Pitch;
1332 last_sy = sy;
1336 else
1338 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1339 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1340 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1341 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1343 /* The color keying flags are checked for correctness in ddraw */
1344 if (Flags & WINEDDBLT_KEYSRC)
1346 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1347 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1349 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1351 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1352 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1355 if (Flags & WINEDDBLT_KEYDEST)
1357 /* Destination color keys are taken from the source surface ! */
1358 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1359 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1361 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1363 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1364 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1367 if(bpp == 1)
1369 keymask = 0xff;
1371 else
1373 keymask = sEntry->red_mask
1374 | sEntry->green_mask
1375 | sEntry->blue_mask;
1377 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1380 if (Flags & WINEDDBLT_DDFX)
1382 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1383 LONG tmpxy;
1384 dTopLeft = dbuf;
1385 dTopRight = dbuf+((dstwidth-1)*bpp);
1386 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1387 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1389 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1391 /* I don't think we need to do anything about this flag */
1392 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1394 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1396 tmp = dTopRight;
1397 dTopRight = dTopLeft;
1398 dTopLeft = tmp;
1399 tmp = dBottomRight;
1400 dBottomRight = dBottomLeft;
1401 dBottomLeft = tmp;
1402 dstxinc = dstxinc *-1;
1404 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1406 tmp = dTopLeft;
1407 dTopLeft = dBottomLeft;
1408 dBottomLeft = tmp;
1409 tmp = dTopRight;
1410 dTopRight = dBottomRight;
1411 dBottomRight = tmp;
1412 dstyinc = dstyinc *-1;
1414 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1416 /* I don't think we need to do anything about this flag */
1417 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1419 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1421 tmp = dBottomRight;
1422 dBottomRight = dTopLeft;
1423 dTopLeft = tmp;
1424 tmp = dBottomLeft;
1425 dBottomLeft = dTopRight;
1426 dTopRight = tmp;
1427 dstxinc = dstxinc * -1;
1428 dstyinc = dstyinc * -1;
1430 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1432 tmp = dTopLeft;
1433 dTopLeft = dBottomLeft;
1434 dBottomLeft = dBottomRight;
1435 dBottomRight = dTopRight;
1436 dTopRight = tmp;
1437 tmpxy = dstxinc;
1438 dstxinc = dstyinc;
1439 dstyinc = tmpxy;
1440 dstxinc = dstxinc * -1;
1442 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1444 tmp = dTopLeft;
1445 dTopLeft = dTopRight;
1446 dTopRight = dBottomRight;
1447 dBottomRight = dBottomLeft;
1448 dBottomLeft = tmp;
1449 tmpxy = dstxinc;
1450 dstxinc = dstyinc;
1451 dstyinc = tmpxy;
1452 dstyinc = dstyinc * -1;
1454 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1456 /* I don't think we need to do anything about this flag */
1457 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1459 dbuf = dTopLeft;
1460 Flags &= ~(WINEDDBLT_DDFX);
1463 #define COPY_COLORKEY_FX(type) { \
1464 const type *s; \
1465 type *d = (type *)dbuf, *dx, tmp; \
1466 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1467 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1468 dx = d; \
1469 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1470 tmp = s[sx >> 16]; \
1471 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1472 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1473 dx[0] = tmp; \
1475 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1477 d = (type*)(((LPBYTE)d)+dstyinc); \
1479 break; }
1481 switch (bpp) {
1482 case 1: COPY_COLORKEY_FX(BYTE)
1483 case 2: COPY_COLORKEY_FX(WORD)
1484 case 4: COPY_COLORKEY_FX(DWORD)
1485 case 3:
1487 const BYTE *s;
1488 BYTE *d = dbuf, *dx;
1489 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1491 sbuf = sbase + (sy >> 16) * slock.Pitch;
1492 dx = d;
1493 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1495 DWORD pixel, dpixel = 0;
1496 s = sbuf+3*(sx>>16);
1497 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1498 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1499 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1500 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1502 dx[0] = (pixel )&0xff;
1503 dx[1] = (pixel>> 8)&0xff;
1504 dx[2] = (pixel>>16)&0xff;
1506 dx+= dstxinc;
1508 d += dstyinc;
1510 break;
1512 default:
1513 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1514 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1515 ret = WINED3DERR_NOTAVAILABLE;
1516 goto error;
1517 #undef COPY_COLORKEY_FX
1522 error:
1523 if (Flags && FIXME_ON(d3d_surface))
1525 FIXME("\tUnsupported flags: %08x\n", Flags);
1528 release:
1529 IWineD3DSurface_UnlockRect(iface);
1530 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1531 /* Release the converted surface if any */
1532 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1533 return ret;
1536 /*****************************************************************************
1537 * IWineD3DSurface::BltFast, SW emulation version
1539 * This is the software implementation of BltFast, as used by GDI surfaces
1540 * and as a fallback for OpenGL surfaces. This code is taken from the old
1541 * DirectDraw code, and was originally written by TransGaming.
1543 * Params:
1544 * dstx:
1545 * dsty:
1546 * Source: Source surface to copy from
1547 * rsrc: Source rectangle
1548 * trans: Some Flags
1550 * Returns:
1551 * WINED3D_OK on success
1553 *****************************************************************************/
1554 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1555 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1557 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1558 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1560 int bpp, w, h, x, y;
1561 WINED3DLOCKED_RECT dlock,slock;
1562 HRESULT ret = WINED3D_OK;
1563 RECT rsrc2;
1564 RECT lock_src, lock_dst, lock_union;
1565 const BYTE *sbuf;
1566 BYTE *dbuf;
1567 const struct GlPixelFormatDesc *sEntry, *dEntry;
1569 if (TRACE_ON(d3d_surface))
1571 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1573 if (rsrc)
1575 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1576 rsrc->right,rsrc->bottom);
1578 else
1580 TRACE(" srcrect: NULL\n");
1584 if ((This->Flags & SFLAG_LOCKED) ||
1585 (Src->Flags & SFLAG_LOCKED))
1587 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1588 return WINEDDERR_SURFACEBUSY;
1591 if (!rsrc)
1593 WARN("rsrc is NULL!\n");
1594 rsrc2.left = 0;
1595 rsrc2.top = 0;
1596 rsrc2.right = Src->currentDesc.Width;
1597 rsrc2.bottom = Src->currentDesc.Height;
1598 rsrc = &rsrc2;
1601 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1602 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1603 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1604 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1605 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1606 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1608 WARN("Application gave us bad source rectangle for BltFast.\n");
1609 return WINEDDERR_INVALIDRECT;
1612 h = rsrc->bottom - rsrc->top;
1613 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1614 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1615 if (h <= 0) return WINEDDERR_INVALIDRECT;
1617 w = rsrc->right - rsrc->left;
1618 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1619 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1620 if (w <= 0) return WINEDDERR_INVALIDRECT;
1622 /* Now compute the locking rectangle... */
1623 lock_src.left = rsrc->left;
1624 lock_src.top = rsrc->top;
1625 lock_src.right = lock_src.left + w;
1626 lock_src.bottom = lock_src.top + h;
1628 lock_dst.left = dstx;
1629 lock_dst.top = dsty;
1630 lock_dst.right = dstx + w;
1631 lock_dst.bottom = dsty + h;
1633 bpp = This->bytesPerPixel;
1635 /* We need to lock the surfaces, or we won't get refreshes when done. */
1636 if (Src == This)
1638 int pitch;
1640 UnionRect(&lock_union, &lock_src, &lock_dst);
1642 /* Lock the union of the two rectangles */
1643 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1644 if(ret != WINED3D_OK) goto error;
1646 pitch = dlock.Pitch;
1647 slock.Pitch = dlock.Pitch;
1649 /* Since slock was originally copied from this surface's description, we can just reuse it */
1650 assert(This->resource.allocatedMemory != NULL);
1651 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1652 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1653 sEntry = Src->resource.format_desc;
1654 dEntry = sEntry;
1656 else
1658 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1659 if(ret != WINED3D_OK) goto error;
1660 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1661 if(ret != WINED3D_OK) goto error;
1663 sbuf = slock.pBits;
1664 dbuf = dlock.pBits;
1665 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1667 sEntry = Src->resource.format_desc;
1668 dEntry = This->resource.format_desc;
1671 /* Handle first the FOURCC surfaces... */
1672 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1674 TRACE("Fourcc -> Fourcc copy\n");
1675 if (trans)
1676 FIXME("trans arg not supported when a FOURCC surface is involved\n");
1677 if (dstx || dsty)
1678 FIXME("offset for destination surface is not supported\n");
1679 if (Src->resource.format_desc != This->resource.format_desc)
1681 FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
1682 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1683 goto error;
1685 /* FIXME: Watch out that the size is correct for FOURCC surfaces */
1686 memcpy(dbuf, sbuf, This->resource.size);
1687 goto error;
1689 if ((sEntry->Flags & WINED3DFMT_FLAG_FOURCC) && !(dEntry->Flags & WINED3DFMT_FLAG_FOURCC))
1691 /* TODO: Use the libtxc_dxtn.so shared library to do
1692 * software decompression
1694 ERR("DXTC decompression not supported by now\n");
1695 goto error;
1698 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1700 DWORD keylow, keyhigh;
1701 TRACE("Color keyed copy\n");
1702 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1704 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1705 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1707 else
1709 /* I'm not sure if this is correct */
1710 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1711 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1712 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1715 #define COPYBOX_COLORKEY(type) { \
1716 const type *s = (const type *)sbuf; \
1717 type *d = (type *)dbuf; \
1718 type tmp; \
1719 for (y = 0; y < h; y++) { \
1720 for (x = 0; x < w; x++) { \
1721 tmp = s[x]; \
1722 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1724 s = (const type *)((const BYTE *)s + slock.Pitch); \
1725 d = (type *)((BYTE *)d + dlock.Pitch); \
1727 break; \
1730 switch (bpp) {
1731 case 1: COPYBOX_COLORKEY(BYTE)
1732 case 2: COPYBOX_COLORKEY(WORD)
1733 case 4: COPYBOX_COLORKEY(DWORD)
1734 case 3:
1736 const BYTE *s;
1737 BYTE *d;
1738 DWORD tmp;
1739 s = sbuf;
1740 d = dbuf;
1741 for (y = 0; y < h; y++)
1743 for (x = 0; x < w * 3; x += 3)
1745 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1746 if (tmp < keylow || tmp > keyhigh)
1748 d[x + 0] = s[x + 0];
1749 d[x + 1] = s[x + 1];
1750 d[x + 2] = s[x + 2];
1753 s += slock.Pitch;
1754 d += dlock.Pitch;
1756 break;
1758 default:
1759 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1760 ret = WINED3DERR_NOTAVAILABLE;
1761 goto error;
1763 #undef COPYBOX_COLORKEY
1764 TRACE("Copy Done\n");
1766 else
1768 int width = w * bpp;
1769 INT sbufpitch, dbufpitch;
1771 TRACE("NO color key copy\n");
1772 /* Handle overlapping surfaces */
1773 if (sbuf < dbuf)
1775 sbuf += (h - 1) * slock.Pitch;
1776 dbuf += (h - 1) * dlock.Pitch;
1777 sbufpitch = -slock.Pitch;
1778 dbufpitch = -dlock.Pitch;
1780 else
1782 sbufpitch = slock.Pitch;
1783 dbufpitch = dlock.Pitch;
1785 for (y = 0; y < h; y++)
1787 /* This is pretty easy, a line for line memcpy */
1788 memmove(dbuf, sbuf, width);
1789 sbuf += sbufpitch;
1790 dbuf += dbufpitch;
1792 TRACE("Copy done\n");
1795 error:
1796 if (Src == This)
1798 IWineD3DSurface_UnlockRect(iface);
1800 else
1802 IWineD3DSurface_UnlockRect(iface);
1803 IWineD3DSurface_UnlockRect(Source);
1806 return ret;
1809 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1811 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1813 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1814 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1816 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1818 if (NULL == pRect)
1820 pLockedRect->pBits = This->resource.allocatedMemory;
1821 This->lockedRect.left = 0;
1822 This->lockedRect.top = 0;
1823 This->lockedRect.right = This->currentDesc.Width;
1824 This->lockedRect.bottom = This->currentDesc.Height;
1826 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1827 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1828 This->lockedRect.right, This->lockedRect.bottom);
1830 else
1832 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1833 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1835 /* DXTn textures are based on compressed blocks of 4x4 pixels, each
1836 * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has
1837 * slightly different meaning compared to regular textures. For DXTn
1838 * textures Pitch is the size of a row of blocks, 4 high and "width"
1839 * long. The x offset is calculated differently as well, since moving 4
1840 * pixels to the right actually moves an entire 4x4 block to right, ie
1841 * 16 bytes (8 in case of DXT1). */
1842 if (This->resource.format_desc->format == WINED3DFMT_DXT1)
1844 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2);
1846 else if (This->resource.format_desc->format == WINED3DFMT_DXT2
1847 || This->resource.format_desc->format == WINED3DFMT_DXT3
1848 || This->resource.format_desc->format == WINED3DFMT_DXT4
1849 || This->resource.format_desc->format == WINED3DFMT_DXT5)
1851 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4);
1853 else
1855 pLockedRect->pBits = This->resource.allocatedMemory +
1856 (pLockedRect->Pitch * pRect->top) +
1857 (pRect->left * This->bytesPerPixel);
1859 This->lockedRect.left = pRect->left;
1860 This->lockedRect.top = pRect->top;
1861 This->lockedRect.right = pRect->right;
1862 This->lockedRect.bottom = pRect->bottom;
1865 /* No dirtifying is needed for this surface implementation */
1866 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1868 return WINED3D_OK;
1871 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1872 ERR("Should not be called on base texture\n");
1873 return;
1876 /* TODO: think about moving this down to resource? */
1877 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1879 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1881 /* This should only be called for sysmem textures, it may be a good idea
1882 * to extend this to all pools at some point in the future */
1883 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1885 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1887 return This->resource.allocatedMemory;