wined3d: Disable the fog before writing the back buffer data.
[wine.git] / dlls / wined3d / surface.c
blobfa4f615e6233fbe4f0c22e1dede783ca451ecc7b
1 /*
2 * IWineD3DSurface Implementation
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 Stefan Dösinger for CodeWeavers
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include "wine/port.h"
29 #include "wined3d_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
32 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
34 typedef enum {
35 NO_CONVERSION,
36 CONVERT_PALETTED,
37 CONVERT_PALETTED_CK,
38 CONVERT_CK_565,
39 CONVERT_CK_5551,
40 CONVERT_CK_4444,
41 CONVERT_CK_4444_ARGB,
42 CONVERT_CK_1555,
43 CONVERT_555,
44 CONVERT_CK_RGB24,
45 CONVERT_CK_8888,
46 CONVERT_CK_8888_ARGB,
47 CONVERT_RGB32_888
48 } CONVERT_TYPES;
50 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf);
52 /* *******************************************
53 IWineD3DSurface IUnknown parts follow
54 ******************************************* */
55 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
57 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
58 /* Warn ,but be nice about things */
59 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
60 if (riid == NULL) {
61 ERR("Probably FIXME: Calling query interface with NULL riid\n");
63 if (IsEqualGUID(riid, &IID_IUnknown)
64 || IsEqualGUID(riid, &IID_IWineD3DBase)
65 || IsEqualGUID(riid, &IID_IWineD3DResource)
66 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
67 IUnknown_AddRef((IUnknown*)iface);
68 *ppobj = This;
69 return S_OK;
71 *ppobj = NULL;
72 return E_NOINTERFACE;
75 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
76 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
77 ULONG ref = InterlockedIncrement(&This->resource.ref);
78 TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
79 return ref;
82 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
83 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
84 ULONG ref = InterlockedDecrement(&This->resource.ref);
85 TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
86 if (ref == 0) {
87 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
88 TRACE("(%p) : cleaning up\n", This);
89 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
90 ENTER_GL();
91 TRACE("Deleting texture %d\n", This->glDescription.textureName);
92 glDeleteTextures(1, &This->glDescription.textureName);
93 LEAVE_GL();
96 if(This->Flags & SFLAG_DIBSECTION) {
97 /* Release the DC */
98 SelectObject(This->hDC, This->dib.holdbitmap);
99 DeleteDC(This->hDC);
100 /* Release the DIB section */
101 DeleteObject(This->dib.DIBsection);
102 This->dib.bitmap_data = NULL;
103 This->resource.allocatedMemory = NULL;
106 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
107 if(iface == device->ddraw_primary)
108 device->ddraw_primary = NULL;
110 TRACE("(%p) Released\n", This);
111 HeapFree(GetProcessHeap(), 0, This);
114 return ref;
117 /* ****************************************************
118 IWineD3DSurface IWineD3DResource parts follow
119 **************************************************** */
120 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
121 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
124 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
125 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
128 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
129 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
132 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
133 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
136 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
137 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
140 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
141 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
144 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
145 /* TODO: re-write the way textures and managed,
146 * use a 'opengl context manager' to manage RenderTarget surfaces
147 ** *********************************************************/
149 /* TODO: check for locks */
150 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
151 IWineD3DBaseTexture *baseTexture = NULL;
152 TRACE("(%p)Checking to see if the container is a base texture\n", This);
153 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
154 TRACE("Passing to conatiner\n");
155 IWineD3DBaseTexture_PreLoad(baseTexture);
156 IWineD3DBaseTexture_Release(baseTexture);
157 } else {
158 TRACE("(%p) : About to load surface\n", This);
159 ENTER_GL();
160 #if 0 /* TODO: context manager support */
161 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
162 #endif
163 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
164 if (This->glDescription.level == 0 && This->glDescription.textureName == 0) {
165 glGenTextures(1, &This->glDescription.textureName);
166 checkGLcall("glGenTextures");
167 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
168 glBindTexture(This->glDescription.target, This->glDescription.textureName);
169 checkGLcall("glBindTexture");
170 IWineD3DSurface_LoadTexture(iface);
171 /* This is where we should be reducing the amount of GLMemoryUsed */
172 } else {
173 if (This->glDescription.level == 0) {
174 glBindTexture(This->glDescription.target, This->glDescription.textureName);
175 checkGLcall("glBindTexture");
176 IWineD3DSurface_LoadTexture(iface);
177 } else if (This->glDescription.textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
178 /* assume this is a coding error not a real error for now */
179 FIXME("Mipmap surface has a glTexture bound to it!\n");
182 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
183 /* Tell opengl to try and keep this texture in video ram (well mostly) */
184 GLclampf tmp;
185 tmp = 0.9f;
186 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
188 /* TODO: disable texture support, if it wastn't enabled when we entered. */
189 #if 0 /* TODO: context manager support */
190 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
191 /* we don't care when the state is disabled(if atall) */);
192 #endif
193 LEAVE_GL();
195 return;
198 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
199 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
200 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
203 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
204 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
205 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
208 /* ******************************************************
209 IWineD3DSurface IWineD3DSurface parts follow
210 ****************************************************** */
212 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainerParent(IWineD3DSurface* iface, IUnknown **ppContainerParent) {
213 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
215 TRACE("(%p) : ppContainerParent %p)\n", This, ppContainerParent);
217 if (!ppContainerParent) {
218 ERR("(%p) : Called without a valid ppContainerParent.\n", This);
221 if (This->container) {
222 IWineD3DBase_GetParent(This->container, ppContainerParent);
223 if (!ppContainerParent) {
224 /* WineD3D objects should always have a parent */
225 ERR("(%p) : GetParent returned NULL\n", This);
227 IUnknown_Release(*ppContainerParent); /* GetParent adds a reference; we want just the pointer */
228 } else {
229 *ppContainerParent = NULL;
232 return WINED3D_OK;
235 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
236 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
237 IWineD3DBase *container = 0;
239 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
241 if (!ppContainer) {
242 ERR("Called without a valid ppContainer.\n");
245 /** From MSDN:
246 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
247 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
248 * GetContainer will return the Direct3D device used to create the surface.
250 if (This->container) {
251 container = This->container;
252 } else {
253 container = (IWineD3DBase *)This->resource.wineD3DDevice;
256 TRACE("Relaying to QueryInterface\n");
257 return IUnknown_QueryInterface(container, riid, ppContainer);
260 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
261 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
263 TRACE("(%p) : copying into %p\n", This, pDesc);
264 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
265 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
266 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
267 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
268 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
269 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
270 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
271 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
272 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
273 return WINED3D_OK;
276 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
277 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
278 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
279 if (This->glDescription.textureName == 0 && textureName != 0) {
280 This->Flags |= SFLAG_DIRTY;
281 IWineD3DSurface_AddDirtyRect(iface, NULL);
283 This->glDescription.textureName = textureName;
284 This->glDescription.target = target;
287 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
288 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
289 TRACE("(%p) : returning %p\n", This, &This->glDescription);
290 *glDescription = &This->glDescription;
293 /* TODO: think about moving this down to resource? */
294 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
295 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
296 /* This should only be called for sysmem textures, it may be a good idea to extend this to all pools at some point in the futture */
297 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
298 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
300 return (CONST void*)(This->resource.allocatedMemory);
303 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) {
304 long j;
305 void *mem;
306 GLint fmt;
307 GLint type;
309 switch(This->resource.format)
311 case WINED3DFMT_P8:
313 /* GL can't return palettized data, so read ARGB pixels into a
314 * seperate block of memory and convert them into palettized format
315 * in software. Slow, but if the app means to use palettized render
316 * targets and lock it...
318 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
319 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
320 * for the color channels when palettizing the colors.
322 fmt = GL_RGB;
323 type = GL_UNSIGNED_BYTE;
324 pitch *= 3;
325 mem = HeapAlloc(GetProcessHeap(), 0, (rect->bottom - rect->top) * pitch);
326 if(!mem) {
327 ERR("Out of memory\n");
328 return;
331 break;
333 default:
334 mem = dest;
335 fmt = This->glDescription.glFormat;
336 type = This->glDescription.glType;
339 if (rect->left == 0 &&
340 rect->right == This->currentDesc.Width ) {
341 BYTE *row, *top, *bottom;
342 int i;
344 glReadPixels(0, rect->top,
345 This->currentDesc.Width,
346 rect->bottom - rect->top,
347 fmt,
348 type,
349 mem);
351 /* glReadPixels returns the image upside down, and there is no way to prevent this.
352 Flip the lines in software */
353 row = HeapAlloc(GetProcessHeap(), 0, pitch);
354 if(!row) {
355 ERR("Out of memory\n");
356 return;
358 top = mem;
359 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
360 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
361 memcpy(row, top, pitch);
362 memcpy(top, bottom, pitch);
363 memcpy(bottom, row, pitch);
364 top += pitch;
365 bottom -= pitch;
367 HeapFree(GetProcessHeap(), 0, row);
369 if(This->lockedRect.top == 0 && This->lockedRect.bottom == This->currentDesc.Height) {
370 This->Flags &= ~SFLAG_GLDIRTY;
372 } else {
373 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
374 glReadPixels(rect->left,
375 rect->bottom - j - 1,
376 rect->right - rect->left,
378 fmt,
379 type,
380 (char *)mem + (pitch * (j-rect->top)));
384 vcheckGLcall("glReadPixels");
386 if(This->resource.format == WINED3DFMT_P8) {
387 PALETTEENTRY *pal;
388 DWORD width = pitch / 3;
389 int x, y, c;
390 if(This->palette) {
391 pal = This->palette->palents;
392 } else {
393 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
396 for(y = rect->top; y < rect->bottom; y++) {
397 for(x = rect->left; x < rect->right; x++) {
398 /* start lines pixels */
399 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
400 BYTE *green = blue + 1;
401 BYTE *red = green + 1;
403 for(c = 0; c < 256; c++) {
404 if(*red == pal[c].peRed &&
405 *green == pal[c].peGreen &&
406 *blue == pal[c].peBlue)
408 *((BYTE *) dest + y * width + x) = c;
409 break;
414 HeapFree(GetProcessHeap(), 0, mem);
418 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
419 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
420 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
421 IWineD3DSwapChainImpl *swapchain = NULL;
422 static UINT messages = 0; /* holds flags to disable fixme messages */
423 BOOL backbuf = FALSE;
425 /* fixme: should we really lock as such? */
426 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
427 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
428 FIXME("Warning: Surface is in texture memory or pbuffer\n");
429 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
432 if (!(This->Flags & SFLAG_LOCKABLE)) {
433 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
434 texture regions, and since the destination is an unlockable region we need
435 to tolerate this */
436 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
437 /*return WINED3DERR_INVALIDCALL; */
440 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
441 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
443 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
444 if(swapchain != NULL) {
445 int i;
446 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
447 if(iface == swapchain->backBuffer[i]) {
448 backbuf = TRUE;
449 break;
453 if (backbuf) {
454 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
455 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
456 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
457 } else if (iface == myDevice->renderTarget) {
458 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
459 } else if (iface == myDevice->depthStencilBuffer) {
460 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
463 if (NULL != swapchain) {
464 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
466 swapchain = NULL;
468 } else {
469 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
472 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
474 if (NULL == pRect) {
475 pLockedRect->pBits = This->resource.allocatedMemory;
476 This->lockedRect.left = 0;
477 This->lockedRect.top = 0;
478 This->lockedRect.right = This->currentDesc.Width;
479 This->lockedRect.bottom = This->currentDesc.Height;
480 TRACE("Locked Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
481 } else {
482 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
484 if ((pRect->top < 0) ||
485 (pRect->left < 0) ||
486 (pRect->left >= pRect->right) ||
487 (pRect->top >= pRect->bottom) ||
488 (pRect->right > This->currentDesc.Width) ||
489 (pRect->bottom > This->currentDesc.Height))
491 WARN(" Invalid values in pRect !!!\n");
492 return D3DERR_INVALIDCALL;
495 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
496 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
497 } else {
498 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
500 This->lockedRect.left = pRect->left;
501 This->lockedRect.top = pRect->top;
502 This->lockedRect.right = pRect->right;
503 This->lockedRect.bottom = pRect->bottom;
506 if (This->Flags & SFLAG_NONPOW2) {
507 TRACE("Locking non-power 2 texture\n");
510 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
511 /* classic surface TODO: non 2d surfaces?
512 These resources may be POOL_SYSTEMMEM, so they must not access the device */
513 TRACE("locking an ordinarary surface\n");
514 /* Check to see if memory has already been allocated from the surface*/
515 if ((NULL == This->resource.allocatedMemory) ||
516 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
517 /* Non-system memory surfaces */
519 This->Flags &= ~SFLAG_GLDIRTY;
521 /*Surface has no memory currently allocated to it!*/
522 TRACE("(%p) Locking rect\n" , This);
523 if(!This->resource.allocatedMemory) {
524 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
526 if (0 != This->glDescription.textureName) {
527 /* Now I have to copy thing bits back */
528 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
529 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
530 ENTER_GL();
532 /* Make sure that the texture is loaded */
533 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
535 TRACE("(%p) glGetTexImage level(%d), fmt(%d), typ(%d), mem(%p)\n" , This, This->glDescription.level, This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
537 if (This->resource.format == WINED3DFMT_DXT1 ||
538 This->resource.format == WINED3DFMT_DXT2 ||
539 This->resource.format == WINED3DFMT_DXT3 ||
540 This->resource.format == WINED3DFMT_DXT4 ||
541 This->resource.format == WINED3DFMT_DXT5) {
542 TRACE("Locking a compressed texture\n");
543 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
544 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
545 This->glDescription.level,
546 This->resource.allocatedMemory);
548 } else {
549 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
551 } else {
552 glGetTexImage(This->glDescription.target,
553 This->glDescription.level,
554 This->glDescription.glFormat,
555 This->glDescription.glType,
556 This->resource.allocatedMemory);
557 vcheckGLcall("glGetTexImage");
558 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
559 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
560 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
561 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
563 Were doing this...
565 instead of boxing the texture :
566 |<-texture width ->| -->pow2width| /\
567 |111111111111111111| | |
568 |222 Texture 222222| boxed empty | texture height
569 |3333 Data 33333333| | |
570 |444444444444444444| | \/
571 ----------------------------------- |
572 | boxed empty | boxed empty | pow2height
573 | | | \/
574 -----------------------------------
577 were repacking the data to the expected texture width
579 |<-texture width ->| -->pow2width| /\
580 |111111111111111111222222222222222| |
581 |222333333333333333333444444444444| texture height
582 |444444 | |
583 | | \/
584 | | |
585 | empty | pow2height
586 | | \/
587 -----------------------------------
589 == is the same as
591 |<-texture width ->| /\
592 |111111111111111111|
593 |222222222222222222|texture height
594 |333333333333333333|
595 |444444444444444444| \/
596 --------------------
598 this also means that any references to allocatedMemory should work with the data as if were a standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
600 internally the texture is still stored in a boxed format so any references to textureName will get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
602 if (This->Flags & SFLAG_NONPOW2) {
603 BYTE* dataa, *datab;
604 int pitcha = 0, pitchb = 0;
605 int y;
606 pitcha = This->bytesPerPixel * This->currentDesc.Width;
607 pitchb = This->bytesPerPixel * This->pow2Width;
608 datab = dataa = This->resource.allocatedMemory;
609 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
610 for (y = 1 ; y < This->currentDesc.Height; y++) {
611 dataa += pitcha; /* skip the first row */
612 datab += pitchb;
613 memcpy(dataa, datab, pitcha);
618 LEAVE_GL();
620 } else { /* Nothing to do */
621 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
624 if (NULL == pRect) {
625 pLockedRect->pBits = This->resource.allocatedMemory;
626 } else{
627 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
628 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
629 } else {
630 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
634 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
635 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
636 GLint prev_store;
637 GLint prev_read;
638 BOOL notInContext = FALSE;
639 IWineD3DSwapChainImpl *targetSwapChain = NULL;
642 ENTER_GL();
645 * for render->surface copy begin to begin of allocatedMemory
646 * unlock can be more easy
649 TRACE("locking a render target\n");
651 if (This->resource.allocatedMemory == NULL)
652 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
654 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
655 pLockedRect->pBits = This->resource.allocatedMemory;
657 glFlush();
658 vcheckGLcall("glFlush");
659 glGetIntegerv(GL_READ_BUFFER, &prev_read);
660 vcheckGLcall("glIntegerv");
661 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
662 vcheckGLcall("glIntegerv");
664 /* Here's what we have to do:
665 See if the swapchain has the same context as the renderTarget or the surface is the render target.
666 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
667 and use the front back buffer as required.
668 if not, we need to switch contexts and then switchback at the end.
670 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
671 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
673 /* NOTE: In a shared context environment the renderTarget will use the same context as the implicit swapchain (we're not in a shared environment yet! */
674 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
675 if (iface == swapchain->frontBuffer) {
676 TRACE("locking front\n");
677 glReadBuffer(GL_FRONT);
679 else if (iface == myDevice->renderTarget || backbuf) {
680 TRACE("locking back buffer\n");
681 glReadBuffer(GL_BACK);
682 } else if (iface == myDevice->depthStencilBuffer) {
683 FIXME("Stencil Buffer lock unsupported for now\n");
684 } else {
685 FIXME("(%p) Shouldn't have got here!\n", This);
686 glReadBuffer(GL_BACK);
688 } else if (swapchain != NULL) {
689 IWineD3DSwapChainImpl *implSwapChain;
690 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
691 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
692 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
693 if (backbuf) {
694 glReadBuffer(GL_BACK);
695 } else if (iface == swapchain->frontBuffer) {
696 glReadBuffer(GL_FRONT);
697 } else if (iface == myDevice->depthStencilBuffer) {
698 FIXME("Stencil Buffer lock unsupported for now\n");
699 } else {
700 FIXME("Should have got here!\n");
701 glReadBuffer(GL_BACK);
703 } else {
704 /* We need to switch contexts to be able to read the buffer!!! */
705 FIXME("The buffer requested isn't in the current openGL context\n");
706 notInContext = TRUE;
707 /* TODO: check the contexts, to see if were shared with the current context */
709 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
711 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
712 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
714 /** the depth stencil in openGL has a format of GL_FLOAT
715 * which should be good for WINED3DFMT_D16_LOCKABLE
716 * and WINED3DFMT_D16
717 * it is unclear what format the stencil buffer is in except.
718 * 'Each index is converted to fixed point...
719 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
720 * mappings in the table GL_PIXEL_MAP_S_TO_S.
721 * glReadPixels(This->lockedRect.left,
722 * This->lockedRect.bottom - j - 1,
723 * This->lockedRect.right - This->lockedRect.left,
724 * 1,
725 * GL_DEPTH_COMPONENT,
726 * type,
727 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
728 *****************************************/
729 if (!notInContext) { /* Only read the buffer if it's in the current context */
730 switch(wined3d_settings.rendertargetlock_mode) {
731 case RTL_AUTO:
732 case RTL_READDRAW:
733 case RTL_READTEX:
734 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
735 break;
737 case RTL_TEXDRAW:
738 case RTL_TEXTEX:
739 ERR("Reading from render target with a texture isn't implemented yet\n");
740 break;
742 case RTL_DISABLE:
744 static BOOL warned = FALSE;
745 if(!warned) {
746 ERR("Application tries to lock the render target, but render target locking is disabled\n");
747 warned = TRUE;
750 break;
753 TRACE("Resetting buffer\n");
755 glReadBuffer(prev_read);
756 vcheckGLcall("glReadBuffer");
758 LEAVE_GL();
760 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
762 if (!messages & 1) {
763 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
766 glReadPixels(This->lockedRect.left,
767 This->lockedRect.bottom - j - 1,
768 This->lockedRect.right - This->lockedRect.left,
770 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
774 messages |= 1;
776 } else {
777 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
780 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
781 /* Don't dirtify */
782 } else {
783 IWineD3DBaseTexture *pBaseTexture;
785 * Dirtify on lock
786 * as seen in msdn docs
788 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
790 /** Dirtify Container if needed */
791 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
792 TRACE("Making container dirty\n");
793 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
794 IWineD3DBaseTexture_Release(pBaseTexture);
795 } else {
796 TRACE("Surface is standalone, no need to dirty the container\n");
800 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
802 This->Flags |= SFLAG_LOCKED;
803 return WINED3D_OK;
806 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
807 GLint prev_store;
808 GLint prev_rasterpos[4];
809 GLint skipBytes = 0;
810 BOOL storechanged = FALSE;
811 GLint fmt, type;
812 void *mem;
814 glDisable(GL_TEXTURE_2D);
815 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
816 glDisable(GL_TEXTURE_1D);
817 vcheckGLcall("glDisable(GL_TEXTURE_1D)");
819 glFlush();
820 vcheckGLcall("glFlush");
821 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
822 vcheckGLcall("glIntegerv");
823 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
824 vcheckGLcall("glIntegerv");
825 glPixelZoom(1.0, -1.0);
826 vcheckGLcall("glPixelZoom");
828 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
829 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
830 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
832 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
833 vcheckGLcall("glRasterPos2f");
835 /* Some drivers(radeon dri, others?) don't like exceptions during
836 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
837 * after ReleaseDC. Reading it will cause an exception, which x11drv will
838 * catch to put the dib section in InSync mode, which leads to a crash
839 * and a blocked x server on my radeon card.
841 * The following lines read the dib section so it is put in inSync mode
842 * before glDrawPixels is called and the crash is prevented. There won't
843 * be any interfering gdi accesses, because UnlockRect is called from
844 * ReleaseDC, and the app won't use the dc any more afterwards.
846 if(This->Flags & SFLAG_DIBSECTION) {
847 volatile BYTE read;
848 read = This->resource.allocatedMemory[0];
851 switch (This->resource.format) {
852 /* No special care needed */
853 case WINED3DFMT_A4R4G4B4:
854 case WINED3DFMT_R5G6B5:
855 case WINED3DFMT_A1R5G5B5:
856 case WINED3DFMT_R8G8B8:
857 type = This->glDescription.glType;
858 fmt = This->glDescription.glFormat;
859 mem = This->resource.allocatedMemory;
860 break;
862 case WINED3DFMT_X4R4G4B4:
864 #if 0 /* Do we still need that? Those pixel formats have no alpha channel in gl any more */
865 int size;
866 unsigned short *data;
867 data = (unsigned short *)This->resource.allocatedMemory;
868 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
869 while(size > 0) {
870 *data |= 0xF000;
871 data++;
872 size--;
874 #endif
875 type = This->glDescription.glType;
876 fmt = This->glDescription.glFormat;
877 mem = This->resource.allocatedMemory;
879 break;
881 case WINED3DFMT_X1R5G5B5:
883 #if 0 /* Do we still need that? Those pixel formats have no alpha channel in gl any more */
884 int size;
885 unsigned short *data;
886 data = (unsigned short *)This->resource.allocatedMemory;
887 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
888 while(size > 0) {
889 *data |= 0x8000;
890 data++;
891 size--;
893 #endif
894 type = This->glDescription.glType;
895 fmt = This->glDescription.glFormat;
896 mem = This->resource.allocatedMemory;
898 break;
900 case WINED3DFMT_X8R8G8B8:
902 #if 0 /* Do we still need that? Those pixel formats have no alpha channel in gl any more */
903 /* make sure the X byte is set to alpha on, since it
904 could be any random value this fixes the intro move in Pirates! */
905 int size;
906 unsigned int *data;
907 data = (unsigned int *)This->resource.allocatedMemory;
908 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
909 while(size > 0) {
910 *data |= 0xFF000000;
911 data++;
912 size--;
914 #endif
917 case WINED3DFMT_A8R8G8B8:
919 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
920 vcheckGLcall("glPixelStorei");
921 storechanged = TRUE;
922 type = This->glDescription.glType;
923 fmt = This->glDescription.glFormat;
924 mem = This->resource.allocatedMemory;
926 break;
928 case WINED3DFMT_A2R10G10B10:
930 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
931 vcheckGLcall("glPixelStorei");
932 storechanged = TRUE;
933 type = This->glDescription.glType;
934 fmt = This->glDescription.glFormat;
935 mem = This->resource.allocatedMemory;
937 break;
939 case WINED3DFMT_P8:
941 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
942 int row;
943 type = GL_UNSIGNED_BYTE;
944 fmt = GL_RGBA;
946 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
947 if(!mem) {
948 ERR("Out of memory\n");
949 return;
951 for(row = This->dirtyRect.top; row < This->dirtyRect.bottom; row++) {
952 d3dfmt_convert_surface(This->resource.allocatedMemory + row * pitch + This->lockedRect.left,
953 (BYTE *) mem + row * pitch * 4 + This->lockedRect.left * 4,
954 This->lockedRect.right - This->lockedRect.left,
955 CONVERT_PALETTED, This);
958 break;
960 default:
961 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
963 /* Give it a try */
964 type = This->glDescription.glType;
965 fmt = This->glDescription.glFormat;
966 mem = This->resource.allocatedMemory;
969 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
970 (This->lockedRect.bottom - This->lockedRect.top)-1,
971 fmt, type,
972 mem);
973 checkGLcall("glDrawPixels");
974 glPixelZoom(1.0,1.0);
975 vcheckGLcall("glPixelZoom");
977 glRasterPos3iv(&prev_rasterpos[0]);
978 vcheckGLcall("glRasterPos3iv");
980 /* Reset to previous pack row length */
981 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
982 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
983 if(storechanged) {
984 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
985 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
988 if(mem != This->resource.allocatedMemory) HeapFree(GetProcessHeap(), 0, mem);
989 return;
992 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
993 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
994 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
995 const char *buffername = "";
996 IWineD3DSwapChainImpl *swapchain = NULL;
997 BOOL backbuf = FALSE;
999 if (!(This->Flags & SFLAG_LOCKED)) {
1000 WARN("trying to Unlock an unlocked surf@%p\n", This);
1001 return WINED3DERR_INVALIDCALL;
1004 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
1005 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1007 if(swapchain) {
1008 int i;
1009 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
1010 if(iface == swapchain->backBuffer[i]) {
1011 backbuf = TRUE;
1012 break;
1017 if (backbuf) {
1018 buffername = "backBuffer";
1019 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
1020 buffername = "frontBuffer";
1021 } else if (iface == myDevice->depthStencilBuffer) {
1022 buffername = "depthStencilBuffer";
1023 } else if (iface == myDevice->renderTarget) {
1024 buffername = "renderTarget";
1028 if (swapchain != NULL) {
1029 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1032 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
1034 if (!(This->Flags & SFLAG_DIRTY)) {
1035 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1036 goto unlock_end;
1039 if (0 == This->resource.usage) { /* classic surface */
1041 * nothing to do
1042 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
1044 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
1046 /****************************
1047 * TODO: Render targets are 'special' and
1048 * ?some? locking needs to be passed onto the context manager
1049 * so that it becomes possible to use auxiliary buffers, pbuffers
1050 * render-to-texture, shared, cached contexts etc...
1051 * ****************************/
1052 IWineD3DSwapChainImpl *implSwapChain;
1053 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
1055 if (backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
1056 int tex;
1058 ENTER_GL();
1060 /* glDrawPixels transforms the raster position as though it was a vertex -
1061 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1062 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1063 d3ddevice_set_ortho(This->resource.wineD3DDevice);
1065 if (iface == implSwapChain->frontBuffer) {
1066 glDrawBuffer(GL_FRONT);
1067 checkGLcall("glDrawBuffer GL_FRONT");
1068 } else if (backbuf || iface == myDevice->renderTarget) {
1069 glDrawBuffer(GL_BACK);
1070 checkGLcall("glDrawBuffer GL_BACK");
1073 /* Disable higher textures before calling glDrawPixels */
1074 for(tex = 1; tex < GL_LIMITS(sampler_stages); tex++) {
1075 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1076 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + tex));
1077 checkGLcall("glActiveTextureARB");
1079 glDisable(GL_TEXTURE_2D);
1080 checkGLcall("glDisable GL_TEXTURE_2D");
1081 glDisable(GL_TEXTURE_1D);
1082 checkGLcall("glDisable GL_TEXTURE_1D");
1084 /* Activate texture 0, but don't disable it necessarilly */
1085 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1086 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1087 checkGLcall("glActiveTextureARB");
1090 /* And back buffers are not blended. Disable the depth test,
1091 that helps performance */
1092 glDisable(GL_BLEND);
1093 glDisable(GL_DEPTH_TEST);
1094 glDisable(GL_FOG);
1096 switch(wined3d_settings.rendertargetlock_mode) {
1097 case RTL_AUTO:
1098 case RTL_READDRAW:
1099 case RTL_TEXDRAW:
1100 flush_to_framebuffer_drawpixels(This);
1101 break;
1103 case RTL_READTEX:
1104 case RTL_TEXTEX:
1105 ERR("Writing to the render target with textures is not implemented yet\n");
1106 break;
1108 case RTL_DISABLE:
1110 static BOOL warned = FALSE;
1111 if(!warned) {
1112 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1113 warned = TRUE;
1116 break;
1119 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
1120 glDrawBuffer(GL_BACK);
1121 vcheckGLcall("glDrawBuffer");
1123 if(myDevice->stateBlock->renderState[D3DRS_ZENABLE] == D3DZB_TRUE ||
1124 myDevice->stateBlock->renderState[D3DRS_ZENABLE] == D3DZB_USEW) glEnable(GL_DEPTH_TEST);
1125 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
1126 if (myDevice->stateBlock->renderState[D3DRS_FOGENABLE]) glEnable(GL_FOG);
1128 LEAVE_GL();
1130 /** restore clean dirty state */
1131 IWineD3DSurface_CleanDirtyRect(iface);
1133 } else {
1134 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1136 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
1138 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
1140 if (iface == myDevice->depthStencilBuffer) {
1141 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
1142 } else {
1143 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
1146 } else {
1147 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1150 unlock_end:
1151 This->Flags &= ~SFLAG_LOCKED;
1152 memset(&This->lockedRect, 0, sizeof(RECT));
1153 return WINED3D_OK;
1156 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1157 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1158 WINED3DLOCKED_RECT lock;
1159 UINT usage;
1160 BITMAPINFO* b_info;
1161 HDC ddc;
1162 DWORD *masks;
1163 HRESULT hr;
1164 RGBQUAD col[256];
1165 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1167 TRACE("(%p)->(%p)\n",This,pHDC);
1169 /* Give more detailed info for ddraw */
1170 if (This->Flags & SFLAG_DCINUSE)
1171 return DDERR_DCALREADYCREATED;
1173 /* Can't GetDC if the surface is locked */
1174 if (This->Flags & SFLAG_LOCKED)
1175 return WINED3DERR_INVALIDCALL;
1177 memset(&lock, 0, sizeof(lock)); /* To be sure */
1179 /* Create a DIB section if there isn't a hdc yet */
1180 if(!This->hDC) {
1181 int extraline = 0;
1182 SYSTEM_INFO sysInfo;
1184 if(This->Flags & SFLAG_ACTIVELOCK) {
1185 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1188 switch (This->bytesPerPixel) {
1189 case 2:
1190 case 4:
1191 /* Allocate extra space to store the RGB bit masks. */
1192 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1193 break;
1195 case 3:
1196 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1197 break;
1199 default:
1200 /* Allocate extra space for a palette. */
1201 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1202 sizeof(BITMAPINFOHEADER)
1203 + sizeof(RGBQUAD)
1204 * (1 << (This->bytesPerPixel * 8)));
1205 break;
1208 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1209 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1210 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1211 * add an extra line to the dib section
1213 GetSystemInfo(&sysInfo);
1214 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1215 extraline = 1;
1216 TRACE("Adding an extra line to the dib section\n");
1219 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1220 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1221 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1222 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1223 b_info->bmiHeader.biSizeImage = This->currentDesc.Width * This->currentDesc.Height * This->bytesPerPixel;
1224 /* Use the full pow2 image size(assigned below) because LockRect
1225 * will need it for a full glGetTexImage call
1227 } else {
1228 b_info->bmiHeader.biWidth = This->pow2Width;
1229 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1230 b_info->bmiHeader.biSizeImage = This->resource.size;
1232 b_info->bmiHeader.biPlanes = 1;
1233 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1235 b_info->bmiHeader.biXPelsPerMeter = 0;
1236 b_info->bmiHeader.biYPelsPerMeter = 0;
1237 b_info->bmiHeader.biClrUsed = 0;
1238 b_info->bmiHeader.biClrImportant = 0;
1240 /* Get the bit masks */
1241 masks = (DWORD *) &(b_info->bmiColors);
1242 switch (This->resource.format) {
1243 case WINED3DFMT_R8G8B8:
1244 usage = DIB_RGB_COLORS;
1245 b_info->bmiHeader.biCompression = BI_RGB;
1246 break;
1248 case WINED3DFMT_X1R5G5B5:
1249 case WINED3DFMT_A1R5G5B5:
1250 case WINED3DFMT_A4R4G4B4:
1251 case WINED3DFMT_X4R4G4B4:
1252 case WINED3DFMT_R3G3B2:
1253 case WINED3DFMT_A8R3G3B2:
1254 case WINED3DFMT_A2B10G10R10:
1255 case WINED3DFMT_A8B8G8R8:
1256 case WINED3DFMT_X8B8G8R8:
1257 case WINED3DFMT_A2R10G10B10:
1258 case WINED3DFMT_R5G6B5:
1259 case WINED3DFMT_A16B16G16R16:
1260 usage = 0;
1261 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1262 masks[0] = formatEntry->redMask;
1263 masks[1] = formatEntry->greenMask;
1264 masks[2] = formatEntry->blueMask;
1265 break;
1267 default:
1268 /* Don't know palette */
1269 b_info->bmiHeader.biCompression = BI_RGB;
1270 usage = 0;
1271 break;
1274 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1275 if (ddc == 0) {
1276 HeapFree(GetProcessHeap(), 0, b_info);
1277 return HRESULT_FROM_WIN32(GetLastError());
1280 TRACE("Creating a DIB section with size %ldx%ldx%d, size=%ld\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
1281 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1282 DeleteDC(ddc);
1284 if (!This->dib.DIBsection) {
1285 ERR("CreateDIBSection failed!\n");
1286 return HRESULT_FROM_WIN32(GetLastError());
1288 HeapFree(GetProcessHeap(), 0, b_info);
1290 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1292 /* copy the existing surface to the dib section */
1293 if(This->resource.allocatedMemory) {
1294 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1295 /* We won't need that any more */
1296 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1297 } else {
1298 /* This is to make LockRect read the gl Texture although memory is allocated */
1299 This->Flags |= SFLAG_GLDIRTY;
1302 /* Use the dib section from now on */
1303 This->resource.allocatedMemory = This->dib.bitmap_data;
1305 /* Now allocate a HDC */
1306 This->hDC = CreateCompatibleDC(0);
1307 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1308 TRACE("using wined3d palette %p\n", This->palette);
1309 SelectPalette(This->hDC,
1310 This->palette ? This->palette->hpal : 0,
1311 FALSE);
1313 This->Flags |= SFLAG_DIBSECTION;
1316 /* Lock the surface */
1317 hr = IWineD3DSurface_LockRect(iface,
1318 &lock,
1319 NULL,
1321 if(FAILED(hr)) {
1322 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1323 /* keep the dib section */
1324 return hr;
1327 if(This->resource.format == WINED3DFMT_P8 ||
1328 This->resource.format == WINED3DFMT_A8P8) {
1329 unsigned int n;
1330 if(This->palette) {
1331 PALETTEENTRY ent[256];
1333 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1334 for (n=0; n<256; n++) {
1335 col[n].rgbRed = ent[n].peRed;
1336 col[n].rgbGreen = ent[n].peGreen;
1337 col[n].rgbBlue = ent[n].peBlue;
1338 col[n].rgbReserved = 0;
1340 } else {
1341 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1343 for (n=0; n<256; n++) {
1344 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1345 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1346 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1347 col[n].rgbReserved = 0;
1351 SetDIBColorTable(This->hDC, 0, 256, col);
1354 *pHDC = This->hDC;
1355 TRACE("returning %p\n",*pHDC);
1356 This->Flags |= SFLAG_DCINUSE;
1358 return WINED3D_OK;
1361 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1362 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1364 TRACE("(%p)->(%p)\n",This,hDC);
1366 if (!(This->Flags & SFLAG_DCINUSE))
1367 return D3DERR_INVALIDCALL;
1369 /* we locked first, so unlock now */
1370 IWineD3DSurface_UnlockRect(iface);
1372 This->Flags &= ~SFLAG_DCINUSE;
1374 return WINED3D_OK;
1377 /* ******************************************************
1378 IWineD3DSurface Internal (No mapping to directx api) parts follow
1379 ****************************************************** */
1381 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp) {
1382 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1383 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1385 /* Default values: From the surface */
1386 *format = formatEntry->glFormat;
1387 *internal = formatEntry->glInternal;
1388 *type = formatEntry->glType;
1389 *convert = NO_CONVERSION;
1390 *target_bpp = This->bytesPerPixel;
1392 /* Ok, now look if we have to do any conversion */
1393 switch(This->resource.format) {
1394 case WINED3DFMT_P8:
1395 /* ****************
1396 Paletted Texture
1397 **************** */
1398 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active) {
1399 *format = GL_RGBA;
1400 *internal = GL_RGBA;
1401 *type = GL_UNSIGNED_BYTE;
1402 *target_bpp = 4;
1403 if(colorkey_active) {
1404 *convert = CONVERT_PALETTED;
1405 } else {
1406 *convert = CONVERT_PALETTED_CK;
1410 break;
1412 case WINED3DFMT_R3G3B2:
1413 /* **********************
1414 GL_UNSIGNED_BYTE_3_3_2
1415 ********************** */
1416 if (colorkey_active) {
1417 /* This texture format will never be used.. So do not care about color keying
1418 up until the point in time it will be needed :-) */
1419 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1421 break;
1423 case WINED3DFMT_R5G6B5:
1424 if (colorkey_active) {
1425 *convert = CONVERT_CK_565;
1426 *format = GL_RGBA;
1427 *internal = GL_RGBA;
1428 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1430 break;
1432 case WINED3DFMT_R8G8B8:
1433 if (colorkey_active) {
1434 *convert = CONVERT_CK_RGB24;
1435 *format = GL_RGBA;
1436 *internal = GL_RGBA;
1437 *type = GL_UNSIGNED_INT_8_8_8_8;
1438 *target_bpp = 4;
1440 break;
1442 case WINED3DFMT_X8R8G8B8:
1443 if (colorkey_active) {
1444 *convert = CONVERT_RGB32_888;
1445 *format = GL_RGBA;
1446 *internal = GL_RGBA;
1447 *type = GL_UNSIGNED_INT_8_8_8_8;
1449 break;
1450 #if 0
1451 /* Not sure if we should do color keying on Alpha-Enabled surfaces */
1452 case WINED3DFMT_A4R4G4B4:
1453 if (colorkey_active)
1455 *convert = CONVERT_CK_4444_ARGB;
1456 *format = GL_RGBA;
1457 *internal = GL_RGBA;
1458 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1460 break;
1462 case WINED3DFMT_A1R5G5B5:
1463 if (colorkey_active)
1465 *convert = CONVERT_CK_1555;
1468 case WINED3DFMT_A8R8G8B8:
1469 if (colorkey_active)
1471 *convert = CONVERT_CK_8888_ARGB;
1472 *format = GL_RGBA;
1473 *internal = GL_RGBA;
1474 *type = GL_UNSIGNED_INT_8_8_8_8;
1476 break;
1477 #endif
1478 default:
1479 break;
1482 return WINED3D_OK;
1485 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1486 TRACE("(%p)->(%p),(%ld,%d,%p)\n", src, dst, len, convert, surf);
1488 switch (convert) {
1489 case NO_CONVERSION:
1491 memcpy(dst, src, len * surf->bytesPerPixel);
1492 break;
1494 case CONVERT_PALETTED:
1495 case CONVERT_PALETTED_CK:
1497 IWineD3DPaletteImpl* pal = surf->palette;
1498 BYTE table[256][4];
1499 unsigned int i;
1500 unsigned int x;
1502 if( pal == NULL) {
1503 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1506 if (pal == NULL) {
1507 /* Still no palette? Use the device's palette */
1508 /* Get the surface's palette */
1509 for (i = 0; i < 256; i++) {
1510 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1512 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1513 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1514 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1515 if ((convert == CONVERT_PALETTED_CK) &&
1516 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1517 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1518 /* We should maybe here put a more 'neutral' color than the standard bright purple
1519 one often used by application to prevent the nice purple borders when bi-linear
1520 filtering is on */
1521 table[i][3] = 0x00;
1522 } else {
1523 table[i][3] = 0xFF;
1526 } else {
1527 TRACE("Using surface palette %p\n", pal);
1528 /* Get the surface's palette */
1529 for (i = 0; i < 256; i++) {
1530 table[i][0] = pal->palents[i].peRed;
1531 table[i][1] = pal->palents[i].peGreen;
1532 table[i][2] = pal->palents[i].peBlue;
1533 if ((convert == CONVERT_PALETTED_CK) &&
1534 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1535 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1536 /* We should maybe here put a more 'neutral' color than the standard bright purple
1537 one often used by application to prevent the nice purple borders when bi-linear
1538 filtering is on */
1539 table[i][3] = 0x00;
1540 } else {
1541 table[i][3] = 0xFF;
1546 for (x = 0; x < len; x++) {
1547 BYTE color = *src++;
1548 *dst++ = table[color][0];
1549 *dst++ = table[color][1];
1550 *dst++ = table[color][2];
1551 *dst++ = table[color][3];
1554 break;
1556 case CONVERT_CK_565:
1558 /* Converting the 565 format in 5551 packed to emulate color-keying.
1560 Note : in all these conversion, it would be best to average the averaging
1561 pixels to get the color of the pixel that will be color-keyed to
1562 prevent 'color bleeding'. This will be done later on if ever it is
1563 too visible.
1565 Note2: when using color-keying + alpha, are the alpha bits part of the
1566 color-space or not ?
1568 unsigned int x;
1569 WORD *Source = (WORD *) src;
1570 WORD *Dest = (WORD *) dst;
1572 TRACE("Color keyed 565\n");
1574 for (x = 0; x < len; x++ ) {
1575 WORD color = *Source++;
1576 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1577 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1578 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1579 *Dest |= 0x0001;
1581 Dest++;
1584 break;
1586 case CONVERT_CK_1555:
1588 unsigned int x;
1589 WORD *Source = (WORD *) src;
1590 WORD *Dest = (WORD *) dst;
1592 for (x = 0; x < len * sizeof(WORD); x+=sizeof(WORD)) {
1593 WORD color = *Source++;
1594 *Dest = (color & 0x7FFF);
1595 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1596 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1597 *Dest |= (color & 0x8000);
1598 Dest++;
1601 break;
1603 case CONVERT_CK_4444_ARGB:
1605 /* Move the four Alpha bits... */
1606 unsigned int x;
1607 WORD *Source = (WORD *) src;
1608 WORD *Dest = (WORD *) dst;
1610 for (x = 0; x < len; x++) {
1611 WORD color = *Source++;
1612 *dst = (color & 0x0FFF) << 4;
1613 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1614 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1615 *Dest |= (color & 0xF000) >> 12;
1616 Dest++;
1618 } break;
1620 default:
1621 ERR("Unsupported conversation type %d\n", convert);
1624 return WINED3D_OK;
1627 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1628 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1630 if (This->Flags & SFLAG_INTEXTURE) {
1631 TRACE("Surface already in texture\n");
1632 return WINED3D_OK;
1634 if (!(This->Flags & SFLAG_DIRTY)) {
1635 TRACE("surface isn't dirty\n");
1636 return WINED3D_OK;
1639 This->Flags &= ~SFLAG_DIRTY;
1641 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1642 * These resources are not bound by device size or format restrictions. Because of this,
1643 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1644 * However, these resources can always be created, locked, and copied.
1646 if (This->resource.pool == WINED3DPOOL_SCRATCH)
1648 FIXME("(%p) Operation not supported for scratch textures\n",This);
1649 return WINED3DERR_INVALIDCALL;
1652 if (This->Flags & SFLAG_INPBUFFER) {
1653 ENTER_GL();
1655 if (This->glDescription.level != 0)
1656 FIXME("Surface in texture is only supported for level 0\n");
1657 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1658 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1659 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1660 This->resource.format == WINED3DFMT_DXT5)
1661 FIXME("Format %d not supported\n", This->resource.format);
1662 else {
1663 GLint prevRead;
1664 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1665 vcheckGLcall("glGetIntegerv");
1666 glReadBuffer(GL_BACK);
1667 vcheckGLcall("glReadBuffer");
1669 glCopyTexImage2D(This->glDescription.target,
1670 This->glDescription.level,
1671 This->glDescription.glFormatInternal,
1674 This->currentDesc.Width,
1675 This->currentDesc.Height,
1678 checkGLcall("glCopyTexImage2D");
1679 glReadBuffer(prevRead);
1680 vcheckGLcall("glReadBuffer");
1681 TRACE("Updating target %d\n", This->glDescription.target);
1682 This->Flags |= SFLAG_INTEXTURE;
1684 LEAVE_GL();
1685 return WINED3D_OK;
1688 /* TODO: Compressed non-power 2 support */
1690 if (This->resource.format == WINED3DFMT_DXT1 ||
1691 This->resource.format == WINED3DFMT_DXT2 ||
1692 This->resource.format == WINED3DFMT_DXT3 ||
1693 This->resource.format == WINED3DFMT_DXT4 ||
1694 This->resource.format == WINED3DFMT_DXT5) {
1695 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1696 FIXME("Using DXT1/3/5 without advertized support\n");
1697 } else if (This->resource.allocatedMemory) {
1698 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1699 This->glDescription.target,
1700 This->glDescription.level,
1701 This->glDescription.glFormatInternal,
1702 This->currentDesc.Width,
1703 This->currentDesc.Height,
1705 This->resource.size,
1706 This->resource.allocatedMemory);
1708 ENTER_GL();
1710 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1711 This->glDescription.level,
1712 This->glDescription.glFormatInternal,
1713 This->currentDesc.Width,
1714 This->currentDesc.Height,
1716 This->resource.size,
1717 This->resource.allocatedMemory);
1718 checkGLcall("glCommpressedTexImage2D");
1720 LEAVE_GL();
1722 if(!(This->Flags & SFLAG_DONOTFREE)){
1723 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1724 This->resource.allocatedMemory = NULL;
1727 } else {
1728 GLenum format, internal, type;
1729 CONVERT_TYPES convert;
1730 int bpp;
1731 BYTE *mem;
1733 d3dfmt_get_conv(This, TRUE /* We need color keying */, &format, &internal, &type, &convert, &bpp);
1735 if((convert != NO_CONVERSION) &&
1736 This->resource.allocatedMemory) {
1737 int width = This->glRect.right - This->glRect.left;
1738 int height = This->glRect.bottom - This->glRect.top;
1739 int row;
1741 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
1742 if(!mem) {
1743 ERR("Out of memory %d, %d!\n", width, height);
1744 return WINED3DERR_OUTOFVIDEOMEMORY;
1747 for(row = This->glRect.top; row < This->glRect.bottom; row++) {
1748 BYTE *cur = This->resource.allocatedMemory + row * This->pow2Width * This->bytesPerPixel;
1749 d3dfmt_convert_surface(cur + This->glRect.left * This->bytesPerPixel,
1750 mem + row * width * bpp,
1751 width,
1752 convert,
1753 This);
1755 This->Flags |= SFLAG_CONVERTED;
1756 } else {
1757 This->Flags &= ~SFLAG_CONVERTED;
1758 mem = This->resource.allocatedMemory;
1761 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1762 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE) ) {
1765 TRACE("non power of two support\n");
1766 ENTER_GL();
1767 TRACE("(%p) Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n", This,
1768 This->glDescription.target,
1769 This->glDescription.level,
1770 debug_d3dformat(This->resource.format),
1771 This->glDescription.glFormatInternal,
1772 This->pow2Width,
1773 This->pow2Height,
1775 This->glDescription.glFormat,
1776 This->glDescription.glType,
1777 NULL);
1779 glTexImage2D(This->glDescription.target,
1780 This->glDescription.level,
1781 This->glDescription.glFormatInternal,
1782 This->pow2Width,
1783 This->pow2Height,
1784 0/*border*/,
1785 This->glDescription.glFormat,
1786 This->glDescription.glType,
1787 NULL);
1789 checkGLcall("glTexImage2D");
1790 if (This->resource.allocatedMemory != NULL) {
1791 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1792 /* And map the non-power two data into the top left corner */
1793 glTexSubImage2D(
1794 This->glDescription.target,
1795 This->glDescription.level,
1796 0 /* xoffset */,
1797 0 /* ysoffset */ ,
1798 This->currentDesc.Width,
1799 This->currentDesc.Height,
1800 This->glDescription.glFormat,
1801 This->glDescription.glType,
1802 This->resource.allocatedMemory
1804 checkGLcall("glTexSubImage2D");
1806 LEAVE_GL();
1808 } else {
1810 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%ld, h=%ld,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1811 This->glDescription.target,
1812 This->glDescription.level,
1813 debug_d3dformat(This->resource.format),
1814 This->glDescription.glFormatInternal,
1815 This->glRect.right - This->glRect.left,
1816 This->glRect.bottom - This->glRect.top,
1818 This->glDescription.glFormat,
1819 This->glDescription.glType,
1820 mem);
1822 ENTER_GL();
1824 /* OK, create the texture */
1825 glTexImage2D(This->glDescription.target,
1826 This->glDescription.level,
1827 internal,
1828 This->glRect.right - This->glRect.left,
1829 This->glRect.bottom - This->glRect.top,
1830 0 /* border */,
1831 format,
1832 type,
1833 mem);
1835 checkGLcall("glTexImage2D");
1837 LEAVE_GL();
1839 if(mem != This->resource.allocatedMemory)
1840 HeapFree(GetProcessHeap(), 0, mem);
1842 #if 0
1844 static unsigned int gen = 0;
1845 char buffer[4096];
1846 ++gen;
1847 if ((gen % 10) == 0) {
1848 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1849 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1852 * debugging crash code
1853 if (gen == 250) {
1854 void** test = NULL;
1855 *test = 0;
1859 #endif
1860 if(!(This->Flags & SFLAG_DONOTFREE)){
1861 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1862 This->resource.allocatedMemory = NULL;
1867 return WINED3D_OK;
1870 #include <errno.h>
1871 #include <stdio.h>
1872 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1873 FILE* f = NULL;
1874 UINT i, y;
1875 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1876 char *allocatedMemory;
1877 char *textureRow;
1878 IWineD3DSwapChain *swapChain = NULL;
1879 int width, height;
1880 GLuint tmpTexture;
1881 DWORD color;
1882 /*FIXME:
1883 Textures my not be stored in ->allocatedgMemory and a GlTexture
1884 so we should lock the surface before saving a snapshot, or at least check that
1886 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1887 by calling GetTexImage and in compressed form by calling
1888 GetCompressedTexImageARB. Queried compressed images can be saved and
1889 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1890 texture images do not need to be processed by the GL and should
1891 significantly improve texture loading performance relative to uncompressed
1892 images. */
1894 /* Setup the width and height to be the internal texture width and height. */
1895 width = This->pow2Width;
1896 height = This->pow2Height;
1897 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1898 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1900 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1901 /* we don't want to interfere with the back buffer so read the data into a temporary texture and then save the data out of the temporary texture */
1902 GLint prevRead;
1903 ENTER_GL();
1904 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1905 glEnable(GL_TEXTURE_2D);
1907 glGenTextures(1, &tmpTexture);
1908 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1910 glTexImage2D(GL_TEXTURE_2D,
1912 GL_RGBA,
1913 width,
1914 height,
1915 0/*border*/,
1916 GL_RGBA,
1917 GL_UNSIGNED_INT_8_8_8_8_REV,
1918 NULL);
1920 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1921 vcheckGLcall("glGetIntegerv");
1922 glReadBuffer(GL_BACK);
1923 vcheckGLcall("glReadBuffer");
1924 glCopyTexImage2D(GL_TEXTURE_2D,
1926 GL_RGBA,
1929 width,
1930 height,
1933 checkGLcall("glCopyTexImage2D");
1934 glReadBuffer(prevRead);
1935 LEAVE_GL();
1937 } else { /* bind the real texture */
1938 IWineD3DSurface_PreLoad(iface);
1940 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1941 ENTER_GL();
1942 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1943 glGetTexImage(GL_TEXTURE_2D,
1944 This->glDescription.level,
1945 GL_RGBA,
1946 GL_UNSIGNED_INT_8_8_8_8_REV,
1947 allocatedMemory);
1948 checkGLcall("glTexImage2D");
1949 if (tmpTexture) {
1950 glBindTexture(GL_TEXTURE_2D, 0);
1951 glDeleteTextures(1, &tmpTexture);
1953 LEAVE_GL();
1955 f = fopen(filename, "w+");
1956 if (NULL == f) {
1957 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1958 return WINED3DERR_INVALIDCALL;
1960 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1961 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1962 /* TGA header */
1963 fputc(0,f);
1964 fputc(0,f);
1965 fputc(2,f);
1966 fputc(0,f);
1967 fputc(0,f);
1968 fputc(0,f);
1969 fputc(0,f);
1970 fputc(0,f);
1971 fputc(0,f);
1972 fputc(0,f);
1973 fputc(0,f);
1974 fputc(0,f);
1975 /* short width*/
1976 fwrite(&width,2,1,f);
1977 /* short height */
1978 fwrite(&height,2,1,f);
1979 /* format rgba */
1980 fputc(0x20,f);
1981 fputc(0x28,f);
1982 /* raw data */
1983 /* if the data is upside down if we've fetched it from a back buffer, so it needs flipping again to make it the correct way up*/
1984 if(swapChain)
1985 textureRow = allocatedMemory + (width * (height - 1) *4);
1986 else
1987 textureRow = allocatedMemory;
1988 for (y = 0 ; y < height; y++) {
1989 for (i = 0; i < width; i++) {
1990 color = *((DWORD*)textureRow);
1991 fputc((color >> 16) & 0xFF, f); /* B */
1992 fputc((color >> 8) & 0xFF, f); /* G */
1993 fputc((color >> 0) & 0xFF, f); /* R */
1994 fputc((color >> 24) & 0xFF, f); /* A */
1995 textureRow += 4;
1997 /* take two rows of the pointer to the texture memory */
1998 if(swapChain)
1999 (textureRow-= width << 3);
2002 TRACE("Closing file\n");
2003 fclose(f);
2005 if(swapChain) {
2006 IWineD3DSwapChain_Release(swapChain);
2008 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2009 return WINED3D_OK;
2012 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
2013 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2014 This->Flags &= ~SFLAG_DIRTY;
2015 This->dirtyRect.left = This->currentDesc.Width;
2016 This->dirtyRect.top = This->currentDesc.Height;
2017 This->dirtyRect.right = 0;
2018 This->dirtyRect.bottom = 0;
2019 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
2020 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2021 return WINED3D_OK;
2025 * Slightly inefficient way to handle multiple dirty rects but it works :)
2027 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2028 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2029 IWineD3DBaseTexture *baseTexture = NULL;
2030 This->Flags |= SFLAG_DIRTY;
2031 if (NULL != pDirtyRect) {
2032 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2033 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2034 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2035 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2036 } else {
2037 This->dirtyRect.left = 0;
2038 This->dirtyRect.top = 0;
2039 This->dirtyRect.right = This->currentDesc.Width;
2040 This->dirtyRect.bottom = This->currentDesc.Height;
2042 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2043 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2044 /* if the container is a basetexture then mark it dirty. */
2045 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2046 TRACE("Passing to conatiner\n");
2047 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2048 IWineD3DBaseTexture_Release(baseTexture);
2050 return WINED3D_OK;
2053 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2054 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2056 TRACE("This %p, container %p\n", This, container);
2058 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2060 TRACE("Setting container to %p from %p\n", container, This->container);
2061 This->container = container;
2063 return WINED3D_OK;
2066 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2067 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2068 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2070 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2071 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2072 return WINED3DERR_INVALIDCALL;
2075 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2076 if (format == WINED3DFMT_UNKNOWN) {
2077 This->resource.size = 0;
2078 } else if (format == WINED3DFMT_DXT1) {
2079 /* DXT1 is half byte per pixel */
2080 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2082 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2083 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2084 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2085 } else {
2086 This->resource.size = (This->pow2Width * formatEntry->bpp) * This->pow2Height;
2090 /* Setup some glformat defaults */
2091 This->glDescription.glFormat = formatEntry->glFormat;
2092 This->glDescription.glFormatInternal = formatEntry->glInternal;
2093 This->glDescription.glType = formatEntry->glType;
2095 if (format != WINED3DFMT_UNKNOWN) {
2096 This->bytesPerPixel = formatEntry->bpp;
2097 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
2098 } else {
2099 This->bytesPerPixel = 0;
2100 This->pow2Size = 0;
2103 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2105 This->resource.format = format;
2107 TRACE("(%p) : Size %d, pow2Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This, This->resource.size, This->pow2Size, This->bytesPerPixel, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType);
2109 return WINED3D_OK;
2112 /* TODO: replace this function with context management routines */
2113 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2114 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2116 if(inPBuffer) {
2117 This->Flags |= SFLAG_INPBUFFER;
2118 } else {
2119 This->Flags &= ~SFLAG_INPBUFFER;
2122 if(inTexture) {
2123 This->Flags |= SFLAG_INTEXTURE;
2124 } else {
2125 This->Flags &= ~SFLAG_INTEXTURE;
2128 return WINED3D_OK;
2131 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2132 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2133 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2134 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
2136 /* Flipping is only supported on RenderTargets */
2137 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2139 if(override) {
2140 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2141 * FIXME("(%p) Target override is not supported by now\n", This);
2142 * Additionally, it isn't really possible to support triple-buffering
2143 * properly on opengl at all
2147 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2148 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2151 /* Not called from the VTable */
2152 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2153 D3DRECT rect;
2154 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2155 IWineD3DSwapChainImpl *swapchain = NULL;
2156 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2157 BOOL SrcOK = TRUE;
2159 TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2161 /* Get the swapchain. One of the surfaces has to be a primary surface */
2162 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2163 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2164 else if(Src) {
2165 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2166 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2167 else return WINED3DERR_INVALIDCALL;
2168 } else {
2169 swapchain = NULL;
2172 if (DestRect) {
2173 rect.x1 = DestRect->left;
2174 rect.y1 = DestRect->top;
2175 rect.x2 = DestRect->right;
2176 rect.y2 = DestRect->bottom;
2177 } else {
2178 rect.x1 = 0;
2179 rect.y1 = 0;
2180 rect.x2 = This->currentDesc.Width;
2181 rect.y2 = This->currentDesc.Height;
2184 /* Half-life does a Blt from the back buffer to the front buffer,
2185 * Full surface size, no flags... Use present instead
2187 if(Src)
2189 /* First, check if we can do a Flip */
2191 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2192 if( SrcRect ) {
2193 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2194 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2195 SrcOK = TRUE;
2197 } else {
2198 SrcOK = TRUE;
2201 /* Check the Destination rect and the surface sizes */
2202 if(SrcOK &&
2203 (rect.x1 == 0) && (rect.y1 == 0) &&
2204 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2205 (This->currentDesc.Width == Src->currentDesc.Width) &&
2206 (This->currentDesc.Height == Src->currentDesc.Height)) {
2207 /* These flags are unimportant for the flag check, remove them */
2209 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2210 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2212 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2214 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2215 * take very long, while a flip is fast.
2216 * This applies to Half-Life, which does such Blts every time it finished
2217 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2218 * menu. This is also used by all apps when they do windowed rendering
2220 * The problem is that flipping is not really the same as copying. After a
2221 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2222 * untouched. Therefore it's necessary to override the swap effect
2223 * and to set it back after the flip.
2226 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2228 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2229 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2230 NULL, NULL, 0, NULL);
2232 swapchain->presentParms.SwapEffect = orig_swap;
2234 return WINED3D_OK;
2239 /* Blt from texture to rendertarget? */
2240 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2241 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2243 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2244 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2245 float glTexCoord[4];
2246 DWORD oldCKey;
2247 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2248 GLint alphafunc;
2249 GLclampf alpharef;
2250 GLint oldStencil;
2251 RECT SourceRectangle;
2252 GLint oldDraw;
2254 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2256 if(SrcRect) {
2257 SourceRectangle.left = SrcRect->left;
2258 SourceRectangle.right = SrcRect->right;
2259 SourceRectangle.top = SrcRect->top;
2260 SourceRectangle.bottom = SrcRect->bottom;
2261 } else {
2262 SourceRectangle.left = 0;
2263 SourceRectangle.right = Src->currentDesc.Width;
2264 SourceRectangle.top = 0;
2265 SourceRectangle.bottom = Src->currentDesc.Height;
2268 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2269 /* Fall back to software */
2270 WARN("(%p) Source texture area (%ld,%ld)-(%ld,%ld) is too big\n", Src,
2271 SourceRectangle.left, SourceRectangle.top,
2272 SourceRectangle.right, SourceRectangle.bottom);
2273 return WINED3DERR_INVALIDCALL;
2276 /* Color keying: Check if we have to do a color keyed blt,
2277 * and if not check if a color key is activated.
2279 oldCKey = Src->CKeyFlags;
2280 if(!(Flags & DDBLT_KEYSRC) &&
2281 Src->CKeyFlags & DDSD_CKSRCBLT) {
2282 /* Ok, the surface has a color key, but we shall not use it -
2283 * Deactivate it for now and dirtify the surface to reload it
2285 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2286 Src->Flags |= SFLAG_DIRTY;
2289 /* Now load the surface */
2290 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2292 ENTER_GL();
2294 /* Save all the old stuff until we have a proper opengl state manager */
2295 oldLight = glIsEnabled(GL_LIGHTING);
2296 oldFog = glIsEnabled(GL_FOG);
2297 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2298 oldBlend = glIsEnabled(GL_BLEND);
2299 oldCull = glIsEnabled(GL_CULL_FACE);
2300 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2301 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2303 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2304 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2305 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2306 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2308 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2309 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2310 TRACE("Drawing to front buffer\n");
2311 glDrawBuffer(GL_FRONT);
2312 checkGLcall("glDrawBuffer GL_FRONT");
2315 /* Unbind the old texture */
2316 glBindTexture(GL_TEXTURE_2D, 0);
2318 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2319 /* We use texture unit 0 for blts */
2320 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2321 checkGLcall("glActiveTextureARB");
2322 } else {
2323 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2326 /* Disable some fancy graphics effects */
2327 glDisable(GL_LIGHTING);
2328 checkGLcall("glDisable GL_LIGHTING");
2329 glDisable(GL_DEPTH_TEST);
2330 checkGLcall("glDisable GL_DEPTH_TEST");
2331 glDisable(GL_FOG);
2332 checkGLcall("glDisable GL_FOG");
2333 glDisable(GL_BLEND);
2334 checkGLcall("glDisable GL_BLEND");
2335 glDisable(GL_CULL_FACE);
2336 checkGLcall("glDisable GL_CULL_FACE");
2337 glDisable(GL_STENCIL_TEST);
2338 checkGLcall("glDisable GL_STENCIL_TEST");
2340 /* Ok, we need 2d textures, but not 1D or 3D */
2341 glDisable(GL_TEXTURE_1D);
2342 checkGLcall("glDisable GL_TEXTURE_1D");
2343 glEnable(GL_TEXTURE_2D);
2344 checkGLcall("glEnable GL_TEXTURE_2D");
2345 glDisable(GL_TEXTURE_3D);
2346 checkGLcall("glDisable GL_TEXTURE_3D");
2348 /* Bind the texture */
2349 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2350 checkGLcall("glBindTexture");
2352 glEnable(GL_SCISSOR_TEST);
2354 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2356 /* No filtering for blts */
2357 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2358 GL_NEAREST);
2359 checkGLcall("glTexParameteri");
2360 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2361 GL_NEAREST);
2362 checkGLcall("glTexParameteri");
2363 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2364 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2365 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2366 checkGLcall("glTexEnvi");
2368 /* This is for color keying */
2369 if(Flags & DDBLT_KEYSRC) {
2370 glEnable(GL_ALPHA_TEST);
2371 checkGLcall("glEnable GL_ALPHA_TEST");
2372 glAlphaFunc(GL_NOTEQUAL, 0.0);
2373 checkGLcall("glAlphaFunc\n");
2374 } else {
2375 glDisable(GL_ALPHA_TEST);
2376 checkGLcall("glDisable GL_ALPHA_TEST");
2379 /* Draw a textured quad
2381 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2383 glBegin(GL_QUADS);
2385 glColor3d(1.0f, 1.0f, 1.0f);
2386 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2387 glVertex3f(rect.x1,
2388 rect.y1,
2389 0.0);
2391 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2392 glVertex3f(rect.x1, rect.y2, 0.0);
2394 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2395 glVertex3f(rect.x2,
2396 rect.y2,
2397 0.0);
2399 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2400 glVertex3f(rect.x2,
2401 rect.y1,
2402 0.0);
2403 glEnd();
2404 checkGLcall("glEnd");
2406 /* Unbind the texture */
2407 glBindTexture(GL_TEXTURE_2D, 0);
2408 checkGLcall("glEnable glBindTexture");
2410 /* Restore the old settings */
2411 if(oldLight) {
2412 glEnable(GL_LIGHTING);
2413 checkGLcall("glEnable GL_LIGHTING");
2415 if(oldFog) {
2416 glEnable(GL_FOG);
2417 checkGLcall("glEnable GL_FOG");
2419 if(oldDepth) {
2420 glEnable(GL_DEPTH_TEST);
2421 checkGLcall("glEnable GL_DEPTH_TEST");
2423 if(oldBlend) {
2424 glEnable(GL_BLEND);
2425 checkGLcall("glEnable GL_BLEND");
2427 if(oldCull) {
2428 glEnable(GL_CULL_FACE);
2429 checkGLcall("glEnable GL_CULL_FACE");
2431 if(oldStencil) {
2432 glEnable(GL_STENCIL_TEST);
2433 checkGLcall("glEnable GL_STENCIL_TEST");
2435 if(!oldAlpha) {
2436 glDisable(GL_ALPHA_TEST);
2437 checkGLcall("glDisable GL_ALPHA_TEST");
2438 } else {
2439 glEnable(GL_ALPHA_TEST);
2440 checkGLcall("glEnable GL_ALPHA_TEST");
2443 glAlphaFunc(alphafunc, alpharef);
2444 checkGLcall("glAlphaFunc\n");
2446 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2447 glDrawBuffer(oldDraw);
2450 /* Restore the color key */
2451 if(oldCKey != Src->CKeyFlags) {
2452 Src->CKeyFlags = oldCKey;
2453 Src->Flags |= SFLAG_DIRTY;
2456 LEAVE_GL();
2458 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2459 This->Flags |= SFLAG_GLDIRTY;
2461 return WINED3D_OK;
2465 /* Blt from rendertarget to texture? */
2466 if( (SrcSurface == swapchain->frontBuffer) ||
2467 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2468 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2469 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2470 UINT row;
2471 D3DRECT srect;
2472 float xrel, yrel;
2474 TRACE("Blt from rendertarget to texture\n");
2476 /* Call preload for the surface to make sure it isn't dirty */
2477 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2479 if(SrcRect) {
2480 srect.x1 = SrcRect->left;
2481 srect.y1 = SrcRect->top;
2482 srect.x2 = SrcRect->right;
2483 srect.y2 = SrcRect->bottom;
2484 } else {
2485 srect.x1 = 0;
2486 srect.y1 = 0;
2487 srect.x2 = Src->currentDesc.Width;
2488 srect.y2 = Src->currentDesc.Height;
2491 ENTER_GL();
2493 /* Bind the target texture */
2494 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2495 checkGLcall("glBindTexture");
2496 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2497 glReadBuffer(GL_BACK);
2498 } else {
2499 glReadBuffer(GL_FRONT);
2501 checkGLcall("glReadBuffer");
2503 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2504 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2506 /* I have to process this row by row to swap the image,
2507 * otherwise it would be upside down, so streching in y direction
2508 * doesn't cost extra time
2510 * However, streching in x direction can be avoided if not necessary
2512 for(row = rect.y1; row < rect.y2; row++) {
2513 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2514 /* Well, that stuff works, but it's very slow.
2515 * find a better way instead
2517 UINT col;
2518 for(col = rect.x1; col < rect.x2; col++) {
2519 glCopyTexSubImage2D(GL_TEXTURE_2D,
2520 0, /* level */
2521 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2522 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2523 1, 1);
2525 } else {
2526 glCopyTexSubImage2D(GL_TEXTURE_2D,
2527 0, /* level */
2528 rect.x1, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2529 srect.x1, Src->currentDesc.Height - srect.y2 + row * yrel,
2530 rect.x2, 1);
2534 vcheckGLcall("glCopyTexSubImage2D");
2535 LEAVE_GL();
2537 if(!(This->Flags & SFLAG_DONOTFREE)) {
2538 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2539 This->resource.allocatedMemory = NULL;
2540 } else {
2541 This->Flags |= SFLAG_GLDIRTY;
2544 return WINED3D_OK;
2549 if (Flags & DDBLT_COLORFILL) {
2550 /* This is easy to handle for the D3D Device... */
2551 DWORD color;
2552 IWineD3DSwapChainImpl *implSwapChain;
2554 TRACE("Colorfill\n");
2556 /* The color as given in the Blt function is in the format of the frame-buffer...
2557 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2559 if (This->resource.format == WINED3DFMT_P8) {
2560 if (This->palette) {
2561 color = ((0xFF000000) |
2562 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2563 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2564 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2565 } else {
2566 color = 0xFF000000;
2569 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2570 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2571 color = 0xFFFFFFFF;
2572 } else {
2573 color = ((0xFF000000) |
2574 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2575 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2576 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2579 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2580 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2581 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2583 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2584 color = DDBltFx->u5.dwFillColor;
2586 else {
2587 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2588 return WINED3DERR_INVALIDCALL;
2591 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2592 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2593 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2594 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2595 glDrawBuffer(GL_BACK);
2596 checkGLcall("glDrawBuffer(GL_BACK)");
2598 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2599 glDrawBuffer(GL_FRONT);
2600 checkGLcall("glDrawBuffer(GL_FRONT)");
2602 else {
2603 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2604 return WINED3DERR_INVALIDCALL;
2607 TRACE("(%p) executing Render Target override, color = %lx\n", This, color);
2609 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2610 1 /* Number of rectangles */,
2611 &rect,
2612 D3DCLEAR_TARGET,
2613 color,
2614 0.0 /* Z */,
2615 0 /* Stencil */);
2617 /* Restore the original draw buffer */
2618 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2619 glDrawBuffer(GL_BACK);
2620 vcheckGLcall("glDrawBuffer");
2623 return WINED3D_OK;
2626 /* Default: Fall back to the generic blt */
2627 return WINED3DERR_INVALIDCALL;
2630 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2631 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2632 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2633 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2634 TRACE("(%p): Usage is %08lx\n", This, This->resource.usage);
2636 /* Special cases for RenderTargets */
2637 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2638 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2639 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2642 /* For the rest call the X11 surface implementation.
2643 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2644 * other Blts are rather rare
2646 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2649 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2650 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2651 TRACE("(%p)->(%lx)\n", This, Flags);
2653 switch (Flags)
2655 case DDGBS_CANBLT:
2656 case DDGBS_ISBLTDONE:
2657 return DD_OK;
2659 default:
2660 return DDERR_INVALIDPARAMS;
2664 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2665 /* XXX: DDERR_INVALIDSURFACETYPE */
2667 TRACE("(%p)->(%08lx)\n",iface,Flags);
2668 switch (Flags) {
2669 case DDGFS_CANFLIP:
2670 case DDGFS_ISFLIPDONE:
2671 return DD_OK;
2673 default:
2674 return DDERR_INVALIDPARAMS;
2678 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2679 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2680 TRACE("(%p)\n", This);
2682 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2685 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2686 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2687 TRACE("(%p)\n", This);
2689 /* So far we don't lose anything :) */
2690 This->Flags &= ~SFLAG_LOST;
2691 return WINED3D_OK;
2694 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2695 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2696 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2697 TRACE("(%p)->(%ld, %ld, %p, %p, %08lx\n", iface, dstx, dsty, Source, rsrc, trans);
2699 /* Special cases for RenderTargets */
2700 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2701 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2703 RECT SrcRect, DstRect;
2705 if(rsrc) {
2706 SrcRect.left = rsrc->left;
2707 SrcRect.top= rsrc->top;
2708 SrcRect.bottom = rsrc->bottom;
2709 SrcRect.right = rsrc->right;
2710 } else {
2711 SrcRect.left = 0;
2712 SrcRect.top = 0;
2713 SrcRect.right = srcImpl->currentDesc.Width;
2714 SrcRect.bottom = srcImpl->currentDesc.Height;
2717 DstRect.left = dstx;
2718 DstRect.top=dsty;
2719 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2720 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2722 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, 0, NULL) == WINED3D_OK) return WINED3D_OK;
2726 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2729 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2730 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2731 TRACE("(%p)->(%p)\n", This, Pal);
2733 *Pal = (IWineD3DPalette *) This->palette;
2734 return DD_OK;
2737 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2738 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2739 RGBQUAD col[256];
2740 IWineD3DPaletteImpl *pal = This->palette;
2741 unsigned int n;
2742 TRACE("(%p)\n", This);
2744 if(This->resource.format == WINED3DFMT_P8 ||
2745 This->resource.format == WINED3DFMT_A8P8)
2747 TRACE("Dirtifying surface\n");
2748 This->Flags |= SFLAG_DIRTY;
2751 if(This->Flags & SFLAG_DIBSECTION) {
2752 TRACE("(%p): Updating the hdc's palette\n", This);
2753 for (n=0; n<256; n++) {
2754 if(pal) {
2755 col[n].rgbRed = pal->palents[n].peRed;
2756 col[n].rgbGreen = pal->palents[n].peGreen;
2757 col[n].rgbBlue = pal->palents[n].peBlue;
2758 } else {
2759 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2760 /* Use the default device palette */
2761 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2762 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2763 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2765 col[n].rgbReserved = 0;
2767 SetDIBColorTable(This->hDC, 0, 256, col);
2770 return WINED3D_OK;
2773 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2774 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2775 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2776 TRACE("(%p)->(%p)\n", This, Pal);
2778 if(This->palette != NULL)
2779 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2780 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2782 if(PalImpl != NULL) {
2783 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2784 /* Set the device's main palette if the palette
2785 * wasn't a primary palette before
2787 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2788 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2789 unsigned int i;
2791 for(i=0; i < 256; i++) {
2792 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2796 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2799 This->palette = PalImpl;
2801 return IWineD3DSurface_RealizePalette(iface);
2804 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2805 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2806 BOOL dirtify = FALSE;
2807 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
2809 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2810 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
2811 return DDERR_INVALIDPARAMS;
2814 /* Dirtify the surface, but only if a key was changed */
2815 if(CKey) {
2816 switch (Flags & ~DDCKEY_COLORSPACE) {
2817 case DDCKEY_DESTBLT:
2818 if(!(This->CKeyFlags & DDSD_CKDESTBLT)) {
2819 dirtify = TRUE;
2820 } else {
2821 dirtify = memcmp(&This->DestBltCKey, CKey, sizeof(*CKey) ) != 0;
2823 This->DestBltCKey = *CKey;
2824 This->CKeyFlags |= DDSD_CKDESTBLT;
2825 break;
2827 case DDCKEY_DESTOVERLAY:
2828 if(!(This->CKeyFlags & DDSD_CKDESTOVERLAY)) {
2829 dirtify = TRUE;
2830 } else {
2831 dirtify = memcmp(&This->DestOverlayCKey, CKey, sizeof(*CKey)) != 0;
2833 This->DestOverlayCKey = *CKey;
2834 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2835 break;
2837 case DDCKEY_SRCOVERLAY:
2838 if(!(This->CKeyFlags & DDSD_CKSRCOVERLAY)) {
2839 dirtify = TRUE;
2840 } else {
2841 dirtify = memcmp(&This->SrcOverlayCKey, CKey, sizeof(*CKey)) != 0;
2843 This->SrcOverlayCKey = *CKey;
2844 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2845 break;
2847 case DDCKEY_SRCBLT:
2848 if(!(This->CKeyFlags & DDSD_CKSRCBLT)) {
2849 dirtify = TRUE;
2850 } else {
2851 dirtify = memcmp(&This->SrcBltCKey, CKey, sizeof(*CKey)) != 0;
2853 This->SrcBltCKey = *CKey;
2854 This->CKeyFlags |= DDSD_CKSRCBLT;
2855 break;
2858 else {
2859 switch (Flags & ~DDCKEY_COLORSPACE) {
2860 case DDCKEY_DESTBLT:
2861 dirtify = This->CKeyFlags & DDSD_CKDESTBLT;
2862 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2863 break;
2865 case DDCKEY_DESTOVERLAY:
2866 dirtify = This->CKeyFlags & DDSD_CKDESTOVERLAY;
2867 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2868 break;
2870 case DDCKEY_SRCOVERLAY:
2871 dirtify = This->CKeyFlags & DDSD_CKSRCOVERLAY;
2872 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2873 break;
2875 case DDCKEY_SRCBLT:
2876 dirtify = This->CKeyFlags & DDSD_CKSRCBLT;
2877 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2878 break;
2882 if(dirtify) {
2883 TRACE("Color key changed, dirtifying surface\n");
2884 This->Flags |= SFLAG_DIRTY;
2887 return WINED3D_OK;
2890 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2891 /** Check against the maximum texture sizes supported by the video card **/
2892 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2894 TRACE("%p\n", This);
2895 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2896 /* one of three options
2897 1: Do the same as we do with nonpow 2 and scale the texture, (any texture ops would require the texture to be scaled which is potentially slow)
2898 2: Set the texture to the maxium size (bad idea)
2899 3: WARN and return WINED3DERR_NOTAVAILABLE;
2900 4: Create the surface, but allow it to be used only for DirectDraw Blts. Some apps(e.g. Swat 3) create textures with a Height of 16 and a Width > 3000 and blt 16x16 letter areas from them to the render target.
2902 WARN("(%p) Creating an oversized surface\n", This);
2903 This->Flags |= SFLAG_OVERSIZE;
2905 /* This will be initialized on the first blt */
2906 This->glRect.left = 0;
2907 This->glRect.top = 0;
2908 This->glRect.right = 0;
2909 This->glRect.bottom = 0;
2910 } else {
2911 /* No oversize, gl rect is the full texture size */
2912 This->Flags &= ~SFLAG_OVERSIZE;
2913 This->glRect.left = 0;
2914 This->glRect.top = 0;
2915 This->glRect.right = This->pow2Width;
2916 This->glRect.bottom = This->pow2Height;
2919 return WINED3D_OK;
2922 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
2923 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2924 DWORD ret;
2925 TRACE("(%p)\n", This);
2927 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
2928 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
2929 ie pitch = (width/4) * bytes per block */
2930 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
2931 ret = (This->currentDesc.Width >> 2) << 3;
2932 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
2933 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
2934 ret = (This->currentDesc.Width >> 2) << 4;
2935 else {
2936 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2937 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
2938 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
2939 } else {
2940 ret = This->bytesPerPixel * This->pow2Width;
2943 TRACE("(%p) Returning %ld\n", This, ret);
2944 return ret;
2947 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
2949 /* IUnknown */
2950 IWineD3DSurfaceImpl_QueryInterface,
2951 IWineD3DSurfaceImpl_AddRef,
2952 IWineD3DSurfaceImpl_Release,
2953 /* IWineD3DResource */
2954 IWineD3DSurfaceImpl_GetParent,
2955 IWineD3DSurfaceImpl_GetDevice,
2956 IWineD3DSurfaceImpl_SetPrivateData,
2957 IWineD3DSurfaceImpl_GetPrivateData,
2958 IWineD3DSurfaceImpl_FreePrivateData,
2959 IWineD3DSurfaceImpl_SetPriority,
2960 IWineD3DSurfaceImpl_GetPriority,
2961 IWineD3DSurfaceImpl_PreLoad,
2962 IWineD3DSurfaceImpl_GetType,
2963 /* IWineD3DSurface */
2964 IWineD3DSurfaceImpl_GetContainerParent,
2965 IWineD3DSurfaceImpl_GetContainer,
2966 IWineD3DSurfaceImpl_GetDesc,
2967 IWineD3DSurfaceImpl_LockRect,
2968 IWineD3DSurfaceImpl_UnlockRect,
2969 IWineD3DSurfaceImpl_GetDC,
2970 IWineD3DSurfaceImpl_ReleaseDC,
2971 IWineD3DSurfaceImpl_Flip,
2972 IWineD3DSurfaceImpl_Blt,
2973 IWineD3DSurfaceImpl_GetBltStatus,
2974 IWineD3DSurfaceImpl_GetFlipStatus,
2975 IWineD3DSurfaceImpl_IsLost,
2976 IWineD3DSurfaceImpl_Restore,
2977 IWineD3DSurfaceImpl_BltFast,
2978 IWineD3DSurfaceImpl_GetPalette,
2979 IWineD3DSurfaceImpl_SetPalette,
2980 IWineD3DSurfaceImpl_RealizePalette,
2981 IWineD3DSurfaceImpl_SetColorKey,
2982 IWineD3DSurfaceImpl_GetPitch,
2983 /* Internal use: */
2984 IWineD3DSurfaceImpl_CleanDirtyRect,
2985 IWineD3DSurfaceImpl_AddDirtyRect,
2986 IWineD3DSurfaceImpl_LoadTexture,
2987 IWineD3DSurfaceImpl_SaveSnapshot,
2988 IWineD3DSurfaceImpl_SetContainer,
2989 IWineD3DSurfaceImpl_SetPBufferState,
2990 IWineD3DSurfaceImpl_SetGlTextureDesc,
2991 IWineD3DSurfaceImpl_GetGlDesc,
2992 IWineD3DSurfaceImpl_GetData,
2993 IWineD3DSurfaceImpl_SetFormat,
2994 IWineD3DSurfaceImpl_PrivateSetup