VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/wined3d/surface_base.c@ 23571

Last change on this file since 23571 was 23571, checked in by vboxsync, 15 years ago

crOpenGL: update to wine 1.1.30

  • Property svn:eol-style set to native
File size: 66.9 KB
Line 
1/*
2 * IWineD3DSurface Implementation of management(non-rendering) functions
3 *
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11 * Copyright 2007 Henri Verbeet
12 * Copyright 2006-2007 Roderick Colenbrander
13 * Copyright 2009 Henri Verbeet for CodeWeavers
14 *
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 */
29
30/*
31 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
32 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
33 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
34 * a choice of LGPL license versions is made available with the language indicating
35 * that LGPLv2 or any later version may be used, or where a choice of which version
36 * of the LGPL is applied is otherwise unspecified.
37 */
38
39#include "config.h"
40#include "wine/port.h"
41#include "wined3d_private.h"
42
43WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
44
45/* See also float_16_to_32() in wined3d_private.h */
46static inline unsigned short float_32_to_16(const float *in)
47{
48 int exp = 0;
49 float tmp = fabs(*in);
50 unsigned int mantissa;
51 unsigned short ret;
52
53 /* Deal with special numbers */
54 if (*in == 0.0f) return 0x0000;
55 if(_isnan(*in)) return 0x7C01;
56 if(!_finite(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
57
58 if(tmp < pow(2, 10)) {
59 do
60 {
61 tmp = tmp * 2.0f;
62 exp--;
63 }while(tmp < pow(2, 10));
64 } else if(tmp >= pow(2, 11)) {
65 do
66 {
67 tmp /= 2.0f;
68 exp++;
69 }while(tmp >= pow(2, 11));
70 }
71
72 mantissa = (unsigned int) tmp;
73 if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
74
75 exp += 10; /* Normalize the mantissa */
76 exp += 15; /* Exponent is encoded with excess 15 */
77
78 if(exp > 30) { /* too big */
79 ret = 0x7c00; /* INF */
80 } else if(exp <= 0) {
81 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
82 while(exp <= 0) {
83 mantissa = mantissa >> 1;
84 exp++;
85 }
86 ret = mantissa & 0x3ff;
87 } else {
88 ret = (exp << 10) | (mantissa & 0x3ff);
89 }
90
91 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
92 return ret;
93}
94
95
96/* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
97
98/* *******************************************
99 IWineD3DSurface IUnknown parts follow
100 ******************************************* */
101HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
102{
103 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
104 /* Warn ,but be nice about things */
105 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
106
107 if (IsEqualGUID(riid, &IID_IUnknown)
108 || IsEqualGUID(riid, &IID_IWineD3DBase)
109 || IsEqualGUID(riid, &IID_IWineD3DResource)
110 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
111 IUnknown_AddRef((IUnknown*)iface);
112 *ppobj = This;
113 return S_OK;
114 }
115 *ppobj = NULL;
116 return E_NOINTERFACE;
117}
118
119ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
120 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
121 ULONG ref = InterlockedIncrement(&This->resource.ref);
122 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
123 return ref;
124}
125
126/* ****************************************************
127 IWineD3DSurface IWineD3DResource parts follow
128 **************************************************** */
129HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
130 return resource_get_device((IWineD3DResource *)iface, ppDevice);
131}
132
133HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
134 return resource_set_private_data((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
135}
136
137HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
138 return resource_get_private_data((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
139}
140
141HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
142 return resource_free_private_data((IWineD3DResource *)iface, refguid);
143}
144
145DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
146 return resource_set_priority((IWineD3DResource *)iface, PriorityNew);
147}
148
149DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
150 return resource_get_priority((IWineD3DResource *)iface);
151}
152
153WINED3DRESOURCETYPE WINAPI IWineD3DBaseSurfaceImpl_GetType(IWineD3DSurface *iface) {
154 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
155 return resource_get_type((IWineD3DResource *)iface);
156}
157
158HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
159 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
160 return resource_get_parent((IWineD3DResource *)iface, pParent);
161}
162
163/* ******************************************************
164 IWineD3DSurface IWineD3DSurface parts follow
165 ****************************************************** */
166
167HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
168 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
169 IWineD3DBase *container = 0;
170
171 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
172
173 if (!ppContainer) {
174 ERR("Called without a valid ppContainer.\n");
175 }
176
177 /* Standalone surfaces return the device as container. */
178 if (This->container) {
179 container = This->container;
180 } else {
181 container = (IWineD3DBase *)This->resource.wineD3DDevice;
182 }
183
184 TRACE("Relaying to QueryInterface\n");
185 return IUnknown_QueryInterface(container, riid, ppContainer);
186}
187
188HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
189 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
190
191 TRACE("(%p) : copying into %p\n", This, pDesc);
192
193 pDesc->format = This->resource.format_desc->format;
194 pDesc->resource_type = This->resource.resourceType;
195 pDesc->usage = This->resource.usage;
196 pDesc->pool = This->resource.pool;
197 pDesc->size = This->resource.size; /* dx8 only */
198 pDesc->multisample_type = This->currentDesc.MultiSampleType;
199 pDesc->multisample_quality = This->currentDesc.MultiSampleQuality;
200 pDesc->width = This->currentDesc.Width;
201 pDesc->height = This->currentDesc.Height;
202
203 return WINED3D_OK;
204}
205
206HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
207 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
208 TRACE("(%p)->(%x)\n", This, Flags);
209
210 switch (Flags)
211 {
212 case WINEDDGBS_CANBLT:
213 case WINEDDGBS_ISBLTDONE:
214 return WINED3D_OK;
215
216 default:
217 return WINED3DERR_INVALIDCALL;
218 }
219}
220
221HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
222 /* XXX: DDERR_INVALIDSURFACETYPE */
223
224 TRACE("(%p)->(%08x)\n",iface,Flags);
225 switch (Flags) {
226 case WINEDDGFS_CANFLIP:
227 case WINEDDGFS_ISFLIPDONE:
228 return WINED3D_OK;
229
230 default:
231 return WINED3DERR_INVALIDCALL;
232 }
233}
234
235HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface) {
236 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
237 TRACE("(%p)\n", This);
238
239 /* D3D8 and 9 loose full devices, ddraw only surfaces */
240 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
241}
242
243HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface) {
244 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
245 TRACE("(%p)\n", This);
246
247 /* So far we don't lose anything :) */
248 This->Flags &= ~SFLAG_LOST;
249 return WINED3D_OK;
250}
251
252HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
253 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
254 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
255 TRACE("(%p)->(%p)\n", This, Pal);
256
257 if(This->palette == PalImpl) {
258 TRACE("Nop palette change\n");
259 return WINED3D_OK;
260 }
261
262 if(This->palette != NULL)
263 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
264 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
265
266 This->palette = PalImpl;
267
268 if(PalImpl != NULL) {
269 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
270 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
271 }
272
273 return IWineD3DSurface_RealizePalette(iface);
274 }
275 else return WINED3D_OK;
276}
277
278HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, const WINEDDCOLORKEY *CKey)
279{
280 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
281 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
282
283 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
284 FIXME(" colorkey value not supported (%08x) !\n", Flags);
285 return WINED3DERR_INVALIDCALL;
286 }
287
288 /* Dirtify the surface, but only if a key was changed */
289 if(CKey) {
290 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
291 case WINEDDCKEY_DESTBLT:
292 This->DestBltCKey = *CKey;
293 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
294 break;
295
296 case WINEDDCKEY_DESTOVERLAY:
297 This->DestOverlayCKey = *CKey;
298 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
299 break;
300
301 case WINEDDCKEY_SRCOVERLAY:
302 This->SrcOverlayCKey = *CKey;
303 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
304 break;
305
306 case WINEDDCKEY_SRCBLT:
307 This->SrcBltCKey = *CKey;
308 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
309 break;
310 }
311 }
312 else {
313 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
314 case WINEDDCKEY_DESTBLT:
315 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
316 break;
317
318 case WINEDDCKEY_DESTOVERLAY:
319 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
320 break;
321
322 case WINEDDCKEY_SRCOVERLAY:
323 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
324 break;
325
326 case WINEDDCKEY_SRCBLT:
327 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
328 break;
329 }
330 }
331
332 return WINED3D_OK;
333}
334
335HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
336 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
337 TRACE("(%p)->(%p)\n", This, Pal);
338
339 *Pal = (IWineD3DPalette *) This->palette;
340 return WINED3D_OK;
341}
342
343DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
344 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
345 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
346 DWORD ret;
347 TRACE("(%p)\n", This);
348
349 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
350 {
351 /* Since compressed formats are block based, pitch means the amount of
352 * bytes to the next row of block rather than the next row of pixels. */
353 UINT row_block_count = (This->currentDesc.Width + format_desc->block_width - 1) / format_desc->block_width;
354 ret = row_block_count * format_desc->block_byte_count;
355 }
356 else
357 {
358 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
359 ret = This->resource.format_desc->byte_count * This->currentDesc.Width; /* Bytes / row */
360 ret = (ret + alignment - 1) & ~(alignment - 1);
361 }
362 TRACE("(%p) Returning %d\n", This, ret);
363 return ret;
364}
365
366HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
367 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
368 LONG w, h;
369
370 TRACE("(%p)->(%d,%d) Stub!\n", This, X, Y);
371
372 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
373 {
374 TRACE("(%p): Not an overlay surface\n", This);
375 return WINEDDERR_NOTAOVERLAYSURFACE;
376 }
377
378 w = This->overlay_destrect.right - This->overlay_destrect.left;
379 h = This->overlay_destrect.bottom - This->overlay_destrect.top;
380 This->overlay_destrect.left = X;
381 This->overlay_destrect.top = Y;
382 This->overlay_destrect.right = X + w;
383 This->overlay_destrect.bottom = Y + h;
384
385 IWineD3DSurface_DrawOverlay(iface);
386
387 return WINED3D_OK;
388}
389
390HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
391 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
392 HRESULT hr;
393
394 TRACE("(%p)->(%p,%p)\n", This, X, Y);
395
396 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
397 {
398 TRACE("(%p): Not an overlay surface\n", This);
399 return WINEDDERR_NOTAOVERLAYSURFACE;
400 }
401 if(This->overlay_dest == NULL) {
402 *X = 0; *Y = 0;
403 hr = WINEDDERR_OVERLAYNOTVISIBLE;
404 } else {
405 *X = This->overlay_destrect.left;
406 *Y = This->overlay_destrect.top;
407 hr = WINED3D_OK;
408 }
409
410 TRACE("Returning 0x%08x, position %d, %d\n", hr, *X, *Y);
411 return hr;
412}
413
414HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
415 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
416 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
417
418 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
419
420 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
421 {
422 TRACE("(%p): Not an overlay surface\n", This);
423 return WINEDDERR_NOTAOVERLAYSURFACE;
424 }
425
426 return WINED3D_OK;
427}
428
429HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *SrcRect,
430 IWineD3DSurface *DstSurface, const RECT *DstRect, DWORD Flags, const WINEDDOVERLAYFX *FX)
431{
432 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
433 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
434 TRACE("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
435
436 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
437 {
438 WARN("(%p): Not an overlay surface\n", This);
439 return WINEDDERR_NOTAOVERLAYSURFACE;
440 } else if(!DstSurface) {
441 WARN("(%p): Dest surface is NULL\n", This);
442 return WINED3DERR_INVALIDCALL;
443 }
444
445 if(SrcRect) {
446 This->overlay_srcrect = *SrcRect;
447 } else {
448 This->overlay_srcrect.left = 0;
449 This->overlay_srcrect.top = 0;
450 This->overlay_srcrect.right = This->currentDesc.Width;
451 This->overlay_srcrect.bottom = This->currentDesc.Height;
452 }
453
454 if(DstRect) {
455 This->overlay_destrect = *DstRect;
456 } else {
457 This->overlay_destrect.left = 0;
458 This->overlay_destrect.top = 0;
459 This->overlay_destrect.right = Dst ? Dst->currentDesc.Width : 0;
460 This->overlay_destrect.bottom = Dst ? Dst->currentDesc.Height : 0;
461 }
462
463 if(This->overlay_dest && (This->overlay_dest != Dst || Flags & WINEDDOVER_HIDE)) {
464 list_remove(&This->overlay_entry);
465 }
466
467 if(Flags & WINEDDOVER_SHOW) {
468 if(This->overlay_dest != Dst) {
469 This->overlay_dest = Dst;
470 list_add_tail(&Dst->overlays, &This->overlay_entry);
471 }
472 } else if(Flags & WINEDDOVER_HIDE) {
473 /* tests show that the rectangles are erased on hide */
474 This->overlay_srcrect.left = 0; This->overlay_srcrect.top = 0;
475 This->overlay_srcrect.right = 0; This->overlay_srcrect.bottom = 0;
476 This->overlay_destrect.left = 0; This->overlay_destrect.top = 0;
477 This->overlay_destrect.right = 0; This->overlay_destrect.bottom = 0;
478 This->overlay_dest = NULL;
479 }
480
481 IWineD3DSurface_DrawOverlay(iface);
482
483 return WINED3D_OK;
484}
485
486HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
487{
488 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
489 TRACE("(%p)->(%p)\n", This, clipper);
490
491 This->clipper = clipper;
492 return WINED3D_OK;
493}
494
495HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
496{
497 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
498 TRACE("(%p)->(%p)\n", This, clipper);
499
500 *clipper = This->clipper;
501 if(*clipper) {
502 IWineD3DClipper_AddRef(*clipper);
503 }
504 return WINED3D_OK;
505}
506
507HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
508 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
509
510 TRACE("This %p, container %p\n", This, container);
511
512 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
513
514 TRACE("Setting container to %p from %p\n", container, This->container);
515 This->container = container;
516
517 return WINED3D_OK;
518}
519
520HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
521 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
522 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format,
523 &This->resource.wineD3DDevice->adapter->gl_info);
524
525 if (This->resource.format_desc->format != WINED3DFMT_UNKNOWN)
526 {
527 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
528 return WINED3DERR_INVALIDCALL;
529 }
530
531 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
532
533 This->resource.size = surface_calculate_size(format_desc, This->resource.wineD3DDevice->surface_alignment,
534 This->pow2Width, This->pow2Height);
535
536 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
537
538 This->resource.format_desc = format_desc;
539
540 TRACE("(%p) : Size %d, bytesPerPixel %d\n", This, This->resource.size, format_desc->byte_count);
541
542 return WINED3D_OK;
543}
544
545HRESULT IWineD3DBaseSurfaceImpl_CreateDIBSection(IWineD3DSurface *iface) {
546 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
547 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
548 int extraline = 0;
549 SYSTEM_INFO sysInfo;
550 BITMAPINFO* b_info;
551 HDC ddc;
552 DWORD *masks;
553 UINT usage;
554
555 if(!(format_desc->Flags & WINED3DFMT_FLAG_GETDC))
556 {
557 WARN("Cannot use GetDC on a %s surface\n", debug_d3dformat(format_desc->format));
558 return WINED3DERR_INVALIDCALL;
559 }
560
561 switch (format_desc->byte_count)
562 {
563 case 2:
564 case 4:
565 /* Allocate extra space to store the RGB bit masks. */
566 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
567 break;
568
569 case 3:
570 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
571 break;
572
573 default:
574 /* Allocate extra space for a palette. */
575 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
576 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format_desc->byte_count * 8)));
577 break;
578 }
579
580 if (!b_info)
581 return E_OUTOFMEMORY;
582
583 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
584 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
585 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
586 * add an extra line to the dib section
587 */
588 GetSystemInfo(&sysInfo);
589 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
590 extraline = 1;
591 TRACE("Adding an extra line to the dib section\n");
592 }
593
594 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
595 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
596 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / format_desc->byte_count;
597 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
598 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
599 b_info->bmiHeader.biPlanes = 1;
600 b_info->bmiHeader.biBitCount = format_desc->byte_count * 8;
601
602 b_info->bmiHeader.biXPelsPerMeter = 0;
603 b_info->bmiHeader.biYPelsPerMeter = 0;
604 b_info->bmiHeader.biClrUsed = 0;
605 b_info->bmiHeader.biClrImportant = 0;
606
607 /* Get the bit masks */
608 masks = (DWORD *)b_info->bmiColors;
609 switch (This->resource.format_desc->format)
610 {
611 case WINED3DFMT_B8G8R8_UNORM:
612 usage = DIB_RGB_COLORS;
613 b_info->bmiHeader.biCompression = BI_RGB;
614 break;
615
616 case WINED3DFMT_B5G5R5X1_UNORM:
617 case WINED3DFMT_B5G5R5A1_UNORM:
618 case WINED3DFMT_B4G4R4A4_UNORM:
619 case WINED3DFMT_B4G4R4X4_UNORM:
620 case WINED3DFMT_B2G3R3_UNORM:
621 case WINED3DFMT_B2G3R3A8_UNORM:
622 case WINED3DFMT_R10G10B10A2_UNORM:
623 case WINED3DFMT_R8G8B8A8_UNORM:
624 case WINED3DFMT_R8G8B8X8_UNORM:
625 case WINED3DFMT_B10G10R10A2_UNORM:
626 case WINED3DFMT_B5G6R5_UNORM:
627 case WINED3DFMT_R16G16B16A16_UNORM:
628 usage = 0;
629 b_info->bmiHeader.biCompression = BI_BITFIELDS;
630 masks[0] = format_desc->red_mask;
631 masks[1] = format_desc->green_mask;
632 masks[2] = format_desc->blue_mask;
633 break;
634
635 default:
636 /* Don't know palette */
637 b_info->bmiHeader.biCompression = BI_RGB;
638 usage = 0;
639 break;
640 }
641
642 ddc = GetDC(0);
643 if (ddc == 0) {
644 HeapFree(GetProcessHeap(), 0, b_info);
645 return HRESULT_FROM_WIN32(GetLastError());
646 }
647
648 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);
649 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
650 ReleaseDC(0, ddc);
651
652 if (!This->dib.DIBsection) {
653 ERR("CreateDIBSection failed!\n");
654 HeapFree(GetProcessHeap(), 0, b_info);
655 return HRESULT_FROM_WIN32(GetLastError());
656 }
657
658 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
659 /* copy the existing surface to the dib section */
660 if(This->resource.allocatedMemory) {
661 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->currentDesc.Height * IWineD3DSurface_GetPitch(iface));
662 } else {
663 /* This is to make LockRect read the gl Texture although memory is allocated */
664 This->Flags &= ~SFLAG_INSYSMEM;
665 }
666 This->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
667
668 HeapFree(GetProcessHeap(), 0, b_info);
669
670 /* Now allocate a HDC */
671 This->hDC = CreateCompatibleDC(0);
672 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
673 TRACE("using wined3d palette %p\n", This->palette);
674 SelectPalette(This->hDC,
675 This->palette ? This->palette->hpal : 0,
676 FALSE);
677
678 This->Flags |= SFLAG_DIBSECTION;
679
680 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
681 This->resource.heapMemory = NULL;
682
683 return WINED3D_OK;
684}
685
686static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out,
687 unsigned int w, unsigned int h)
688{
689 unsigned int x, y;
690 const float *src_f;
691 unsigned short *dst_s;
692
693 TRACE("Converting %dx%d pixels, pitches %d %d\n", w, h, pitch_in, pitch_out);
694 for(y = 0; y < h; y++) {
695 src_f = (const float *)(src + y * pitch_in);
696 dst_s = (unsigned short *) (dst + y * pitch_out);
697 for(x = 0; x < w; x++) {
698 dst_s[x] = float_32_to_16(src_f + x);
699 }
700 }
701}
702
703static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
704 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
705{
706 static const unsigned char convert_5to8[] =
707 {
708 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
709 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
710 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
711 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
712 };
713 static const unsigned char convert_6to8[] =
714 {
715 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
716 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
717 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
718 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
719 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
720 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
721 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
722 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
723 };
724 unsigned int x, y;
725
726 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
727
728 for (y = 0; y < h; ++y)
729 {
730 const WORD *src_line = (const WORD *)(src + y * pitch_in);
731 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
732 for (x = 0; x < w; ++x)
733 {
734 WORD pixel = src_line[x];
735 dst_line[x] = 0xff000000
736 | convert_5to8[(pixel & 0xf800) >> 11] << 16
737 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
738 | convert_5to8[(pixel & 0x001f)];
739 }
740 }
741}
742
743static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
744 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
745{
746 unsigned int x, y;
747
748 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
749
750 for (y = 0; y < h; ++y)
751 {
752 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
753 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
754
755 for (x = 0; x < w; ++x)
756 {
757 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
758 }
759 }
760}
761
762struct d3dfmt_convertor_desc {
763 WINED3DFORMAT from, to;
764 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
765};
766
767static const struct d3dfmt_convertor_desc convertors[] =
768{
769 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
770 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
771 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
772};
773
774static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
775{
776 unsigned int i;
777 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
778 if(convertors[i].from == from && convertors[i].to == to) {
779 return &convertors[i];
780 }
781 }
782 return NULL;
783}
784
785/*****************************************************************************
786 * surface_convert_format
787 *
788 * Creates a duplicate of a surface in a different format. Is used by Blt to
789 * blit between surfaces with different formats
790 *
791 * Parameters
792 * source: Source surface
793 * fmt: Requested destination format
794 *
795 *****************************************************************************/
796static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
797 IWineD3DSurface *ret = NULL;
798 const struct d3dfmt_convertor_desc *conv;
799 WINED3DLOCKED_RECT lock_src, lock_dst;
800 HRESULT hr;
801
802 conv = find_convertor(source->resource.format_desc->format, to_fmt);
803 if(!conv) {
804 FIXME("Cannot find a conversion function from format %s to %s\n",
805 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
806 return NULL;
807 }
808
809 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.wineD3DDevice, source->currentDesc.Width,
810 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
811 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
812 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
813 NULL /* parent */, &wined3d_null_parent_ops);
814 if(!ret) {
815 ERR("Failed to create a destination surface for conversion\n");
816 return NULL;
817 }
818
819 memset(&lock_src, 0, sizeof(lock_src));
820 memset(&lock_dst, 0, sizeof(lock_dst));
821
822 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
823 if(FAILED(hr)) {
824 ERR("Failed to lock the source surface\n");
825 IWineD3DSurface_Release(ret);
826 return NULL;
827 }
828 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
829 if(FAILED(hr)) {
830 ERR("Failed to lock the dest surface\n");
831 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
832 IWineD3DSurface_Release(ret);
833 return NULL;
834 }
835
836 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
837 source->currentDesc.Width, source->currentDesc.Height);
838
839 IWineD3DSurface_UnlockRect(ret);
840 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
841
842 return (IWineD3DSurfaceImpl *) ret;
843}
844
845/*****************************************************************************
846 * _Blt_ColorFill
847 *
848 * Helper function that fills a memory area with a specific color
849 *
850 * Params:
851 * buf: memory address to start filling at
852 * width, height: Dimensions of the area to fill
853 * bpp: Bit depth of the surface
854 * lPitch: pitch of the surface
855 * color: Color to fill with
856 *
857 *****************************************************************************/
858static HRESULT
859 _Blt_ColorFill(BYTE *buf,
860 int width, int height,
861 int bpp, LONG lPitch,
862 DWORD color)
863{
864 int x, y;
865 LPBYTE first;
866
867 /* Do first row */
868
869#define COLORFILL_ROW(type) \
870 { \
871 type *d = (type *) buf; \
872 for (x = 0; x < width; x++) \
873 d[x] = (type) color; \
874 break; \
875}
876 switch(bpp)
877 {
878 case 1: COLORFILL_ROW(BYTE)
879 case 2: COLORFILL_ROW(WORD)
880 case 3:
881 {
882 BYTE *d = buf;
883 for (x = 0; x < width; x++,d+=3)
884 {
885 d[0] = (color ) & 0xFF;
886 d[1] = (color>> 8) & 0xFF;
887 d[2] = (color>>16) & 0xFF;
888 }
889 break;
890 }
891 case 4: COLORFILL_ROW(DWORD)
892 default:
893 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
894 return WINED3DERR_NOTAVAILABLE;
895 }
896
897#undef COLORFILL_ROW
898
899 /* Now copy first row */
900 first = buf;
901 for (y = 1; y < height; y++)
902 {
903 buf += lPitch;
904 memcpy(buf, first, width * bpp);
905 }
906 return WINED3D_OK;
907}
908
909/*****************************************************************************
910 * IWineD3DSurface::Blt, SW emulation version
911 *
912 * Performs blits to a surface, eigher from a source of source-less blts
913 * This is the main functionality of DirectDraw
914 *
915 * Params:
916 * DestRect: Destination rectangle to write to
917 * SrcSurface: Source surface, can be NULL
918 * SrcRect: Source rectangle
919 *****************************************************************************/
920HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
921 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
922{
923 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
924 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
925 RECT xdst,xsrc;
926 HRESULT ret = WINED3D_OK;
927 WINED3DLOCKED_RECT dlock, slock;
928 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
929 const struct GlPixelFormatDesc *sEntry, *dEntry;
930 int x, y;
931 const BYTE *sbuf;
932 BYTE *dbuf;
933 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
934
935 if (TRACE_ON(d3d_surface))
936 {
937 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
938 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
939 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
940 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
941#if 0
942 TRACE("\tflags: ");
943 DDRAW_dump_DDBLT(Flags);
944 if (Flags & WINEDDBLT_DDFX)
945 {
946 TRACE("\tblitfx: ");
947 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
948 }
949#endif
950 }
951
952 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
953 {
954 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
955 return WINEDDERR_SURFACEBUSY;
956 }
957
958 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
959 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
960 FIXME("Filters not supported in software blit\n");
961 }
962
963 /* First check for the validity of source / destination rectangles. This was
964 * verified using a test application + by MSDN.
965 */
966 if ((Src != NULL) && (SrcRect != NULL) &&
967 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
968 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
969 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
970 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
971 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
972 {
973 WARN("Application gave us bad source rectangle for Blt.\n");
974 return WINEDDERR_INVALIDRECT;
975 }
976 /* For the Destination rect, it can be out of bounds on the condition that a clipper
977 * is set for the given surface.
978 */
979 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
980 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
981 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
982 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
983 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
984 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
985 {
986 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
987 return WINEDDERR_INVALIDRECT;
988 }
989
990 /* Now handle negative values in the rectangles. Warning: only supported for now
991 in the 'simple' cases (ie not in any stretching / rotation cases).
992
993 First, the case where nothing is to be done.
994 */
995 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
996 (DestRect->top >= (int) This->currentDesc.Height) ||
997 (DestRect->left >= (int) This->currentDesc.Width))) ||
998 ((Src != NULL) && (SrcRect != NULL) &&
999 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
1000 (SrcRect->top >= (int) Src->currentDesc.Height) ||
1001 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
1002 {
1003 TRACE("Nothing to be done !\n");
1004 return WINED3D_OK;
1005 }
1006
1007 if (DestRect)
1008 {
1009 xdst = *DestRect;
1010 }
1011 else
1012 {
1013 xdst.top = 0;
1014 xdst.bottom = This->currentDesc.Height;
1015 xdst.left = 0;
1016 xdst.right = This->currentDesc.Width;
1017 }
1018
1019 if (SrcRect)
1020 {
1021 xsrc = *SrcRect;
1022 }
1023 else
1024 {
1025 if (Src)
1026 {
1027 xsrc.top = 0;
1028 xsrc.bottom = Src->currentDesc.Height;
1029 xsrc.left = 0;
1030 xsrc.right = Src->currentDesc.Width;
1031 }
1032 else
1033 {
1034 memset(&xsrc,0,sizeof(xsrc));
1035 }
1036 }
1037
1038 /* The easy case : the source-less blits.... */
1039 if (Src == NULL && DestRect)
1040 {
1041 RECT full_rect;
1042 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1043
1044 full_rect.left = 0;
1045 full_rect.top = 0;
1046 full_rect.right = This->currentDesc.Width;
1047 full_rect.bottom = This->currentDesc.Height;
1048 IntersectRect(&temp_rect, &full_rect, DestRect);
1049 xdst = temp_rect;
1050 }
1051 else if (DestRect)
1052 {
1053 /* Only handle clipping on the destination rectangle */
1054 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1055 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1056 if (clip_vert || clip_horiz)
1057 {
1058 /* Now check if this is a special case or not... */
1059 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1060 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1061 (Flags & WINEDDBLT_DDFX))
1062 {
1063 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1064 return WINED3D_OK;
1065 }
1066
1067 if (clip_horiz)
1068 {
1069 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1070 if (DestRect->right > This->currentDesc.Width)
1071 {
1072 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1073 xdst.right = (int) This->currentDesc.Width;
1074 }
1075 }
1076 if (clip_vert)
1077 {
1078 if (DestRect->top < 0)
1079 {
1080 xsrc.top -= DestRect->top;
1081 xdst.top = 0;
1082 }
1083 if (DestRect->bottom > This->currentDesc.Height)
1084 {
1085 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1086 xdst.bottom = (int) This->currentDesc.Height;
1087 }
1088 }
1089 /* And check if after clipping something is still to be done... */
1090 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1091 (xdst.top >= (int) This->currentDesc.Height) ||
1092 (xdst.left >= (int) This->currentDesc.Width) ||
1093 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1094 (xsrc.top >= (int) Src->currentDesc.Height) ||
1095 (xsrc.left >= (int) Src->currentDesc.Width))
1096 {
1097 TRACE("Nothing to be done after clipping !\n");
1098 return WINED3D_OK;
1099 }
1100 }
1101 }
1102
1103 if (Src == This)
1104 {
1105 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1106 slock = dlock;
1107 sEntry = This->resource.format_desc;
1108 dEntry = sEntry;
1109 }
1110 else
1111 {
1112 dEntry = This->resource.format_desc;
1113 if (Src)
1114 {
1115 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1116 {
1117 Src = surface_convert_format(Src, dEntry->format);
1118 if(!Src) {
1119 /* The conv function writes a FIXME */
1120 WARN("Cannot convert source surface format to dest format\n");
1121 goto release;
1122 }
1123 }
1124 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1125 sEntry = Src->resource.format_desc;
1126 }
1127 else
1128 {
1129 sEntry = dEntry;
1130 }
1131 if (DestRect)
1132 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1133 else
1134 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1135 }
1136
1137 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1138
1139 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1140 {
1141 if (!DestRect || Src == This)
1142 {
1143 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1144 goto release;
1145 }
1146 }
1147
1148 bpp = This->resource.format_desc->byte_count;
1149 srcheight = xsrc.bottom - xsrc.top;
1150 srcwidth = xsrc.right - xsrc.left;
1151 dstheight = xdst.bottom - xdst.top;
1152 dstwidth = xdst.right - xdst.left;
1153 width = (xdst.right - xdst.left) * bpp;
1154
1155 if (DestRect && Src != This)
1156 dbuf = dlock.pBits;
1157 else
1158 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1159
1160 if (Flags & WINEDDBLT_WAIT)
1161 {
1162 Flags &= ~WINEDDBLT_WAIT;
1163 }
1164 if (Flags & WINEDDBLT_ASYNC)
1165 {
1166 static BOOL displayed = FALSE;
1167 if (!displayed)
1168 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1169 displayed = TRUE;
1170 Flags &= ~WINEDDBLT_ASYNC;
1171 }
1172 if (Flags & WINEDDBLT_DONOTWAIT)
1173 {
1174 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1175 static BOOL displayed = FALSE;
1176 if (!displayed)
1177 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1178 displayed = TRUE;
1179 Flags &= ~WINEDDBLT_DONOTWAIT;
1180 }
1181
1182 /* First, all the 'source-less' blits */
1183 if (Flags & WINEDDBLT_COLORFILL)
1184 {
1185 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1186 dlock.Pitch, DDBltFx->u5.dwFillColor);
1187 Flags &= ~WINEDDBLT_COLORFILL;
1188 }
1189
1190 if (Flags & WINEDDBLT_DEPTHFILL)
1191 {
1192 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1193 }
1194 if (Flags & WINEDDBLT_ROP)
1195 {
1196 /* Catch some degenerate cases here */
1197 switch(DDBltFx->dwROP)
1198 {
1199 case BLACKNESS:
1200 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1201 break;
1202 case 0xAA0029: /* No-op */
1203 break;
1204 case WHITENESS:
1205 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1206 break;
1207 case SRCCOPY: /* well, we do that below ? */
1208 break;
1209 default:
1210 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1211 goto error;
1212 }
1213 Flags &= ~WINEDDBLT_ROP;
1214 }
1215 if (Flags & WINEDDBLT_DDROPS)
1216 {
1217 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1218 }
1219 /* Now the 'with source' blits */
1220 if (Src)
1221 {
1222 const BYTE *sbase;
1223 int sx, xinc, sy, yinc;
1224
1225 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1226 goto release;
1227 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1228 xinc = (srcwidth << 16) / dstwidth;
1229 yinc = (srcheight << 16) / dstheight;
1230
1231 if (!Flags)
1232 {
1233 /* No effects, we can cheat here */
1234 if (dstwidth == srcwidth)
1235 {
1236 if (dstheight == srcheight)
1237 {
1238 /* No stretching in either direction. This needs to be as
1239 * fast as possible */
1240 sbuf = sbase;
1241
1242 /* check for overlapping surfaces */
1243 if (Src != This || xdst.top < xsrc.top ||
1244 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1245 {
1246 /* no overlap, or dst above src, so copy from top downwards */
1247 for (y = 0; y < dstheight; y++)
1248 {
1249 memcpy(dbuf, sbuf, width);
1250 sbuf += slock.Pitch;
1251 dbuf += dlock.Pitch;
1252 }
1253 }
1254 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1255 {
1256 sbuf += (slock.Pitch*dstheight);
1257 dbuf += (dlock.Pitch*dstheight);
1258 for (y = 0; y < dstheight; y++)
1259 {
1260 sbuf -= slock.Pitch;
1261 dbuf -= dlock.Pitch;
1262 memcpy(dbuf, sbuf, width);
1263 }
1264 }
1265 else /* src and dst overlapping on the same line, use memmove */
1266 {
1267 for (y = 0; y < dstheight; y++)
1268 {
1269 memmove(dbuf, sbuf, width);
1270 sbuf += slock.Pitch;
1271 dbuf += dlock.Pitch;
1272 }
1273 }
1274 } else {
1275 /* Stretching in Y direction only */
1276 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1277 sbuf = sbase + (sy >> 16) * slock.Pitch;
1278 memcpy(dbuf, sbuf, width);
1279 dbuf += dlock.Pitch;
1280 }
1281 }
1282 }
1283 else
1284 {
1285 /* Stretching in X direction */
1286 int last_sy = -1;
1287 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1288 {
1289 sbuf = sbase + (sy >> 16) * slock.Pitch;
1290
1291 if ((sy >> 16) == (last_sy >> 16))
1292 {
1293 /* this sourcerow is the same as last sourcerow -
1294 * copy already stretched row
1295 */
1296 memcpy(dbuf, dbuf - dlock.Pitch, width);
1297 }
1298 else
1299 {
1300#define STRETCH_ROW(type) { \
1301 const type *s = (const type *)sbuf; \
1302 type *d = (type *)dbuf; \
1303 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1304 d[x] = s[sx >> 16]; \
1305 break; }
1306
1307 switch(bpp)
1308 {
1309 case 1: STRETCH_ROW(BYTE)
1310 case 2: STRETCH_ROW(WORD)
1311 case 4: STRETCH_ROW(DWORD)
1312 case 3:
1313 {
1314 const BYTE *s;
1315 BYTE *d = dbuf;
1316 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1317 {
1318 DWORD pixel;
1319
1320 s = sbuf+3*(sx>>16);
1321 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1322 d[0] = (pixel )&0xff;
1323 d[1] = (pixel>> 8)&0xff;
1324 d[2] = (pixel>>16)&0xff;
1325 d+=3;
1326 }
1327 break;
1328 }
1329 default:
1330 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1331 ret = WINED3DERR_NOTAVAILABLE;
1332 goto error;
1333 }
1334#undef STRETCH_ROW
1335 }
1336 dbuf += dlock.Pitch;
1337 last_sy = sy;
1338 }
1339 }
1340 }
1341 else
1342 {
1343 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1344 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1345 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1346 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1347 {
1348 /* The color keying flags are checked for correctness in ddraw */
1349 if (Flags & WINEDDBLT_KEYSRC)
1350 {
1351 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1352 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1353 }
1354 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1355 {
1356 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1357 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1358 }
1359
1360 if (Flags & WINEDDBLT_KEYDEST)
1361 {
1362 /* Destination color keys are taken from the source surface ! */
1363 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1364 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1365 }
1366 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1367 {
1368 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1369 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1370 }
1371
1372 if(bpp == 1)
1373 {
1374 keymask = 0xff;
1375 }
1376 else
1377 {
1378 keymask = sEntry->red_mask
1379 | sEntry->green_mask
1380 | sEntry->blue_mask;
1381 }
1382 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1383 }
1384
1385 if (Flags & WINEDDBLT_DDFX)
1386 {
1387 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1388 LONG tmpxy;
1389 dTopLeft = dbuf;
1390 dTopRight = dbuf+((dstwidth-1)*bpp);
1391 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1392 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1393
1394 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1395 {
1396 /* I don't think we need to do anything about this flag */
1397 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1398 }
1399 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1400 {
1401 tmp = dTopRight;
1402 dTopRight = dTopLeft;
1403 dTopLeft = tmp;
1404 tmp = dBottomRight;
1405 dBottomRight = dBottomLeft;
1406 dBottomLeft = tmp;
1407 dstxinc = dstxinc *-1;
1408 }
1409 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1410 {
1411 tmp = dTopLeft;
1412 dTopLeft = dBottomLeft;
1413 dBottomLeft = tmp;
1414 tmp = dTopRight;
1415 dTopRight = dBottomRight;
1416 dBottomRight = tmp;
1417 dstyinc = dstyinc *-1;
1418 }
1419 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1420 {
1421 /* I don't think we need to do anything about this flag */
1422 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1423 }
1424 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1425 {
1426 tmp = dBottomRight;
1427 dBottomRight = dTopLeft;
1428 dTopLeft = tmp;
1429 tmp = dBottomLeft;
1430 dBottomLeft = dTopRight;
1431 dTopRight = tmp;
1432 dstxinc = dstxinc * -1;
1433 dstyinc = dstyinc * -1;
1434 }
1435 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1436 {
1437 tmp = dTopLeft;
1438 dTopLeft = dBottomLeft;
1439 dBottomLeft = dBottomRight;
1440 dBottomRight = dTopRight;
1441 dTopRight = tmp;
1442 tmpxy = dstxinc;
1443 dstxinc = dstyinc;
1444 dstyinc = tmpxy;
1445 dstxinc = dstxinc * -1;
1446 }
1447 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1448 {
1449 tmp = dTopLeft;
1450 dTopLeft = dTopRight;
1451 dTopRight = dBottomRight;
1452 dBottomRight = dBottomLeft;
1453 dBottomLeft = tmp;
1454 tmpxy = dstxinc;
1455 dstxinc = dstyinc;
1456 dstyinc = tmpxy;
1457 dstyinc = dstyinc * -1;
1458 }
1459 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1460 {
1461 /* I don't think we need to do anything about this flag */
1462 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1463 }
1464 dbuf = dTopLeft;
1465 Flags &= ~(WINEDDBLT_DDFX);
1466 }
1467
1468#define COPY_COLORKEY_FX(type) { \
1469 const type *s; \
1470 type *d = (type *)dbuf, *dx, tmp; \
1471 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1472 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1473 dx = d; \
1474 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1475 tmp = s[sx >> 16]; \
1476 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1477 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1478 dx[0] = tmp; \
1479 } \
1480 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1481 } \
1482 d = (type*)(((LPBYTE)d)+dstyinc); \
1483 } \
1484 break; }
1485
1486 switch (bpp) {
1487 case 1: COPY_COLORKEY_FX(BYTE)
1488 case 2: COPY_COLORKEY_FX(WORD)
1489 case 4: COPY_COLORKEY_FX(DWORD)
1490 case 3:
1491 {
1492 const BYTE *s;
1493 BYTE *d = dbuf, *dx;
1494 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1495 {
1496 sbuf = sbase + (sy >> 16) * slock.Pitch;
1497 dx = d;
1498 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1499 {
1500 DWORD pixel, dpixel = 0;
1501 s = sbuf+3*(sx>>16);
1502 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1503 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1504 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1505 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1506 {
1507 dx[0] = (pixel )&0xff;
1508 dx[1] = (pixel>> 8)&0xff;
1509 dx[2] = (pixel>>16)&0xff;
1510 }
1511 dx+= dstxinc;
1512 }
1513 d += dstyinc;
1514 }
1515 break;
1516 }
1517 default:
1518 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1519 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1520 ret = WINED3DERR_NOTAVAILABLE;
1521 goto error;
1522#undef COPY_COLORKEY_FX
1523 }
1524 }
1525 }
1526
1527error:
1528 if (Flags && FIXME_ON(d3d_surface))
1529 {
1530 FIXME("\tUnsupported flags: %08x\n", Flags);
1531 }
1532
1533release:
1534 IWineD3DSurface_UnlockRect(iface);
1535 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1536 /* Release the converted surface if any */
1537 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1538 return ret;
1539}
1540
1541/*****************************************************************************
1542 * IWineD3DSurface::BltFast, SW emulation version
1543 *
1544 * This is the software implementation of BltFast, as used by GDI surfaces
1545 * and as a fallback for OpenGL surfaces. This code is taken from the old
1546 * DirectDraw code, and was originally written by TransGaming.
1547 *
1548 * Params:
1549 * dstx:
1550 * dsty:
1551 * Source: Source surface to copy from
1552 * rsrc: Source rectangle
1553 * trans: Some Flags
1554 *
1555 * Returns:
1556 * WINED3D_OK on success
1557 *
1558 *****************************************************************************/
1559HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1560 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1561{
1562 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1563 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1564
1565 int bpp, w, h, x, y;
1566 WINED3DLOCKED_RECT dlock,slock;
1567 HRESULT ret = WINED3D_OK;
1568 RECT rsrc2;
1569 RECT lock_src, lock_dst, lock_union;
1570 const BYTE *sbuf;
1571 BYTE *dbuf;
1572 const struct GlPixelFormatDesc *sEntry, *dEntry;
1573
1574 if (TRACE_ON(d3d_surface))
1575 {
1576 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1577
1578 if (rsrc)
1579 {
1580 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1581 rsrc->right,rsrc->bottom);
1582 }
1583 else
1584 {
1585 TRACE(" srcrect: NULL\n");
1586 }
1587 }
1588
1589 if ((This->Flags & SFLAG_LOCKED) ||
1590 (Src->Flags & SFLAG_LOCKED))
1591 {
1592 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1593 return WINEDDERR_SURFACEBUSY;
1594 }
1595
1596 if (!rsrc)
1597 {
1598 WARN("rsrc is NULL!\n");
1599 rsrc2.left = 0;
1600 rsrc2.top = 0;
1601 rsrc2.right = Src->currentDesc.Width;
1602 rsrc2.bottom = Src->currentDesc.Height;
1603 rsrc = &rsrc2;
1604 }
1605
1606 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1607 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1608 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1609 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1610 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1611 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1612 {
1613 WARN("Application gave us bad source rectangle for BltFast.\n");
1614 return WINEDDERR_INVALIDRECT;
1615 }
1616
1617 h = rsrc->bottom - rsrc->top;
1618 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1619 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1620 if (h <= 0) return WINEDDERR_INVALIDRECT;
1621
1622 w = rsrc->right - rsrc->left;
1623 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1624 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1625 if (w <= 0) return WINEDDERR_INVALIDRECT;
1626
1627 /* Now compute the locking rectangle... */
1628 lock_src.left = rsrc->left;
1629 lock_src.top = rsrc->top;
1630 lock_src.right = lock_src.left + w;
1631 lock_src.bottom = lock_src.top + h;
1632
1633 lock_dst.left = dstx;
1634 lock_dst.top = dsty;
1635 lock_dst.right = dstx + w;
1636 lock_dst.bottom = dsty + h;
1637
1638 bpp = This->resource.format_desc->byte_count;
1639
1640 /* We need to lock the surfaces, or we won't get refreshes when done. */
1641 if (Src == This)
1642 {
1643 int pitch;
1644
1645 UnionRect(&lock_union, &lock_src, &lock_dst);
1646
1647 /* Lock the union of the two rectangles */
1648 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1649 if(ret != WINED3D_OK) goto error;
1650
1651 pitch = dlock.Pitch;
1652 slock.Pitch = dlock.Pitch;
1653
1654 /* Since slock was originally copied from this surface's description, we can just reuse it */
1655 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1656 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1657 sEntry = Src->resource.format_desc;
1658 dEntry = sEntry;
1659 }
1660 else
1661 {
1662 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1663 if(ret != WINED3D_OK) goto error;
1664 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1665 if(ret != WINED3D_OK) goto error;
1666
1667 sbuf = slock.pBits;
1668 dbuf = dlock.pBits;
1669 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1670
1671 sEntry = Src->resource.format_desc;
1672 dEntry = This->resource.format_desc;
1673 }
1674
1675 /* Handle compressed surfaces first... */
1676 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1677 {
1678 UINT row_block_count;
1679
1680 TRACE("compressed -> compressed copy\n");
1681 if (trans)
1682 FIXME("trans arg not supported when a compressed surface is involved\n");
1683 if (dstx || dsty)
1684 FIXME("offset for destination surface is not supported\n");
1685 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1686 {
1687 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1688 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1689 goto error;
1690 }
1691
1692 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1693 for (y = 0; y < h; y += dEntry->block_height)
1694 {
1695 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1696 dbuf += dlock.Pitch;
1697 sbuf += slock.Pitch;
1698 }
1699
1700 goto error;
1701 }
1702 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1703 {
1704 /* TODO: Use the libtxc_dxtn.so shared library to do
1705 * software decompression
1706 */
1707 ERR("Software decompression not supported.\n");
1708 goto error;
1709 }
1710
1711 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1712 {
1713 DWORD keylow, keyhigh;
1714 TRACE("Color keyed copy\n");
1715 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1716 {
1717 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1718 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1719 }
1720 else
1721 {
1722 /* I'm not sure if this is correct */
1723 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1724 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1725 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1726 }
1727
1728#define COPYBOX_COLORKEY(type) { \
1729 const type *s = (const type *)sbuf; \
1730 type *d = (type *)dbuf; \
1731 type tmp; \
1732 for (y = 0; y < h; y++) { \
1733 for (x = 0; x < w; x++) { \
1734 tmp = s[x]; \
1735 if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \
1736 } \
1737 s = (const type *)((const BYTE *)s + slock.Pitch); \
1738 d = (type *)((BYTE *)d + dlock.Pitch); \
1739 } \
1740 break; \
1741 }
1742
1743 switch (bpp) {
1744 case 1: COPYBOX_COLORKEY(BYTE)
1745 case 2: COPYBOX_COLORKEY(WORD)
1746 case 4: COPYBOX_COLORKEY(DWORD)
1747 case 3:
1748 {
1749 const BYTE *s;
1750 BYTE *d;
1751 DWORD tmp;
1752 s = sbuf;
1753 d = dbuf;
1754 for (y = 0; y < h; y++)
1755 {
1756 for (x = 0; x < w * 3; x += 3)
1757 {
1758 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1759 if (tmp < keylow || tmp > keyhigh)
1760 {
1761 d[x + 0] = s[x + 0];
1762 d[x + 1] = s[x + 1];
1763 d[x + 2] = s[x + 2];
1764 }
1765 }
1766 s += slock.Pitch;
1767 d += dlock.Pitch;
1768 }
1769 break;
1770 }
1771 default:
1772 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1773 ret = WINED3DERR_NOTAVAILABLE;
1774 goto error;
1775 }
1776#undef COPYBOX_COLORKEY
1777 TRACE("Copy Done\n");
1778 }
1779 else
1780 {
1781 int width = w * bpp;
1782 INT sbufpitch, dbufpitch;
1783
1784 TRACE("NO color key copy\n");
1785 /* Handle overlapping surfaces */
1786 if (sbuf < dbuf)
1787 {
1788 sbuf += (h - 1) * slock.Pitch;
1789 dbuf += (h - 1) * dlock.Pitch;
1790 sbufpitch = -slock.Pitch;
1791 dbufpitch = -dlock.Pitch;
1792 }
1793 else
1794 {
1795 sbufpitch = slock.Pitch;
1796 dbufpitch = dlock.Pitch;
1797 }
1798 for (y = 0; y < h; y++)
1799 {
1800 /* This is pretty easy, a line for line memcpy */
1801 memmove(dbuf, sbuf, width);
1802 sbuf += sbufpitch;
1803 dbuf += dbufpitch;
1804 }
1805 TRACE("Copy done\n");
1806 }
1807
1808error:
1809 if (Src == This)
1810 {
1811 IWineD3DSurface_UnlockRect(iface);
1812 }
1813 else
1814 {
1815 IWineD3DSurface_UnlockRect(iface);
1816 IWineD3DSurface_UnlockRect(Source);
1817 }
1818
1819 return ret;
1820}
1821
1822HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1823{
1824 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1825
1826 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1827 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1828
1829 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1830
1831 if (NULL == pRect)
1832 {
1833 pLockedRect->pBits = This->resource.allocatedMemory;
1834 This->lockedRect.left = 0;
1835 This->lockedRect.top = 0;
1836 This->lockedRect.right = This->currentDesc.Width;
1837 This->lockedRect.bottom = This->currentDesc.Height;
1838
1839 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1840 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1841 This->lockedRect.right, This->lockedRect.bottom);
1842 }
1843 else
1844 {
1845 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
1846
1847 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1848 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1849
1850 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1851 {
1852 /* Compressed textures are block based, so calculate the offset of
1853 * the block that contains the top-left pixel of the locked rectangle. */
1854 pLockedRect->pBits = This->resource.allocatedMemory
1855 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1856 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1857 }
1858 else
1859 {
1860 pLockedRect->pBits = This->resource.allocatedMemory +
1861 (pLockedRect->Pitch * pRect->top) +
1862 (pRect->left * format_desc->byte_count);
1863 }
1864 This->lockedRect.left = pRect->left;
1865 This->lockedRect.top = pRect->top;
1866 This->lockedRect.right = pRect->right;
1867 This->lockedRect.bottom = pRect->bottom;
1868 }
1869
1870 /* No dirtifying is needed for this surface implementation */
1871 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1872
1873 return WINED3D_OK;
1874}
1875
1876void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1877 ERR("Should not be called on base texture\n");
1878 return;
1879}
1880
1881/* TODO: think about moving this down to resource? */
1882const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1883{
1884 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1885
1886 /* This should only be called for sysmem textures, it may be a good idea
1887 * to extend this to all pools at some point in the future */
1888 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1889 {
1890 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1891 }
1892 return This->resource.allocatedMemory;
1893}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette