push cc8bc80451cc24f4d7cf75168b569f0ebfe19547
[wine/hacks.git] / dlls / wined3d / surface_base.c
blobd776785a018daf4000e2a443356889d26464a77d
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);
185 pDesc->format = This->resource.format_desc->format;
186 pDesc->resource_type = This->resource.resourceType;
187 pDesc->usage = This->resource.usage;
188 pDesc->pool = This->resource.pool;
189 pDesc->size = This->resource.size; /* dx8 only */
190 pDesc->multisample_type = This->currentDesc.MultiSampleType;
191 pDesc->multisample_quality = This->currentDesc.MultiSampleQuality;
192 pDesc->width = This->currentDesc.Width;
193 pDesc->height = This->currentDesc.Height;
195 return WINED3D_OK;
198 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
199 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
200 TRACE("(%p)->(%x)\n", This, Flags);
202 switch (Flags)
204 case WINEDDGBS_CANBLT:
205 case WINEDDGBS_ISBLTDONE:
206 return WINED3D_OK;
208 default:
209 return WINED3DERR_INVALIDCALL;
213 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
214 /* XXX: DDERR_INVALIDSURFACETYPE */
216 TRACE("(%p)->(%08x)\n",iface,Flags);
217 switch (Flags) {
218 case WINEDDGFS_CANFLIP:
219 case WINEDDGFS_ISFLIPDONE:
220 return WINED3D_OK;
222 default:
223 return WINED3DERR_INVALIDCALL;
227 HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
228 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
229 TRACE("(%p)\n", This);
231 /* D3D8 and 9 loose full devices, ddraw only surfaces */
232 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
235 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
236 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
237 TRACE("(%p)\n", This);
239 /* So far we don't lose anything :) */
240 This->Flags &= ~SFLAG_LOST;
241 return WINED3D_OK;
244 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
245 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
246 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
247 TRACE("(%p)->(%p)\n", This, Pal);
249 if(This->palette == PalImpl) {
250 TRACE("Nop palette change\n");
251 return WINED3D_OK;
254 if(This->palette != NULL)
255 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
256 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
258 This->palette = PalImpl;
260 if(PalImpl != NULL) {
261 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
262 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
265 return IWineD3DSurface_RealizePalette(iface);
267 else return WINED3D_OK;
270 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
272 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
273 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
275 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
276 FIXME(" colorkey value not supported (%08x) !\n", Flags);
277 return WINED3DERR_INVALIDCALL;
280 /* Dirtify the surface, but only if a key was changed */
281 if(CKey) {
282 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
283 case WINEDDCKEY_DESTBLT:
284 This->DestBltCKey = *CKey;
285 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
286 break;
288 case WINEDDCKEY_DESTOVERLAY:
289 This->DestOverlayCKey = *CKey;
290 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
291 break;
293 case WINEDDCKEY_SRCOVERLAY:
294 This->SrcOverlayCKey = *CKey;
295 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
296 break;
298 case WINEDDCKEY_SRCBLT:
299 This->SrcBltCKey = *CKey;
300 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
301 break;
304 else {
305 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
306 case WINEDDCKEY_DESTBLT:
307 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
308 break;
310 case WINEDDCKEY_DESTOVERLAY:
311 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
312 break;
314 case WINEDDCKEY_SRCOVERLAY:
315 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
316 break;
318 case WINEDDCKEY_SRCBLT:
319 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
320 break;
324 return WINED3D_OK;
327 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
328 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
329 TRACE("(%p)->(%p)\n", This, Pal);
331 *Pal = (IWineD3DPalette *) This->palette;
332 return WINED3D_OK;
335 DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
336 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
337 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
338 DWORD ret;
339 TRACE("(%p)\n", This);
341 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
343 /* Since compressed formats are block based, pitch means the amount of
344 * bytes to the next row of block rather than the next row of pixels. */
345 UINT row_block_count = (This->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
346 ret = row_block_count * format_desc->block_byte_count;
348 else
350 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
351 ret = This->resource.format_desc->byte_count * This->currentDesc.Width; /* Bytes / row */
352 ret = (ret + alignment - 1) & ~(alignment - 1);
354 TRACE("(%p) Returning %d\n", This, ret);
355 return ret;
358 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
359 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
360 LONG w, h;
362 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
364 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
366 TRACE("(%p): Not an overlay surface\n", This);
367 return WINEDDERR_NOTAOVERLAYSURFACE;
370 w = This->overlay_destrect.right - This->overlay_destrect.left;
371 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
372 This->overlay_destrect.left = X;
373 This->overlay_destrect.top = Y;
374 This->overlay_destrect.right = X + w;
375 This->overlay_destrect.bottom = Y + h;
377 IWineD3DSurface_DrawOverlay(iface);
379 return WINED3D_OK;
382 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
383 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
384 HRESULT hr;
386 TRACE("(%p)->(%p,%p)\n", This, X, Y);
388 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
390 TRACE("(%p): Not an overlay surface\n", This);
391 return WINEDDERR_NOTAOVERLAYSURFACE;
393 if(This->overlay_dest == NULL) {
394 *X = 0; *Y = 0;
395 hr = WINEDDERR_OVERLAYNOTVISIBLE;
396 } else {
397 *X = This->overlay_destrect.left;
398 *Y = This->overlay_destrect.top;
399 hr = WINED3D_OK;
402 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
403 return hr;
406 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
407 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
408 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
410 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
412 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
414 TRACE("(%p): Not an overlay surface\n", This);
415 return WINEDDERR_NOTAOVERLAYSURFACE;
418 return WINED3D_OK;
421 HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
422 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
424 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
425 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
426 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
428 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
430 WARN("(%p): Not an overlay surface\n", This);
431 return WINEDDERR_NOTAOVERLAYSURFACE;
432 } else if(!DstSurface) {
433 WARN("(%p): Dest surface is NULL\n", This);
434 return WINED3DERR_INVALIDCALL;
437 if(SrcRect) {
438 This->overlay_srcrect = *SrcRect;
439 } else {
440 This->overlay_srcrect.left = 0;
441 This->overlay_srcrect.top = 0;
442 This->overlay_srcrect.right = This->currentDesc.Width;
443 This->overlay_srcrect.bottom = This->currentDesc.Height;
446 if(DstRect) {
447 This->overlay_destrect = *DstRect;
448 } else {
449 This->overlay_destrect.left = 0;
450 This->overlay_destrect.top = 0;
451 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
452 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
455 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
456 list_remove(&This->overlay_entry);
459 if(Flags & WINEDDOVER_SHOW) {
460 if(This->overlay_dest != Dst) {
461 This->overlay_dest = Dst;
462 list_add_tail(&Dst->overlays, &This->overlay_entry);
464 } else if(Flags & WINEDDOVER_HIDE) {
465 /* tests show that the rectangles are erased on hide */
466 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
467 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
468 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
469 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
470 This->overlay_dest = NULL;
473 IWineD3DSurface_DrawOverlay(iface);
475 return WINED3D_OK;
478 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
480 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
481 TRACE("(%p)->(%p)\n", This, clipper);
483 This->clipper = clipper;
484 return WINED3D_OK;
487 HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
489 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
490 TRACE("(%p)->(%p)\n", This, clipper);
492 *clipper = This->clipper;
493 if(*clipper) {
494 IWineD3DClipper_AddRef(*clipper);
496 return WINED3D_OK;
499 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
500 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
502 TRACE("This %p, container %p\n", This, container);
504 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
506 TRACE("Setting container to %p from %p\n", container, This->container);
507 This->container = container;
509 return WINED3D_OK;
512 HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
513 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
514 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format,
515 &This->resource.wineD3DDevice->adapter->gl_info);
517 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
519 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
520 return WINED3DERR_INVALIDCALL;
523 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
525 This->resource.size = surface_calculate_size(format_desc, This->resource.wineD3DDevice->surface_alignment,
526 This->pow2Width, This->pow2Height);
528 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
530 This->resource.format_desc = format_desc;
532 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
534 return WINED3D_OK;
537 HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
538 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
539 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
540 int extraline = 0;
541 SYSTEM_INFO sysInfo;
542 BITMAPINFO* b_info;
543 HDC ddc;
544 DWORD *masks;
545 UINT usage;
547 switch (format_desc->byte_count)
549 case 2:
550 case 4:
551 /* Allocate extra space to store the RGB bit masks. */
552 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
553 break;
555 case 3:
556 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
557 break;
559 default:
560 /* Allocate extra space for a palette. */
561 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
562 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
563 break;
566 if (!b_info)
567 return E_OUTOFMEMORY;
569 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
570 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
571 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
572 * add an extra line to the dib section
574 GetSystemInfo(&sysInfo);
575 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
576 extraline = 1;
577 TRACE("Adding an extra line to the dib section\n");
580 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
581 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
582 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
583 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
584 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
585 b_info->bmiHeader.biPlanes = 1;
586 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
588 b_info->bmiHeader.biXPelsPerMeter = 0;
589 b_info->bmiHeader.biYPelsPerMeter = 0;
590 b_info->bmiHeader.biClrUsed = 0;
591 b_info->bmiHeader.biClrImportant = 0;
593 /* Get the bit masks */
594 masks = (DWORD *)b_info->bmiColors;
595 switch (This->resource.format_desc->format)
597 case WINED3DFMT_R8G8B8:
598 usage = DIB_RGB_COLORS;
599 b_info->bmiHeader.biCompression = BI_RGB;
600 break;
602 case WINED3DFMT_X1R5G5B5:
603 case WINED3DFMT_A1R5G5B5:
604 case WINED3DFMT_A4R4G4B4:
605 case WINED3DFMT_X4R4G4B4:
606 case WINED3DFMT_R3G3B2:
607 case WINED3DFMT_A8R3G3B2:
608 case WINED3DFMT_R10G10B10A2_UNORM:
609 case WINED3DFMT_R8G8B8A8_UNORM:
610 case WINED3DFMT_X8B8G8R8:
611 case WINED3DFMT_A2R10G10B10:
612 case WINED3DFMT_R5G6B5:
613 case WINED3DFMT_R16G16B16A16_UNORM:
614 usage = 0;
615 b_info->bmiHeader.biCompression = BI_BITFIELDS;
616 masks[0] = format_desc->red_mask;
617 masks[1] = format_desc->green_mask;
618 masks[2] = format_desc->blue_mask;
619 break;
621 default:
622 /* Don't know palette */
623 b_info->bmiHeader.biCompression = BI_RGB;
624 usage = 0;
625 break;
628 ddc = GetDC(0);
629 if (ddc == 0) {
630 HeapFree(GetProcessHeap(), 0, b_info);
631 return HRESULT_FROM_WIN32(GetLastError());
634 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);
635 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
636 ReleaseDC(0, ddc);
638 if (!This->dib.DIBsection) {
639 ERR("CreateDIBSection failed!\n");
640 HeapFree(GetProcessHeap(), 0, b_info);
641 return HRESULT_FROM_WIN32(GetLastError());
644 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
645 /* copy the existing surface to the dib section */
646 if(This->resource.allocatedMemory) {
647 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
648 } else {
649 /* This is to make LockRect read the gl Texture although memory is allocated */
650 This->Flags &= ~SFLAG_INSYSMEM;
652 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
654 HeapFree(GetProcessHeap(), 0, b_info);
656 /* Now allocate a HDC */
657 This->hDC = CreateCompatibleDC(0);
658 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
659 TRACE("using wined3d palette %p\n", This->palette);
660 SelectPalette(This->hDC,
661 This->palette ? This->palette->hpal : 0,
662 FALSE);
664 This->Flags |= SFLAG_DIBSECTION;
666 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
667 This->resource.heapMemory = NULL;
669 return WINED3D_OK;
672 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
673 unsigned int w, unsigned int h)
675 unsigned int x, y;
676 const float *src_f;
677 unsigned short *dst_s;
679 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
680 for(y = 0; y < h; y++) {
681 src_f = (const float *)(src + y * pitch_in);
682 dst_s = (unsigned short *) (dst + y * pitch_out);
683 for(x = 0; x < w; x++) {
684 dst_s[x] = float_32_to_16(src_f + x);
689 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
690 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
692 static const unsigned char convert_5to8[] =
694 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
695 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
696 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
697 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
699 static const unsigned char convert_6to8[] =
701 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
702 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
703 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
704 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
705 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
706 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
707 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
708 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
710 unsigned int x, y;
712 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
714 for (y = 0; y < h; ++y)
716 const WORD *src_line = (const WORD *)(src + y * pitch_in);
717 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
718 for (x = 0; x < w; ++x)
720 WORD pixel = src_line[x];
721 dst_line[x] = 0xff000000
722 | convert_5to8[(pixel & 0xf800) >> 11] << 16
723 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
724 | convert_5to8[(pixel & 0x001f)];
729 struct d3dfmt_convertor_desc {
730 WINED3DFORMAT from, to;
731 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
734 static const struct d3dfmt_convertor_desc convertors[] =
736 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
737 {WINED3DFMT_R5G6B5, WINED3DFMT_X8R8G8B8, convert_r5g6b5_x8r8g8b8},
740 static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
742 unsigned int i;
743 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
744 if(convertors[i].from == from && convertors[i].to == to) {
745 return &convertors[i];
748 return NULL;
751 /*****************************************************************************
752 * surface_convert_format
754 * Creates a duplicate of a surface in a different format. Is used by Blt to
755 * blit between surfaces with different formats
757 * Parameters
758 * source: Source surface
759 * fmt: Requested destination format
761 *****************************************************************************/
762 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
763 IWineD3DSurface *ret = NULL;
764 const struct d3dfmt_convertor_desc *conv;
765 WINED3DLOCKED_RECT lock_src, lock_dst;
766 HRESULT hr;
768 conv = find_convertor(source->resource.format_desc->format, to_fmt);
769 if(!conv) {
770 FIXME("Cannot find a conversion function from format %s to %s\n",
771 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
772 return NULL;
775 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.wineD3DDevice, source->currentDesc.Width,
776 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
777 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
778 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source), NULL /* parent */);
779 if(!ret) {
780 ERR("Failed to create a destination surface for conversion\n");
781 return NULL;
784 memset(&lock_src, 0, sizeof(lock_src));
785 memset(&lock_dst, 0, sizeof(lock_dst));
787 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
788 if(FAILED(hr)) {
789 ERR("Failed to lock the source surface\n");
790 IWineD3DSurface_Release(ret);
791 return NULL;
793 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
794 if(FAILED(hr)) {
795 ERR("Failed to lock the dest surface\n");
796 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
797 IWineD3DSurface_Release(ret);
798 return NULL;
801 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
802 source->currentDesc.Width, source->currentDesc.Height);
804 IWineD3DSurface_UnlockRect(ret);
805 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
807 return (IWineD3DSurfaceImpl *) ret;
810 /*****************************************************************************
811 * _Blt_ColorFill
813 * Helper function that fills a memory area with a specific color
815 * Params:
816 * buf: memory address to start filling at
817 * width, height: Dimensions of the area to fill
818 * bpp: Bit depth of the surface
819 * lPitch: pitch of the surface
820 * color: Color to fill with
822 *****************************************************************************/
823 static HRESULT
824 _Blt_ColorFill(BYTE *buf,
825 int width, int height,
826 int bpp, LONG lPitch,
827 DWORD color)
829 int x, y;
830 LPBYTE first;
832 /* Do first row */
834 #define COLORFILL_ROW(type) \
836 type *d = (type *) buf; \
837 for (x = 0; x < width; x++) \
838 d[x] = (type) color; \
839 break; \
841 switch(bpp)
843 case 1: COLORFILL_ROW(BYTE)
844 case 2: COLORFILL_ROW(WORD)
845 case 3:
847 BYTE *d = buf;
848 for (x = 0; x < width; x++,d+=3)
850 d[0] = (color ) & 0xFF;
851 d[1] = (color>> 8) & 0xFF;
852 d[2] = (color>>16) & 0xFF;
854 break;
856 case 4: COLORFILL_ROW(DWORD)
857 default:
858 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
859 return WINED3DERR_NOTAVAILABLE;
862 #undef COLORFILL_ROW
864 /* Now copy first row */
865 first = buf;
866 for (y = 1; y < height; y++)
868 buf += lPitch;
869 memcpy(buf, first, width * bpp);
871 return WINED3D_OK;
874 /*****************************************************************************
875 * IWineD3DSurface::Blt, SW emulation version
877 * Performs blits to a surface, eigher from a source of source-less blts
878 * This is the main functionality of DirectDraw
880 * Params:
881 * DestRect: Destination rectangle to write to
882 * SrcSurface: Source surface, can be NULL
883 * SrcRect: Source rectangle
884 *****************************************************************************/
885 HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
886 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
888 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
889 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
890 RECT xdst,xsrc;
891 HRESULT ret = WINED3D_OK;
892 WINED3DLOCKED_RECT dlock, slock;
893 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
894 const struct GlPixelFormatDesc *sEntry, *dEntry;
895 int x, y;
896 const BYTE *sbuf;
897 BYTE *dbuf;
898 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
900 if (TRACE_ON(d3d_surface))
902 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
903 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
904 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
905 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
906 #if 0
907 TRACE("\tflags: ");
908 DDRAW_dump_DDBLT(Flags);
909 if (Flags & WINEDDBLT_DDFX)
911 TRACE("\tblitfx: ");
912 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
914 #endif
917 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
919 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
920 return WINEDDERR_SURFACEBUSY;
923 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
924 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
925 FIXME("Filters not supported in software blit\n");
928 /* First check for the validity of source / destination rectangles. This was
929 * verified using a test application + by MSDN.
931 if ((Src != NULL) && (SrcRect != NULL) &&
932 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
933 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
934 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
935 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
936 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
938 WARN("Application gave us bad source rectangle for Blt.\n");
939 return WINEDDERR_INVALIDRECT;
941 /* For the Destination rect, it can be out of bounds on the condition that a clipper
942 * is set for the given surface.
944 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
945 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
946 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
947 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
948 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
949 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
951 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
952 return WINEDDERR_INVALIDRECT;
955 /* Now handle negative values in the rectangles. Warning: only supported for now
956 in the 'simple' cases (ie not in any stretching / rotation cases).
958 First, the case where nothing is to be done.
960 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
961 (DestRect->top >= (int) This->currentDesc.Height) ||
962 (DestRect->left >= (int) This->currentDesc.Width))) ||
963 ((Src != NULL) && (SrcRect != NULL) &&
964 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
965 (SrcRect->top >= (int) Src->currentDesc.Height) ||
966 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
968 TRACE("Nothing to be done !\n");
969 return WINED3D_OK;
972 if (DestRect)
974 xdst = *DestRect;
976 else
978 xdst.top = 0;
979 xdst.bottom = This->currentDesc.Height;
980 xdst.left = 0;
981 xdst.right = This->currentDesc.Width;
984 if (SrcRect)
986 xsrc = *SrcRect;
988 else
990 if (Src)
992 xsrc.top = 0;
993 xsrc.bottom = Src->currentDesc.Height;
994 xsrc.left = 0;
995 xsrc.right = Src->currentDesc.Width;
997 else
999 memset(&xsrc,0,sizeof(xsrc));
1003 /* The easy case : the source-less blits.... */
1004 if (Src == NULL && DestRect)
1006 RECT full_rect;
1007 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1009 full_rect.left = 0;
1010 full_rect.top = 0;
1011 full_rect.right = This->currentDesc.Width;
1012 full_rect.bottom = This->currentDesc.Height;
1013 IntersectRect(&temp_rect, &full_rect, DestRect);
1014 xdst = temp_rect;
1016 else if (DestRect)
1018 /* Only handle clipping on the destination rectangle */
1019 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1020 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1021 if (clip_vert || clip_horiz)
1023 /* Now check if this is a special case or not... */
1024 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1025 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1026 (Flags & WINEDDBLT_DDFX))
1028 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1029 return WINED3D_OK;
1032 if (clip_horiz)
1034 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1035 if (DestRect->right > This->currentDesc.Width)
1037 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1038 xdst.right = (int) This->currentDesc.Width;
1041 if (clip_vert)
1043 if (DestRect->top < 0)
1045 xsrc.top -= DestRect->top;
1046 xdst.top = 0;
1048 if (DestRect->bottom > This->currentDesc.Height)
1050 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1051 xdst.bottom = (int) This->currentDesc.Height;
1054 /* And check if after clipping something is still to be done... */
1055 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1056 (xdst.top >= (int) This->currentDesc.Height) ||
1057 (xdst.left >= (int) This->currentDesc.Width) ||
1058 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1059 (xsrc.top >= (int) Src->currentDesc.Height) ||
1060 (xsrc.left >= (int) Src->currentDesc.Width))
1062 TRACE("Nothing to be done after clipping !\n");
1063 return WINED3D_OK;
1068 if (Src == This)
1070 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1071 slock = dlock;
1072 sEntry = This->resource.format_desc;
1073 dEntry = sEntry;
1075 else
1077 dEntry = This->resource.format_desc;
1078 if (Src)
1080 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1082 Src = surface_convert_format(Src, dEntry->format);
1083 if(!Src) {
1084 /* The conv function writes a FIXME */
1085 WARN("Cannot convert source surface format to dest format\n");
1086 goto release;
1089 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1090 sEntry = Src->resource.format_desc;
1092 else
1094 sEntry = dEntry;
1096 if (DestRect)
1097 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1098 else
1099 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1102 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1104 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1106 if (!DestRect || Src == This)
1108 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1109 goto release;
1113 bpp = This->resource.format_desc->byte_count;
1114 srcheight = xsrc.bottom - xsrc.top;
1115 srcwidth = xsrc.right - xsrc.left;
1116 dstheight = xdst.bottom - xdst.top;
1117 dstwidth = xdst.right - xdst.left;
1118 width = (xdst.right - xdst.left) * bpp;
1120 assert(width <= dlock.Pitch);
1122 if (DestRect && Src != This)
1123 dbuf = dlock.pBits;
1124 else
1125 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1127 if (Flags & WINEDDBLT_WAIT)
1129 Flags &= ~WINEDDBLT_WAIT;
1131 if (Flags & WINEDDBLT_ASYNC)
1133 static BOOL displayed = FALSE;
1134 if (!displayed)
1135 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1136 displayed = TRUE;
1137 Flags &= ~WINEDDBLT_ASYNC;
1139 if (Flags & WINEDDBLT_DONOTWAIT)
1141 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1142 static BOOL displayed = FALSE;
1143 if (!displayed)
1144 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1145 displayed = TRUE;
1146 Flags &= ~WINEDDBLT_DONOTWAIT;
1149 /* First, all the 'source-less' blits */
1150 if (Flags & WINEDDBLT_COLORFILL)
1152 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1153 dlock.Pitch, DDBltFx->u5.dwFillColor);
1154 Flags &= ~WINEDDBLT_COLORFILL;
1157 if (Flags & WINEDDBLT_DEPTHFILL)
1159 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1161 if (Flags & WINEDDBLT_ROP)
1163 /* Catch some degenerate cases here */
1164 switch(DDBltFx->dwROP)
1166 case BLACKNESS:
1167 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1168 break;
1169 case 0xAA0029: /* No-op */
1170 break;
1171 case WHITENESS:
1172 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1173 break;
1174 case SRCCOPY: /* well, we do that below ? */
1175 break;
1176 default:
1177 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1178 goto error;
1180 Flags &= ~WINEDDBLT_ROP;
1182 if (Flags & WINEDDBLT_DDROPS)
1184 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1186 /* Now the 'with source' blits */
1187 if (Src)
1189 const BYTE *sbase;
1190 int sx, xinc, sy, yinc;
1192 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1193 goto release;
1194 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1195 xinc = (srcwidth << 16) / dstwidth;
1196 yinc = (srcheight << 16) / dstheight;
1198 if (!Flags)
1200 /* No effects, we can cheat here */
1201 if (dstwidth == srcwidth)
1203 if (dstheight == srcheight)
1205 /* No stretching in either direction. This needs to be as
1206 * fast as possible */
1207 sbuf = sbase;
1209 /* check for overlapping surfaces */
1210 if (Src != This || xdst.top < xsrc.top ||
1211 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1213 /* no overlap, or dst above src, so copy from top downwards */
1214 for (y = 0; y < dstheight; y++)
1216 memcpy(dbuf, sbuf, width);
1217 sbuf += slock.Pitch;
1218 dbuf += dlock.Pitch;
1221 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1223 sbuf += (slock.Pitch*dstheight);
1224 dbuf += (dlock.Pitch*dstheight);
1225 for (y = 0; y < dstheight; y++)
1227 sbuf -= slock.Pitch;
1228 dbuf -= dlock.Pitch;
1229 memcpy(dbuf, sbuf, width);
1232 else /* src and dst overlapping on the same line, use memmove */
1234 for (y = 0; y < dstheight; y++)
1236 memmove(dbuf, sbuf, width);
1237 sbuf += slock.Pitch;
1238 dbuf += dlock.Pitch;
1241 } else {
1242 /* Stretching in Y direction only */
1243 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1244 sbuf = sbase + (sy >> 16) * slock.Pitch;
1245 memcpy(dbuf, sbuf, width);
1246 dbuf += dlock.Pitch;
1250 else
1252 /* Stretching in X direction */
1253 int last_sy = -1;
1254 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1256 sbuf = sbase + (sy >> 16) * slock.Pitch;
1258 if ((sy >> 16) == (last_sy >> 16))
1260 /* this sourcerow is the same as last sourcerow -
1261 * copy already stretched row
1263 memcpy(dbuf, dbuf - dlock.Pitch, width);
1265 else
1267 #define STRETCH_ROW(type) { \
1268 const type *s = (const type *)sbuf; \
1269 type *d = (type *)dbuf; \
1270 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1271 d[x] = s[sx >> 16]; \
1272 break; }
1274 switch(bpp)
1276 case 1: STRETCH_ROW(BYTE)
1277 case 2: STRETCH_ROW(WORD)
1278 case 4: STRETCH_ROW(DWORD)
1279 case 3:
1281 const BYTE *s;
1282 BYTE *d = dbuf;
1283 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1285 DWORD pixel;
1287 s = sbuf+3*(sx>>16);
1288 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1289 d[0] = (pixel )&0xff;
1290 d[1] = (pixel>> 8)&0xff;
1291 d[2] = (pixel>>16)&0xff;
1292 d+=3;
1294 break;
1296 default:
1297 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1298 ret = WINED3DERR_NOTAVAILABLE;
1299 goto error;
1301 #undef STRETCH_ROW
1303 dbuf += dlock.Pitch;
1304 last_sy = sy;
1308 else
1310 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1311 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1312 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1313 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1315 /* The color keying flags are checked for correctness in ddraw */
1316 if (Flags & WINEDDBLT_KEYSRC)
1318 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1319 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1321 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1323 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1324 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1327 if (Flags & WINEDDBLT_KEYDEST)
1329 /* Destination color keys are taken from the source surface ! */
1330 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1331 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1333 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1335 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1336 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1339 if(bpp == 1)
1341 keymask = 0xff;
1343 else
1345 keymask = sEntry->red_mask
1346 | sEntry->green_mask
1347 | sEntry->blue_mask;
1349 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1352 if (Flags & WINEDDBLT_DDFX)
1354 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1355 LONG tmpxy;
1356 dTopLeft = dbuf;
1357 dTopRight = dbuf+((dstwidth-1)*bpp);
1358 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1359 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1361 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1363 /* I don't think we need to do anything about this flag */
1364 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1366 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1368 tmp = dTopRight;
1369 dTopRight = dTopLeft;
1370 dTopLeft = tmp;
1371 tmp = dBottomRight;
1372 dBottomRight = dBottomLeft;
1373 dBottomLeft = tmp;
1374 dstxinc = dstxinc *-1;
1376 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1378 tmp = dTopLeft;
1379 dTopLeft = dBottomLeft;
1380 dBottomLeft = tmp;
1381 tmp = dTopRight;
1382 dTopRight = dBottomRight;
1383 dBottomRight = tmp;
1384 dstyinc = dstyinc *-1;
1386 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1388 /* I don't think we need to do anything about this flag */
1389 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1391 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1393 tmp = dBottomRight;
1394 dBottomRight = dTopLeft;
1395 dTopLeft = tmp;
1396 tmp = dBottomLeft;
1397 dBottomLeft = dTopRight;
1398 dTopRight = tmp;
1399 dstxinc = dstxinc * -1;
1400 dstyinc = dstyinc * -1;
1402 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1404 tmp = dTopLeft;
1405 dTopLeft = dBottomLeft;
1406 dBottomLeft = dBottomRight;
1407 dBottomRight = dTopRight;
1408 dTopRight = tmp;
1409 tmpxy = dstxinc;
1410 dstxinc = dstyinc;
1411 dstyinc = tmpxy;
1412 dstxinc = dstxinc * -1;
1414 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1416 tmp = dTopLeft;
1417 dTopLeft = dTopRight;
1418 dTopRight = dBottomRight;
1419 dBottomRight = dBottomLeft;
1420 dBottomLeft = tmp;
1421 tmpxy = dstxinc;
1422 dstxinc = dstyinc;
1423 dstyinc = tmpxy;
1424 dstyinc = dstyinc * -1;
1426 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1428 /* I don't think we need to do anything about this flag */
1429 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1431 dbuf = dTopLeft;
1432 Flags &= ~(WINEDDBLT_DDFX);
1435 #define COPY_COLORKEY_FX(type) { \
1436 const type *s; \
1437 type *d = (type *)dbuf, *dx, tmp; \
1438 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1439 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1440 dx = d; \
1441 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1442 tmp = s[sx >> 16]; \
1443 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1444 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1445 dx[0] = tmp; \
1447 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1449 d = (type*)(((LPBYTE)d)+dstyinc); \
1451 break; }
1453 switch (bpp) {
1454 case 1: COPY_COLORKEY_FX(BYTE)
1455 case 2: COPY_COLORKEY_FX(WORD)
1456 case 4: COPY_COLORKEY_FX(DWORD)
1457 case 3:
1459 const BYTE *s;
1460 BYTE *d = dbuf, *dx;
1461 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1463 sbuf = sbase + (sy >> 16) * slock.Pitch;
1464 dx = d;
1465 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1467 DWORD pixel, dpixel = 0;
1468 s = sbuf+3*(sx>>16);
1469 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1470 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1471 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1472 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1474 dx[0] = (pixel )&0xff;
1475 dx[1] = (pixel>> 8)&0xff;
1476 dx[2] = (pixel>>16)&0xff;
1478 dx+= dstxinc;
1480 d += dstyinc;
1482 break;
1484 default:
1485 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1486 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1487 ret = WINED3DERR_NOTAVAILABLE;
1488 goto error;
1489 #undef COPY_COLORKEY_FX
1494 error:
1495 if (Flags && FIXME_ON(d3d_surface))
1497 FIXME("\tUnsupported flags: %08x\n", Flags);
1500 release:
1501 IWineD3DSurface_UnlockRect(iface);
1502 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1503 /* Release the converted surface if any */
1504 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1505 return ret;
1508 /*****************************************************************************
1509 * IWineD3DSurface::BltFast, SW emulation version
1511 * This is the software implementation of BltFast, as used by GDI surfaces
1512 * and as a fallback for OpenGL surfaces. This code is taken from the old
1513 * DirectDraw code, and was originally written by TransGaming.
1515 * Params:
1516 * dstx:
1517 * dsty:
1518 * Source: Source surface to copy from
1519 * rsrc: Source rectangle
1520 * trans: Some Flags
1522 * Returns:
1523 * WINED3D_OK on success
1525 *****************************************************************************/
1526 HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1527 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1529 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1530 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1532 int bpp, w, h, x, y;
1533 WINED3DLOCKED_RECT dlock,slock;
1534 HRESULT ret = WINED3D_OK;
1535 RECT rsrc2;
1536 RECT lock_src, lock_dst, lock_union;
1537 const BYTE *sbuf;
1538 BYTE *dbuf;
1539 const struct GlPixelFormatDesc *sEntry, *dEntry;
1541 if (TRACE_ON(d3d_surface))
1543 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1545 if (rsrc)
1547 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1548 rsrc->right,rsrc->bottom);
1550 else
1552 TRACE(" srcrect: NULL\n");
1556 if ((This->Flags & SFLAG_LOCKED) ||
1557 (Src->Flags & SFLAG_LOCKED))
1559 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1560 return WINEDDERR_SURFACEBUSY;
1563 if (!rsrc)
1565 WARN("rsrc is NULL!\n");
1566 rsrc2.left = 0;
1567 rsrc2.top = 0;
1568 rsrc2.right = Src->currentDesc.Width;
1569 rsrc2.bottom = Src->currentDesc.Height;
1570 rsrc = &rsrc2;
1573 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1574 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1575 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1576 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1577 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1578 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1580 WARN("Application gave us bad source rectangle for BltFast.\n");
1581 return WINEDDERR_INVALIDRECT;
1584 h = rsrc->bottom - rsrc->top;
1585 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1586 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1587 if (h <= 0) return WINEDDERR_INVALIDRECT;
1589 w = rsrc->right - rsrc->left;
1590 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1591 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1592 if (w <= 0) return WINEDDERR_INVALIDRECT;
1594 /* Now compute the locking rectangle... */
1595 lock_src.left = rsrc->left;
1596 lock_src.top = rsrc->top;
1597 lock_src.right = lock_src.left + w;
1598 lock_src.bottom = lock_src.top + h;
1600 lock_dst.left = dstx;
1601 lock_dst.top = dsty;
1602 lock_dst.right = dstx + w;
1603 lock_dst.bottom = dsty + h;
1605 bpp = This->resource.format_desc->byte_count;
1607 /* We need to lock the surfaces, or we won't get refreshes when done. */
1608 if (Src == This)
1610 int pitch;
1612 UnionRect(&lock_union, &lock_src, &lock_dst);
1614 /* Lock the union of the two rectangles */
1615 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1616 if(ret != WINED3D_OK) goto error;
1618 pitch = dlock.Pitch;
1619 slock.Pitch = dlock.Pitch;
1621 /* Since slock was originally copied from this surface's description, we can just reuse it */
1622 assert(This->resource.allocatedMemory != NULL);
1623 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1624 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1625 sEntry = Src->resource.format_desc;
1626 dEntry = sEntry;
1628 else
1630 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1631 if(ret != WINED3D_OK) goto error;
1632 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1633 if(ret != WINED3D_OK) goto error;
1635 sbuf = slock.pBits;
1636 dbuf = dlock.pBits;
1637 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1639 sEntry = Src->resource.format_desc;
1640 dEntry = This->resource.format_desc;
1643 /* Handle compressed surfaces first... */
1644 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1646 UINT row_block_count;
1648 TRACE("compressed -> compressed copy\n");
1649 if (trans)
1650 FIXME("trans arg not supported when a compressed surface is involved\n");
1651 if (dstx || dsty)
1652 FIXME("offset for destination surface is not supported\n");
1653 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1655 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1656 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1657 goto error;
1660 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1661 for (y = 0; y < h; y += dEntry->block_height)
1663 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1664 dbuf += dlock.Pitch;
1665 sbuf += slock.Pitch;
1668 goto error;
1670 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1672 /* TODO: Use the libtxc_dxtn.so shared library to do
1673 * software decompression
1675 ERR("Software decompression not supported.\n");
1676 goto error;
1679 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1681 DWORD keylow, keyhigh;
1682 TRACE("Color keyed copy\n");
1683 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1685 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1686 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1688 else
1690 /* I'm not sure if this is correct */
1691 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1692 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1693 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1696 #define COPYBOX_COLORKEY(type) { \
1697 const type *s = (const type *)sbuf; \
1698 type *d = (type *)dbuf; \
1699 type tmp; \
1700 for (y = 0; y < h; y++) { \
1701 for (x = 0; x < w; x++) { \
1702 tmp = s[x]; \
1703 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1705 s = (const type *)((const BYTE *)s + slock.Pitch); \
1706 d = (type *)((BYTE *)d + dlock.Pitch); \
1708 break; \
1711 switch (bpp) {
1712 case 1: COPYBOX_COLORKEY(BYTE)
1713 case 2: COPYBOX_COLORKEY(WORD)
1714 case 4: COPYBOX_COLORKEY(DWORD)
1715 case 3:
1717 const BYTE *s;
1718 BYTE *d;
1719 DWORD tmp;
1720 s = sbuf;
1721 d = dbuf;
1722 for (y = 0; y < h; y++)
1724 for (x = 0; x < w * 3; x += 3)
1726 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1727 if (tmp < keylow || tmp > keyhigh)
1729 d[x + 0] = s[x + 0];
1730 d[x + 1] = s[x + 1];
1731 d[x + 2] = s[x + 2];
1734 s += slock.Pitch;
1735 d += dlock.Pitch;
1737 break;
1739 default:
1740 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1741 ret = WINED3DERR_NOTAVAILABLE;
1742 goto error;
1744 #undef COPYBOX_COLORKEY
1745 TRACE("Copy Done\n");
1747 else
1749 int width = w * bpp;
1750 INT sbufpitch, dbufpitch;
1752 TRACE("NO color key copy\n");
1753 /* Handle overlapping surfaces */
1754 if (sbuf < dbuf)
1756 sbuf += (h - 1) * slock.Pitch;
1757 dbuf += (h - 1) * dlock.Pitch;
1758 sbufpitch = -slock.Pitch;
1759 dbufpitch = -dlock.Pitch;
1761 else
1763 sbufpitch = slock.Pitch;
1764 dbufpitch = dlock.Pitch;
1766 for (y = 0; y < h; y++)
1768 /* This is pretty easy, a line for line memcpy */
1769 memmove(dbuf, sbuf, width);
1770 sbuf += sbufpitch;
1771 dbuf += dbufpitch;
1773 TRACE("Copy done\n");
1776 error:
1777 if (Src == This)
1779 IWineD3DSurface_UnlockRect(iface);
1781 else
1783 IWineD3DSurface_UnlockRect(iface);
1784 IWineD3DSurface_UnlockRect(Source);
1787 return ret;
1790 HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1792 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1794 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1795 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1797 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1799 if (NULL == pRect)
1801 pLockedRect->pBits = This->resource.allocatedMemory;
1802 This->lockedRect.left = 0;
1803 This->lockedRect.top = 0;
1804 This->lockedRect.right = This->currentDesc.Width;
1805 This->lockedRect.bottom = This->currentDesc.Height;
1807 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1808 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1809 This->lockedRect.right, This->lockedRect.bottom);
1811 else
1813 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
1815 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1816 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1818 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1820 /* Compressed textures are block based, so calculate the offset of
1821 * the block that contains the top-left pixel of the locked rectangle. */
1822 pLockedRect->pBits = This->resource.allocatedMemory
1823 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1824 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1826 else
1828 pLockedRect->pBits = This->resource.allocatedMemory +
1829 (pLockedRect->Pitch * pRect->top) +
1830 (pRect->left * format_desc->byte_count);
1832 This->lockedRect.left = pRect->left;
1833 This->lockedRect.top = pRect->top;
1834 This->lockedRect.right = pRect->right;
1835 This->lockedRect.bottom = pRect->bottom;
1838 /* No dirtifying is needed for this surface implementation */
1839 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1841 return WINED3D_OK;
1844 void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1845 ERR("Should not be called on base texture\n");
1846 return;
1849 /* TODO: think about moving this down to resource? */
1850 const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1852 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1854 /* This should only be called for sysmem textures, it may be a good idea
1855 * to extend this to all pools at some point in the future */
1856 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1858 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1860 return This->resource.allocatedMemory;