VirtualBox

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

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

crOpenGL: update to wine 1.1.36 and disable unnecessary fbo state poll

  • Property svn:eol-style set to native
File size: 66.9 KB
Line 
1/*
2 * IWineD3DSurface Implementation of management(non-rendering) functions
3 *
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11 * Copyright 2007 Henri Verbeet
12 * Copyright 2006-2007 Roderick Colenbrander
13 * Copyright 2009 Henri Verbeet for CodeWeavers
14 *
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 */
29
30/*
31 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
32 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
33 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
34 * a choice of LGPL license versions is made available with the language indicating
35 * that LGPLv2 or any later version may be used, or where a choice of which version
36 * of the LGPL is applied is otherwise unspecified.
37 */
38
39#include "config.h"
40#include "wine/port.h"
41#include "wined3d_private.h"
42
43WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
44
45/* See also float_16_to_32() in wined3d_private.h */
46static inline unsigned short float_32_to_16(const float *in)
47{
48 int exp = 0;
49 float tmp = fabs(*in);
50 unsigned int mantissa;
51 unsigned short ret;
52
53 /* Deal with special numbers */
54 if (*in == 0.0f) return 0x0000;
55 if(_isnan(*in)) return 0x7C01;
56 if(!_finite(*in)) return (*in < 0.0f ? 0xFC00 : 0x7c00);
57
58 if(tmp < pow(2, 10)) {
59 do
60 {
61 tmp = tmp * 2.0f;
62 exp--;
63 }while(tmp < pow(2, 10));
64 } else if(tmp >= pow(2, 11)) {
65 do
66 {
67 tmp /= 2.0f;
68 exp++;
69 }while(tmp >= pow(2, 11));
70 }
71
72 mantissa = (unsigned int) tmp;
73 if(tmp - mantissa >= 0.5f) mantissa++; /* round to nearest, away from zero */
74
75 exp += 10; /* Normalize the mantissa */
76 exp += 15; /* Exponent is encoded with excess 15 */
77
78 if(exp > 30) { /* too big */
79 ret = 0x7c00; /* INF */
80 } else if(exp <= 0) {
81 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers */
82 while(exp <= 0) {
83 mantissa = mantissa >> 1;
84 exp++;
85 }
86 ret = mantissa & 0x3ff;
87 } else {
88 ret = (exp << 10) | (mantissa & 0x3ff);
89 }
90
91 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
92 return ret;
93}
94
95
96/* Do NOT define GLINFO_LOCATION in this file. THIS CODE MUST NOT USE IT */
97
98/* *******************************************
99 IWineD3DSurface IUnknown parts follow
100 ******************************************* */
101HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
102{
103 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
104 /* Warn ,but be nice about things */
105 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
106
107 if (IsEqualGUID(riid, &IID_IUnknown)
108 || IsEqualGUID(riid, &IID_IWineD3DBase)
109 || IsEqualGUID(riid, &IID_IWineD3DResource)
110 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
111 IUnknown_AddRef((IUnknown*)iface);
112 *ppobj = This;
113 return S_OK;
114 }
115 *ppobj = NULL;
116 return E_NOINTERFACE;
117}
118
119ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface) {
120 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
121 ULONG ref = InterlockedIncrement(&This->resource.ref);
122 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
123 return ref;
124}
125
126/* ****************************************************
127 IWineD3DSurface IWineD3DResource parts follow
128 **************************************************** */
129HRESULT WINAPI IWineD3DBaseSurfaceImpl_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 GlPixelFormatDesc *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 GlPixelFormatDesc *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 GlPixelFormatDesc *format_desc = This->resource.format_desc;
540 int extraline = 0;
541 SYSTEM_INFO sysInfo;
542 BITMAPINFO* b_info;
543 HDC ddc;
544 DWORD *masks;
545 UINT usage;
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
754struct d3dfmt_convertor_desc {
755 WINED3DFORMAT from, to;
756 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
757};
758
759static const struct d3dfmt_convertor_desc convertors[] =
760{
761 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
762 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
763 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
764};
765
766static inline const struct d3dfmt_convertor_desc *find_convertor(WINED3DFORMAT from, WINED3DFORMAT to)
767{
768 unsigned int i;
769 for(i = 0; i < (sizeof(convertors) / sizeof(convertors[0])); i++) {
770 if(convertors[i].from == from && convertors[i].to == to) {
771 return &convertors[i];
772 }
773 }
774 return NULL;
775}
776
777/*****************************************************************************
778 * surface_convert_format
779 *
780 * Creates a duplicate of a surface in a different format. Is used by Blt to
781 * blit between surfaces with different formats
782 *
783 * Parameters
784 * source: Source surface
785 * fmt: Requested destination format
786 *
787 *****************************************************************************/
788static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, WINED3DFORMAT to_fmt) {
789 IWineD3DSurface *ret = NULL;
790 const struct d3dfmt_convertor_desc *conv;
791 WINED3DLOCKED_RECT lock_src, lock_dst;
792 HRESULT hr;
793
794 conv = find_convertor(source->resource.format_desc->format, to_fmt);
795 if(!conv) {
796 FIXME("Cannot find a conversion function from format %s to %s\n",
797 debug_d3dformat(source->resource.format_desc->format), debug_d3dformat(to_fmt));
798 return NULL;
799 }
800
801 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->currentDesc.Width,
802 source->currentDesc.Height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */, &ret,
803 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
804 0 /* MultiSampleQuality */, IWineD3DSurface_GetImplType((IWineD3DSurface *) source),
805 NULL /* parent */, &wined3d_null_parent_ops);
806 if(!ret) {
807 ERR("Failed to create a destination surface for conversion\n");
808 return NULL;
809 }
810
811 memset(&lock_src, 0, sizeof(lock_src));
812 memset(&lock_dst, 0, sizeof(lock_dst));
813
814 hr = IWineD3DSurface_LockRect((IWineD3DSurface *) source, &lock_src, NULL, WINED3DLOCK_READONLY);
815 if(FAILED(hr)) {
816 ERR("Failed to lock the source surface\n");
817 IWineD3DSurface_Release(ret);
818 return NULL;
819 }
820 hr = IWineD3DSurface_LockRect(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
821 if(FAILED(hr)) {
822 ERR("Failed to lock the dest surface\n");
823 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
824 IWineD3DSurface_Release(ret);
825 return NULL;
826 }
827
828 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
829 source->currentDesc.Width, source->currentDesc.Height);
830
831 IWineD3DSurface_UnlockRect(ret);
832 IWineD3DSurface_UnlockRect((IWineD3DSurface *) source);
833
834 return (IWineD3DSurfaceImpl *) ret;
835}
836
837/*****************************************************************************
838 * _Blt_ColorFill
839 *
840 * Helper function that fills a memory area with a specific color
841 *
842 * Params:
843 * buf: memory address to start filling at
844 * width, height: Dimensions of the area to fill
845 * bpp: Bit depth of the surface
846 * lPitch: pitch of the surface
847 * color: Color to fill with
848 *
849 *****************************************************************************/
850static HRESULT
851 _Blt_ColorFill(BYTE *buf,
852 int width, int height,
853 int bpp, LONG lPitch,
854 DWORD color)
855{
856 int x, y;
857 LPBYTE first;
858
859 /* Do first row */
860
861#define COLORFILL_ROW(type) \
862 { \
863 type *d = (type *) buf; \
864 for (x = 0; x < width; x++) \
865 d[x] = (type) color; \
866 break; \
867}
868 switch(bpp)
869 {
870 case 1: COLORFILL_ROW(BYTE)
871 case 2: COLORFILL_ROW(WORD)
872 case 3:
873 {
874 BYTE *d = buf;
875 for (x = 0; x < width; x++,d+=3)
876 {
877 d[0] = (color ) & 0xFF;
878 d[1] = (color>> 8) & 0xFF;
879 d[2] = (color>>16) & 0xFF;
880 }
881 break;
882 }
883 case 4: COLORFILL_ROW(DWORD)
884 default:
885 FIXME("Color fill not implemented for bpp %d!\n", bpp*8);
886 return WINED3DERR_NOTAVAILABLE;
887 }
888
889#undef COLORFILL_ROW
890
891 /* Now copy first row */
892 first = buf;
893 for (y = 1; y < height; y++)
894 {
895 buf += lPitch;
896 memcpy(buf, first, width * bpp);
897 }
898 return WINED3D_OK;
899}
900
901/*****************************************************************************
902 * IWineD3DSurface::Blt, SW emulation version
903 *
904 * Performs blits to a surface, eigher from a source of source-less blts
905 * This is the main functionality of DirectDraw
906 *
907 * Params:
908 * DestRect: Destination rectangle to write to
909 * SrcSurface: Source surface, can be NULL
910 * SrcRect: Source rectangle
911 *****************************************************************************/
912HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
913 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
914{
915 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
916 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
917 RECT xdst,xsrc;
918 HRESULT ret = WINED3D_OK;
919 WINED3DLOCKED_RECT dlock, slock;
920 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
921 const struct GlPixelFormatDesc *sEntry, *dEntry;
922 int x, y;
923 const BYTE *sbuf;
924 BYTE *dbuf;
925 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
926
927 if (TRACE_ON(d3d_surface))
928 {
929 if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n",
930 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
931 if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n",
932 SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom);
933#if 0
934 TRACE("\tflags: ");
935 DDRAW_dump_DDBLT(Flags);
936 if (Flags & WINEDDBLT_DDFX)
937 {
938 TRACE("\tblitfx: ");
939 DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX);
940 }
941#endif
942 }
943
944 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
945 {
946 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
947 return WINEDDERR_SURFACEBUSY;
948 }
949
950 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
951 /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */
952 FIXME("Filters not supported in software blit\n");
953 }
954
955 /* First check for the validity of source / destination rectangles. This was
956 * verified using a test application + by MSDN.
957 */
958 if ((Src != NULL) && (SrcRect != NULL) &&
959 ((SrcRect->bottom > Src->currentDesc.Height)||(SrcRect->bottom < 0) ||
960 (SrcRect->top > Src->currentDesc.Height)||(SrcRect->top < 0) ||
961 (SrcRect->left > Src->currentDesc.Width) ||(SrcRect->left < 0) ||
962 (SrcRect->right > Src->currentDesc.Width) ||(SrcRect->right < 0) ||
963 (SrcRect->right < SrcRect->left) ||(SrcRect->bottom < SrcRect->top)))
964 {
965 WARN("Application gave us bad source rectangle for Blt.\n");
966 return WINEDDERR_INVALIDRECT;
967 }
968 /* For the Destination rect, it can be out of bounds on the condition that a clipper
969 * is set for the given surface.
970 */
971 if ((/*This->clipper == NULL*/ TRUE) && (DestRect) &&
972 ((DestRect->bottom > This->currentDesc.Height)||(DestRect->bottom < 0) ||
973 (DestRect->top > This->currentDesc.Height)||(DestRect->top < 0) ||
974 (DestRect->left > This->currentDesc.Width) ||(DestRect->left < 0) ||
975 (DestRect->right > This->currentDesc.Width) ||(DestRect->right < 0) ||
976 (DestRect->right < DestRect->left) ||(DestRect->bottom < DestRect->top)))
977 {
978 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
979 return WINEDDERR_INVALIDRECT;
980 }
981
982 /* Now handle negative values in the rectangles. Warning: only supported for now
983 in the 'simple' cases (ie not in any stretching / rotation cases).
984
985 First, the case where nothing is to be done.
986 */
987 if ((DestRect && ((DestRect->bottom <= 0) || (DestRect->right <= 0) ||
988 (DestRect->top >= (int) This->currentDesc.Height) ||
989 (DestRect->left >= (int) This->currentDesc.Width))) ||
990 ((Src != NULL) && (SrcRect != NULL) &&
991 ((SrcRect->bottom <= 0) || (SrcRect->right <= 0) ||
992 (SrcRect->top >= (int) Src->currentDesc.Height) ||
993 (SrcRect->left >= (int) Src->currentDesc.Width)) ))
994 {
995 TRACE("Nothing to be done !\n");
996 return WINED3D_OK;
997 }
998
999 if (DestRect)
1000 {
1001 xdst = *DestRect;
1002 }
1003 else
1004 {
1005 xdst.top = 0;
1006 xdst.bottom = This->currentDesc.Height;
1007 xdst.left = 0;
1008 xdst.right = This->currentDesc.Width;
1009 }
1010
1011 if (SrcRect)
1012 {
1013 xsrc = *SrcRect;
1014 }
1015 else
1016 {
1017 if (Src)
1018 {
1019 xsrc.top = 0;
1020 xsrc.bottom = Src->currentDesc.Height;
1021 xsrc.left = 0;
1022 xsrc.right = Src->currentDesc.Width;
1023 }
1024 else
1025 {
1026 memset(&xsrc,0,sizeof(xsrc));
1027 }
1028 }
1029
1030 /* The easy case : the source-less blits.... */
1031 if (Src == NULL && DestRect)
1032 {
1033 RECT full_rect;
1034 RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
1035
1036 full_rect.left = 0;
1037 full_rect.top = 0;
1038 full_rect.right = This->currentDesc.Width;
1039 full_rect.bottom = This->currentDesc.Height;
1040 IntersectRect(&temp_rect, &full_rect, DestRect);
1041 xdst = temp_rect;
1042 }
1043 else if (DestRect)
1044 {
1045 /* Only handle clipping on the destination rectangle */
1046 int clip_horiz = (DestRect->left < 0) || (DestRect->right > (int) This->currentDesc.Width );
1047 int clip_vert = (DestRect->top < 0) || (DestRect->bottom > (int) This->currentDesc.Height);
1048 if (clip_vert || clip_horiz)
1049 {
1050 /* Now check if this is a special case or not... */
1051 if ((((DestRect->bottom - DestRect->top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
1052 (((DestRect->right - DestRect->left) != (xsrc.right - xsrc.left)) && clip_horiz) ||
1053 (Flags & WINEDDBLT_DDFX))
1054 {
1055 WARN("Out of screen rectangle in special case. Not handled right now.\n");
1056 return WINED3D_OK;
1057 }
1058
1059 if (clip_horiz)
1060 {
1061 if (DestRect->left < 0) { xsrc.left -= DestRect->left; xdst.left = 0; }
1062 if (DestRect->right > This->currentDesc.Width)
1063 {
1064 xsrc.right -= (DestRect->right - (int) This->currentDesc.Width);
1065 xdst.right = (int) This->currentDesc.Width;
1066 }
1067 }
1068 if (clip_vert)
1069 {
1070 if (DestRect->top < 0)
1071 {
1072 xsrc.top -= DestRect->top;
1073 xdst.top = 0;
1074 }
1075 if (DestRect->bottom > This->currentDesc.Height)
1076 {
1077 xsrc.bottom -= (DestRect->bottom - (int) This->currentDesc.Height);
1078 xdst.bottom = (int) This->currentDesc.Height;
1079 }
1080 }
1081 /* And check if after clipping something is still to be done... */
1082 if ((xdst.bottom <= 0) || (xdst.right <= 0) ||
1083 (xdst.top >= (int) This->currentDesc.Height) ||
1084 (xdst.left >= (int) This->currentDesc.Width) ||
1085 (xsrc.bottom <= 0) || (xsrc.right <= 0) ||
1086 (xsrc.top >= (int) Src->currentDesc.Height) ||
1087 (xsrc.left >= (int) Src->currentDesc.Width))
1088 {
1089 TRACE("Nothing to be done after clipping !\n");
1090 return WINED3D_OK;
1091 }
1092 }
1093 }
1094
1095 if (Src == This)
1096 {
1097 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1098 slock = dlock;
1099 sEntry = This->resource.format_desc;
1100 dEntry = sEntry;
1101 }
1102 else
1103 {
1104 dEntry = This->resource.format_desc;
1105 if (Src)
1106 {
1107 if (This->resource.format_desc->format != Src->resource.format_desc->format)
1108 {
1109 Src = surface_convert_format(Src, dEntry->format);
1110 if(!Src) {
1111 /* The conv function writes a FIXME */
1112 WARN("Cannot convert source surface format to dest format\n");
1113 goto release;
1114 }
1115 }
1116 IWineD3DSurface_LockRect((IWineD3DSurface *) Src, &slock, NULL, WINED3DLOCK_READONLY);
1117 sEntry = Src->resource.format_desc;
1118 }
1119 else
1120 {
1121 sEntry = dEntry;
1122 }
1123 if (DestRect)
1124 IWineD3DSurface_LockRect(iface, &dlock, &xdst, 0);
1125 else
1126 IWineD3DSurface_LockRect(iface, &dlock, NULL, 0);
1127 }
1128
1129 if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX;
1130
1131 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_FOURCC)
1132 {
1133 if (!DestRect || Src == This)
1134 {
1135 memcpy(dlock.pBits, slock.pBits, This->resource.size);
1136 goto release;
1137 }
1138 }
1139
1140 bpp = This->resource.format_desc->byte_count;
1141 srcheight = xsrc.bottom - xsrc.top;
1142 srcwidth = xsrc.right - xsrc.left;
1143 dstheight = xdst.bottom - xdst.top;
1144 dstwidth = xdst.right - xdst.left;
1145 width = (xdst.right - xdst.left) * bpp;
1146
1147 if (DestRect && Src != This)
1148 dbuf = dlock.pBits;
1149 else
1150 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
1151
1152 if (Flags & WINEDDBLT_WAIT)
1153 {
1154 Flags &= ~WINEDDBLT_WAIT;
1155 }
1156 if (Flags & WINEDDBLT_ASYNC)
1157 {
1158 static BOOL displayed = FALSE;
1159 if (!displayed)
1160 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
1161 displayed = TRUE;
1162 Flags &= ~WINEDDBLT_ASYNC;
1163 }
1164 if (Flags & WINEDDBLT_DONOTWAIT)
1165 {
1166 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
1167 static BOOL displayed = FALSE;
1168 if (!displayed)
1169 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
1170 displayed = TRUE;
1171 Flags &= ~WINEDDBLT_DONOTWAIT;
1172 }
1173
1174 /* First, all the 'source-less' blits */
1175 if (Flags & WINEDDBLT_COLORFILL)
1176 {
1177 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
1178 dlock.Pitch, DDBltFx->u5.dwFillColor);
1179 Flags &= ~WINEDDBLT_COLORFILL;
1180 }
1181
1182 if (Flags & WINEDDBLT_DEPTHFILL)
1183 {
1184 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
1185 }
1186 if (Flags & WINEDDBLT_ROP)
1187 {
1188 /* Catch some degenerate cases here */
1189 switch(DDBltFx->dwROP)
1190 {
1191 case BLACKNESS:
1192 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
1193 break;
1194 case 0xAA0029: /* No-op */
1195 break;
1196 case WHITENESS:
1197 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
1198 break;
1199 case SRCCOPY: /* well, we do that below ? */
1200 break;
1201 default:
1202 FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern);
1203 goto error;
1204 }
1205 Flags &= ~WINEDDBLT_ROP;
1206 }
1207 if (Flags & WINEDDBLT_DDROPS)
1208 {
1209 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern);
1210 }
1211 /* Now the 'with source' blits */
1212 if (Src)
1213 {
1214 const BYTE *sbase;
1215 int sx, xinc, sy, yinc;
1216
1217 if (!dstwidth || !dstheight) /* hmm... stupid program ? */
1218 goto release;
1219 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
1220 xinc = (srcwidth << 16) / dstwidth;
1221 yinc = (srcheight << 16) / dstheight;
1222
1223 if (!Flags)
1224 {
1225 /* No effects, we can cheat here */
1226 if (dstwidth == srcwidth)
1227 {
1228 if (dstheight == srcheight)
1229 {
1230 /* No stretching in either direction. This needs to be as
1231 * fast as possible */
1232 sbuf = sbase;
1233
1234 /* check for overlapping surfaces */
1235 if (Src != This || xdst.top < xsrc.top ||
1236 xdst.right <= xsrc.left || xsrc.right <= xdst.left)
1237 {
1238 /* no overlap, or dst above src, so copy from top downwards */
1239 for (y = 0; y < dstheight; y++)
1240 {
1241 memcpy(dbuf, sbuf, width);
1242 sbuf += slock.Pitch;
1243 dbuf += dlock.Pitch;
1244 }
1245 }
1246 else if (xdst.top > xsrc.top) /* copy from bottom upwards */
1247 {
1248 sbuf += (slock.Pitch*dstheight);
1249 dbuf += (dlock.Pitch*dstheight);
1250 for (y = 0; y < dstheight; y++)
1251 {
1252 sbuf -= slock.Pitch;
1253 dbuf -= dlock.Pitch;
1254 memcpy(dbuf, sbuf, width);
1255 }
1256 }
1257 else /* src and dst overlapping on the same line, use memmove */
1258 {
1259 for (y = 0; y < dstheight; y++)
1260 {
1261 memmove(dbuf, sbuf, width);
1262 sbuf += slock.Pitch;
1263 dbuf += dlock.Pitch;
1264 }
1265 }
1266 } else {
1267 /* Stretching in Y direction only */
1268 for (y = sy = 0; y < dstheight; y++, sy += yinc) {
1269 sbuf = sbase + (sy >> 16) * slock.Pitch;
1270 memcpy(dbuf, sbuf, width);
1271 dbuf += dlock.Pitch;
1272 }
1273 }
1274 }
1275 else
1276 {
1277 /* Stretching in X direction */
1278 int last_sy = -1;
1279 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1280 {
1281 sbuf = sbase + (sy >> 16) * slock.Pitch;
1282
1283 if ((sy >> 16) == (last_sy >> 16))
1284 {
1285 /* this sourcerow is the same as last sourcerow -
1286 * copy already stretched row
1287 */
1288 memcpy(dbuf, dbuf - dlock.Pitch, width);
1289 }
1290 else
1291 {
1292#define STRETCH_ROW(type) { \
1293 const type *s = (const type *)sbuf; \
1294 type *d = (type *)dbuf; \
1295 for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
1296 d[x] = s[sx >> 16]; \
1297 break; }
1298
1299 switch(bpp)
1300 {
1301 case 1: STRETCH_ROW(BYTE)
1302 case 2: STRETCH_ROW(WORD)
1303 case 4: STRETCH_ROW(DWORD)
1304 case 3:
1305 {
1306 const BYTE *s;
1307 BYTE *d = dbuf;
1308 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1309 {
1310 DWORD pixel;
1311
1312 s = sbuf+3*(sx>>16);
1313 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1314 d[0] = (pixel )&0xff;
1315 d[1] = (pixel>> 8)&0xff;
1316 d[2] = (pixel>>16)&0xff;
1317 d+=3;
1318 }
1319 break;
1320 }
1321 default:
1322 FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
1323 ret = WINED3DERR_NOTAVAILABLE;
1324 goto error;
1325 }
1326#undef STRETCH_ROW
1327 }
1328 dbuf += dlock.Pitch;
1329 last_sy = sy;
1330 }
1331 }
1332 }
1333 else
1334 {
1335 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
1336 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
1337 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
1338 if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
1339 {
1340 /* The color keying flags are checked for correctness in ddraw */
1341 if (Flags & WINEDDBLT_KEYSRC)
1342 {
1343 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1344 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1345 }
1346 else if (Flags & WINEDDBLT_KEYSRCOVERRIDE)
1347 {
1348 keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue;
1349 keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue;
1350 }
1351
1352 if (Flags & WINEDDBLT_KEYDEST)
1353 {
1354 /* Destination color keys are taken from the source surface ! */
1355 destkeylow = Src->DestBltCKey.dwColorSpaceLowValue;
1356 destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue;
1357 }
1358 else if (Flags & WINEDDBLT_KEYDESTOVERRIDE)
1359 {
1360 destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue;
1361 destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue;
1362 }
1363
1364 if(bpp == 1)
1365 {
1366 keymask = 0xff;
1367 }
1368 else
1369 {
1370 keymask = sEntry->red_mask
1371 | sEntry->green_mask
1372 | sEntry->blue_mask;
1373 }
1374 Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
1375 }
1376
1377 if (Flags & WINEDDBLT_DDFX)
1378 {
1379 LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
1380 LONG tmpxy;
1381 dTopLeft = dbuf;
1382 dTopRight = dbuf+((dstwidth-1)*bpp);
1383 dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch);
1384 dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
1385
1386 if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
1387 {
1388 /* I don't think we need to do anything about this flag */
1389 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
1390 }
1391 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
1392 {
1393 tmp = dTopRight;
1394 dTopRight = dTopLeft;
1395 dTopLeft = tmp;
1396 tmp = dBottomRight;
1397 dBottomRight = dBottomLeft;
1398 dBottomLeft = tmp;
1399 dstxinc = dstxinc *-1;
1400 }
1401 if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
1402 {
1403 tmp = dTopLeft;
1404 dTopLeft = dBottomLeft;
1405 dBottomLeft = tmp;
1406 tmp = dTopRight;
1407 dTopRight = dBottomRight;
1408 dBottomRight = tmp;
1409 dstyinc = dstyinc *-1;
1410 }
1411 if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING)
1412 {
1413 /* I don't think we need to do anything about this flag */
1414 WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
1415 }
1416 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180)
1417 {
1418 tmp = dBottomRight;
1419 dBottomRight = dTopLeft;
1420 dTopLeft = tmp;
1421 tmp = dBottomLeft;
1422 dBottomLeft = dTopRight;
1423 dTopRight = tmp;
1424 dstxinc = dstxinc * -1;
1425 dstyinc = dstyinc * -1;
1426 }
1427 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270)
1428 {
1429 tmp = dTopLeft;
1430 dTopLeft = dBottomLeft;
1431 dBottomLeft = dBottomRight;
1432 dBottomRight = dTopRight;
1433 dTopRight = tmp;
1434 tmpxy = dstxinc;
1435 dstxinc = dstyinc;
1436 dstyinc = tmpxy;
1437 dstxinc = dstxinc * -1;
1438 }
1439 if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90)
1440 {
1441 tmp = dTopLeft;
1442 dTopLeft = dTopRight;
1443 dTopRight = dBottomRight;
1444 dBottomRight = dBottomLeft;
1445 dBottomLeft = tmp;
1446 tmpxy = dstxinc;
1447 dstxinc = dstyinc;
1448 dstyinc = tmpxy;
1449 dstyinc = dstyinc * -1;
1450 }
1451 if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
1452 {
1453 /* I don't think we need to do anything about this flag */
1454 WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
1455 }
1456 dbuf = dTopLeft;
1457 Flags &= ~(WINEDDBLT_DDFX);
1458 }
1459
1460#define COPY_COLORKEY_FX(type) { \
1461 const type *s; \
1462 type *d = (type *)dbuf, *dx, tmp; \
1463 for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
1464 s = (const type*)(sbase + (sy >> 16) * slock.Pitch); \
1465 dx = d; \
1466 for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
1467 tmp = s[sx >> 16]; \
1468 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \
1469 ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \
1470 dx[0] = tmp; \
1471 } \
1472 dx = (type*)(((LPBYTE)dx)+dstxinc); \
1473 } \
1474 d = (type*)(((LPBYTE)d)+dstyinc); \
1475 } \
1476 break; }
1477
1478 switch (bpp) {
1479 case 1: COPY_COLORKEY_FX(BYTE)
1480 case 2: COPY_COLORKEY_FX(WORD)
1481 case 4: COPY_COLORKEY_FX(DWORD)
1482 case 3:
1483 {
1484 const BYTE *s;
1485 BYTE *d = dbuf, *dx;
1486 for (y = sy = 0; y < dstheight; y++, sy += yinc)
1487 {
1488 sbuf = sbase + (sy >> 16) * slock.Pitch;
1489 dx = d;
1490 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
1491 {
1492 DWORD pixel, dpixel = 0;
1493 s = sbuf+3*(sx>>16);
1494 pixel = s[0]|(s[1]<<8)|(s[2]<<16);
1495 dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16);
1496 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) &&
1497 ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
1498 {
1499 dx[0] = (pixel )&0xff;
1500 dx[1] = (pixel>> 8)&0xff;
1501 dx[2] = (pixel>>16)&0xff;
1502 }
1503 dx+= dstxinc;
1504 }
1505 d += dstyinc;
1506 }
1507 break;
1508 }
1509 default:
1510 FIXME("%s color-keyed blit not implemented for bpp %d!\n",
1511 (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
1512 ret = WINED3DERR_NOTAVAILABLE;
1513 goto error;
1514#undef COPY_COLORKEY_FX
1515 }
1516 }
1517 }
1518
1519error:
1520 if (Flags && FIXME_ON(d3d_surface))
1521 {
1522 FIXME("\tUnsupported flags: %08x\n", Flags);
1523 }
1524
1525release:
1526 IWineD3DSurface_UnlockRect(iface);
1527 if (Src && Src != This) IWineD3DSurface_UnlockRect((IWineD3DSurface *) Src);
1528 /* Release the converted surface if any */
1529 if (Src && SrcSurface != (IWineD3DSurface *) Src) IWineD3DSurface_Release((IWineD3DSurface *) Src);
1530 return ret;
1531}
1532
1533/*****************************************************************************
1534 * IWineD3DSurface::BltFast, SW emulation version
1535 *
1536 * This is the software implementation of BltFast, as used by GDI surfaces
1537 * and as a fallback for OpenGL surfaces. This code is taken from the old
1538 * DirectDraw code, and was originally written by TransGaming.
1539 *
1540 * Params:
1541 * dstx:
1542 * dsty:
1543 * Source: Source surface to copy from
1544 * rsrc: Source rectangle
1545 * trans: Some Flags
1546 *
1547 * Returns:
1548 * WINED3D_OK on success
1549 *
1550 *****************************************************************************/
1551HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
1552 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
1553{
1554 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1555 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source;
1556
1557 int bpp, w, h, x, y;
1558 WINED3DLOCKED_RECT dlock,slock;
1559 HRESULT ret = WINED3D_OK;
1560 RECT rsrc2;
1561 RECT lock_src, lock_dst, lock_union;
1562 const BYTE *sbuf;
1563 BYTE *dbuf;
1564 const struct GlPixelFormatDesc *sEntry, *dEntry;
1565
1566 if (TRACE_ON(d3d_surface))
1567 {
1568 TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans);
1569
1570 if (rsrc)
1571 {
1572 TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top,
1573 rsrc->right,rsrc->bottom);
1574 }
1575 else
1576 {
1577 TRACE(" srcrect: NULL\n");
1578 }
1579 }
1580
1581 if ((This->Flags & SFLAG_LOCKED) ||
1582 (Src->Flags & SFLAG_LOCKED))
1583 {
1584 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1585 return WINEDDERR_SURFACEBUSY;
1586 }
1587
1588 if (!rsrc)
1589 {
1590 WARN("rsrc is NULL!\n");
1591 rsrc2.left = 0;
1592 rsrc2.top = 0;
1593 rsrc2.right = Src->currentDesc.Width;
1594 rsrc2.bottom = Src->currentDesc.Height;
1595 rsrc = &rsrc2;
1596 }
1597
1598 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/
1599 if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) ||
1600 (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) ||
1601 (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) ||
1602 (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) ||
1603 (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
1604 {
1605 WARN("Application gave us bad source rectangle for BltFast.\n");
1606 return WINEDDERR_INVALIDRECT;
1607 }
1608
1609 h = rsrc->bottom - rsrc->top;
1610 if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty;
1611 if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top;
1612 if (h <= 0) return WINEDDERR_INVALIDRECT;
1613
1614 w = rsrc->right - rsrc->left;
1615 if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx;
1616 if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left;
1617 if (w <= 0) return WINEDDERR_INVALIDRECT;
1618
1619 /* Now compute the locking rectangle... */
1620 lock_src.left = rsrc->left;
1621 lock_src.top = rsrc->top;
1622 lock_src.right = lock_src.left + w;
1623 lock_src.bottom = lock_src.top + h;
1624
1625 lock_dst.left = dstx;
1626 lock_dst.top = dsty;
1627 lock_dst.right = dstx + w;
1628 lock_dst.bottom = dsty + h;
1629
1630 bpp = This->resource.format_desc->byte_count;
1631
1632 /* We need to lock the surfaces, or we won't get refreshes when done. */
1633 if (Src == This)
1634 {
1635 int pitch;
1636
1637 UnionRect(&lock_union, &lock_src, &lock_dst);
1638
1639 /* Lock the union of the two rectangles */
1640 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0);
1641 if(ret != WINED3D_OK) goto error;
1642
1643 pitch = dlock.Pitch;
1644 slock.Pitch = dlock.Pitch;
1645
1646 /* Since slock was originally copied from this surface's description, we can just reuse it */
1647 sbuf = This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
1648 dbuf = This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
1649 sEntry = Src->resource.format_desc;
1650 dEntry = sEntry;
1651 }
1652 else
1653 {
1654 ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY);
1655 if(ret != WINED3D_OK) goto error;
1656 ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0);
1657 if(ret != WINED3D_OK) goto error;
1658
1659 sbuf = slock.pBits;
1660 dbuf = dlock.pBits;
1661 TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf);
1662
1663 sEntry = Src->resource.format_desc;
1664 dEntry = This->resource.format_desc;
1665 }
1666
1667 /* Handle compressed surfaces first... */
1668 if (sEntry->Flags & dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED)
1669 {
1670 UINT row_block_count;
1671
1672 TRACE("compressed -> compressed copy\n");
1673 if (trans)
1674 FIXME("trans arg not supported when a compressed surface is involved\n");
1675 if (dstx || dsty)
1676 FIXME("offset for destination surface is not supported\n");
1677 if (Src->resource.format_desc->format != This->resource.format_desc->format)
1678 {
1679 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
1680 ret = WINED3DERR_WRONGTEXTUREFORMAT;
1681 goto error;
1682 }
1683
1684 row_block_count = (w + dEntry->block_width - 1) / dEntry->block_width;
1685 for (y = 0; y < h; y += dEntry->block_height)
1686 {
1687 memcpy(dbuf, sbuf, row_block_count * dEntry->block_byte_count);
1688 dbuf += dlock.Pitch;
1689 sbuf += slock.Pitch;
1690 }
1691
1692 goto error;
1693 }
1694 if ((sEntry->Flags & WINED3DFMT_FLAG_COMPRESSED) && !(dEntry->Flags & WINED3DFMT_FLAG_COMPRESSED))
1695 {
1696 /* TODO: Use the libtxc_dxtn.so shared library to do
1697 * software decompression
1698 */
1699 ERR("Software decompression not supported.\n");
1700 goto error;
1701 }
1702
1703 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
1704 {
1705 DWORD keylow, keyhigh;
1706 DWORD mask = Src->resource.format_desc->red_mask |
1707 Src->resource.format_desc->green_mask |
1708 Src->resource.format_desc->blue_mask;
1709
1710 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
1711 if(!mask && bpp==1)
1712 mask = 0xff;
1713
1714 TRACE("Color keyed copy\n");
1715 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1716 {
1717 keylow = Src->SrcBltCKey.dwColorSpaceLowValue;
1718 keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue;
1719 }
1720 else
1721 {
1722 /* I'm not sure if this is correct */
1723 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
1724 keylow = This->DestBltCKey.dwColorSpaceLowValue;
1725 keyhigh = This->DestBltCKey.dwColorSpaceHighValue;
1726 }
1727
1728#define COPYBOX_COLORKEY(type) { \
1729 const type *s = (const type *)sbuf; \
1730 type *d = (type *)dbuf; \
1731 type tmp; \
1732 for (y = 0; y < h; y++) { \
1733 for (x = 0; x < w; x++) { \
1734 tmp = s[x]; \
1735 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
1736 } \
1737 s = (const type *)((const BYTE *)s + slock.Pitch); \
1738 d = (type *)((BYTE *)d + dlock.Pitch); \
1739 } \
1740 break; \
1741 }
1742
1743 switch (bpp) {
1744 case 1: COPYBOX_COLORKEY(BYTE)
1745 case 2: COPYBOX_COLORKEY(WORD)
1746 case 4: COPYBOX_COLORKEY(DWORD)
1747 case 3:
1748 {
1749 const BYTE *s;
1750 BYTE *d;
1751 DWORD tmp;
1752 s = sbuf;
1753 d = dbuf;
1754 for (y = 0; y < h; y++)
1755 {
1756 for (x = 0; x < w * 3; x += 3)
1757 {
1758 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
1759 if (tmp < keylow || tmp > keyhigh)
1760 {
1761 d[x + 0] = s[x + 0];
1762 d[x + 1] = s[x + 1];
1763 d[x + 2] = s[x + 2];
1764 }
1765 }
1766 s += slock.Pitch;
1767 d += dlock.Pitch;
1768 }
1769 break;
1770 }
1771 default:
1772 FIXME("Source color key blitting not supported for bpp %d\n",bpp*8);
1773 ret = WINED3DERR_NOTAVAILABLE;
1774 goto error;
1775 }
1776#undef COPYBOX_COLORKEY
1777 TRACE("Copy Done\n");
1778 }
1779 else
1780 {
1781 int width = w * bpp;
1782 INT sbufpitch, dbufpitch;
1783
1784 TRACE("NO color key copy\n");
1785 /* Handle overlapping surfaces */
1786 if (sbuf < dbuf)
1787 {
1788 sbuf += (h - 1) * slock.Pitch;
1789 dbuf += (h - 1) * dlock.Pitch;
1790 sbufpitch = -slock.Pitch;
1791 dbufpitch = -dlock.Pitch;
1792 }
1793 else
1794 {
1795 sbufpitch = slock.Pitch;
1796 dbufpitch = dlock.Pitch;
1797 }
1798 for (y = 0; y < h; y++)
1799 {
1800 /* This is pretty easy, a line for line memcpy */
1801 memmove(dbuf, sbuf, width);
1802 sbuf += sbufpitch;
1803 dbuf += dbufpitch;
1804 }
1805 TRACE("Copy done\n");
1806 }
1807
1808error:
1809 if (Src == This)
1810 {
1811 IWineD3DSurface_UnlockRect(iface);
1812 }
1813 else
1814 {
1815 IWineD3DSurface_UnlockRect(iface);
1816 IWineD3DSurface_UnlockRect(Source);
1817 }
1818
1819 return ret;
1820}
1821
1822HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags)
1823{
1824 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1825
1826 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n",
1827 This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1828
1829 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
1830
1831 if (NULL == pRect)
1832 {
1833 pLockedRect->pBits = This->resource.allocatedMemory;
1834 This->lockedRect.left = 0;
1835 This->lockedRect.top = 0;
1836 This->lockedRect.right = This->currentDesc.Width;
1837 This->lockedRect.bottom = This->currentDesc.Height;
1838
1839 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n",
1840 &This->lockedRect, This->lockedRect.left, This->lockedRect.top,
1841 This->lockedRect.right, This->lockedRect.bottom);
1842 }
1843 else
1844 {
1845 const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
1846
1847 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n",
1848 pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
1849
1850 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
1851 {
1852 /* Compressed textures are block based, so calculate the offset of
1853 * the block that contains the top-left pixel of the locked rectangle. */
1854 pLockedRect->pBits = This->resource.allocatedMemory
1855 + ((pRect->top / format_desc->block_height) * pLockedRect->Pitch)
1856 + ((pRect->left / format_desc->block_width) * format_desc->block_byte_count);
1857 }
1858 else
1859 {
1860 pLockedRect->pBits = This->resource.allocatedMemory +
1861 (pLockedRect->Pitch * pRect->top) +
1862 (pRect->left * format_desc->byte_count);
1863 }
1864 This->lockedRect.left = pRect->left;
1865 This->lockedRect.top = pRect->top;
1866 This->lockedRect.right = pRect->right;
1867 This->lockedRect.bottom = pRect->bottom;
1868 }
1869
1870 /* No dirtifying is needed for this surface implementation */
1871 TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
1872
1873 return WINED3D_OK;
1874}
1875
1876void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
1877 ERR("Should not be called on base texture\n");
1878}
1879
1880/* TODO: think about moving this down to resource? */
1881const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface)
1882{
1883 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1884
1885 /* This should only be called for sysmem textures, it may be a good idea
1886 * to extend this to all pools at some point in the future */
1887 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM)
1888 {
1889 FIXME("(%p) Attempting to get system memory for a non-system memory texture\n", iface);
1890 }
1891 return This->resource.allocatedMemory;
1892}
Note: See TracBrowser for help on using the repository browser.

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