VirtualBox

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

Last change on this file since 41283 was 39602, checked in by vboxsync, 13 years ago

wine/XPDM: 1. Additional swapchain creation fixes 2. De-libwine'ize wined3d 3. Single context per swapchain 4. wine & crOgl current context sync fixes 5. Proper Get/ReleaseDC handling

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

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