VirtualBox

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

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

wddm/3d: Aero: fix gdi-backend textures update, avoid extra memcpy for sysmem textures Lock/Unlock

  • Property svn:eol-style set to native
File size: 69.4 KB
Line 
1/*
2 * IWineD3DSurface Implementation of management(non-rendering) functions
3 *
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11 * Copyright 2007 Henri Verbeet
12 * Copyright 2006-2007 Roderick Colenbrander
13 * Copyright 2009 Henri Verbeet for CodeWeavers
14 *
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 */
29
30/*
31 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
32 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
33 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
34 * a choice of LGPL license versions is made available with the language indicating
35 * that LGPLv2 or any later version may be used, or where a choice of which version
36 * of the LGPL is applied is otherwise unspecified.
37 */
38
39#include "config.h"
40#include "wine/port.h"
41#include "wined3d_private.h"
42
43WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
44
45/* See also float_16_to_32() in wined3d_private.h */
46static inline unsigned short float_32_to_16(const float *in)
47{
48 int exp = 0;
49 float tmp = fabs(*in);
50 unsigned int mantissa;
51 unsigned short ret;
52
53 /* Deal with special numbers */
54 if (*in == 0.0f) return 0x0000;
55 if(_isnan(*in)) return 0x7C01;
56 if(!_finite(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
57
58 if(tmp < pow(2, 10)) {
59 do
60 {
61 tmp = tmp * 2.0f;
62 exp--;
63 }while(tmp < pow(2, 10));
64 } else if(tmp >= pow(2, 11)) {
65 do
66 {
67 tmp /= 2.0f;
68 exp++;
69 }while(tmp >= pow(2, 11));
70 }
71
72 mantissa = (unsigned int) tmp;
73 if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
74
75 exp += 10; /* Normalize the mantissa */
76 exp += 15; /* Exponent is encoded with excess 15 */
77
78 if(exp > 30) { /* too big */
79 ret = 0x7c00; /* INF */
80 } else if(exp <= 0) {
81 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
82 while(exp <= 0) {
83 mantissa = mantissa >> 1;
84 exp++;
85 }
86 ret = mantissa & 0x3ff;
87 } else {
88 ret = (exp << 10) | (mantissa & 0x3ff);
89 }
90
91 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
92 return ret;
93}
94
95
96/* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
97
98/* *******************************************
99 IWineD3DSurface IUnknown parts follow
100 ******************************************* */
101HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
102{
103 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
104 /* Warn ,but be nice about things */
105 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
106
107 if (IsEqualGUID(riid, &IID_IUnknown)
108 || IsEqualGUID(riid, &IID_IWineD3DBase)
109 || IsEqualGUID(riid, &IID_IWineD3DResource)
110 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
111 IUnknown_AddRef((IUnknown*)iface);
112 *ppobj = This;
113 return S_OK;
114 }
115 *ppobj = NULL;
116 return E_NOINTERFACE;
117}
118
119ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
120 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
121 ULONG ref = InterlockedIncrement(&This->resource.ref);
122 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
123 return ref;
124}
125
126/* ****************************************************
127 IWineD3DSurface IWineD3DResource parts follow
128 **************************************************** */
129HRESULT WINAPI IWineD3DBaseSurfaceImpl_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 VBOXWDDM
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 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1157 slock = dlock;
1158 sEntry = This->resource.format_desc;
1159 dEntry = sEntry;
1160 }
1161 else
1162 {
1163 dEntry = This->resource.format_desc;
1164 if (Src)
1165 {
1166 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1167 {
1168 Src = surface_convert_format(Src, dEntry->format);
1169 if(!Src) {
1170 /* The conv function writes a FIXME */
1171 WARN("Cannot convert source surface format to dest format\n");
1172 goto release;
1173 }
1174 }
1175 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1176 sEntry = Src->resource.format_desc;
1177 }
1178 else
1179 {
1180 sEntry = dEntry;
1181 }
1182 if (DestRect)
1183 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1184 else
1185 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1186 }
1187
1188 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1189
1190 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1191 {
1192 if (!DestRect || Src == This)
1193 {
1194 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1195 goto release;
1196 }
1197 }
1198
1199 bpp = This->resource.format_desc->byte_count;
1200 srcheight = xsrc.bottom - xsrc.top;
1201 srcwidth = xsrc.right - xsrc.left;
1202 dstheight = xdst.bottom - xdst.top;
1203 dstwidth = xdst.right - xdst.left;
1204 width = (xdst.right - xdst.left) * bpp;
1205
1206 if (DestRect && Src != This)
1207 dbuf = dlock.pBits;
1208 else
1209 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1210
1211 if (Flags & WINEDDBLT_WAIT)
1212 {
1213 Flags &= ~WINEDDBLT_WAIT;
1214 }
1215 if (Flags & WINEDDBLT_ASYNC)
1216 {
1217 static BOOL displayed = FALSE;
1218 if (!displayed)
1219 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1220 displayed = TRUE;
1221 Flags &= ~WINEDDBLT_ASYNC;
1222 }
1223 if (Flags & WINEDDBLT_DONOTWAIT)
1224 {
1225 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1226 static BOOL displayed = FALSE;
1227 if (!displayed)
1228 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1229 displayed = TRUE;
1230 Flags &= ~WINEDDBLT_DONOTWAIT;
1231 }
1232
1233 /* First, all the 'source-less' blits */
1234 if (Flags & WINEDDBLT_COLORFILL)
1235 {
1236 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1237 dlock.Pitch, DDBltFx->u5.dwFillColor);
1238 Flags &= ~WINEDDBLT_COLORFILL;
1239 }
1240
1241 if (Flags & WINEDDBLT_DEPTHFILL)
1242 {
1243 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1244 }
1245 if (Flags & WINEDDBLT_ROP)
1246 {
1247 /* Catch some degenerate cases here */
1248 switch(DDBltFx->dwROP)
1249 {
1250 case BLACKNESS:
1251 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1252 break;
1253 case 0xAA0029: /* No-op */
1254 break;
1255 case WHITENESS:
1256 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1257 break;
1258 case SRCCOPY: /* well, we do that below ? */
1259 break;
1260 default:
1261 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1262 goto error;
1263 }
1264 Flags &= ~WINEDDBLT_ROP;
1265 }
1266 if (Flags & WINEDDBLT_DDROPS)
1267 {
1268 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1269 }
1270 /* Now the 'with source' blits */
1271 if (Src)
1272 {
1273 const BYTE *sbase;
1274 int sx, xinc, sy, yinc;
1275
1276 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1277 goto release;
1278 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1279 xinc = (srcwidth << 16) / dstwidth;
1280 yinc = (srcheight << 16) / dstheight;
1281
1282 if (!Flags)
1283 {
1284 /* No effects, we can cheat here */
1285 if (dstwidth == srcwidth)
1286 {
1287 if (dstheight == srcheight)
1288 {
1289 /* No stretching in either direction. This needs to be as
1290 * fast as possible */
1291 sbuf = sbase;
1292
1293 /* check for overlapping surfaces */
1294 if (Src != This || xdst.top < xsrc.top ||
1295 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1296 {
1297 /* no overlap, or dst above src, so copy from top downwards */
1298 for (y = 0; y < dstheight; y++)
1299 {
1300 memcpy(dbuf, sbuf, width);
1301 sbuf += slock.Pitch;
1302 dbuf += dlock.Pitch;
1303 }
1304 }
1305 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1306 {
1307 sbuf += (slock.Pitch*dstheight);
1308 dbuf += (dlock.Pitch*dstheight);
1309 for (y = 0; y < dstheight; y++)
1310 {
1311 sbuf -= slock.Pitch;
1312 dbuf -= dlock.Pitch;
1313 memcpy(dbuf, sbuf, width);
1314 }
1315 }
1316 else /* src and dst overlapping on the same line, use memmove */
1317 {
1318 for (y = 0; y < dstheight; y++)
1319 {
1320 memmove(dbuf, sbuf, width);
1321 sbuf += slock.Pitch;
1322 dbuf += dlock.Pitch;
1323 }
1324 }
1325 } else {
1326 /* Stretching in Y direction only */
1327 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1328 sbuf = sbase + (sy >> 16) * slock.Pitch;
1329 memcpy(dbuf, sbuf, width);
1330 dbuf += dlock.Pitch;
1331 }
1332 }
1333 }
1334 else
1335 {
1336 /* Stretching in X direction */
1337 int last_sy = -1;
1338 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1339 {
1340 sbuf = sbase + (sy >> 16) * slock.Pitch;
1341
1342 if ((sy >> 16) == (last_sy >> 16))
1343 {
1344 /* this sourcerow is the same as last sourcerow -
1345 * copy already stretched row
1346 */
1347 memcpy(dbuf, dbuf - dlock.Pitch, width);
1348 }
1349 else
1350 {
1351#define STRETCH_ROW(type) { \
1352 const type *s = (const type *)sbuf; \
1353 type *d = (type *)dbuf; \
1354 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1355 d[x] = s[sx >> 16]; \
1356 break; }
1357
1358 switch(bpp)
1359 {
1360 case 1: STRETCH_ROW(BYTE)
1361 case 2: STRETCH_ROW(WORD)
1362 case 4: STRETCH_ROW(DWORD)
1363 case 3:
1364 {
1365 const BYTE *s;
1366 BYTE *d = dbuf;
1367 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1368 {
1369 DWORD pixel;
1370
1371 s = sbuf+3*(sx>>16);
1372 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1373 d[0] = (pixel )&0xff;
1374 d[1] = (pixel>> 8)&0xff;
1375 d[2] = (pixel>>16)&0xff;
1376 d+=3;
1377 }
1378 break;
1379 }
1380 default:
1381 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1382 ret = WINED3DERR_NOTAVAILABLE;
1383 goto error;
1384 }
1385#undef STRETCH_ROW
1386 }
1387 dbuf += dlock.Pitch;
1388 last_sy = sy;
1389 }
1390 }
1391 }
1392 else
1393 {
1394 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1395 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1396 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1397 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1398 {
1399 /* The color keying flags are checked for correctness in ddraw */
1400 if (Flags & WINEDDBLT_KEYSRC)
1401 {
1402 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1403 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1404 }
1405 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1406 {
1407 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1408 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1409 }
1410
1411 if (Flags & WINEDDBLT_KEYDEST)
1412 {
1413 /* Destination color keys are taken from the source surface ! */
1414 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1415 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1416 }
1417 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1418 {
1419 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1420 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1421 }
1422
1423 if(bpp == 1)
1424 {
1425 keymask = 0xff;
1426 }
1427 else
1428 {
1429 keymask = sEntry->red_mask
1430 | sEntry->green_mask
1431 | sEntry->blue_mask;
1432 }
1433 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1434 }
1435
1436 if (Flags & WINEDDBLT_DDFX)
1437 {
1438 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1439 LONG tmpxy;
1440 dTopLeft = dbuf;
1441 dTopRight = dbuf+((dstwidth-1)*bpp);
1442 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1443 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1444
1445 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1446 {
1447 /* I don't think we need to do anything about this flag */
1448 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1449 }
1450 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1451 {
1452 tmp = dTopRight;
1453 dTopRight = dTopLeft;
1454 dTopLeft = tmp;
1455 tmp = dBottomRight;
1456 dBottomRight = dBottomLeft;
1457 dBottomLeft = tmp;
1458 dstxinc = dstxinc *-1;
1459 }
1460 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1461 {
1462 tmp = dTopLeft;
1463 dTopLeft = dBottomLeft;
1464 dBottomLeft = tmp;
1465 tmp = dTopRight;
1466 dTopRight = dBottomRight;
1467 dBottomRight = tmp;
1468 dstyinc = dstyinc *-1;
1469 }
1470 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1471 {
1472 /* I don't think we need to do anything about this flag */
1473 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1474 }
1475 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1476 {
1477 tmp = dBottomRight;
1478 dBottomRight = dTopLeft;
1479 dTopLeft = tmp;
1480 tmp = dBottomLeft;
1481 dBottomLeft = dTopRight;
1482 dTopRight = tmp;
1483 dstxinc = dstxinc * -1;
1484 dstyinc = dstyinc * -1;
1485 }
1486 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1487 {
1488 tmp = dTopLeft;
1489 dTopLeft = dBottomLeft;
1490 dBottomLeft = dBottomRight;
1491 dBottomRight = dTopRight;
1492 dTopRight = tmp;
1493 tmpxy = dstxinc;
1494 dstxinc = dstyinc;
1495 dstyinc = tmpxy;
1496 dstxinc = dstxinc * -1;
1497 }
1498 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1499 {
1500 tmp = dTopLeft;
1501 dTopLeft = dTopRight;
1502 dTopRight = dBottomRight;
1503 dBottomRight = dBottomLeft;
1504 dBottomLeft = tmp;
1505 tmpxy = dstxinc;
1506 dstxinc = dstyinc;
1507 dstyinc = tmpxy;
1508 dstyinc = dstyinc * -1;
1509 }
1510 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1511 {
1512 /* I don't think we need to do anything about this flag */
1513 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1514 }
1515 dbuf = dTopLeft;
1516 Flags &= ~(WINEDDBLT_DDFX);
1517 }
1518
1519#define COPY_COLORKEY_FX(type) { \
1520 const type *s; \
1521 type *d = (type *)dbuf, *dx, tmp; \
1522 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1523 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1524 dx = d; \
1525 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1526 tmp = s[sx >> 16]; \
1527 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1528 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1529 dx[0] = tmp; \
1530 } \
1531 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1532 } \
1533 d = (type*)(((LPBYTE)d)+dstyinc); \
1534 } \
1535 break; }
1536
1537 switch (bpp) {
1538 case 1: COPY_COLORKEY_FX(BYTE)
1539 case 2: COPY_COLORKEY_FX(WORD)
1540 case 4: COPY_COLORKEY_FX(DWORD)
1541 case 3:
1542 {
1543 const BYTE *s;
1544 BYTE *d = dbuf, *dx;
1545 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1546 {
1547 sbuf = sbase + (sy >> 16) * slock.Pitch;
1548 dx = d;
1549 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1550 {
1551 DWORD pixel, dpixel = 0;
1552 s = sbuf+3*(sx>>16);
1553 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1554 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1555 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1556 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1557 {
1558 dx[0] = (pixel )&0xff;
1559 dx[1] = (pixel>> 8)&0xff;
1560 dx[2] = (pixel>>16)&0xff;
1561 }
1562 dx+= dstxinc;
1563 }
1564 d += dstyinc;
1565 }
1566 break;
1567 }
1568 default:
1569 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1570 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1571 ret = WINED3DERR_NOTAVAILABLE;
1572 goto error;
1573#undef COPY_COLORKEY_FX
1574 }
1575 }
1576 }
1577
1578error:
1579 if (Flags && FIXME_ON(d3d_surface))
1580 {
1581 FIXME("\tUnsupported flags: %08x\n", Flags);
1582 }
1583
1584release:
1585 IWineD3DSurface_UnlockRect(iface);
1586 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1587 /* Release the converted surface if any */
1588 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1589 return ret;
1590}
1591
1592/*****************************************************************************
1593 * IWineD3DSurface::BltFast, SW emulation version
1594 *
1595 * This is the software implementation of BltFast, as used by GDI surfaces
1596 * and as a fallback for OpenGL surfaces. This code is taken from the old
1597 * DirectDraw code, and was originally written by TransGaming.
1598 *
1599 * Params:
1600 * dstx:
1601 * dsty:
1602 * Source: Source surface to copy from
1603 * rsrc: Source rectangle
1604 * trans: Some Flags
1605 *
1606 * Returns:
1607 * WINED3D_OK on success
1608 *
1609 *****************************************************************************/
1610HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1611 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1612{
1613 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1614 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1615
1616 int bpp, w, h, x, y;
1617 WINED3DLOCKED_RECT dlock,slock;
1618 HRESULT ret = WINED3D_OK;
1619 RECT rsrc2;
1620 RECT lock_src, lock_dst, lock_union;
1621 const BYTE *sbuf;
1622 BYTE *dbuf;
1623 const struct wined3d_format_desc *sEntry, *dEntry;
1624
1625 if (TRACE_ON(d3d_surface))
1626 {
1627 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1628
1629 if (rsrc)
1630 {
1631 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1632 rsrc->right,rsrc->bottom);
1633 }
1634 else
1635 {
1636 TRACE(" srcrect: NULL\n");
1637 }
1638 }
1639
1640 if ((This->Flags & SFLAG_LOCKED) ||
1641 (Src->Flags & SFLAG_LOCKED))
1642 {
1643 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1644 return WINEDDERR_SURFACEBUSY;
1645 }
1646
1647 if (!rsrc)
1648 {
1649 WARN("rsrc is NULL!\n");
1650 rsrc2.left = 0;
1651 rsrc2.top = 0;
1652 rsrc2.right = Src->currentDesc.Width;
1653 rsrc2.bottom = Src->currentDesc.Height;
1654 rsrc = &rsrc2;
1655 }
1656
1657 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1658 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1659 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1660 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1661 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1662 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1663 {
1664 WARN("Application gave us bad source rectangle for BltFast.\n");
1665 return WINEDDERR_INVALIDRECT;
1666 }
1667
1668 h = rsrc->bottom - rsrc->top;
1669 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1670 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1671 if (h <= 0) return WINEDDERR_INVALIDRECT;
1672
1673 w = rsrc->right - rsrc->left;
1674 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1675 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1676 if (w <= 0) return WINEDDERR_INVALIDRECT;
1677
1678 /* Now compute the locking rectangle... */
1679 lock_src.left = rsrc->left;
1680 lock_src.top = rsrc->top;
1681 lock_src.right = lock_src.left + w;
1682 lock_src.bottom = lock_src.top + h;
1683
1684 lock_dst.left = dstx;
1685 lock_dst.top = dsty;
1686 lock_dst.right = dstx + w;
1687 lock_dst.bottom = dsty + h;
1688
1689 bpp = This->resource.format_desc->byte_count;
1690
1691 /* We need to lock the surfaces, or we won't get refreshes when done. */
1692 if (Src == This)
1693 {
1694 int pitch;
1695
1696 UnionRect(&lock_union, &lock_src, &lock_dst);
1697
1698 /* Lock the union of the two rectangles */
1699 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1700 if(ret != WINED3D_OK) goto error;
1701
1702 pitch = dlock.Pitch;
1703 slock.Pitch = dlock.Pitch;
1704
1705 /* Since slock was originally copied from this surface's description, we can just reuse it */
1706 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1707 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1708 sEntry = Src->resource.format_desc;
1709 dEntry = sEntry;
1710 }
1711 else
1712 {
1713 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1714 if(ret != WINED3D_OK) goto error;
1715 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1716 if(ret != WINED3D_OK) goto error;
1717
1718 sbuf = slock.pBits;
1719 dbuf = dlock.pBits;
1720 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1721
1722 sEntry = Src->resource.format_desc;
1723 dEntry = This->resource.format_desc;
1724 }
1725
1726 /* Handle compressed surfaces first... */
1727 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1728 {
1729 UINT row_block_count;
1730
1731 TRACE("compressed -> compressed copy\n");
1732 if (trans)
1733 FIXME("trans arg not supported when a compressed surface is involved\n");
1734 if (dstx || dsty)
1735 FIXME("offset for destination surface is not supported\n");
1736 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1737 {
1738 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1739 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1740 goto error;
1741 }
1742
1743 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1744 for (y = 0; y < h; y += dEntry->block_height)
1745 {
1746 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1747 dbuf += dlock.Pitch;
1748 sbuf += slock.Pitch;
1749 }
1750
1751 goto error;
1752 }
1753 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1754 {
1755 /* TODO: Use the libtxc_dxtn.so shared library to do
1756 * software decompression
1757 */
1758 ERR("Software decompression not supported.\n");
1759 goto error;
1760 }
1761
1762 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1763 {
1764 DWORD keylow, keyhigh;
1765 DWORD mask = Src->resource.format_desc->red_mask |
1766 Src->resource.format_desc->green_mask |
1767 Src->resource.format_desc->blue_mask;
1768
1769 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1770 if(!mask && bpp==1)
1771 mask = 0xff;
1772
1773 TRACE("Color keyed copy\n");
1774 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1775 {
1776 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1777 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1778 }
1779 else
1780 {
1781 /* I'm not sure if this is correct */
1782 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1783 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1784 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1785 }
1786
1787#define COPYBOX_COLORKEY(type) { \
1788 const type *s = (const type *)sbuf; \
1789 type *d = (type *)dbuf; \
1790 type tmp; \
1791 for (y = 0; y < h; y++) { \
1792 for (x = 0; x < w; x++) { \
1793 tmp = s[x]; \
1794 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1795 } \
1796 s = (const type *)((const BYTE *)s + slock.Pitch); \
1797 d = (type *)((BYTE *)d + dlock.Pitch); \
1798 } \
1799 break; \
1800 }
1801
1802 switch (bpp) {
1803 case 1: COPYBOX_COLORKEY(BYTE)
1804 case 2: COPYBOX_COLORKEY(WORD)
1805 case 4: COPYBOX_COLORKEY(DWORD)
1806 case 3:
1807 {
1808 const BYTE *s;
1809 BYTE *d;
1810 DWORD tmp;
1811 s = sbuf;
1812 d = dbuf;
1813 for (y = 0; y < h; y++)
1814 {
1815 for (x = 0; x < w * 3; x += 3)
1816 {
1817 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1818 if (tmp < keylow || tmp > keyhigh)
1819 {
1820 d[x + 0] = s[x + 0];
1821 d[x + 1] = s[x + 1];
1822 d[x + 2] = s[x + 2];
1823 }
1824 }
1825 s += slock.Pitch;
1826 d += dlock.Pitch;
1827 }
1828 break;
1829 }
1830 default:
1831 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1832 ret = WINED3DERR_NOTAVAILABLE;
1833 goto error;
1834 }
1835#undef COPYBOX_COLORKEY
1836 TRACE("Copy Done\n");
1837 }
1838 else
1839 {
1840 int width = w * bpp;
1841 INT sbufpitch, dbufpitch;
1842
1843 TRACE("NO color key copy\n");
1844 /* Handle overlapping surfaces */
1845 if (sbuf < dbuf)
1846 {
1847 sbuf += (h - 1) * slock.Pitch;
1848 dbuf += (h - 1) * dlock.Pitch;
1849 sbufpitch = -slock.Pitch;
1850 dbufpitch = -dlock.Pitch;
1851 }
1852 else
1853 {
1854 sbufpitch = slock.Pitch;
1855 dbufpitch = dlock.Pitch;
1856 }
1857 for (y = 0; y < h; y++)
1858 {
1859 /* This is pretty easy, a line for line memcpy */
1860 memmove(dbuf, sbuf, width);
1861 sbuf += sbufpitch;
1862 dbuf += dbufpitch;
1863 }
1864 TRACE("Copy done\n");
1865 }
1866
1867error:
1868 if (Src == This)
1869 {
1870 IWineD3DSurface_UnlockRect(iface);
1871 }
1872 else
1873 {
1874 IWineD3DSurface_UnlockRect(iface);
1875 IWineD3DSurface_UnlockRect(Source);
1876 }
1877
1878 return ret;
1879}
1880
1881HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1882{
1883 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1884
1885 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1886 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1887
1888 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1889
1890 if (NULL == pRect)
1891 {
1892 pLockedRect->pBits = This->resource.allocatedMemory;
1893 This->lockedRect.left = 0;
1894 This->lockedRect.top = 0;
1895 This->lockedRect.right = This->currentDesc.Width;
1896 This->lockedRect.bottom = This->currentDesc.Height;
1897
1898 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1899 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1900 This->lockedRect.right, This->lockedRect.bottom);
1901 }
1902 else
1903 {
1904 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
1905
1906 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1907 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1908
1909 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1910 {
1911 /* Compressed textures are block based, so calculate the offset of
1912 * the block that contains the top-left pixel of the locked rectangle. */
1913 pLockedRect->pBits = This->resource.allocatedMemory
1914 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1915 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1916 }
1917 else
1918 {
1919 pLockedRect->pBits = This->resource.allocatedMemory +
1920 (pLockedRect->Pitch * pRect->top) +
1921 (pRect->left * format_desc->byte_count);
1922 }
1923 This->lockedRect.left = pRect->left;
1924 This->lockedRect.top = pRect->top;
1925 This->lockedRect.right = pRect->right;
1926 This->lockedRect.bottom = pRect->bottom;
1927 }
1928
1929 /* No dirtifying is needed for this surface implementation */
1930 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1931
1932 return WINED3D_OK;
1933}
1934
1935void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1936 ERR("Should not be called on base texture\n");
1937}
1938
1939/* TODO: think about moving this down to resource? */
1940const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1941{
1942 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1943
1944 /* This should only be called for sysmem textures, it may be a good idea
1945 * to extend this to all pools at some point in the future */
1946 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1947 {
1948 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1949 }
1950 return This->resource.allocatedMemory;
1951}
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