VirtualBox

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

Last change on this file since 39570 was 37760, checked in by vboxsync, 14 years ago

WDDM/3D: fix windows expirience index crashed on win7 with ati cards

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