wined3d: GLSL: Implement texrect coord fixup.
[wine/hacks.git] / dlls / wined3d / surface_base.c
blob8d9d941fa0c51a4162a8bf51227eb2c877788984
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->resource.format_desc->byte_count * 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 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
539 This->resource.format_desc = format_desc;
541 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
543 return WINED3D_OK;
546 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
547 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
548 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
549 int extraline = 0;
550 SYSTEM_INFO sysInfo;
551 BITMAPINFO* b_info;
552 HDC ddc;
553 DWORD *masks;
554 UINT usage;
556 switch (format_desc->byte_count)
558 case 2:
559 case 4:
560 /* Allocate extra space to store the RGB bit masks. */
561 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
562 break;
564 case 3:
565 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
566 break;
568 default:
569 /* Allocate extra space for a palette. */
570 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
571 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
572 break;
575 if (!b_info)
576 return E_OUTOFMEMORY;
578 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
579 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
580 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
581 * add an extra line to the dib section
583 GetSystemInfo(&sysInfo);
584 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
585 extraline = 1;
586 TRACE("Adding an extra line to the dib section\n");
589 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
590 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
591 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
592 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
593 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
594 b_info->bmiHeader.biPlanes = 1;
595 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
597 b_info->bmiHeader.biXPelsPerMeter = 0;
598 b_info->bmiHeader.biYPelsPerMeter = 0;
599 b_info->bmiHeader.biClrUsed = 0;
600 b_info->bmiHeader.biClrImportant = 0;
602 /* Get the bit masks */
603 masks = (DWORD *)b_info->bmiColors;
604 switch (This->resource.format_desc->format)
606 case WINED3DFMT_R8G8B8:
607 usage = DIB_RGB_COLORS;
608 b_info->bmiHeader.biCompression = BI_RGB;
609 break;
611 case WINED3DFMT_X1R5G5B5:
612 case WINED3DFMT_A1R5G5B5:
613 case WINED3DFMT_A4R4G4B4:
614 case WINED3DFMT_X4R4G4B4:
615 case WINED3DFMT_R3G3B2:
616 case WINED3DFMT_A8R3G3B2:
617 case WINED3DFMT_R10G10B10A2_UNORM:
618 case WINED3DFMT_R8G8B8A8_UNORM:
619 case WINED3DFMT_X8B8G8R8:
620 case WINED3DFMT_A2R10G10B10:
621 case WINED3DFMT_R5G6B5:
622 case WINED3DFMT_R16G16B16A16_UNORM:
623 usage = 0;
624 b_info->bmiHeader.biCompression = BI_BITFIELDS;
625 masks[0] = format_desc->red_mask;
626 masks[1] = format_desc->green_mask;
627 masks[2] = format_desc->blue_mask;
628 break;
630 default:
631 /* Don't know palette */
632 b_info->bmiHeader.biCompression = BI_RGB;
633 usage = 0;
634 break;
637 ddc = GetDC(0);
638 if (ddc == 0) {
639 HeapFree(GetProcessHeap(), 0, b_info);
640 return HRESULT_FROM_WIN32(GetLastError());
643 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);
644 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
645 ReleaseDC(0, ddc);
647 if (!This->dib.DIBsection) {
648 ERR("CreateDIBSection failed!\n");
649 HeapFree(GetProcessHeap(), 0, b_info);
650 return HRESULT_FROM_WIN32(GetLastError());
653 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
654 /* copy the existing surface to the dib section */
655 if(This->resource.allocatedMemory) {
656 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
657 } else {
658 /* This is to make LockRect read the gl Texture although memory is allocated */
659 This->Flags &= ~SFLAG_INSYSMEM;
661 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
663 HeapFree(GetProcessHeap(), 0, b_info);
665 /* Now allocate a HDC */
666 This->hDC = CreateCompatibleDC(0);
667 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
668 TRACE("using wined3d palette %p\n", This->palette);
669 SelectPalette(This->hDC,
670 This->palette ? This->palette->hpal : 0,
671 FALSE);
673 This->Flags |= SFLAG_DIBSECTION;
675 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
676 This->resource.heapMemory = NULL;
678 return WINED3D_OK;
681 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
682 unsigned int w, unsigned int h)
684 unsigned int x, y;
685 const float *src_f;
686 unsigned short *dst_s;
688 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
689 for(y = 0; y < h; y++) {
690 src_f = (const float *)(src + y * pitch_in);
691 dst_s = (unsigned short *) (dst + y * pitch_out);
692 for(x = 0; x < w; x++) {
693 dst_s[x] = float_32_to_16(src_f + x);
698 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
699 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
701 static const unsigned char convert_5to8[] =
703 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
704 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
705 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
706 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
708 static const unsigned char convert_6to8[] =
710 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
711 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
712 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
713 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
714 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
715 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
716 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
717 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
719 unsigned int x, y;
721 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
723 for (y = 0; y < h; ++y)
725 const WORD *src_line = (const WORD *)(src + y * pitch_in);
726 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
727 for (x = 0; x < w; ++x)
729 WORD pixel = src_line[x];
730 dst_line[x] = 0xff000000
731 | convert_5to8[(pixel & 0xf800) >> 11] << 16
732 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
733 | convert_5to8[(pixel & 0x001f)];
738 struct d3dfmt_convertor_desc {
739 WINED3DFORMAT from, to;
740 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
743 static const struct d3dfmt_convertor_desc convertors[] =
745 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
746 {WINED3DFMT_R5G6B5, WINED3DFMT_X8R8G8B8, convert_r5g6b5_x8r8g8b8},
749 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
751 unsigned int i;
752 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
753 if(convertors[i].from == from && convertors[i].to == to) {
754 return &convertors[i];
757 return NULL;
760 /*****************************************************************************
761 * surface_convert_format
763 * Creates a duplicate of a surface in a different format. Is used by Blt to
764 * blit between surfaces with different formats
766 * Parameters
767 * source: Source surface
768 * fmt: Requested destination format
770 *****************************************************************************/
771 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
772 IWineD3DSurface *ret = NULL;
773 const struct d3dfmt_convertor_desc *conv;
774 WINED3DLOCKED_RECT lock_src, lock_dst;
775 HRESULT hr;
777 conv = find_convertor(source->resource.format_desc->format, to_fmt);
778 if(!conv) {
779 FIXME("Cannot find a conversion function from format %s to %s\n",
780 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
781 return NULL;
784 IWineD3DDevice_CreateSurface((IWineD3DDevice *) source->resource.wineD3DDevice,
785 source->currentDesc.Width,
786 source->currentDesc.Height,
787 to_fmt,
788 TRUE, /* lockable */
789 TRUE, /* discard */
790 0, /* level */
791 &ret,
792 WINED3DRTYPE_SURFACE,
793 0, /* usage */
794 WINED3DPOOL_SCRATCH,
795 WINED3DMULTISAMPLE_NONE, /* TODO: Multisampled conversion */
796 0, /* MultiSampleQuality */
797 NULL, /* SharedHandle */
798 IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
799 NULL); /* parent */
800 if(!ret) {
801 ERR("Failed to create a destination surface for conversion\n");
802 return NULL;
805 memset(&lock_src, 0, sizeof(lock_src));
806 memset(&lock_dst, 0, sizeof(lock_dst));
808 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
809 if(FAILED(hr)) {
810 ERR("Failed to lock the source surface\n");
811 IWineD3DSurface_Release(ret);
812 return NULL;
814 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
815 if(FAILED(hr)) {
816 ERR("Failed to lock the dest surface\n");
817 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
818 IWineD3DSurface_Release(ret);
819 return NULL;
822 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
823 source->currentDesc.Width, source->currentDesc.Height);
825 IWineD3DSurface_UnlockRect(ret);
826 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
828 return (IWineD3DSurfaceImpl *) ret;
831 /*****************************************************************************
832 * _Blt_ColorFill
834 * Helper function that fills a memory area with a specific color
836 * Params:
837 * buf: memory address to start filling at
838 * width, height: Dimensions of the area to fill
839 * bpp: Bit depth of the surface
840 * lPitch: pitch of the surface
841 * color: Color to fill with
843 *****************************************************************************/
844 static HRESULT
845 _Blt_ColorFill(BYTE *buf,
846 int width, int height,
847 int bpp, LONG lPitch,
848 DWORD color)
850 int x, y;
851 LPBYTE first;
853 /* Do first row */
855 #define COLORFILL_ROW(type) \
857 type *d = (type *) buf; \
858 for (x = 0; x < width; x++) \
859 d[x] = (type) color; \
860 break; \
862 switch(bpp)
864 case 1: COLORFILL_ROW(BYTE)
865 case 2: COLORFILL_ROW(WORD)
866 case 3:
868 BYTE *d = buf;
869 for (x = 0; x < width; x++,d+=3)
871 d[0] = (color ) & 0xFF;
872 d[1] = (color>> 8) & 0xFF;
873 d[2] = (color>>16) & 0xFF;
875 break;
877 case 4: COLORFILL_ROW(DWORD)
878 default:
879 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
880 return WINED3DERR_NOTAVAILABLE;
883 #undef COLORFILL_ROW
885 /* Now copy first row */
886 first = buf;
887 for (y = 1; y < height; y++)
889 buf += lPitch;
890 memcpy(buf, first, width * bpp);
892 return WINED3D_OK;
895 /*****************************************************************************
896 * IWineD3DSurface::Blt, SW emulation version
898 * Performs blits to a surface, eigher from a source of source-less blts
899 * This is the main functionality of DirectDraw
901 * Params:
902 * DestRect: Destination rectangle to write to
903 * SrcSurface: Source surface, can be NULL
904 * SrcRect: Source rectangle
905 *****************************************************************************/
906 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
907 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
909 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
910 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
911 RECT xdst,xsrc;
912 HRESULT ret = WINED3D_OK;
913 WINED3DLOCKED_RECT dlock, slock;
914 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
915 const struct GlPixelFormatDesc *sEntry, *dEntry;
916 int x, y;
917 const BYTE *sbuf;
918 BYTE *dbuf;
919 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
921 if (TRACE_ON(d3d_surface))
923 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
924 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
925 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
926 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
927 #if 0
928 TRACE("\tflags: ");
929 DDRAW_dump_DDBLT(Flags);
930 if (Flags & WINEDDBLT_DDFX)
932 TRACE("\tblitfx: ");
933 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
935 #endif
938 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
940 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
941 return WINEDDERR_SURFACEBUSY;
944 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
945 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
946 FIXME("Filters not supported in software blit\n");
949 /* First check for the validity of source / destination rectangles. This was
950 * verified using a test application + by MSDN.
952 if ((Src != NULL) && (SrcRect != NULL) &&
953 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
954 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
955 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
956 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
957 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
959 WARN("Application gave us bad source rectangle for Blt.\n");
960 return WINEDDERR_INVALIDRECT;
962 /* For the Destination rect, it can be out of bounds on the condition that a clipper
963 * is set for the given surface.
965 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
966 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
967 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
968 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
969 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
970 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
972 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
973 return WINEDDERR_INVALIDRECT;
976 /* Now handle negative values in the rectangles. Warning: only supported for now
977 in the 'simple' cases (ie not in any stretching / rotation cases).
979 First, the case where nothing is to be done.
981 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
982 (DestRect->top >= (int) This->currentDesc.Height) ||
983 (DestRect->left >= (int) This->currentDesc.Width))) ||
984 ((Src != NULL) && (SrcRect != NULL) &&
985 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
986 (SrcRect->top >= (int) Src->currentDesc.Height) ||
987 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
989 TRACE("Nothing to be done !\n");
990 return WINED3D_OK;
993 if (DestRect)
995 xdst = *DestRect;
997 else
999 xdst.top = 0;
1000 xdst.bottom = This->currentDesc.Height;
1001 xdst.left = 0;
1002 xdst.right = This->currentDesc.Width;
1005 if (SrcRect)
1007 xsrc = *SrcRect;
1009 else
1011 if (Src)
1013 xsrc.top = 0;
1014 xsrc.bottom = Src->currentDesc.Height;
1015 xsrc.left = 0;
1016 xsrc.right = Src->currentDesc.Width;
1018 else
1020 memset(&xsrc,0,sizeof(xsrc));
1024 /* The easy case : the source-less blits.... */
1025 if (Src == NULL && DestRect)
1027 RECT full_rect;
1028 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1030 full_rect.left = 0;
1031 full_rect.top = 0;
1032 full_rect.right = This->currentDesc.Width;
1033 full_rect.bottom = This->currentDesc.Height;
1034 IntersectRect(&temp_rect, &full_rect, DestRect);
1035 xdst = temp_rect;
1037 else if (DestRect)
1039 /* Only handle clipping on the destination rectangle */
1040 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1041 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1042 if (clip_vert || clip_horiz)
1044 /* Now check if this is a special case or not... */
1045 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1046 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1047 (Flags & WINEDDBLT_DDFX))
1049 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1050 return WINED3D_OK;
1053 if (clip_horiz)
1055 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1056 if (DestRect->right > This->currentDesc.Width)
1058 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1059 xdst.right = (int) This->currentDesc.Width;
1062 if (clip_vert)
1064 if (DestRect->top < 0)
1066 xsrc.top -= DestRect->top;
1067 xdst.top = 0;
1069 if (DestRect->bottom > This->currentDesc.Height)
1071 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1072 xdst.bottom = (int) This->currentDesc.Height;
1075 /* And check if after clipping something is still to be done... */
1076 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1077 (xdst.top >= (int) This->currentDesc.Height) ||
1078 (xdst.left >= (int) This->currentDesc.Width) ||
1079 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1080 (xsrc.top >= (int) Src->currentDesc.Height) ||
1081 (xsrc.left >= (int) Src->currentDesc.Width))
1083 TRACE("Nothing to be done after clipping !\n");
1084 return WINED3D_OK;
1089 if (Src == This)
1091 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1092 slock = dlock;
1093 sEntry = This->resource.format_desc;
1094 dEntry = sEntry;
1096 else
1098 dEntry = This->resource.format_desc;
1099 if (Src)
1101 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1103 Src = surface_convert_format(Src, dEntry->format);
1104 if(!Src) {
1105 /* The conv function writes a FIXME */
1106 WARN("Cannot convert source surface format to dest format\n");
1107 goto release;
1110 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1111 sEntry = Src->resource.format_desc;
1113 else
1115 sEntry = dEntry;
1117 if (DestRect)
1118 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1119 else
1120 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1123 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1125 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1127 if (!DestRect || Src == This)
1129 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1130 goto release;
1134 bpp = This->resource.format_desc->byte_count;
1135 srcheight = xsrc.bottom - xsrc.top;
1136 srcwidth = xsrc.right - xsrc.left;
1137 dstheight = xdst.bottom - xdst.top;
1138 dstwidth = xdst.right - xdst.left;
1139 width = (xdst.right - xdst.left) * bpp;
1141 assert(width <= dlock.Pitch);
1143 if (DestRect && Src != This)
1144 dbuf = dlock.pBits;
1145 else
1146 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1148 if (Flags & WINEDDBLT_WAIT)
1150 Flags &= ~WINEDDBLT_WAIT;
1152 if (Flags & WINEDDBLT_ASYNC)
1154 static BOOL displayed = FALSE;
1155 if (!displayed)
1156 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1157 displayed = TRUE;
1158 Flags &= ~WINEDDBLT_ASYNC;
1160 if (Flags & WINEDDBLT_DONOTWAIT)
1162 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1163 static BOOL displayed = FALSE;
1164 if (!displayed)
1165 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1166 displayed = TRUE;
1167 Flags &= ~WINEDDBLT_DONOTWAIT;
1170 /* First, all the 'source-less' blits */
1171 if (Flags & WINEDDBLT_COLORFILL)
1173 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1174 dlock.Pitch, DDBltFx->u5.dwFillColor);
1175 Flags &= ~WINEDDBLT_COLORFILL;
1178 if (Flags & WINEDDBLT_DEPTHFILL)
1180 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1182 if (Flags & WINEDDBLT_ROP)
1184 /* Catch some degenerate cases here */
1185 switch(DDBltFx->dwROP)
1187 case BLACKNESS:
1188 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1189 break;
1190 case 0xAA0029: /* No-op */
1191 break;
1192 case WHITENESS:
1193 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1194 break;
1195 case SRCCOPY: /* well, we do that below ? */
1196 break;
1197 default:
1198 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1199 goto error;
1201 Flags &= ~WINEDDBLT_ROP;
1203 if (Flags & WINEDDBLT_DDROPS)
1205 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1207 /* Now the 'with source' blits */
1208 if (Src)
1210 const BYTE *sbase;
1211 int sx, xinc, sy, yinc;
1213 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1214 goto release;
1215 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1216 xinc = (srcwidth << 16) / dstwidth;
1217 yinc = (srcheight << 16) / dstheight;
1219 if (!Flags)
1221 /* No effects, we can cheat here */
1222 if (dstwidth == srcwidth)
1224 if (dstheight == srcheight)
1226 /* No stretching in either direction. This needs to be as
1227 * fast as possible */
1228 sbuf = sbase;
1230 /* check for overlapping surfaces */
1231 if (Src != This || xdst.top < xsrc.top ||
1232 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1234 /* no overlap, or dst above src, so copy from top downwards */
1235 for (y = 0; y < dstheight; y++)
1237 memcpy(dbuf, sbuf, width);
1238 sbuf += slock.Pitch;
1239 dbuf += dlock.Pitch;
1242 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1244 sbuf += (slock.Pitch*dstheight);
1245 dbuf += (dlock.Pitch*dstheight);
1246 for (y = 0; y < dstheight; y++)
1248 sbuf -= slock.Pitch;
1249 dbuf -= dlock.Pitch;
1250 memcpy(dbuf, sbuf, width);
1253 else /* src and dst overlapping on the same line, use memmove */
1255 for (y = 0; y < dstheight; y++)
1257 memmove(dbuf, sbuf, width);
1258 sbuf += slock.Pitch;
1259 dbuf += dlock.Pitch;
1262 } else {
1263 /* Stretching in Y direction only */
1264 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1265 sbuf = sbase + (sy >> 16) * slock.Pitch;
1266 memcpy(dbuf, sbuf, width);
1267 dbuf += dlock.Pitch;
1271 else
1273 /* Stretching in X direction */
1274 int last_sy = -1;
1275 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1277 sbuf = sbase + (sy >> 16) * slock.Pitch;
1279 if ((sy >> 16) == (last_sy >> 16))
1281 /* this sourcerow is the same as last sourcerow -
1282 * copy already stretched row
1284 memcpy(dbuf, dbuf - dlock.Pitch, width);
1286 else
1288 #define STRETCH_ROW(type) { \
1289 const type *s = (const type *)sbuf; \
1290 type *d = (type *)dbuf; \
1291 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1292 d[x] = s[sx >> 16]; \
1293 break; }
1295 switch(bpp)
1297 case 1: STRETCH_ROW(BYTE)
1298 case 2: STRETCH_ROW(WORD)
1299 case 4: STRETCH_ROW(DWORD)
1300 case 3:
1302 const BYTE *s;
1303 BYTE *d = dbuf;
1304 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1306 DWORD pixel;
1308 s = sbuf+3*(sx>>16);
1309 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1310 d[0] = (pixel )&0xff;
1311 d[1] = (pixel>> 8)&0xff;
1312 d[2] = (pixel>>16)&0xff;
1313 d+=3;
1315 break;
1317 default:
1318 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1319 ret = WINED3DERR_NOTAVAILABLE;
1320 goto error;
1322 #undef STRETCH_ROW
1324 dbuf += dlock.Pitch;
1325 last_sy = sy;
1329 else
1331 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1332 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1333 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1334 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1336 /* The color keying flags are checked for correctness in ddraw */
1337 if (Flags & WINEDDBLT_KEYSRC)
1339 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1340 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1342 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1344 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1345 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1348 if (Flags & WINEDDBLT_KEYDEST)
1350 /* Destination color keys are taken from the source surface ! */
1351 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1352 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1354 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1356 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1357 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1360 if(bpp == 1)
1362 keymask = 0xff;
1364 else
1366 keymask = sEntry->red_mask
1367 | sEntry->green_mask
1368 | sEntry->blue_mask;
1370 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1373 if (Flags & WINEDDBLT_DDFX)
1375 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1376 LONG tmpxy;
1377 dTopLeft = dbuf;
1378 dTopRight = dbuf+((dstwidth-1)*bpp);
1379 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1380 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1382 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1384 /* I don't think we need to do anything about this flag */
1385 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1387 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1389 tmp = dTopRight;
1390 dTopRight = dTopLeft;
1391 dTopLeft = tmp;
1392 tmp = dBottomRight;
1393 dBottomRight = dBottomLeft;
1394 dBottomLeft = tmp;
1395 dstxinc = dstxinc *-1;
1397 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1399 tmp = dTopLeft;
1400 dTopLeft = dBottomLeft;
1401 dBottomLeft = tmp;
1402 tmp = dTopRight;
1403 dTopRight = dBottomRight;
1404 dBottomRight = tmp;
1405 dstyinc = dstyinc *-1;
1407 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1409 /* I don't think we need to do anything about this flag */
1410 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1412 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1414 tmp = dBottomRight;
1415 dBottomRight = dTopLeft;
1416 dTopLeft = tmp;
1417 tmp = dBottomLeft;
1418 dBottomLeft = dTopRight;
1419 dTopRight = tmp;
1420 dstxinc = dstxinc * -1;
1421 dstyinc = dstyinc * -1;
1423 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1425 tmp = dTopLeft;
1426 dTopLeft = dBottomLeft;
1427 dBottomLeft = dBottomRight;
1428 dBottomRight = dTopRight;
1429 dTopRight = tmp;
1430 tmpxy = dstxinc;
1431 dstxinc = dstyinc;
1432 dstyinc = tmpxy;
1433 dstxinc = dstxinc * -1;
1435 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1437 tmp = dTopLeft;
1438 dTopLeft = dTopRight;
1439 dTopRight = dBottomRight;
1440 dBottomRight = dBottomLeft;
1441 dBottomLeft = tmp;
1442 tmpxy = dstxinc;
1443 dstxinc = dstyinc;
1444 dstyinc = tmpxy;
1445 dstyinc = dstyinc * -1;
1447 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1449 /* I don't think we need to do anything about this flag */
1450 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1452 dbuf = dTopLeft;
1453 Flags &= ~(WINEDDBLT_DDFX);
1456 #define COPY_COLORKEY_FX(type) { \
1457 const type *s; \
1458 type *d = (type *)dbuf, *dx, tmp; \
1459 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1460 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1461 dx = d; \
1462 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1463 tmp = s[sx >> 16]; \
1464 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1465 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1466 dx[0] = tmp; \
1468 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1470 d = (type*)(((LPBYTE)d)+dstyinc); \
1472 break; }
1474 switch (bpp) {
1475 case 1: COPY_COLORKEY_FX(BYTE)
1476 case 2: COPY_COLORKEY_FX(WORD)
1477 case 4: COPY_COLORKEY_FX(DWORD)
1478 case 3:
1480 const BYTE *s;
1481 BYTE *d = dbuf, *dx;
1482 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1484 sbuf = sbase + (sy >> 16) * slock.Pitch;
1485 dx = d;
1486 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1488 DWORD pixel, dpixel = 0;
1489 s = sbuf+3*(sx>>16);
1490 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1491 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1492 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1493 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1495 dx[0] = (pixel )&0xff;
1496 dx[1] = (pixel>> 8)&0xff;
1497 dx[2] = (pixel>>16)&0xff;
1499 dx+= dstxinc;
1501 d += dstyinc;
1503 break;
1505 default:
1506 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1507 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1508 ret = WINED3DERR_NOTAVAILABLE;
1509 goto error;
1510 #undef COPY_COLORKEY_FX
1515 error:
1516 if (Flags && FIXME_ON(d3d_surface))
1518 FIXME("\tUnsupported flags: %08x\n", Flags);
1521 release:
1522 IWineD3DSurface_UnlockRect(iface);
1523 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1524 /* Release the converted surface if any */
1525 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1526 return ret;
1529 /*****************************************************************************
1530 * IWineD3DSurface::BltFast, SW emulation version
1532 * This is the software implementation of BltFast, as used by GDI surfaces
1533 * and as a fallback for OpenGL surfaces. This code is taken from the old
1534 * DirectDraw code, and was originally written by TransGaming.
1536 * Params:
1537 * dstx:
1538 * dsty:
1539 * Source: Source surface to copy from
1540 * rsrc: Source rectangle
1541 * trans: Some Flags
1543 * Returns:
1544 * WINED3D_OK on success
1546 *****************************************************************************/
1547 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1548 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1550 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1551 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1553 int bpp, w, h, x, y;
1554 WINED3DLOCKED_RECT dlock,slock;
1555 HRESULT ret = WINED3D_OK;
1556 RECT rsrc2;
1557 RECT lock_src, lock_dst, lock_union;
1558 const BYTE *sbuf;
1559 BYTE *dbuf;
1560 const struct GlPixelFormatDesc *sEntry, *dEntry;
1562 if (TRACE_ON(d3d_surface))
1564 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1566 if (rsrc)
1568 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1569 rsrc->right,rsrc->bottom);
1571 else
1573 TRACE(" srcrect: NULL\n");
1577 if ((This->Flags & SFLAG_LOCKED) ||
1578 (Src->Flags & SFLAG_LOCKED))
1580 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1581 return WINEDDERR_SURFACEBUSY;
1584 if (!rsrc)
1586 WARN("rsrc is NULL!\n");
1587 rsrc2.left = 0;
1588 rsrc2.top = 0;
1589 rsrc2.right = Src->currentDesc.Width;
1590 rsrc2.bottom = Src->currentDesc.Height;
1591 rsrc = &rsrc2;
1594 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1595 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1596 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1597 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1598 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1599 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1601 WARN("Application gave us bad source rectangle for BltFast.\n");
1602 return WINEDDERR_INVALIDRECT;
1605 h = rsrc->bottom - rsrc->top;
1606 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1607 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1608 if (h <= 0) return WINEDDERR_INVALIDRECT;
1610 w = rsrc->right - rsrc->left;
1611 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1612 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1613 if (w <= 0) return WINEDDERR_INVALIDRECT;
1615 /* Now compute the locking rectangle... */
1616 lock_src.left = rsrc->left;
1617 lock_src.top = rsrc->top;
1618 lock_src.right = lock_src.left + w;
1619 lock_src.bottom = lock_src.top + h;
1621 lock_dst.left = dstx;
1622 lock_dst.top = dsty;
1623 lock_dst.right = dstx + w;
1624 lock_dst.bottom = dsty + h;
1626 bpp = This->resource.format_desc->byte_count;
1628 /* We need to lock the surfaces, or we won't get refreshes when done. */
1629 if (Src == This)
1631 int pitch;
1633 UnionRect(&lock_union, &lock_src, &lock_dst);
1635 /* Lock the union of the two rectangles */
1636 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1637 if(ret != WINED3D_OK) goto error;
1639 pitch = dlock.Pitch;
1640 slock.Pitch = dlock.Pitch;
1642 /* Since slock was originally copied from this surface's description, we can just reuse it */
1643 assert(This->resource.allocatedMemory != NULL);
1644 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1645 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1646 sEntry = Src->resource.format_desc;
1647 dEntry = sEntry;
1649 else
1651 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1652 if(ret != WINED3D_OK) goto error;
1653 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1654 if(ret != WINED3D_OK) goto error;
1656 sbuf = slock.pBits;
1657 dbuf = dlock.pBits;
1658 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1660 sEntry = Src->resource.format_desc;
1661 dEntry = This->resource.format_desc;
1664 /* Handle first the FOURCC surfaces... */
1665 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1667 TRACE("Fourcc -> Fourcc copy\n");
1668 if (trans)
1669 FIXME("trans arg not supported when a FOURCC surface is involved\n");
1670 if (dstx || dsty)
1671 FIXME("offset for destination surface is not supported\n");
1672 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1674 FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n");
1675 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1676 goto error;
1678 /* FIXME: Watch out that the size is correct for FOURCC surfaces */
1679 memcpy(dbuf, sbuf, This->resource.size);
1680 goto error;
1682 if ((sEntry->Flags & WINED3DFMT_FLAG_FOURCC) && !(dEntry->Flags & WINED3DFMT_FLAG_FOURCC))
1684 /* TODO: Use the libtxc_dxtn.so shared library to do
1685 * software decompression
1687 ERR("DXTC decompression not supported by now\n");
1688 goto error;
1691 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1693 DWORD keylow, keyhigh;
1694 TRACE("Color keyed copy\n");
1695 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1697 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1698 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1700 else
1702 /* I'm not sure if this is correct */
1703 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1704 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1705 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1708 #define COPYBOX_COLORKEY(type) { \
1709 const type *s = (const type *)sbuf; \
1710 type *d = (type *)dbuf; \
1711 type tmp; \
1712 for (y = 0; y < h; y++) { \
1713 for (x = 0; x < w; x++) { \
1714 tmp = s[x]; \
1715 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1717 s = (const type *)((const BYTE *)s + slock.Pitch); \
1718 d = (type *)((BYTE *)d + dlock.Pitch); \
1720 break; \
1723 switch (bpp) {
1724 case 1: COPYBOX_COLORKEY(BYTE)
1725 case 2: COPYBOX_COLORKEY(WORD)
1726 case 4: COPYBOX_COLORKEY(DWORD)
1727 case 3:
1729 const BYTE *s;
1730 BYTE *d;
1731 DWORD tmp;
1732 s = sbuf;
1733 d = dbuf;
1734 for (y = 0; y < h; y++)
1736 for (x = 0; x < w * 3; x += 3)
1738 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1739 if (tmp < keylow || tmp > keyhigh)
1741 d[x + 0] = s[x + 0];
1742 d[x + 1] = s[x + 1];
1743 d[x + 2] = s[x + 2];
1746 s += slock.Pitch;
1747 d += dlock.Pitch;
1749 break;
1751 default:
1752 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1753 ret = WINED3DERR_NOTAVAILABLE;
1754 goto error;
1756 #undef COPYBOX_COLORKEY
1757 TRACE("Copy Done\n");
1759 else
1761 int width = w * bpp;
1762 INT sbufpitch, dbufpitch;
1764 TRACE("NO color key copy\n");
1765 /* Handle overlapping surfaces */
1766 if (sbuf < dbuf)
1768 sbuf += (h - 1) * slock.Pitch;
1769 dbuf += (h - 1) * dlock.Pitch;
1770 sbufpitch = -slock.Pitch;
1771 dbufpitch = -dlock.Pitch;
1773 else
1775 sbufpitch = slock.Pitch;
1776 dbufpitch = dlock.Pitch;
1778 for (y = 0; y < h; y++)
1780 /* This is pretty easy, a line for line memcpy */
1781 memmove(dbuf, sbuf, width);
1782 sbuf += sbufpitch;
1783 dbuf += dbufpitch;
1785 TRACE("Copy done\n");
1788 error:
1789 if (Src == This)
1791 IWineD3DSurface_UnlockRect(iface);
1793 else
1795 IWineD3DSurface_UnlockRect(iface);
1796 IWineD3DSurface_UnlockRect(Source);
1799 return ret;
1802 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1804 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1806 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1807 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1809 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1811 if (NULL == pRect)
1813 pLockedRect->pBits = This->resource.allocatedMemory;
1814 This->lockedRect.left = 0;
1815 This->lockedRect.top = 0;
1816 This->lockedRect.right = This->currentDesc.Width;
1817 This->lockedRect.bottom = This->currentDesc.Height;
1819 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1820 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1821 This->lockedRect.right, This->lockedRect.bottom);
1823 else
1825 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1826 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1828 /* DXTn textures are based on compressed blocks of 4x4 pixels, each
1829 * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has
1830 * slightly different meaning compared to regular textures. For DXTn
1831 * textures Pitch is the size of a row of blocks, 4 high and "width"
1832 * long. The x offset is calculated differently as well, since moving 4
1833 * pixels to the right actually moves an entire 4x4 block to right, ie
1834 * 16 bytes (8 in case of DXT1). */
1835 if (This->resource.format_desc->format == WINED3DFMT_DXT1)
1837 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2);
1839 else if (This->resource.format_desc->format == WINED3DFMT_DXT2
1840 || This->resource.format_desc->format == WINED3DFMT_DXT3
1841 || This->resource.format_desc->format == WINED3DFMT_DXT4
1842 || This->resource.format_desc->format == WINED3DFMT_DXT5)
1844 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4);
1846 else
1848 pLockedRect->pBits = This->resource.allocatedMemory +
1849 (pLockedRect->Pitch * pRect->top) +
1850 (pRect->left * This->resource.format_desc->byte_count);
1852 This->lockedRect.left = pRect->left;
1853 This->lockedRect.top = pRect->top;
1854 This->lockedRect.right = pRect->right;
1855 This->lockedRect.bottom = pRect->bottom;
1858 /* No dirtifying is needed for this surface implementation */
1859 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1861 return WINED3D_OK;
1864 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1865 ERR("Should not be called on base texture\n");
1866 return;
1869 /* TODO: think about moving this down to resource? */
1870 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1872 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1874 /* This should only be called for sysmem textures, it may be a good idea
1875 * to extend this to all pools at some point in the future */
1876 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1878 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1880 return This->resource.allocatedMemory;