wined3d: Add a setting for the render target locking method.
[wine/testsucceed.git] / dlls / wined3d / surface.c
blobf28561e1d9ef32932c05e20c67c83d5e8167619d
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);
1095 switch(wined3d_settings.rendertargetlock_mode) {
1096 case RTL_AUTO:
1097 case RTL_READDRAW:
1098 case RTL_TEXDRAW:
1099 flush_to_framebuffer_drawpixels(This);
1100 break;
1102 case RTL_READTEX:
1103 case RTL_TEXTEX:
1104 ERR("Writing to the render target with textures is not implemented yet\n");
1105 break;
1107 case RTL_DISABLE:
1109 static BOOL warned = FALSE;
1110 if(!warned) {
1111 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1112 warned = TRUE;
1115 break;
1118 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
1119 glDrawBuffer(GL_BACK);
1120 vcheckGLcall("glDrawBuffer");
1122 if(myDevice->stateBlock->renderState[D3DRS_ZENABLE] == D3DZB_TRUE ||
1123 myDevice->stateBlock->renderState[D3DRS_ZENABLE] == D3DZB_USEW) glEnable(GL_DEPTH_TEST);
1124 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
1126 LEAVE_GL();
1128 /** restore clean dirty state */
1129 IWineD3DSurface_CleanDirtyRect(iface);
1131 } else {
1132 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1134 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
1136 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
1138 if (iface == myDevice->depthStencilBuffer) {
1139 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
1140 } else {
1141 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
1144 } else {
1145 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1148 unlock_end:
1149 This->Flags &= ~SFLAG_LOCKED;
1150 memset(&This->lockedRect, 0, sizeof(RECT));
1151 return WINED3D_OK;
1154 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1155 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1156 WINED3DLOCKED_RECT lock;
1157 UINT usage;
1158 BITMAPINFO* b_info;
1159 HDC ddc;
1160 DWORD *masks;
1161 HRESULT hr;
1162 RGBQUAD col[256];
1163 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1165 TRACE("(%p)->(%p)\n",This,pHDC);
1167 /* Give more detailed info for ddraw */
1168 if (This->Flags & SFLAG_DCINUSE)
1169 return DDERR_DCALREADYCREATED;
1171 /* Can't GetDC if the surface is locked */
1172 if (This->Flags & SFLAG_LOCKED)
1173 return WINED3DERR_INVALIDCALL;
1175 memset(&lock, 0, sizeof(lock)); /* To be sure */
1177 /* Create a DIB section if there isn't a hdc yet */
1178 if(!This->hDC) {
1179 int extraline = 0;
1180 SYSTEM_INFO sysInfo;
1182 if(This->Flags & SFLAG_ACTIVELOCK) {
1183 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1186 switch (This->bytesPerPixel) {
1187 case 2:
1188 case 4:
1189 /* Allocate extra space to store the RGB bit masks. */
1190 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1191 break;
1193 case 3:
1194 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1195 break;
1197 default:
1198 /* Allocate extra space for a palette. */
1199 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1200 sizeof(BITMAPINFOHEADER)
1201 + sizeof(RGBQUAD)
1202 * (1 << (This->bytesPerPixel * 8)));
1203 break;
1206 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1207 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1208 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1209 * add an extra line to the dib section
1211 GetSystemInfo(&sysInfo);
1212 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1213 extraline = 1;
1214 TRACE("Adding an extra line to the dib section\n");
1217 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1218 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1219 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1220 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1221 b_info->bmiHeader.biSizeImage = This->currentDesc.Width * This->currentDesc.Height * This->bytesPerPixel;
1222 /* Use the full pow2 image size(assigned below) because LockRect
1223 * will need it for a full glGetTexImage call
1225 } else {
1226 b_info->bmiHeader.biWidth = This->pow2Width;
1227 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1228 b_info->bmiHeader.biSizeImage = This->resource.size;
1230 b_info->bmiHeader.biPlanes = 1;
1231 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1233 b_info->bmiHeader.biXPelsPerMeter = 0;
1234 b_info->bmiHeader.biYPelsPerMeter = 0;
1235 b_info->bmiHeader.biClrUsed = 0;
1236 b_info->bmiHeader.biClrImportant = 0;
1238 /* Get the bit masks */
1239 masks = (DWORD *) &(b_info->bmiColors);
1240 switch (This->resource.format) {
1241 case WINED3DFMT_R8G8B8:
1242 usage = DIB_RGB_COLORS;
1243 b_info->bmiHeader.biCompression = BI_RGB;
1244 break;
1246 case WINED3DFMT_X1R5G5B5:
1247 case WINED3DFMT_A1R5G5B5:
1248 case WINED3DFMT_A4R4G4B4:
1249 case WINED3DFMT_X4R4G4B4:
1250 case WINED3DFMT_R3G3B2:
1251 case WINED3DFMT_A8R3G3B2:
1252 case WINED3DFMT_A2B10G10R10:
1253 case WINED3DFMT_A8B8G8R8:
1254 case WINED3DFMT_X8B8G8R8:
1255 case WINED3DFMT_A2R10G10B10:
1256 case WINED3DFMT_R5G6B5:
1257 case WINED3DFMT_A16B16G16R16:
1258 usage = 0;
1259 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1260 masks[0] = formatEntry->redMask;
1261 masks[1] = formatEntry->greenMask;
1262 masks[2] = formatEntry->blueMask;
1263 break;
1265 default:
1266 /* Don't know palette */
1267 b_info->bmiHeader.biCompression = BI_RGB;
1268 usage = 0;
1269 break;
1272 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1273 if (ddc == 0) {
1274 HeapFree(GetProcessHeap(), 0, b_info);
1275 return HRESULT_FROM_WIN32(GetLastError());
1278 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);
1279 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1280 DeleteDC(ddc);
1282 if (!This->dib.DIBsection) {
1283 ERR("CreateDIBSection failed!\n");
1284 return HRESULT_FROM_WIN32(GetLastError());
1286 HeapFree(GetProcessHeap(), 0, b_info);
1288 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1290 /* copy the existing surface to the dib section */
1291 if(This->resource.allocatedMemory) {
1292 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1293 /* We won't need that any more */
1294 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1295 } else {
1296 /* This is to make LockRect read the gl Texture although memory is allocated */
1297 This->Flags |= SFLAG_GLDIRTY;
1300 /* Use the dib section from now on */
1301 This->resource.allocatedMemory = This->dib.bitmap_data;
1303 /* Now allocate a HDC */
1304 This->hDC = CreateCompatibleDC(0);
1305 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1306 TRACE("using wined3d palette %p\n", This->palette);
1307 SelectPalette(This->hDC,
1308 This->palette ? This->palette->hpal : 0,
1309 FALSE);
1311 This->Flags |= SFLAG_DIBSECTION;
1314 /* Lock the surface */
1315 hr = IWineD3DSurface_LockRect(iface,
1316 &lock,
1317 NULL,
1319 if(FAILED(hr)) {
1320 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1321 /* keep the dib section */
1322 return hr;
1325 if(This->resource.format == WINED3DFMT_P8 ||
1326 This->resource.format == WINED3DFMT_A8P8) {
1327 unsigned int n;
1328 if(This->palette) {
1329 PALETTEENTRY ent[256];
1331 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1332 for (n=0; n<256; n++) {
1333 col[n].rgbRed = ent[n].peRed;
1334 col[n].rgbGreen = ent[n].peGreen;
1335 col[n].rgbBlue = ent[n].peBlue;
1336 col[n].rgbReserved = 0;
1338 } else {
1339 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1341 for (n=0; n<256; n++) {
1342 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1343 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1344 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1345 col[n].rgbReserved = 0;
1349 SetDIBColorTable(This->hDC, 0, 256, col);
1352 *pHDC = This->hDC;
1353 TRACE("returning %p\n",*pHDC);
1354 This->Flags |= SFLAG_DCINUSE;
1356 return WINED3D_OK;
1359 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1360 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1362 TRACE("(%p)->(%p)\n",This,hDC);
1364 if (!(This->Flags & SFLAG_DCINUSE))
1365 return D3DERR_INVALIDCALL;
1367 /* we locked first, so unlock now */
1368 IWineD3DSurface_UnlockRect(iface);
1370 This->Flags &= ~SFLAG_DCINUSE;
1372 return WINED3D_OK;
1375 /* ******************************************************
1376 IWineD3DSurface Internal (No mapping to directx api) parts follow
1377 ****************************************************** */
1379 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp) {
1380 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1381 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1383 /* Default values: From the surface */
1384 *format = formatEntry->glFormat;
1385 *internal = formatEntry->glInternal;
1386 *type = formatEntry->glType;
1387 *convert = NO_CONVERSION;
1388 *target_bpp = This->bytesPerPixel;
1390 /* Ok, now look if we have to do any conversion */
1391 switch(This->resource.format) {
1392 case WINED3DFMT_P8:
1393 /* ****************
1394 Paletted Texture
1395 **************** */
1396 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active) {
1397 *format = GL_RGBA;
1398 *internal = GL_RGBA;
1399 *type = GL_UNSIGNED_BYTE;
1400 *target_bpp = 4;
1401 if(colorkey_active) {
1402 *convert = CONVERT_PALETTED;
1403 } else {
1404 *convert = CONVERT_PALETTED_CK;
1408 break;
1410 case WINED3DFMT_R3G3B2:
1411 /* **********************
1412 GL_UNSIGNED_BYTE_3_3_2
1413 ********************** */
1414 if (colorkey_active) {
1415 /* This texture format will never be used.. So do not care about color keying
1416 up until the point in time it will be needed :-) */
1417 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1419 break;
1421 case WINED3DFMT_R5G6B5:
1422 if (colorkey_active) {
1423 *convert = CONVERT_CK_565;
1424 *format = GL_RGBA;
1425 *internal = GL_RGBA;
1426 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1428 break;
1430 case WINED3DFMT_R8G8B8:
1431 if (colorkey_active) {
1432 *convert = CONVERT_CK_RGB24;
1433 *format = GL_RGBA;
1434 *internal = GL_RGBA;
1435 *type = GL_UNSIGNED_INT_8_8_8_8;
1436 *target_bpp = 4;
1438 break;
1440 case WINED3DFMT_X8R8G8B8:
1441 if (colorkey_active) {
1442 *convert = CONVERT_RGB32_888;
1443 *format = GL_RGBA;
1444 *internal = GL_RGBA;
1445 *type = GL_UNSIGNED_INT_8_8_8_8;
1447 break;
1448 #if 0
1449 /* Not sure if we should do color keying on Alpha-Enabled surfaces */
1450 case WINED3DFMT_A4R4G4B4:
1451 if (colorkey_active)
1453 *convert = CONVERT_CK_4444_ARGB;
1454 *format = GL_RGBA;
1455 *internal = GL_RGBA;
1456 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1458 break;
1460 case WINED3DFMT_A1R5G5B5:
1461 if (colorkey_active)
1463 *convert = CONVERT_CK_1555;
1466 case WINED3DFMT_A8R8G8B8:
1467 if (colorkey_active)
1469 *convert = CONVERT_CK_8888_ARGB;
1470 *format = GL_RGBA;
1471 *internal = GL_RGBA;
1472 *type = GL_UNSIGNED_INT_8_8_8_8;
1474 break;
1475 #endif
1476 default:
1477 break;
1480 return WINED3D_OK;
1483 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1484 TRACE("(%p)->(%p),(%ld,%d,%p)\n", src, dst, len, convert, surf);
1486 switch (convert) {
1487 case NO_CONVERSION:
1489 memcpy(dst, src, len * surf->bytesPerPixel);
1490 break;
1492 case CONVERT_PALETTED:
1493 case CONVERT_PALETTED_CK:
1495 IWineD3DPaletteImpl* pal = surf->palette;
1496 BYTE table[256][4];
1497 unsigned int i;
1498 unsigned int x;
1500 if( pal == NULL) {
1501 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1504 if (pal == NULL) {
1505 /* Still no palette? Use the device's palette */
1506 /* Get the surface's palette */
1507 for (i = 0; i < 256; i++) {
1508 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1510 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1511 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1512 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1513 if ((convert == CONVERT_PALETTED_CK) &&
1514 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1515 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1516 /* We should maybe here put a more 'neutral' color than the standard bright purple
1517 one often used by application to prevent the nice purple borders when bi-linear
1518 filtering is on */
1519 table[i][3] = 0x00;
1520 } else {
1521 table[i][3] = 0xFF;
1524 } else {
1525 TRACE("Using surface palette %p\n", pal);
1526 /* Get the surface's palette */
1527 for (i = 0; i < 256; i++) {
1528 table[i][0] = pal->palents[i].peRed;
1529 table[i][1] = pal->palents[i].peGreen;
1530 table[i][2] = pal->palents[i].peBlue;
1531 if ((convert == CONVERT_PALETTED_CK) &&
1532 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1533 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1534 /* We should maybe here put a more 'neutral' color than the standard bright purple
1535 one often used by application to prevent the nice purple borders when bi-linear
1536 filtering is on */
1537 table[i][3] = 0x00;
1538 } else {
1539 table[i][3] = 0xFF;
1544 for (x = 0; x < len; x++) {
1545 BYTE color = *src++;
1546 *dst++ = table[color][0];
1547 *dst++ = table[color][1];
1548 *dst++ = table[color][2];
1549 *dst++ = table[color][3];
1552 break;
1554 case CONVERT_CK_565:
1556 /* Converting the 565 format in 5551 packed to emulate color-keying.
1558 Note : in all these conversion, it would be best to average the averaging
1559 pixels to get the color of the pixel that will be color-keyed to
1560 prevent 'color bleeding'. This will be done later on if ever it is
1561 too visible.
1563 Note2: when using color-keying + alpha, are the alpha bits part of the
1564 color-space or not ?
1566 unsigned int x;
1567 WORD *Source = (WORD *) src;
1568 WORD *Dest = (WORD *) dst;
1570 TRACE("Color keyed 565\n");
1572 for (x = 0; x < len; x++ ) {
1573 WORD color = *Source++;
1574 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1575 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1576 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1577 *Dest |= 0x0001;
1579 Dest++;
1582 break;
1584 case CONVERT_CK_1555:
1586 unsigned int x;
1587 WORD *Source = (WORD *) src;
1588 WORD *Dest = (WORD *) dst;
1590 for (x = 0; x < len * sizeof(WORD); x+=sizeof(WORD)) {
1591 WORD color = *Source++;
1592 *Dest = (color & 0x7FFF);
1593 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1594 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1595 *Dest |= (color & 0x8000);
1596 Dest++;
1599 break;
1601 case CONVERT_CK_4444_ARGB:
1603 /* Move the four Alpha bits... */
1604 unsigned int x;
1605 WORD *Source = (WORD *) src;
1606 WORD *Dest = (WORD *) dst;
1608 for (x = 0; x < len; x++) {
1609 WORD color = *Source++;
1610 *dst = (color & 0x0FFF) << 4;
1611 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1612 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1613 *Dest |= (color & 0xF000) >> 12;
1614 Dest++;
1616 } break;
1618 default:
1619 ERR("Unsupported conversation type %d\n", convert);
1622 return WINED3D_OK;
1625 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1626 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1628 if (This->Flags & SFLAG_INTEXTURE) {
1629 TRACE("Surface already in texture\n");
1630 return WINED3D_OK;
1632 if (!(This->Flags & SFLAG_DIRTY)) {
1633 TRACE("surface isn't dirty\n");
1634 return WINED3D_OK;
1637 This->Flags &= ~SFLAG_DIRTY;
1639 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1640 * These resources are not bound by device size or format restrictions. Because of this,
1641 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1642 * However, these resources can always be created, locked, and copied.
1644 if (This->resource.pool == WINED3DPOOL_SCRATCH)
1646 FIXME("(%p) Operation not supported for scratch textures\n",This);
1647 return WINED3DERR_INVALIDCALL;
1650 if (This->Flags & SFLAG_INPBUFFER) {
1651 ENTER_GL();
1653 if (This->glDescription.level != 0)
1654 FIXME("Surface in texture is only supported for level 0\n");
1655 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1656 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1657 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1658 This->resource.format == WINED3DFMT_DXT5)
1659 FIXME("Format %d not supported\n", This->resource.format);
1660 else {
1661 GLint prevRead;
1662 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1663 vcheckGLcall("glGetIntegerv");
1664 glReadBuffer(GL_BACK);
1665 vcheckGLcall("glReadBuffer");
1667 glCopyTexImage2D(This->glDescription.target,
1668 This->glDescription.level,
1669 This->glDescription.glFormatInternal,
1672 This->currentDesc.Width,
1673 This->currentDesc.Height,
1676 checkGLcall("glCopyTexImage2D");
1677 glReadBuffer(prevRead);
1678 vcheckGLcall("glReadBuffer");
1679 TRACE("Updating target %d\n", This->glDescription.target);
1680 This->Flags |= SFLAG_INTEXTURE;
1682 LEAVE_GL();
1683 return WINED3D_OK;
1686 /* TODO: Compressed non-power 2 support */
1688 if (This->resource.format == WINED3DFMT_DXT1 ||
1689 This->resource.format == WINED3DFMT_DXT2 ||
1690 This->resource.format == WINED3DFMT_DXT3 ||
1691 This->resource.format == WINED3DFMT_DXT4 ||
1692 This->resource.format == WINED3DFMT_DXT5) {
1693 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1694 FIXME("Using DXT1/3/5 without advertized support\n");
1695 } else if (This->resource.allocatedMemory) {
1696 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1697 This->glDescription.target,
1698 This->glDescription.level,
1699 This->glDescription.glFormatInternal,
1700 This->currentDesc.Width,
1701 This->currentDesc.Height,
1703 This->resource.size,
1704 This->resource.allocatedMemory);
1706 ENTER_GL();
1708 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1709 This->glDescription.level,
1710 This->glDescription.glFormatInternal,
1711 This->currentDesc.Width,
1712 This->currentDesc.Height,
1714 This->resource.size,
1715 This->resource.allocatedMemory);
1716 checkGLcall("glCommpressedTexImage2D");
1718 LEAVE_GL();
1720 if(!(This->Flags & SFLAG_DONOTFREE)){
1721 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1722 This->resource.allocatedMemory = NULL;
1725 } else {
1726 GLenum format, internal, type;
1727 CONVERT_TYPES convert;
1728 int bpp;
1729 BYTE *mem;
1731 d3dfmt_get_conv(This, TRUE /* We need color keying */, &format, &internal, &type, &convert, &bpp);
1733 if((convert != NO_CONVERSION) &&
1734 This->resource.allocatedMemory) {
1735 int width = This->glRect.right - This->glRect.left;
1736 int height = This->glRect.bottom - This->glRect.top;
1737 int row;
1739 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
1740 if(!mem) {
1741 ERR("Out of memory %d, %d!\n", width, height);
1742 return WINED3DERR_OUTOFVIDEOMEMORY;
1745 for(row = This->glRect.top; row < This->glRect.bottom; row++) {
1746 BYTE *cur = This->resource.allocatedMemory + row * This->pow2Width * This->bytesPerPixel;
1747 d3dfmt_convert_surface(cur + This->glRect.left * This->bytesPerPixel,
1748 mem + row * width * bpp,
1749 width,
1750 convert,
1751 This);
1753 This->Flags |= SFLAG_CONVERTED;
1754 } else {
1755 This->Flags &= ~SFLAG_CONVERTED;
1756 mem = This->resource.allocatedMemory;
1759 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1760 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE) ) {
1763 TRACE("non power of two support\n");
1764 ENTER_GL();
1765 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,
1766 This->glDescription.target,
1767 This->glDescription.level,
1768 debug_d3dformat(This->resource.format),
1769 This->glDescription.glFormatInternal,
1770 This->pow2Width,
1771 This->pow2Height,
1773 This->glDescription.glFormat,
1774 This->glDescription.glType,
1775 NULL);
1777 glTexImage2D(This->glDescription.target,
1778 This->glDescription.level,
1779 This->glDescription.glFormatInternal,
1780 This->pow2Width,
1781 This->pow2Height,
1782 0/*border*/,
1783 This->glDescription.glFormat,
1784 This->glDescription.glType,
1785 NULL);
1787 checkGLcall("glTexImage2D");
1788 if (This->resource.allocatedMemory != NULL) {
1789 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1790 /* And map the non-power two data into the top left corner */
1791 glTexSubImage2D(
1792 This->glDescription.target,
1793 This->glDescription.level,
1794 0 /* xoffset */,
1795 0 /* ysoffset */ ,
1796 This->currentDesc.Width,
1797 This->currentDesc.Height,
1798 This->glDescription.glFormat,
1799 This->glDescription.glType,
1800 This->resource.allocatedMemory
1802 checkGLcall("glTexSubImage2D");
1804 LEAVE_GL();
1806 } else {
1808 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%ld, h=%ld,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1809 This->glDescription.target,
1810 This->glDescription.level,
1811 debug_d3dformat(This->resource.format),
1812 This->glDescription.glFormatInternal,
1813 This->glRect.right - This->glRect.left,
1814 This->glRect.bottom - This->glRect.top,
1816 This->glDescription.glFormat,
1817 This->glDescription.glType,
1818 mem);
1820 ENTER_GL();
1822 /* OK, create the texture */
1823 glTexImage2D(This->glDescription.target,
1824 This->glDescription.level,
1825 internal,
1826 This->glRect.right - This->glRect.left,
1827 This->glRect.bottom - This->glRect.top,
1828 0 /* border */,
1829 format,
1830 type,
1831 mem);
1833 checkGLcall("glTexImage2D");
1835 LEAVE_GL();
1837 if(mem != This->resource.allocatedMemory)
1838 HeapFree(GetProcessHeap(), 0, mem);
1840 #if 0
1842 static unsigned int gen = 0;
1843 char buffer[4096];
1844 ++gen;
1845 if ((gen % 10) == 0) {
1846 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1847 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1850 * debugging crash code
1851 if (gen == 250) {
1852 void** test = NULL;
1853 *test = 0;
1857 #endif
1858 if(!(This->Flags & SFLAG_DONOTFREE)){
1859 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1860 This->resource.allocatedMemory = NULL;
1865 return WINED3D_OK;
1868 #include <errno.h>
1869 #include <stdio.h>
1870 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1871 FILE* f = NULL;
1872 UINT i, y;
1873 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1874 char *allocatedMemory;
1875 char *textureRow;
1876 IWineD3DSwapChain *swapChain = NULL;
1877 int width, height;
1878 GLuint tmpTexture;
1879 DWORD color;
1880 /*FIXME:
1881 Textures my not be stored in ->allocatedgMemory and a GlTexture
1882 so we should lock the surface before saving a snapshot, or at least check that
1884 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1885 by calling GetTexImage and in compressed form by calling
1886 GetCompressedTexImageARB. Queried compressed images can be saved and
1887 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1888 texture images do not need to be processed by the GL and should
1889 significantly improve texture loading performance relative to uncompressed
1890 images. */
1892 /* Setup the width and height to be the internal texture width and height. */
1893 width = This->pow2Width;
1894 height = This->pow2Height;
1895 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1896 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1898 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1899 /* 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 */
1900 GLint prevRead;
1901 ENTER_GL();
1902 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1903 glEnable(GL_TEXTURE_2D);
1905 glGenTextures(1, &tmpTexture);
1906 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1908 glTexImage2D(GL_TEXTURE_2D,
1910 GL_RGBA,
1911 width,
1912 height,
1913 0/*border*/,
1914 GL_RGBA,
1915 GL_UNSIGNED_INT_8_8_8_8_REV,
1916 NULL);
1918 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1919 vcheckGLcall("glGetIntegerv");
1920 glReadBuffer(GL_BACK);
1921 vcheckGLcall("glReadBuffer");
1922 glCopyTexImage2D(GL_TEXTURE_2D,
1924 GL_RGBA,
1927 width,
1928 height,
1931 checkGLcall("glCopyTexImage2D");
1932 glReadBuffer(prevRead);
1933 LEAVE_GL();
1935 } else { /* bind the real texture */
1936 IWineD3DSurface_PreLoad(iface);
1938 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1939 ENTER_GL();
1940 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1941 glGetTexImage(GL_TEXTURE_2D,
1942 This->glDescription.level,
1943 GL_RGBA,
1944 GL_UNSIGNED_INT_8_8_8_8_REV,
1945 allocatedMemory);
1946 checkGLcall("glTexImage2D");
1947 if (tmpTexture) {
1948 glBindTexture(GL_TEXTURE_2D, 0);
1949 glDeleteTextures(1, &tmpTexture);
1951 LEAVE_GL();
1953 f = fopen(filename, "w+");
1954 if (NULL == f) {
1955 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1956 return WINED3DERR_INVALIDCALL;
1958 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1959 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1960 /* TGA header */
1961 fputc(0,f);
1962 fputc(0,f);
1963 fputc(2,f);
1964 fputc(0,f);
1965 fputc(0,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 /* short width*/
1974 fwrite(&width,2,1,f);
1975 /* short height */
1976 fwrite(&height,2,1,f);
1977 /* format rgba */
1978 fputc(0x20,f);
1979 fputc(0x28,f);
1980 /* raw data */
1981 /* 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*/
1982 if(swapChain)
1983 textureRow = allocatedMemory + (width * (height - 1) *4);
1984 else
1985 textureRow = allocatedMemory;
1986 for (y = 0 ; y < height; y++) {
1987 for (i = 0; i < width; i++) {
1988 color = *((DWORD*)textureRow);
1989 fputc((color >> 16) & 0xFF, f); /* B */
1990 fputc((color >> 8) & 0xFF, f); /* G */
1991 fputc((color >> 0) & 0xFF, f); /* R */
1992 fputc((color >> 24) & 0xFF, f); /* A */
1993 textureRow += 4;
1995 /* take two rows of the pointer to the texture memory */
1996 if(swapChain)
1997 (textureRow-= width << 3);
2000 TRACE("Closing file\n");
2001 fclose(f);
2003 if(swapChain) {
2004 IWineD3DSwapChain_Release(swapChain);
2006 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2007 return WINED3D_OK;
2010 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
2011 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2012 This->Flags &= ~SFLAG_DIRTY;
2013 This->dirtyRect.left = This->currentDesc.Width;
2014 This->dirtyRect.top = This->currentDesc.Height;
2015 This->dirtyRect.right = 0;
2016 This->dirtyRect.bottom = 0;
2017 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
2018 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2019 return WINED3D_OK;
2023 * Slightly inefficient way to handle multiple dirty rects but it works :)
2025 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2026 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2027 IWineD3DBaseTexture *baseTexture = NULL;
2028 This->Flags |= SFLAG_DIRTY;
2029 if (NULL != pDirtyRect) {
2030 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2031 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2032 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2033 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2034 } else {
2035 This->dirtyRect.left = 0;
2036 This->dirtyRect.top = 0;
2037 This->dirtyRect.right = This->currentDesc.Width;
2038 This->dirtyRect.bottom = This->currentDesc.Height;
2040 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2041 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2042 /* if the container is a basetexture then mark it dirty. */
2043 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2044 TRACE("Passing to conatiner\n");
2045 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2046 IWineD3DBaseTexture_Release(baseTexture);
2048 return WINED3D_OK;
2051 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2052 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2054 TRACE("This %p, container %p\n", This, container);
2056 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2058 TRACE("Setting container to %p from %p\n", container, This->container);
2059 This->container = container;
2061 return WINED3D_OK;
2064 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2065 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2066 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2068 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2069 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2070 return WINED3DERR_INVALIDCALL;
2073 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2074 if (format == WINED3DFMT_UNKNOWN) {
2075 This->resource.size = 0;
2076 } else if (format == WINED3DFMT_DXT1) {
2077 /* DXT1 is half byte per pixel */
2078 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2080 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2081 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2082 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2083 } else {
2084 This->resource.size = (This->pow2Width * formatEntry->bpp) * This->pow2Height;
2088 /* Setup some glformat defaults */
2089 This->glDescription.glFormat = formatEntry->glFormat;
2090 This->glDescription.glFormatInternal = formatEntry->glInternal;
2091 This->glDescription.glType = formatEntry->glType;
2093 if (format != WINED3DFMT_UNKNOWN) {
2094 This->bytesPerPixel = formatEntry->bpp;
2095 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
2096 } else {
2097 This->bytesPerPixel = 0;
2098 This->pow2Size = 0;
2101 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2103 This->resource.format = format;
2105 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);
2107 return WINED3D_OK;
2110 /* TODO: replace this function with context management routines */
2111 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2112 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2114 if(inPBuffer) {
2115 This->Flags |= SFLAG_INPBUFFER;
2116 } else {
2117 This->Flags &= ~SFLAG_INPBUFFER;
2120 if(inTexture) {
2121 This->Flags |= SFLAG_INTEXTURE;
2122 } else {
2123 This->Flags &= ~SFLAG_INTEXTURE;
2126 return WINED3D_OK;
2129 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2130 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2131 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2132 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
2134 /* Flipping is only supported on RenderTargets */
2135 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2137 if(override) {
2138 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2139 * FIXME("(%p) Target override is not supported by now\n", This);
2140 * Additionally, it isn't really possible to support triple-buffering
2141 * properly on opengl at all
2145 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2146 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2149 /* Not called from the VTable */
2150 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2151 D3DRECT rect;
2152 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2153 IWineD3DSwapChainImpl *swapchain = NULL;
2154 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2155 BOOL SrcOK = TRUE;
2157 TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2159 /* Get the swapchain. One of the surfaces has to be a primary surface */
2160 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2161 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2162 else if(Src) {
2163 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2164 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2165 else return WINED3DERR_INVALIDCALL;
2166 } else {
2167 swapchain = NULL;
2170 if (DestRect) {
2171 rect.x1 = DestRect->left;
2172 rect.y1 = DestRect->top;
2173 rect.x2 = DestRect->right;
2174 rect.y2 = DestRect->bottom;
2175 } else {
2176 rect.x1 = 0;
2177 rect.y1 = 0;
2178 rect.x2 = This->currentDesc.Width;
2179 rect.y2 = This->currentDesc.Height;
2182 /* Half-life does a Blt from the back buffer to the front buffer,
2183 * Full surface size, no flags... Use present instead
2185 if(Src)
2187 /* First, check if we can do a Flip */
2189 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2190 if( SrcRect ) {
2191 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2192 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2193 SrcOK = TRUE;
2195 } else {
2196 SrcOK = TRUE;
2199 /* Check the Destination rect and the surface sizes */
2200 if(SrcOK &&
2201 (rect.x1 == 0) && (rect.y1 == 0) &&
2202 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2203 (This->currentDesc.Width == Src->currentDesc.Width) &&
2204 (This->currentDesc.Height == Src->currentDesc.Height)) {
2205 /* These flags are unimportant for the flag check, remove them */
2207 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2208 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2210 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2212 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2213 * take very long, while a flip is fast.
2214 * This applies to Half-Life, which does such Blts every time it finished
2215 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2216 * menu. This is also used by all apps when they do windowed rendering
2218 * The problem is that flipping is not really the same as copying. After a
2219 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2220 * untouched. Therefore it's necessary to override the swap effect
2221 * and to set it back after the flip.
2224 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2226 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2227 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2228 NULL, NULL, 0, NULL);
2230 swapchain->presentParms.SwapEffect = orig_swap;
2232 return WINED3D_OK;
2237 /* Blt from texture to rendertarget? */
2238 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2239 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2241 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2242 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2243 float glTexCoord[4];
2244 DWORD oldCKey;
2245 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2246 GLint alphafunc;
2247 GLclampf alpharef;
2248 GLint oldStencil;
2249 RECT SourceRectangle;
2250 GLint oldDraw;
2252 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2254 if(SrcRect) {
2255 SourceRectangle.left = SrcRect->left;
2256 SourceRectangle.right = SrcRect->right;
2257 SourceRectangle.top = SrcRect->top;
2258 SourceRectangle.bottom = SrcRect->bottom;
2259 } else {
2260 SourceRectangle.left = 0;
2261 SourceRectangle.right = Src->currentDesc.Width;
2262 SourceRectangle.top = 0;
2263 SourceRectangle.bottom = Src->currentDesc.Height;
2266 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2267 /* Fall back to software */
2268 WARN("(%p) Source texture area (%ld,%ld)-(%ld,%ld) is too big\n", Src,
2269 SourceRectangle.left, SourceRectangle.top,
2270 SourceRectangle.right, SourceRectangle.bottom);
2271 return WINED3DERR_INVALIDCALL;
2274 /* Color keying: Check if we have to do a color keyed blt,
2275 * and if not check if a color key is activated.
2277 oldCKey = Src->CKeyFlags;
2278 if(!(Flags & DDBLT_KEYSRC) &&
2279 Src->CKeyFlags & DDSD_CKSRCBLT) {
2280 /* Ok, the surface has a color key, but we shall not use it -
2281 * Deactivate it for now and dirtify the surface to reload it
2283 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2284 Src->Flags |= SFLAG_DIRTY;
2287 /* Now load the surface */
2288 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2290 ENTER_GL();
2292 /* Save all the old stuff until we have a proper opengl state manager */
2293 oldLight = glIsEnabled(GL_LIGHTING);
2294 oldFog = glIsEnabled(GL_FOG);
2295 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2296 oldBlend = glIsEnabled(GL_BLEND);
2297 oldCull = glIsEnabled(GL_CULL_FACE);
2298 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2299 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2301 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2302 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2303 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2304 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2306 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2307 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2308 TRACE("Drawing to front buffer\n");
2309 glDrawBuffer(GL_FRONT);
2310 checkGLcall("glDrawBuffer GL_FRONT");
2313 /* Unbind the old texture */
2314 glBindTexture(GL_TEXTURE_2D, 0);
2316 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2317 /* We use texture unit 0 for blts */
2318 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2319 checkGLcall("glActiveTextureARB");
2320 } else {
2321 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2324 /* Disable some fancy graphics effects */
2325 glDisable(GL_LIGHTING);
2326 checkGLcall("glDisable GL_LIGHTING");
2327 glDisable(GL_DEPTH_TEST);
2328 checkGLcall("glDisable GL_DEPTH_TEST");
2329 glDisable(GL_FOG);
2330 checkGLcall("glDisable GL_FOG");
2331 glDisable(GL_BLEND);
2332 checkGLcall("glDisable GL_BLEND");
2333 glDisable(GL_CULL_FACE);
2334 checkGLcall("glDisable GL_CULL_FACE");
2335 glDisable(GL_STENCIL_TEST);
2336 checkGLcall("glDisable GL_STENCIL_TEST");
2338 /* Ok, we need 2d textures, but not 1D or 3D */
2339 glDisable(GL_TEXTURE_1D);
2340 checkGLcall("glDisable GL_TEXTURE_1D");
2341 glEnable(GL_TEXTURE_2D);
2342 checkGLcall("glEnable GL_TEXTURE_2D");
2343 glDisable(GL_TEXTURE_3D);
2344 checkGLcall("glDisable GL_TEXTURE_3D");
2346 /* Bind the texture */
2347 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2348 checkGLcall("glBindTexture");
2350 glEnable(GL_SCISSOR_TEST);
2352 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2354 /* No filtering for blts */
2355 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2356 GL_NEAREST);
2357 checkGLcall("glTexParameteri");
2358 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2359 GL_NEAREST);
2360 checkGLcall("glTexParameteri");
2361 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2362 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2363 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2364 checkGLcall("glTexEnvi");
2366 /* This is for color keying */
2367 if(Flags & DDBLT_KEYSRC) {
2368 glEnable(GL_ALPHA_TEST);
2369 checkGLcall("glEnable GL_ALPHA_TEST");
2370 glAlphaFunc(GL_NOTEQUAL, 0.0);
2371 checkGLcall("glAlphaFunc\n");
2372 } else {
2373 glDisable(GL_ALPHA_TEST);
2374 checkGLcall("glDisable GL_ALPHA_TEST");
2377 /* Draw a textured quad
2379 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2381 glBegin(GL_QUADS);
2383 glColor3d(1.0f, 1.0f, 1.0f);
2384 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2385 glVertex3f(rect.x1,
2386 rect.y1,
2387 0.0);
2389 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2390 glVertex3f(rect.x1, rect.y2, 0.0);
2392 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2393 glVertex3f(rect.x2,
2394 rect.y2,
2395 0.0);
2397 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2398 glVertex3f(rect.x2,
2399 rect.y1,
2400 0.0);
2401 glEnd();
2402 checkGLcall("glEnd");
2404 /* Unbind the texture */
2405 glBindTexture(GL_TEXTURE_2D, 0);
2406 checkGLcall("glEnable glBindTexture");
2408 /* Restore the old settings */
2409 if(oldLight) {
2410 glEnable(GL_LIGHTING);
2411 checkGLcall("glEnable GL_LIGHTING");
2413 if(oldFog) {
2414 glEnable(GL_FOG);
2415 checkGLcall("glEnable GL_FOG");
2417 if(oldDepth) {
2418 glEnable(GL_DEPTH_TEST);
2419 checkGLcall("glEnable GL_DEPTH_TEST");
2421 if(oldBlend) {
2422 glEnable(GL_BLEND);
2423 checkGLcall("glEnable GL_BLEND");
2425 if(oldCull) {
2426 glEnable(GL_CULL_FACE);
2427 checkGLcall("glEnable GL_CULL_FACE");
2429 if(oldStencil) {
2430 glEnable(GL_STENCIL_TEST);
2431 checkGLcall("glEnable GL_STENCIL_TEST");
2433 if(!oldAlpha) {
2434 glDisable(GL_ALPHA_TEST);
2435 checkGLcall("glDisable GL_ALPHA_TEST");
2436 } else {
2437 glEnable(GL_ALPHA_TEST);
2438 checkGLcall("glEnable GL_ALPHA_TEST");
2441 glAlphaFunc(alphafunc, alpharef);
2442 checkGLcall("glAlphaFunc\n");
2444 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2445 glDrawBuffer(oldDraw);
2448 /* Restore the color key */
2449 if(oldCKey != Src->CKeyFlags) {
2450 Src->CKeyFlags = oldCKey;
2451 Src->Flags |= SFLAG_DIRTY;
2454 LEAVE_GL();
2456 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2457 This->Flags |= SFLAG_GLDIRTY;
2459 return WINED3D_OK;
2463 /* Blt from rendertarget to texture? */
2464 if( (SrcSurface == swapchain->frontBuffer) ||
2465 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2466 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2467 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2468 UINT row;
2469 D3DRECT srect;
2470 float xrel, yrel;
2472 TRACE("Blt from rendertarget to texture\n");
2474 /* Call preload for the surface to make sure it isn't dirty */
2475 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2477 if(SrcRect) {
2478 srect.x1 = SrcRect->left;
2479 srect.y1 = SrcRect->top;
2480 srect.x2 = SrcRect->right;
2481 srect.y2 = SrcRect->bottom;
2482 } else {
2483 srect.x1 = 0;
2484 srect.y1 = 0;
2485 srect.x2 = Src->currentDesc.Width;
2486 srect.y2 = Src->currentDesc.Height;
2489 ENTER_GL();
2491 /* Bind the target texture */
2492 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2493 checkGLcall("glBindTexture");
2494 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2495 glReadBuffer(GL_BACK);
2496 } else {
2497 glReadBuffer(GL_FRONT);
2499 checkGLcall("glReadBuffer");
2501 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2502 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2504 /* I have to process this row by row to swap the image,
2505 * otherwise it would be upside down, so streching in y direction
2506 * doesn't cost extra time
2508 * However, streching in x direction can be avoided if not necessary
2510 for(row = rect.y1; row < rect.y2; row++) {
2511 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2512 /* Well, that stuff works, but it's very slow.
2513 * find a better way instead
2515 UINT col;
2516 for(col = rect.x1; col < rect.x2; col++) {
2517 glCopyTexSubImage2D(GL_TEXTURE_2D,
2518 0, /* level */
2519 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2520 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2521 1, 1);
2523 } else {
2524 glCopyTexSubImage2D(GL_TEXTURE_2D,
2525 0, /* level */
2526 rect.x1, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2527 srect.x1, Src->currentDesc.Height - srect.y2 + row * yrel,
2528 rect.x2, 1);
2532 vcheckGLcall("glCopyTexSubImage2D");
2533 LEAVE_GL();
2535 if(!(This->Flags & SFLAG_DONOTFREE)) {
2536 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2537 This->resource.allocatedMemory = NULL;
2538 } else {
2539 This->Flags |= SFLAG_GLDIRTY;
2542 return WINED3D_OK;
2547 if (Flags & DDBLT_COLORFILL) {
2548 /* This is easy to handle for the D3D Device... */
2549 DWORD color;
2550 IWineD3DSwapChainImpl *implSwapChain;
2552 TRACE("Colorfill\n");
2554 /* The color as given in the Blt function is in the format of the frame-buffer...
2555 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2557 if (This->resource.format == WINED3DFMT_P8) {
2558 if (This->palette) {
2559 color = ((0xFF000000) |
2560 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2561 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2562 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2563 } else {
2564 color = 0xFF000000;
2567 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2568 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2569 color = 0xFFFFFFFF;
2570 } else {
2571 color = ((0xFF000000) |
2572 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2573 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2574 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2577 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2578 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2579 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2581 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2582 color = DDBltFx->u5.dwFillColor;
2584 else {
2585 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2586 return WINED3DERR_INVALIDCALL;
2589 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2590 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2591 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2592 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2593 glDrawBuffer(GL_BACK);
2594 checkGLcall("glDrawBuffer(GL_BACK)");
2596 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2597 glDrawBuffer(GL_FRONT);
2598 checkGLcall("glDrawBuffer(GL_FRONT)");
2600 else {
2601 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2602 return WINED3DERR_INVALIDCALL;
2605 TRACE("(%p) executing Render Target override, color = %lx\n", This, color);
2607 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2608 1 /* Number of rectangles */,
2609 &rect,
2610 D3DCLEAR_TARGET,
2611 color,
2612 0.0 /* Z */,
2613 0 /* Stencil */);
2615 /* Restore the original draw buffer */
2616 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2617 glDrawBuffer(GL_BACK);
2618 vcheckGLcall("glDrawBuffer");
2621 return WINED3D_OK;
2624 /* Default: Fall back to the generic blt */
2625 return WINED3DERR_INVALIDCALL;
2628 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2629 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2630 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2631 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2632 TRACE("(%p): Usage is %08lx\n", This, This->resource.usage);
2634 /* Special cases for RenderTargets */
2635 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2636 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2637 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2640 /* For the rest call the X11 surface implementation.
2641 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2642 * other Blts are rather rare
2644 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2647 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2648 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2649 TRACE("(%p)->(%lx)\n", This, Flags);
2651 switch (Flags)
2653 case DDGBS_CANBLT:
2654 case DDGBS_ISBLTDONE:
2655 return DD_OK;
2657 default:
2658 return DDERR_INVALIDPARAMS;
2662 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2663 /* XXX: DDERR_INVALIDSURFACETYPE */
2665 TRACE("(%p)->(%08lx)\n",iface,Flags);
2666 switch (Flags) {
2667 case DDGFS_CANFLIP:
2668 case DDGFS_ISFLIPDONE:
2669 return DD_OK;
2671 default:
2672 return DDERR_INVALIDPARAMS;
2676 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2677 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2678 TRACE("(%p)\n", This);
2680 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2683 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2684 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2685 TRACE("(%p)\n", This);
2687 /* So far we don't lose anything :) */
2688 This->Flags &= ~SFLAG_LOST;
2689 return WINED3D_OK;
2692 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2693 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2694 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2695 TRACE("(%p)->(%ld, %ld, %p, %p, %08lx\n", iface, dstx, dsty, Source, rsrc, trans);
2697 /* Special cases for RenderTargets */
2698 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2699 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2701 RECT SrcRect, DstRect;
2703 if(rsrc) {
2704 SrcRect.left = rsrc->left;
2705 SrcRect.top= rsrc->top;
2706 SrcRect.bottom = rsrc->bottom;
2707 SrcRect.right = rsrc->right;
2708 } else {
2709 SrcRect.left = 0;
2710 SrcRect.top = 0;
2711 SrcRect.right = srcImpl->currentDesc.Width;
2712 SrcRect.bottom = srcImpl->currentDesc.Height;
2715 DstRect.left = dstx;
2716 DstRect.top=dsty;
2717 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2718 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2720 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, 0, NULL) == WINED3D_OK) return WINED3D_OK;
2724 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2727 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2728 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2729 TRACE("(%p)->(%p)\n", This, Pal);
2731 *Pal = (IWineD3DPalette *) This->palette;
2732 return DD_OK;
2735 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2736 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2737 RGBQUAD col[256];
2738 IWineD3DPaletteImpl *pal = This->palette;
2739 unsigned int n;
2740 TRACE("(%p)\n", This);
2742 if(This->resource.format == WINED3DFMT_P8 ||
2743 This->resource.format == WINED3DFMT_A8P8)
2745 TRACE("Dirtifying surface\n");
2746 This->Flags |= SFLAG_DIRTY;
2749 if(This->Flags & SFLAG_DIBSECTION) {
2750 TRACE("(%p): Updating the hdc's palette\n", This);
2751 for (n=0; n<256; n++) {
2752 if(pal) {
2753 col[n].rgbRed = pal->palents[n].peRed;
2754 col[n].rgbGreen = pal->palents[n].peGreen;
2755 col[n].rgbBlue = pal->palents[n].peBlue;
2756 } else {
2757 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2758 /* Use the default device palette */
2759 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2760 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2761 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2763 col[n].rgbReserved = 0;
2765 SetDIBColorTable(This->hDC, 0, 256, col);
2768 return WINED3D_OK;
2771 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2772 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2773 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2774 TRACE("(%p)->(%p)\n", This, Pal);
2776 if(This->palette != NULL)
2777 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2778 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2780 if(PalImpl != NULL) {
2781 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2782 /* Set the device's main palette if the palette
2783 * wasn't a primary palette before
2785 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2786 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2787 unsigned int i;
2789 for(i=0; i < 256; i++) {
2790 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2794 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2797 This->palette = PalImpl;
2799 return IWineD3DSurface_RealizePalette(iface);
2802 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2803 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2804 BOOL dirtify = FALSE;
2805 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
2807 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2808 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
2809 return DDERR_INVALIDPARAMS;
2812 /* Dirtify the surface, but only if a key was changed */
2813 if(CKey) {
2814 switch (Flags & ~DDCKEY_COLORSPACE) {
2815 case DDCKEY_DESTBLT:
2816 if(!(This->CKeyFlags & DDSD_CKDESTBLT)) {
2817 dirtify = TRUE;
2818 } else {
2819 dirtify = memcmp(&This->DestBltCKey, CKey, sizeof(*CKey) ) != 0;
2821 This->DestBltCKey = *CKey;
2822 This->CKeyFlags |= DDSD_CKDESTBLT;
2823 break;
2825 case DDCKEY_DESTOVERLAY:
2826 if(!(This->CKeyFlags & DDSD_CKDESTOVERLAY)) {
2827 dirtify = TRUE;
2828 } else {
2829 dirtify = memcmp(&This->DestOverlayCKey, CKey, sizeof(*CKey)) != 0;
2831 This->DestOverlayCKey = *CKey;
2832 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2833 break;
2835 case DDCKEY_SRCOVERLAY:
2836 if(!(This->CKeyFlags & DDSD_CKSRCOVERLAY)) {
2837 dirtify = TRUE;
2838 } else {
2839 dirtify = memcmp(&This->SrcOverlayCKey, CKey, sizeof(*CKey)) != 0;
2841 This->SrcOverlayCKey = *CKey;
2842 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2843 break;
2845 case DDCKEY_SRCBLT:
2846 if(!(This->CKeyFlags & DDSD_CKSRCBLT)) {
2847 dirtify = TRUE;
2848 } else {
2849 dirtify = memcmp(&This->SrcBltCKey, CKey, sizeof(*CKey)) != 0;
2851 This->SrcBltCKey = *CKey;
2852 This->CKeyFlags |= DDSD_CKSRCBLT;
2853 break;
2856 else {
2857 switch (Flags & ~DDCKEY_COLORSPACE) {
2858 case DDCKEY_DESTBLT:
2859 dirtify = This->CKeyFlags & DDSD_CKDESTBLT;
2860 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2861 break;
2863 case DDCKEY_DESTOVERLAY:
2864 dirtify = This->CKeyFlags & DDSD_CKDESTOVERLAY;
2865 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2866 break;
2868 case DDCKEY_SRCOVERLAY:
2869 dirtify = This->CKeyFlags & DDSD_CKSRCOVERLAY;
2870 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2871 break;
2873 case DDCKEY_SRCBLT:
2874 dirtify = This->CKeyFlags & DDSD_CKSRCBLT;
2875 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2876 break;
2880 if(dirtify) {
2881 TRACE("Color key changed, dirtifying surface\n");
2882 This->Flags |= SFLAG_DIRTY;
2885 return WINED3D_OK;
2888 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2889 /** Check against the maximum texture sizes supported by the video card **/
2890 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2892 TRACE("%p\n", This);
2893 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2894 /* one of three options
2895 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)
2896 2: Set the texture to the maxium size (bad idea)
2897 3: WARN and return WINED3DERR_NOTAVAILABLE;
2898 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.
2900 WARN("(%p) Creating an oversized surface\n", This);
2901 This->Flags |= SFLAG_OVERSIZE;
2903 /* This will be initialized on the first blt */
2904 This->glRect.left = 0;
2905 This->glRect.top = 0;
2906 This->glRect.right = 0;
2907 This->glRect.bottom = 0;
2908 } else {
2909 /* No oversize, gl rect is the full texture size */
2910 This->Flags &= ~SFLAG_OVERSIZE;
2911 This->glRect.left = 0;
2912 This->glRect.top = 0;
2913 This->glRect.right = This->pow2Width;
2914 This->glRect.bottom = This->pow2Height;
2917 return WINED3D_OK;
2920 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
2921 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2922 DWORD ret;
2923 TRACE("(%p)\n", This);
2925 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
2926 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
2927 ie pitch = (width/4) * bytes per block */
2928 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
2929 ret = (This->currentDesc.Width >> 2) << 3;
2930 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
2931 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
2932 ret = (This->currentDesc.Width >> 2) << 4;
2933 else {
2934 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2935 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
2936 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
2937 } else {
2938 ret = This->bytesPerPixel * This->pow2Width;
2941 TRACE("(%p) Returning %ld\n", This, ret);
2942 return ret;
2945 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
2947 /* IUnknown */
2948 IWineD3DSurfaceImpl_QueryInterface,
2949 IWineD3DSurfaceImpl_AddRef,
2950 IWineD3DSurfaceImpl_Release,
2951 /* IWineD3DResource */
2952 IWineD3DSurfaceImpl_GetParent,
2953 IWineD3DSurfaceImpl_GetDevice,
2954 IWineD3DSurfaceImpl_SetPrivateData,
2955 IWineD3DSurfaceImpl_GetPrivateData,
2956 IWineD3DSurfaceImpl_FreePrivateData,
2957 IWineD3DSurfaceImpl_SetPriority,
2958 IWineD3DSurfaceImpl_GetPriority,
2959 IWineD3DSurfaceImpl_PreLoad,
2960 IWineD3DSurfaceImpl_GetType,
2961 /* IWineD3DSurface */
2962 IWineD3DSurfaceImpl_GetContainerParent,
2963 IWineD3DSurfaceImpl_GetContainer,
2964 IWineD3DSurfaceImpl_GetDesc,
2965 IWineD3DSurfaceImpl_LockRect,
2966 IWineD3DSurfaceImpl_UnlockRect,
2967 IWineD3DSurfaceImpl_GetDC,
2968 IWineD3DSurfaceImpl_ReleaseDC,
2969 IWineD3DSurfaceImpl_Flip,
2970 IWineD3DSurfaceImpl_Blt,
2971 IWineD3DSurfaceImpl_GetBltStatus,
2972 IWineD3DSurfaceImpl_GetFlipStatus,
2973 IWineD3DSurfaceImpl_IsLost,
2974 IWineD3DSurfaceImpl_Restore,
2975 IWineD3DSurfaceImpl_BltFast,
2976 IWineD3DSurfaceImpl_GetPalette,
2977 IWineD3DSurfaceImpl_SetPalette,
2978 IWineD3DSurfaceImpl_RealizePalette,
2979 IWineD3DSurfaceImpl_SetColorKey,
2980 IWineD3DSurfaceImpl_GetPitch,
2981 /* Internal use: */
2982 IWineD3DSurfaceImpl_CleanDirtyRect,
2983 IWineD3DSurfaceImpl_AddDirtyRect,
2984 IWineD3DSurfaceImpl_LoadTexture,
2985 IWineD3DSurfaceImpl_SaveSnapshot,
2986 IWineD3DSurfaceImpl_SetContainer,
2987 IWineD3DSurfaceImpl_SetPBufferState,
2988 IWineD3DSurfaceImpl_SetGlTextureDesc,
2989 IWineD3DSurfaceImpl_GetGlDesc,
2990 IWineD3DSurfaceImpl_GetData,
2991 IWineD3DSurfaceImpl_SetFormat,
2992 IWineD3DSurfaceImpl_PrivateSetup