gphoto2.ds: Added Norwegian Bokmål resources.
[wine/wine-kai.git] / dlls / wined3d / surface.c
blobda0ef63e4a1f88d33d2ee1c5d818a7979660b37f
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 /* *******************************************
35 IWineD3DSurface IUnknown parts follow
36 ******************************************* */
37 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
39 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
40 /* Warn ,but be nice about things */
41 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
42 if (riid == NULL) {
43 ERR("Probably FIXME: Calling query interface with NULL riid\n");
45 if (IsEqualGUID(riid, &IID_IUnknown)
46 || IsEqualGUID(riid, &IID_IWineD3DBase)
47 || IsEqualGUID(riid, &IID_IWineD3DResource)
48 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
49 IUnknown_AddRef((IUnknown*)iface);
50 *ppobj = This;
51 return S_OK;
53 *ppobj = NULL;
54 return E_NOINTERFACE;
57 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
58 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
59 ULONG ref = InterlockedIncrement(&This->resource.ref);
60 TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
61 return ref;
64 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
65 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
66 ULONG ref = InterlockedDecrement(&This->resource.ref);
67 TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
68 if (ref == 0) {
69 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
70 TRACE("(%p) : cleaning up\n", This);
71 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
72 ENTER_GL();
73 TRACE("Deleting texture %d\n", This->glDescription.textureName);
74 glDeleteTextures(1, &This->glDescription.textureName);
75 LEAVE_GL();
78 if(This->Flags & SFLAG_DIBSECTION) {
79 /* Release the DC */
80 SelectObject(This->hDC, This->dib.holdbitmap);
81 DeleteDC(This->hDC);
82 /* Release the DIB section */
83 DeleteObject(This->dib.DIBsection);
84 This->dib.bitmap_data = NULL;
85 This->resource.allocatedMemory = NULL;
88 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
89 if(iface == device->ddraw_primary)
90 device->ddraw_primary = NULL;
92 TRACE("(%p) Released\n", This);
93 HeapFree(GetProcessHeap(), 0, This);
96 return ref;
99 /* ****************************************************
100 IWineD3DSurface IWineD3DResource parts follow
101 **************************************************** */
102 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
103 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
106 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
107 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
110 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
111 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
114 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
115 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
118 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
119 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
122 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
123 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
126 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
127 /* TODO: re-write the way textures and managed,
128 * use a 'opengl context manager' to manage RenderTarget surfaces
129 ** *********************************************************/
131 /* TODO: check for locks */
132 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
133 IWineD3DBaseTexture *baseTexture = NULL;
134 TRACE("(%p)Checking to see if the container is a base texture\n", This);
135 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
136 TRACE("Passing to conatiner\n");
137 IWineD3DBaseTexture_PreLoad(baseTexture);
138 IWineD3DBaseTexture_Release(baseTexture);
139 } else {
140 TRACE("(%p) : About to load surface\n", This);
141 ENTER_GL();
142 #if 0 /* TODO: context manager support */
143 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
144 #endif
145 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
146 if (This->glDescription.level == 0 && This->glDescription.textureName == 0) {
147 glGenTextures(1, &This->glDescription.textureName);
148 checkGLcall("glGenTextures");
149 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
150 glBindTexture(This->glDescription.target, This->glDescription.textureName);
151 checkGLcall("glBindTexture");
152 IWineD3DSurface_LoadTexture(iface);
153 /* This is where we should be reducing the amount of GLMemoryUsed */
154 } else {
155 if (This->glDescription.level == 0) {
156 glBindTexture(This->glDescription.target, This->glDescription.textureName);
157 checkGLcall("glBindTexture");
158 IWineD3DSurface_LoadTexture(iface);
159 } else if (This->glDescription.textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
160 /* assume this is a coding error not a real error for now */
161 FIXME("Mipmap surface has a glTexture bound to it!\n");
164 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
165 /* Tell opengl to try and keep this texture in video ram (well mostly) */
166 GLclampf tmp;
167 tmp = 0.9f;
168 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
170 /* TODO: disable texture support, if it wastn't enabled when we entered. */
171 #if 0 /* TODO: context manager support */
172 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
173 /* we don't care when the state is disabled(if atall) */);
174 #endif
175 LEAVE_GL();
177 return;
180 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
181 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
182 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
185 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
186 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
187 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
190 /* ******************************************************
191 IWineD3DSurface IWineD3DSurface parts follow
192 ****************************************************** */
194 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainerParent(IWineD3DSurface* iface, IUnknown **ppContainerParent) {
195 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
197 TRACE("(%p) : ppContainerParent %p)\n", This, ppContainerParent);
199 if (!ppContainerParent) {
200 ERR("(%p) : Called without a valid ppContainerParent.\n", This);
203 if (This->container) {
204 IWineD3DBase_GetParent(This->container, ppContainerParent);
205 if (!ppContainerParent) {
206 /* WineD3D objects should always have a parent */
207 ERR("(%p) : GetParent returned NULL\n", This);
209 IUnknown_Release(*ppContainerParent); /* GetParent adds a reference; we want just the pointer */
210 } else {
211 *ppContainerParent = NULL;
214 return WINED3D_OK;
217 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
218 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
219 IWineD3DBase *container = 0;
221 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
223 if (!ppContainer) {
224 ERR("Called without a valid ppContainer.\n");
227 /** From MSDN:
228 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
229 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
230 * GetContainer will return the Direct3D device used to create the surface.
232 if (This->container) {
233 container = This->container;
234 } else {
235 container = (IWineD3DBase *)This->resource.wineD3DDevice;
238 TRACE("Relaying to QueryInterface\n");
239 return IUnknown_QueryInterface(container, riid, ppContainer);
242 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
243 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
245 TRACE("(%p) : copying into %p\n", This, pDesc);
246 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
247 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
248 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
249 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
250 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
251 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
252 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
253 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
254 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
255 return WINED3D_OK;
258 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
259 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
260 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
261 if (This->glDescription.textureName == 0 && textureName != 0) {
262 This->Flags |= SFLAG_DIRTY;
263 IWineD3DSurface_AddDirtyRect(iface, NULL);
265 This->glDescription.textureName = textureName;
266 This->glDescription.target = target;
269 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
270 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
271 TRACE("(%p) : returning %p\n", This, &This->glDescription);
272 *glDescription = &This->glDescription;
275 /* TODO: think about moving this down to resource? */
276 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
277 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
278 /* 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 */
279 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
280 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
282 return (CONST void*)(This->resource.allocatedMemory);
285 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
286 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
287 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
288 IWineD3DSwapChainImpl *swapchain = NULL;
289 static UINT messages = 0; /* holds flags to disable fixme messages */
291 /* fixme: should we really lock as such? */
292 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
293 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
294 FIXME("Warning: Surface is in texture memory or pbuffer\n");
295 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
298 if (!(This->Flags & SFLAG_LOCKABLE)) {
299 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
300 texture regions, and since the destination is an unlockable region we need
301 to tolerate this */
302 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
303 /*return WINED3DERR_INVALIDCALL; */
306 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
307 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
309 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
310 if (swapchain != NULL && iface == swapchain->backBuffer) {
311 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
312 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
313 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
314 } else if (iface == myDevice->renderTarget) {
315 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
316 } else if (iface == myDevice->depthStencilBuffer) {
317 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
320 if (NULL != swapchain) {
321 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
323 swapchain = NULL;
325 } else {
326 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
329 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
331 if (NULL == pRect) {
332 pLockedRect->pBits = This->resource.allocatedMemory;
333 This->lockedRect.left = 0;
334 This->lockedRect.top = 0;
335 This->lockedRect.right = This->currentDesc.Width;
336 This->lockedRect.bottom = This->currentDesc.Height;
337 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);
338 } else {
339 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
341 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
342 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
343 } else {
344 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
346 This->lockedRect.left = pRect->left;
347 This->lockedRect.top = pRect->top;
348 This->lockedRect.right = pRect->right;
349 This->lockedRect.bottom = pRect->bottom;
352 if (This->Flags & SFLAG_NONPOW2) {
353 TRACE("Locking non-power 2 texture\n");
356 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
357 /* classic surface TODO: non 2d surfaces?
358 These resources may be POOL_SYSTEMMEM, so they must not access the device */
359 TRACE("locking an ordinarary surface\n");
360 /* Check to see if memory has already been allocated from the surface*/
361 if ((NULL == This->resource.allocatedMemory) ||
362 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
363 /* Non-system memory surfaces */
365 This->Flags &= ~SFLAG_GLDIRTY;
367 /*Surface has no memory currently allocated to it!*/
368 TRACE("(%p) Locking rect\n" , This);
369 if(!This->resource.allocatedMemory) {
370 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
372 if (0 != This->glDescription.textureName) {
373 /* Now I have to copy thing bits back */
374 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
375 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
376 ENTER_GL();
378 /* Make sure that the texture is loaded */
379 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
381 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);
383 if (This->resource.format == WINED3DFMT_DXT1 ||
384 This->resource.format == WINED3DFMT_DXT2 ||
385 This->resource.format == WINED3DFMT_DXT3 ||
386 This->resource.format == WINED3DFMT_DXT4 ||
387 This->resource.format == WINED3DFMT_DXT5) {
388 TRACE("Locking a compressed texture\n");
389 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
390 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
391 This->glDescription.level,
392 This->resource.allocatedMemory);
394 } else {
395 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
397 } else {
398 glGetTexImage(This->glDescription.target,
399 This->glDescription.level,
400 This->glDescription.glFormat,
401 This->glDescription.glType,
402 This->resource.allocatedMemory);
403 vcheckGLcall("glGetTexImage");
404 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
405 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
406 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
407 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
409 Were doing this...
411 instead of boxing the texture :
412 |<-texture width ->| -->pow2width| /\
413 |111111111111111111| | |
414 |222 Texture 222222| boxed empty | texture height
415 |3333 Data 33333333| | |
416 |444444444444444444| | \/
417 ----------------------------------- |
418 | boxed empty | boxed empty | pow2height
419 | | | \/
420 -----------------------------------
423 were repacking the data to the expected texture width
425 |<-texture width ->| -->pow2width| /\
426 |111111111111111111222222222222222| |
427 |222333333333333333333444444444444| texture height
428 |444444 | |
429 | | \/
430 | | |
431 | empty | pow2height
432 | | \/
433 -----------------------------------
435 == is the same as
437 |<-texture width ->| /\
438 |111111111111111111|
439 |222222222222222222|texture height
440 |333333333333333333|
441 |444444444444444444| \/
442 --------------------
444 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.
446 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.
448 if (This->Flags & SFLAG_NONPOW2) {
449 BYTE* dataa, *datab;
450 int pitcha = 0, pitchb = 0;
451 int y;
452 pitcha = This->bytesPerPixel * This->currentDesc.Width;
453 pitchb = This->bytesPerPixel * This->pow2Width;
454 datab = dataa = This->resource.allocatedMemory;
455 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
456 for (y = 1 ; y < This->currentDesc.Height; y++) {
457 dataa += pitcha; /* skip the first row */
458 datab += pitchb;
459 memcpy(dataa, datab, pitcha);
464 LEAVE_GL();
466 } else { /* Nothing to do */
467 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
470 if (NULL == pRect) {
471 pLockedRect->pBits = This->resource.allocatedMemory;
472 } else{
473 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
474 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
475 } else {
476 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
480 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
481 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
482 GLint prev_store;
483 GLint prev_read;
484 BOOL notInContext = FALSE;
485 IWineD3DSwapChainImpl *targetSwapChain = NULL;
488 ENTER_GL();
491 * for render->surface copy begin to begin of allocatedMemory
492 * unlock can be more easy
495 TRACE("locking a render target\n");
497 if (This->resource.allocatedMemory == NULL)
498 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
500 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
501 pLockedRect->pBits = This->resource.allocatedMemory;
503 glFlush();
504 vcheckGLcall("glFlush");
505 glGetIntegerv(GL_READ_BUFFER, &prev_read);
506 vcheckGLcall("glIntegerv");
507 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
508 vcheckGLcall("glIntegerv");
510 /* Here's what we have to do:
511 See if the swapchain has the same context as the renderTarget or the surface is the render target.
512 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
513 and use the front back buffer as required.
514 if not, we need to switch contexts and then switchback at the end.
516 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
517 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
519 /* 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! */
520 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
521 if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) {
522 TRACE("locking back buffer\n");
523 glReadBuffer(GL_BACK);
524 } else if (iface == swapchain->frontBuffer) {
525 TRACE("locking front\n");
526 glReadBuffer(GL_FRONT);
527 } else if (iface == myDevice->depthStencilBuffer) {
528 FIXME("Stencil Buffer lock unsupported for now\n");
529 } else {
530 FIXME("(%p) Shouldn't have got here!\n", This);
531 glReadBuffer(GL_BACK);
533 } else if (swapchain != NULL) {
534 IWineD3DSwapChainImpl *implSwapChain;
535 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
536 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
537 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
538 if (iface == swapchain->backBuffer) {
539 glReadBuffer(GL_BACK);
540 } else if (iface == swapchain->frontBuffer) {
541 glReadBuffer(GL_FRONT);
542 } else if (iface == myDevice->depthStencilBuffer) {
543 FIXME("Stencil Buffer lock unsupported for now\n");
544 } else {
545 FIXME("Should have got here!\n");
546 glReadBuffer(GL_BACK);
548 } else {
549 /* We need to switch contexts to be able to read the buffer!!! */
550 FIXME("The buffer requested isn't in the current openGL context\n");
551 notInContext = TRUE;
552 /* TODO: check the contexts, to see if were shared with the current context */
554 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
556 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
557 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
559 /** the depth stencil in openGL has a format of GL_FLOAT
560 * which should be good for WINED3DFMT_D16_LOCKABLE
561 * and WINED3DFMT_D16
562 * it is unclear what format the stencil buffer is in except.
563 * 'Each index is converted to fixed point...
564 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
565 * mappings in the table GL_PIXEL_MAP_S_TO_S.
566 * glReadPixels(This->lockedRect.left,
567 * This->lockedRect.bottom - j - 1,
568 * This->lockedRect.right - This->lockedRect.left,
569 * 1,
570 * GL_DEPTH_COMPONENT,
571 * type,
572 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
573 *****************************************/
574 if (!notInContext) { /* Only read the buffer if it's in the current context */
575 long j;
577 #if 0
578 /* Bizarly it takes 120 millseconds to get an 800x600 region a line at a time, but only 10 to get the whole lot every time,
579 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
580 * run ten times faster!
581 * ************************************/
582 BOOL ati_performance_hack = FALSE;
583 ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
584 #endif
585 if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
586 This->lockedRect.right == This->currentDesc.Width
587 && This->lockedRect.bottom == This->currentDesc.Height)) {
588 BYTE *row, *top, *bottom;
589 int i;
591 glReadPixels(0, 0,
592 This->currentDesc.Width,
593 This->currentDesc.Height,
594 This->glDescription.glFormat,
595 This->glDescription.glType,
596 (char *)pLockedRect->pBits);
598 /* glReadPixels returns the image upside down, and there is no way to prevent this.
599 Flip the lines in software*/
600 row = HeapAlloc(GetProcessHeap(), 0, pLockedRect->Pitch);
601 if(!row) {
602 ERR("Out of memory\n");
603 return E_OUTOFMEMORY;
605 top = This->resource.allocatedMemory;
606 bottom = ( (BYTE *) This->resource.allocatedMemory) + pLockedRect->Pitch * ( This->currentDesc.Height - 1);
607 for(i = 0; i < This->currentDesc.Height / 2; i++) {
608 memcpy(row, top, pLockedRect->Pitch);
609 memcpy(top, bottom, pLockedRect->Pitch);
610 memcpy(bottom, row, pLockedRect->Pitch);
611 top += pLockedRect->Pitch;
612 bottom -= pLockedRect->Pitch;
614 HeapFree(GetProcessHeap(), 0, row);
616 This->Flags &= ~SFLAG_GLDIRTY;
618 } else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
619 glReadPixels(0,
620 This->lockedRect.top,
621 This->currentDesc.Width,
622 This->currentDesc.Height,
623 This->glDescription.glFormat,
624 This->glDescription.glType,
625 (char *)pLockedRect->pBits);
626 } else{
628 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
629 glReadPixels(This->lockedRect.left,
630 This->lockedRect.bottom - j - 1,
631 This->lockedRect.right - This->lockedRect.left,
633 This->glDescription.glFormat,
634 This->glDescription.glType,
635 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
640 vcheckGLcall("glReadPixels");
641 TRACE("Resetting buffer\n");
642 glReadBuffer(prev_read);
643 vcheckGLcall("glReadBuffer");
645 LEAVE_GL();
647 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
649 if (!messages & 1) {
650 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
653 glReadPixels(This->lockedRect.left,
654 This->lockedRect.bottom - j - 1,
655 This->lockedRect.right - This->lockedRect.left,
657 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
661 messages |= 1;
663 } else {
664 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
667 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
668 /* Don't dirtify */
669 } else {
670 IWineD3DBaseTexture *pBaseTexture;
672 * Dirtify on lock
673 * as seen in msdn docs
675 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
677 /** Dirtify Container if needed */
678 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
679 TRACE("Making container dirty\n");
680 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
681 IWineD3DBaseTexture_Release(pBaseTexture);
682 } else {
683 TRACE("Surface is standalone, no need to dirty the container\n");
687 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
689 This->Flags |= SFLAG_LOCKED;
690 return WINED3D_OK;
693 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
694 GLint skipBytes = 0;
695 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
696 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
697 const char *buffername = "";
698 IWineD3DSwapChainImpl *swapchain = NULL;
700 if (!(This->Flags & SFLAG_LOCKED)) {
701 WARN("trying to Unlock an unlocked surf@%p\n", This);
702 return WINED3DERR_INVALIDCALL;
705 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
706 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
708 if ((swapchain != NULL) && iface == swapchain->backBuffer) {
709 buffername = "backBuffer";
710 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
711 buffername = "frontBuffer";
712 } else if (iface == myDevice->depthStencilBuffer) {
713 buffername = "depthStencilBuffer";
714 } else if (iface == myDevice->renderTarget) {
715 buffername = "renderTarget";
719 if (swapchain != NULL) {
720 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
723 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
725 if (!(This->Flags & SFLAG_DIRTY)) {
726 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
727 goto unlock_end;
730 if (0 == This->resource.usage) { /* classic surface */
732 * nothing to do
733 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
735 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
737 /****************************
738 * TODO: Render targets are 'special' and
739 * ?some? locking needs to be passed onto the context manager
740 * so that it becomes possible to use auxiliary buffers, pbuffers
741 * render-to-texture, shared, cached contexts etc...
742 * ****************************/
743 IWineD3DSwapChainImpl *implSwapChain;
744 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
746 if (iface == implSwapChain->backBuffer || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
747 GLint prev_store;
748 GLint prev_draw;
749 GLint prev_depth_test;
750 GLint prev_rasterpos[4];
752 /* Some drivers(radeon dri, others?) don't like exceptions during
753 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
754 * after ReleaseDC. Reading it will cause an exception, which x11drv will
755 * catch to put the dib section in InSync mode, which leads to a crash
756 * and a blocked x server on my radeon card.
758 * The following lines read the dib section so it is put in inSync mode
759 * before glDrawPixels is called and the crash is prevented. There won't
760 * be any interfering gdi accesses, because UnlockRect is called from
761 * ReleaseDC, and the app won't use the dc any more afterwards.
763 if(This->Flags & SFLAG_DIBSECTION) {
764 volatile BYTE read;
765 read = This->resource.allocatedMemory[0];
768 ENTER_GL();
770 glFlush();
771 vcheckGLcall("glFlush");
772 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
773 vcheckGLcall("glIntegerv");
774 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
775 vcheckGLcall("glIntegerv");
776 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
777 vcheckGLcall("glIntegerv");
778 glPixelZoom(1.0, -1.0);
779 vcheckGLcall("glPixelZoom");
780 prev_depth_test = glIsEnabled(GL_DEPTH_TEST);
782 /* glDrawPixels transforms the raster position as though it was a vertex -
783 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
784 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
785 d3ddevice_set_ortho(This->resource.wineD3DDevice);
787 if (iface == implSwapChain->frontBuffer) {
788 glDrawBuffer(GL_FRONT);
789 checkGLcall("glDrawBuffer GL_FRONT");
790 } else if (iface == implSwapChain->backBuffer || iface == myDevice->renderTarget) {
791 glDrawBuffer(GL_BACK);
792 checkGLcall("glDrawBuffer GL_BACK");
795 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
796 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
797 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
799 /* And back buffers are not blended */
800 glDisable(GL_BLEND);
801 glDisable(GL_DEPTH_TEST);
803 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
804 vcheckGLcall("glRasterPos2f");
805 switch (This->resource.format) {
806 case WINED3DFMT_X4R4G4B4:
808 int size;
809 unsigned short *data;
810 data = (unsigned short *)This->resource.allocatedMemory;
811 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
812 while(size > 0) {
813 *data |= 0xF000;
814 data++;
815 size--;
818 case WINED3DFMT_A4R4G4B4:
820 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
821 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
822 vcheckGLcall("glDrawPixels");
824 break;
825 case WINED3DFMT_R5G6B5:
827 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
828 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
829 vcheckGLcall("glDrawPixels");
831 break;
832 case WINED3DFMT_X1R5G5B5:
834 int size;
835 unsigned short *data;
836 data = (unsigned short *)This->resource.allocatedMemory;
837 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
838 while(size > 0) {
839 *data |= 0x8000;
840 data++;
841 size--;
844 case WINED3DFMT_A1R5G5B5:
846 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
847 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
848 vcheckGLcall("glDrawPixels");
850 break;
851 case WINED3DFMT_R8G8B8:
853 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
854 GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
855 vcheckGLcall("glDrawPixels");
857 break;
858 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
859 could be any random value this fixes the intro move in Pirates! */
861 int size;
862 unsigned int *data;
863 data = (unsigned int *)This->resource.allocatedMemory;
864 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
865 while(size > 0) {
866 *data |= 0xFF000000;
867 data++;
868 size--;
871 case WINED3DFMT_A8R8G8B8:
873 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
874 vcheckGLcall("glPixelStorei");
875 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
876 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
877 vcheckGLcall("glDrawPixels");
878 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
879 vcheckGLcall("glPixelStorei");
881 break;
882 case WINED3DFMT_A2R10G10B10:
884 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
885 vcheckGLcall("glPixelStorei");
886 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
887 GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
888 vcheckGLcall("glDrawPixels");
889 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
890 vcheckGLcall("glPixelStorei");
892 break;
893 default:
894 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
897 glPixelZoom(1.0,1.0);
898 vcheckGLcall("glPixelZoom");
899 glDrawBuffer(prev_draw);
900 vcheckGLcall("glDrawBuffer");
901 glRasterPos3iv(&prev_rasterpos[0]);
902 vcheckGLcall("glRasterPos3iv");
903 if(prev_depth_test) glEnable(GL_DEPTH_TEST);
905 /* Reset to previous pack row length / blending state */
906 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
907 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
909 LEAVE_GL();
911 /** restore clean dirty state */
912 IWineD3DSurface_CleanDirtyRect(iface);
914 } else {
915 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
917 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
919 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
921 if (iface == myDevice->depthStencilBuffer) {
922 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
923 } else {
924 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
927 } else {
928 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
931 unlock_end:
932 This->Flags &= ~SFLAG_LOCKED;
933 memset(&This->lockedRect, 0, sizeof(RECT));
934 return WINED3D_OK;
937 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
938 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
939 WINED3DLOCKED_RECT lock;
940 UINT usage;
941 BITMAPINFO* b_info;
942 HDC ddc;
943 DWORD *masks;
944 HRESULT hr;
945 RGBQUAD col[256];
947 TRACE("(%p)->(%p)\n",This,pHDC);
949 /* Give more detailed info for ddraw */
950 if (This->Flags & SFLAG_DCINUSE)
951 return DDERR_DCALREADYCREATED;
953 /* Can't GetDC if the surface is locked */
954 if (This->Flags & SFLAG_LOCKED)
955 return WINED3DERR_INVALIDCALL;
957 memset(&lock, 0, sizeof(lock)); /* To be sure */
959 /* Create a DIB section if there isn't a hdc yet */
960 if(!This->hDC) {
961 if(This->Flags & SFLAG_ACTIVELOCK) {
962 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
965 switch (This->bytesPerPixel) {
966 case 2:
967 case 4:
968 /* Allocate extra space to store the RGB bit masks. */
969 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
970 break;
972 case 3:
973 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
974 break;
976 default:
977 /* Allocate extra space for a palette. */
978 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
979 sizeof(BITMAPINFOHEADER)
980 + sizeof(RGBQUAD)
981 * (1 << (This->bytesPerPixel * 8)));
982 break;
985 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
986 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
987 b_info->bmiHeader.biWidth = This->currentDesc.Width;
988 b_info->bmiHeader.biHeight = -This->currentDesc.Height;
989 /* Use the full pow2 image size(assigned below) because LockRect
990 * will need it for a full glGetTexImage call
992 } else {
993 b_info->bmiHeader.biWidth = This->pow2Width;
994 b_info->bmiHeader.biHeight = -This->pow2Height;
996 b_info->bmiHeader.biPlanes = 1;
997 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
999 b_info->bmiHeader.biSizeImage = This->resource.size;
1001 b_info->bmiHeader.biXPelsPerMeter = 0;
1002 b_info->bmiHeader.biYPelsPerMeter = 0;
1003 b_info->bmiHeader.biClrUsed = 0;
1004 b_info->bmiHeader.biClrImportant = 0;
1006 /* Get the bit masks */
1007 masks = (DWORD *) &(b_info->bmiColors);
1008 switch (This->resource.format) {
1009 case WINED3DFMT_R8G8B8:
1010 usage = DIB_RGB_COLORS;
1011 b_info->bmiHeader.biCompression = BI_RGB;
1012 break;
1014 case WINED3DFMT_X1R5G5B5:
1015 case WINED3DFMT_A1R5G5B5:
1016 case WINED3DFMT_A4R4G4B4:
1017 case WINED3DFMT_X4R4G4B4:
1018 case WINED3DFMT_R3G3B2:
1019 case WINED3DFMT_A8R3G3B2:
1020 case WINED3DFMT_A2B10G10R10:
1021 case WINED3DFMT_A8B8G8R8:
1022 case WINED3DFMT_X8B8G8R8:
1023 case WINED3DFMT_A2R10G10B10:
1024 case WINED3DFMT_R5G6B5:
1025 case WINED3DFMT_A16B16G16R16:
1026 usage = 0;
1027 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1028 masks[0] = get_bitmask_red(This->resource.format);
1029 masks[1] = get_bitmask_green(This->resource.format);
1030 masks[2] = get_bitmask_blue(This->resource.format);
1031 break;
1033 default:
1034 /* Don't know palette */
1035 b_info->bmiHeader.biCompression = BI_RGB;
1036 usage = 0;
1037 break;
1040 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1041 if (ddc == 0) {
1042 HeapFree(GetProcessHeap(), 0, b_info);
1043 return HRESULT_FROM_WIN32(GetLastError());
1046 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);
1047 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1048 DeleteDC(ddc);
1050 if (!This->dib.DIBsection) {
1051 ERR("CreateDIBSection failed!\n");
1052 return HRESULT_FROM_WIN32(GetLastError());
1054 HeapFree(GetProcessHeap(), 0, b_info);
1056 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1058 /* copy the existing surface to the dib section */
1059 if(This->resource.allocatedMemory) {
1060 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->resource.size);
1061 /* We won't need that any more */
1062 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1063 } else {
1064 /* This is to make LockRect read the gl Texture although memory is allocated */
1065 This->Flags |= SFLAG_GLDIRTY;
1068 /* Use the dib section from now on */
1069 This->resource.allocatedMemory = This->dib.bitmap_data;
1071 /* Now allocate a HDC */
1072 This->hDC = CreateCompatibleDC(0);
1073 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1074 TRACE("using wined3d palette %p\n", This->palette);
1075 SelectPalette(This->hDC,
1076 This->palette ? This->palette->hpal : 0,
1077 FALSE);
1079 This->Flags |= SFLAG_DIBSECTION;
1082 /* Lock the surface */
1083 hr = IWineD3DSurface_LockRect(iface,
1084 &lock,
1085 NULL,
1087 if(FAILED(hr)) {
1088 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1089 /* keep the dib section */
1090 return hr;
1093 if(This->resource.format == WINED3DFMT_P8 ||
1094 This->resource.format == WINED3DFMT_A8P8) {
1095 unsigned int n;
1096 if(This->palette) {
1097 PALETTEENTRY ent[256];
1099 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1100 for (n=0; n<256; n++) {
1101 col[n].rgbRed = ent[n].peRed;
1102 col[n].rgbGreen = ent[n].peGreen;
1103 col[n].rgbBlue = ent[n].peBlue;
1104 col[n].rgbReserved = 0;
1106 } else {
1107 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1109 for (n=0; n<256; n++) {
1110 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1111 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1112 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1113 col[n].rgbReserved = 0;
1117 SetDIBColorTable(This->hDC, 0, 256, col);
1120 *pHDC = This->hDC;
1121 TRACE("returning %p\n",*pHDC);
1122 This->Flags |= SFLAG_DCINUSE;
1124 return WINED3D_OK;
1127 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1128 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1130 TRACE("(%p)->(%p)\n",This,hDC);
1132 if (!(This->Flags & SFLAG_DCINUSE))
1133 return D3DERR_INVALIDCALL;
1135 /* we locked first, so unlock now */
1136 IWineD3DSurface_UnlockRect(iface);
1138 This->Flags &= ~SFLAG_DCINUSE;
1140 return WINED3D_OK;
1143 /* ******************************************************
1144 IWineD3DSurface Internal (No mapping to directx api) parts follow
1145 ****************************************************** */
1147 typedef enum {
1148 NO_CONVERSION,
1149 CONVERT_PALETTED,
1150 CONVERT_PALETTED_CK,
1151 CONVERT_CK_565,
1152 CONVERT_CK_5551,
1153 CONVERT_CK_4444,
1154 CONVERT_CK_4444_ARGB,
1155 CONVERT_CK_1555,
1156 CONVERT_555,
1157 CONVERT_CK_RGB24,
1158 CONVERT_CK_8888,
1159 CONVERT_CK_8888_ARGB,
1160 CONVERT_RGB32_888
1161 } CONVERT_TYPES;
1163 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp) {
1164 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1166 /* Default values: From the surface */
1167 *format = D3DFmt2GLFmt(This->resource.wineD3DDevice,
1168 This->resource.format);
1169 *internal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice,
1170 This->resource.format);
1171 *type = D3DFmt2GLType(This->resource.wineD3DDevice,
1172 This->resource.format);
1173 *convert = NO_CONVERSION;
1174 *target_bpp = This->bytesPerPixel;
1176 /* Ok, now look if we have to do any conversion */
1177 switch(This->resource.format) {
1178 case WINED3DFMT_P8:
1179 /* ****************
1180 Paletted Texture
1181 **************** */
1182 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active) {
1183 *format = GL_RGBA;
1184 *internal = GL_RGBA;
1185 *type = GL_UNSIGNED_BYTE;
1186 *target_bpp = 4;
1187 if(colorkey_active) {
1188 *convert = CONVERT_PALETTED;
1189 } else {
1190 *convert = CONVERT_PALETTED_CK;
1194 break;
1196 case WINED3DFMT_R3G3B2:
1197 /* **********************
1198 GL_UNSIGNED_BYTE_3_3_2
1199 ********************** */
1200 if (colorkey_active) {
1201 /* This texture format will never be used.. So do not care about color keying
1202 up until the point in time it will be needed :-) */
1203 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1205 break;
1207 case WINED3DFMT_R5G6B5:
1208 if (colorkey_active) {
1209 *convert = CONVERT_CK_565;
1210 *format = GL_RGBA;
1211 *internal = GL_RGBA;
1212 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1214 break;
1216 case WINED3DFMT_R8G8B8:
1217 if (colorkey_active) {
1218 *convert = CONVERT_CK_RGB24;
1219 *format = GL_RGBA;
1220 *internal = GL_RGBA;
1221 *type = GL_UNSIGNED_INT_8_8_8_8;
1222 *target_bpp = 4;
1224 break;
1226 case WINED3DFMT_X8R8G8B8:
1227 if (colorkey_active) {
1228 *convert = CONVERT_RGB32_888;
1229 *format = GL_RGBA;
1230 *internal = GL_RGBA;
1231 *type = GL_UNSIGNED_INT_8_8_8_8;
1233 break;
1234 #if 0
1235 /* Not sure if we should do color keying on Alpha-Enabled surfaces */
1236 case WINED3DFMT_A4R4G4B4:
1237 if (colorkey_active)
1239 *convert = CONVERT_CK_4444_ARGB;
1240 *format = GL_RGBA;
1241 *internal = GL_RGBA;
1242 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1244 break;
1246 case WINED3DFMT_A1R5G5B5:
1247 if (colorkey_active)
1249 *convert = CONVERT_CK_1555;
1252 case WINED3DFMT_A8R8G8B8:
1253 if (colorkey_active)
1255 *convert = CONVERT_CK_8888_ARGB;
1256 *format = GL_RGBA;
1257 *internal = GL_RGBA;
1258 *type = GL_UNSIGNED_INT_8_8_8_8;
1260 break;
1261 #endif
1262 default:
1263 break;
1266 return WINED3D_OK;
1269 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1270 TRACE("(%p)->(%p),(%ld,%d,%p)\n", src, dst, len, convert, surf);
1272 switch (convert) {
1273 case NO_CONVERSION:
1275 memcpy(dst, src, len * surf->bytesPerPixel);
1276 break;
1278 case CONVERT_PALETTED:
1279 case CONVERT_PALETTED_CK:
1281 IWineD3DPaletteImpl* pal = surf->palette;
1282 BYTE table[256][4];
1283 unsigned int i;
1284 unsigned int x;
1286 if( pal == NULL) {
1287 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1290 if (pal == NULL) {
1291 /* Still no palette? Use the device's palette */
1292 /* Get the surface's palette */
1293 for (i = 0; i < 256; i++) {
1294 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1296 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1297 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1298 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1299 if ((convert == CONVERT_PALETTED_CK) &&
1300 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1301 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1302 /* We should maybe here put a more 'neutral' color than the standard bright purple
1303 one often used by application to prevent the nice purple borders when bi-linear
1304 filtering is on */
1305 table[i][3] = 0x00;
1306 } else {
1307 table[i][3] = 0xFF;
1310 } else {
1311 TRACE("Using surface palette %p\n", pal);
1312 /* Get the surface's palette */
1313 for (i = 0; i < 256; i++) {
1314 table[i][0] = pal->palents[i].peRed;
1315 table[i][1] = pal->palents[i].peGreen;
1316 table[i][2] = pal->palents[i].peBlue;
1317 if ((convert == CONVERT_PALETTED_CK) &&
1318 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1319 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1320 /* We should maybe here put a more 'neutral' color than the standard bright purple
1321 one often used by application to prevent the nice purple borders when bi-linear
1322 filtering is on */
1323 table[i][3] = 0x00;
1324 } else {
1325 table[i][3] = 0xFF;
1330 for (x = 0; x < len; x++) {
1331 BYTE color = *src++;
1332 *dst++ = table[color][0];
1333 *dst++ = table[color][1];
1334 *dst++ = table[color][2];
1335 *dst++ = table[color][3];
1338 break;
1340 case CONVERT_CK_565:
1342 /* Converting the 565 format in 5551 packed to emulate color-keying.
1344 Note : in all these conversion, it would be best to average the averaging
1345 pixels to get the color of the pixel that will be color-keyed to
1346 prevent 'color bleeding'. This will be done later on if ever it is
1347 too visible.
1349 Note2: when using color-keying + alpha, are the alpha bits part of the
1350 color-space or not ?
1352 unsigned int x;
1353 WORD *Source = (WORD *) src;
1354 WORD *Dest = (WORD *) dst;
1356 TRACE("Color keyed 565\n");
1358 for (x = 0; x < len; x++ ) {
1359 WORD color = *Source++;
1360 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1361 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1362 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1363 *Dest |= 0x0001;
1365 Dest++;
1368 break;
1370 case CONVERT_CK_1555:
1372 unsigned int x;
1373 WORD *Source = (WORD *) src;
1374 WORD *Dest = (WORD *) dst;
1376 for (x = 0; x < len * sizeof(WORD); x+=sizeof(WORD)) {
1377 WORD color = *Source++;
1378 *Dest = (color & 0x7FFF);
1379 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1380 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1381 *Dest |= (color & 0x8000);
1382 Dest++;
1385 break;
1387 case CONVERT_CK_4444_ARGB:
1389 /* Move the four Alpha bits... */
1390 unsigned int x;
1391 WORD *Source = (WORD *) src;
1392 WORD *Dest = (WORD *) dst;
1394 for (x = 0; x < len; x++) {
1395 WORD color = *Source++;
1396 *dst = (color & 0x0FFF) << 4;
1397 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1398 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1399 *Dest |= (color & 0xF000) >> 12;
1400 Dest++;
1402 } break;
1404 default:
1405 ERR("Unsupported conversation type %d\n", convert);
1408 return WINED3D_OK;
1411 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1412 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1414 if (This->Flags & SFLAG_INTEXTURE) {
1415 TRACE("Surface already in texture\n");
1416 return WINED3D_OK;
1418 if (!(This->Flags & SFLAG_DIRTY)) {
1419 TRACE("surface isn't dirty\n");
1420 return WINED3D_OK;
1423 This->Flags &= ~SFLAG_DIRTY;
1425 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1426 * These resources are not bound by device size or format restrictions. Because of this,
1427 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1428 * However, these resources can always be created, locked, and copied.
1430 if (This->resource.pool == WINED3DPOOL_SCRATCH)
1432 FIXME("(%p) Operation not supported for scratch textures\n",This);
1433 return WINED3DERR_INVALIDCALL;
1436 if (This->Flags & SFLAG_INPBUFFER) {
1437 ENTER_GL();
1439 if (This->glDescription.level != 0)
1440 FIXME("Surface in texture is only supported for level 0\n");
1441 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1442 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1443 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1444 This->resource.format == WINED3DFMT_DXT5)
1445 FIXME("Format %d not supported\n", This->resource.format);
1446 else {
1447 GLint prevRead;
1448 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1449 vcheckGLcall("glGetIntegerv");
1450 glReadBuffer(GL_BACK);
1451 vcheckGLcall("glReadBuffer");
1453 glCopyTexImage2D(This->glDescription.target,
1454 This->glDescription.level,
1455 This->glDescription.glFormatInternal,
1458 This->currentDesc.Width,
1459 This->currentDesc.Height,
1462 checkGLcall("glCopyTexImage2D");
1463 glReadBuffer(prevRead);
1464 vcheckGLcall("glReadBuffer");
1465 TRACE("Updating target %d\n", This->glDescription.target);
1466 This->Flags |= SFLAG_INTEXTURE;
1468 LEAVE_GL();
1469 return WINED3D_OK;
1472 /* TODO: Compressed non-power 2 support */
1474 if (This->resource.format == WINED3DFMT_DXT1 ||
1475 This->resource.format == WINED3DFMT_DXT2 ||
1476 This->resource.format == WINED3DFMT_DXT3 ||
1477 This->resource.format == WINED3DFMT_DXT4 ||
1478 This->resource.format == WINED3DFMT_DXT5) {
1479 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1480 FIXME("Using DXT1/3/5 without advertized support\n");
1481 } else if (This->resource.allocatedMemory) {
1482 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1483 This->glDescription.target,
1484 This->glDescription.level,
1485 This->glDescription.glFormatInternal,
1486 This->currentDesc.Width,
1487 This->currentDesc.Height,
1489 This->resource.size,
1490 This->resource.allocatedMemory);
1492 ENTER_GL();
1494 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1495 This->glDescription.level,
1496 This->glDescription.glFormatInternal,
1497 This->currentDesc.Width,
1498 This->currentDesc.Height,
1500 This->resource.size,
1501 This->resource.allocatedMemory);
1502 checkGLcall("glCommpressedTexImage2D");
1504 LEAVE_GL();
1506 if(!(This->Flags & SFLAG_DONOTFREE)){
1507 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1508 This->resource.allocatedMemory = NULL;
1511 } else {
1512 GLenum format, internal, type;
1513 CONVERT_TYPES convert;
1514 int bpp;
1515 BYTE *mem;
1517 d3dfmt_get_conv(This, TRUE /* We need color keying */, &format, &internal, &type, &convert, &bpp);
1519 if((convert != NO_CONVERSION) &&
1520 This->resource.allocatedMemory) {
1521 int width = This->glRect.right - This->glRect.left;
1522 int height = This->glRect.bottom - This->glRect.top;
1523 int row;
1525 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
1526 if(!mem) {
1527 ERR("Out of memory %d, %d!\n", width, height);
1528 return WINED3DERR_OUTOFVIDEOMEMORY;
1531 for(row = This->glRect.top; row < This->glRect.bottom; row++) {
1532 BYTE *cur = This->resource.allocatedMemory + row * This->pow2Width * This->bytesPerPixel;
1533 d3dfmt_convert_surface(cur + This->glRect.left * This->bytesPerPixel,
1534 mem + row * width * bpp,
1535 width,
1536 convert,
1537 This);
1539 This->Flags |= SFLAG_CONVERTED;
1540 } else {
1541 This->Flags &= ~SFLAG_CONVERTED;
1542 mem = This->resource.allocatedMemory;
1545 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1546 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE) ) {
1549 TRACE("non power of two support\n");
1550 ENTER_GL();
1551 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,
1552 This->glDescription.target,
1553 This->glDescription.level,
1554 debug_d3dformat(This->resource.format),
1555 This->glDescription.glFormatInternal,
1556 This->pow2Width,
1557 This->pow2Height,
1559 This->glDescription.glFormat,
1560 This->glDescription.glType,
1561 NULL);
1563 glTexImage2D(This->glDescription.target,
1564 This->glDescription.level,
1565 This->glDescription.glFormatInternal,
1566 This->pow2Width,
1567 This->pow2Height,
1568 0/*border*/,
1569 This->glDescription.glFormat,
1570 This->glDescription.glType,
1571 NULL);
1573 checkGLcall("glTexImage2D");
1574 if (This->resource.allocatedMemory != NULL) {
1575 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1576 /* And map the non-power two data into the top left corner */
1577 glTexSubImage2D(
1578 This->glDescription.target,
1579 This->glDescription.level,
1580 0 /* xoffset */,
1581 0 /* ysoffset */ ,
1582 This->currentDesc.Width,
1583 This->currentDesc.Height,
1584 This->glDescription.glFormat,
1585 This->glDescription.glType,
1586 This->resource.allocatedMemory
1588 checkGLcall("glTexSubImage2D");
1590 LEAVE_GL();
1592 } else {
1594 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%ld, h=%ld,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1595 This->glDescription.target,
1596 This->glDescription.level,
1597 debug_d3dformat(This->resource.format),
1598 This->glDescription.glFormatInternal,
1599 This->glRect.right - This->glRect.left,
1600 This->glRect.bottom - This->glRect.top,
1602 This->glDescription.glFormat,
1603 This->glDescription.glType,
1604 mem);
1606 ENTER_GL();
1608 /* OK, create the texture */
1609 glTexImage2D(This->glDescription.target,
1610 This->glDescription.level,
1611 internal,
1612 This->glRect.right - This->glRect.left,
1613 This->glRect.bottom - This->glRect.top,
1614 0 /* border */,
1615 format,
1616 type,
1617 mem);
1619 checkGLcall("glTexImage2D");
1621 LEAVE_GL();
1623 if(mem != This->resource.allocatedMemory)
1624 HeapFree(GetProcessHeap(), 0, mem);
1626 #if 0
1628 static unsigned int gen = 0;
1629 char buffer[4096];
1630 ++gen;
1631 if ((gen % 10) == 0) {
1632 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1633 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1636 * debugging crash code
1637 if (gen == 250) {
1638 void** test = NULL;
1639 *test = 0;
1643 #endif
1644 if(!(This->Flags & SFLAG_DONOTFREE)){
1645 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1646 This->resource.allocatedMemory = NULL;
1651 return WINED3D_OK;
1654 #include <errno.h>
1655 #include <stdio.h>
1656 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1657 FILE* f = NULL;
1658 UINT i, y;
1659 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1660 char *allocatedMemory;
1661 char *textureRow;
1662 IWineD3DSwapChain *swapChain = NULL;
1663 int width, height;
1664 GLuint tmpTexture;
1665 DWORD color;
1666 /*FIXME:
1667 Textures my not be stored in ->allocatedgMemory and a GlTexture
1668 so we should lock the surface before saving a snapshot, or at least check that
1670 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1671 by calling GetTexImage and in compressed form by calling
1672 GetCompressedTexImageARB. Queried compressed images can be saved and
1673 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1674 texture images do not need to be processed by the GL and should
1675 significantly improve texture loading performance relative to uncompressed
1676 images. */
1678 /* Setup the width and height to be the internal texture width and height. */
1679 width = This->pow2Width;
1680 height = This->pow2Height;
1681 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1682 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1684 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1685 /* 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 */
1686 GLint prevRead;
1687 ENTER_GL();
1688 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1689 glEnable(GL_TEXTURE_2D);
1691 glGenTextures(1, &tmpTexture);
1692 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1694 glTexImage2D(GL_TEXTURE_2D,
1696 GL_RGBA,
1697 width,
1698 height,
1699 0/*border*/,
1700 GL_RGBA,
1701 GL_UNSIGNED_INT_8_8_8_8_REV,
1702 NULL);
1704 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1705 vcheckGLcall("glGetIntegerv");
1706 glReadBuffer(GL_BACK);
1707 vcheckGLcall("glReadBuffer");
1708 glCopyTexImage2D(GL_TEXTURE_2D,
1710 GL_RGBA,
1713 width,
1714 height,
1717 checkGLcall("glCopyTexImage2D");
1718 glReadBuffer(prevRead);
1719 LEAVE_GL();
1721 } else { /* bind the real texture */
1722 IWineD3DSurface_PreLoad(iface);
1724 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1725 ENTER_GL();
1726 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1727 glGetTexImage(GL_TEXTURE_2D,
1728 This->glDescription.level,
1729 GL_RGBA,
1730 GL_UNSIGNED_INT_8_8_8_8_REV,
1731 allocatedMemory);
1732 checkGLcall("glTexImage2D");
1733 if (tmpTexture) {
1734 glBindTexture(GL_TEXTURE_2D, 0);
1735 glDeleteTextures(1, &tmpTexture);
1737 LEAVE_GL();
1739 f = fopen(filename, "w+");
1740 if (NULL == f) {
1741 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1742 return WINED3DERR_INVALIDCALL;
1744 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1745 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1746 /* TGA header */
1747 fputc(0,f);
1748 fputc(0,f);
1749 fputc(2,f);
1750 fputc(0,f);
1751 fputc(0,f);
1752 fputc(0,f);
1753 fputc(0,f);
1754 fputc(0,f);
1755 fputc(0,f);
1756 fputc(0,f);
1757 fputc(0,f);
1758 fputc(0,f);
1759 /* short width*/
1760 fwrite(&width,2,1,f);
1761 /* short height */
1762 fwrite(&height,2,1,f);
1763 /* format rgba */
1764 fputc(0x20,f);
1765 fputc(0x28,f);
1766 /* raw data */
1767 /* 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*/
1768 if(swapChain)
1769 textureRow = allocatedMemory + (width * (height - 1) *4);
1770 else
1771 textureRow = allocatedMemory;
1772 for (y = 0 ; y < height; y++) {
1773 for (i = 0; i < width; i++) {
1774 color = *((DWORD*)textureRow);
1775 fputc((color >> 16) & 0xFF, f); /* B */
1776 fputc((color >> 8) & 0xFF, f); /* G */
1777 fputc((color >> 0) & 0xFF, f); /* R */
1778 fputc((color >> 24) & 0xFF, f); /* A */
1779 textureRow += 4;
1781 /* take two rows of the pointer to the texture memory */
1782 if(swapChain)
1783 (textureRow-= width << 3);
1786 TRACE("Closing file\n");
1787 fclose(f);
1789 if(swapChain) {
1790 IWineD3DSwapChain_Release(swapChain);
1792 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1793 return WINED3D_OK;
1796 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1797 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1798 This->Flags &= ~SFLAG_DIRTY;
1799 This->dirtyRect.left = This->currentDesc.Width;
1800 This->dirtyRect.top = This->currentDesc.Height;
1801 This->dirtyRect.right = 0;
1802 This->dirtyRect.bottom = 0;
1803 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1804 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1805 return WINED3D_OK;
1809 * Slightly inefficient way to handle multiple dirty rects but it works :)
1811 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1812 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1813 IWineD3DBaseTexture *baseTexture = NULL;
1814 This->Flags |= SFLAG_DIRTY;
1815 if (NULL != pDirtyRect) {
1816 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1817 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1818 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1819 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1820 } else {
1821 This->dirtyRect.left = 0;
1822 This->dirtyRect.top = 0;
1823 This->dirtyRect.right = This->currentDesc.Width;
1824 This->dirtyRect.bottom = This->currentDesc.Height;
1826 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
1827 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1828 /* if the container is a basetexture then mark it dirty. */
1829 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1830 TRACE("Passing to conatiner\n");
1831 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1832 IWineD3DBaseTexture_Release(baseTexture);
1834 return WINED3D_OK;
1837 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1838 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1840 TRACE("This %p, container %p\n", This, container);
1842 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1844 TRACE("Setting container to %p from %p\n", container, This->container);
1845 This->container = container;
1847 return WINED3D_OK;
1850 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1851 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1853 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1854 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1855 return WINED3DERR_INVALIDCALL;
1858 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1859 if (format == WINED3DFMT_UNKNOWN) {
1860 This->resource.size = 0;
1861 } else if (format == WINED3DFMT_DXT1) {
1862 /* DXT1 is half byte per pixel */
1863 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1865 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1866 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1867 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1868 } else {
1869 This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1873 /* Setup some glformat defaults */
1874 if (format != WINED3DFMT_UNKNOWN) {
1875 This->glDescription.glFormat = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1876 This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1877 This->glDescription.glType = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1878 } else {
1879 This->glDescription.glFormat = 0;
1880 This->glDescription.glFormatInternal = 0;
1881 This->glDescription.glType = 0;
1884 if (format != WINED3DFMT_UNKNOWN) {
1885 This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1886 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1887 } else {
1888 This->bytesPerPixel = 0;
1889 This->pow2Size = 0;
1892 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
1894 This->resource.format = format;
1896 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);
1898 return WINED3D_OK;
1901 /* TODO: replace this function with context management routines */
1902 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1903 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1905 if(inPBuffer) {
1906 This->Flags |= SFLAG_INPBUFFER;
1907 } else {
1908 This->Flags &= ~SFLAG_INPBUFFER;
1911 if(inTexture) {
1912 This->Flags |= SFLAG_INTEXTURE;
1913 } else {
1914 This->Flags &= ~SFLAG_INTEXTURE;
1917 return WINED3D_OK;
1920 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
1921 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1922 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
1923 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
1925 /* Flipping is only supported on RenderTargets */
1926 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
1928 if(override) {
1929 /* DDraw sets this for the X11 surfaces, so don't confuse the user
1930 * FIXME("(%p) Target override is not supported by now\n", This);
1931 * Additionally, it isn't really possible to support triple-buffering
1932 * properly on opengl at all
1936 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
1937 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
1940 /* Not called from the VTable */
1941 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
1942 D3DRECT rect;
1943 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1944 IWineD3DSwapChainImpl *swapchain = NULL;
1945 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
1946 BOOL SrcOK = TRUE;
1948 TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
1950 /* Get the swapchain. One of the surfaces has to be a primary surface */
1951 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
1952 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1953 else if(Src) {
1954 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
1955 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1956 else return WINED3DERR_INVALIDCALL;
1957 } else {
1958 swapchain = NULL;
1961 if (DestRect) {
1962 rect.x1 = DestRect->left;
1963 rect.y1 = DestRect->top;
1964 rect.x2 = DestRect->right;
1965 rect.y2 = DestRect->bottom;
1966 } else {
1967 rect.x1 = 0;
1968 rect.y1 = 0;
1969 rect.x2 = This->currentDesc.Width;
1970 rect.y2 = This->currentDesc.Height;
1973 /* Half-life does a Blt from the back buffer to the front buffer,
1974 * Full surface size, no flags... Use present instead
1976 if(Src)
1978 /* First, check if we can do a Flip */
1980 /* Check rects - IWineD3DDevice_Present doesn't handle them */
1981 if( SrcRect ) {
1982 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
1983 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
1984 SrcOK = TRUE;
1986 } else {
1987 SrcOK = TRUE;
1990 /* Check the Destination rect and the surface sizes */
1991 if(SrcOK &&
1992 (rect.x1 == 0) && (rect.y1 == 0) &&
1993 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
1994 (This->currentDesc.Width == Src->currentDesc.Width) &&
1995 (This->currentDesc.Height == Src->currentDesc.Height)) {
1996 /* These flags are unimportant for the flag check, remove them */
1998 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
1999 if( ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer) ) {
2001 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2003 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2004 * take very long, while a flip is fast.
2005 * This applies to Half-Life, which does such Blts every time it finished
2006 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2007 * menu. This is also used by all apps when they do windowed rendering
2009 * The problem is that flipping is not really the same as copying. After a
2010 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2011 * untouched. Therefore it's necessary to override the swap effect
2012 * and to set it back after the flip.
2015 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2017 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2018 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2019 NULL, NULL, 0, NULL);
2021 swapchain->presentParms.SwapEffect = orig_swap;
2023 return WINED3D_OK;
2028 /* Blt from texture to rendertarget? */
2029 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2030 ((IWineD3DSurface *) This == swapchain->backBuffer) )
2032 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2033 ( (IWineD3DSurface *) Src != swapchain->backBuffer) ) ) {
2034 float glTexCoord[4];
2035 DWORD oldCKey;
2036 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2037 GLint alphafunc;
2038 GLclampf alpharef;
2039 GLint oldStencil;
2040 RECT SourceRectangle;
2041 GLint oldDraw;
2043 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2045 if(SrcRect) {
2046 SourceRectangle.left = SrcRect->left;
2047 SourceRectangle.right = SrcRect->right;
2048 SourceRectangle.top = SrcRect->top;
2049 SourceRectangle.bottom = SrcRect->bottom;
2050 } else {
2051 SourceRectangle.left = 0;
2052 SourceRectangle.right = Src->currentDesc.Width;
2053 SourceRectangle.top = 0;
2054 SourceRectangle.bottom = Src->currentDesc.Height;
2057 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2058 /* Fall back to software */
2059 WARN("(%p) Source texture area (%ld,%ld)-(%ld,%ld) is too big\n", Src,
2060 SourceRectangle.left, SourceRectangle.top,
2061 SourceRectangle.right, SourceRectangle.bottom);
2062 return WINED3DERR_INVALIDCALL;
2065 /* Color keying: Check if we have to do a color keyed blt,
2066 * and if not check if a color key is activated.
2068 oldCKey = Src->CKeyFlags;
2069 if(!(Flags & DDBLT_KEYSRC) &&
2070 Src->CKeyFlags & DDSD_CKSRCBLT) {
2071 /* Ok, the surface has a color key, but we shall not use it -
2072 * Deactivate it for now and dirtify the surface to reload it
2074 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2075 Src->Flags |= SFLAG_DIRTY;
2078 /* Now load the surface */
2079 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2081 ENTER_GL();
2083 /* Save all the old stuff until we have a proper opengl state manager */
2084 oldLight = glIsEnabled(GL_LIGHTING);
2085 oldFog = glIsEnabled(GL_FOG);
2086 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2087 oldBlend = glIsEnabled(GL_BLEND);
2088 oldCull = glIsEnabled(GL_CULL_FACE);
2089 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2090 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2092 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2093 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2094 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2095 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2097 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2098 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2099 TRACE("Drawing to front buffer\n");
2100 glDrawBuffer(GL_FRONT);
2101 checkGLcall("glDrawBuffer GL_FRONT");
2104 /* Unbind the old texture */
2105 glBindTexture(GL_TEXTURE_2D, 0);
2107 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2108 /* We use texture unit 0 for blts */
2109 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2110 checkGLcall("glActiveTextureARB");
2111 } else {
2112 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2115 /* Disable some fancy graphics effects */
2116 glDisable(GL_LIGHTING);
2117 checkGLcall("glDisable GL_LIGHTING");
2118 glDisable(GL_DEPTH_TEST);
2119 checkGLcall("glDisable GL_DEPTH_TEST");
2120 glDisable(GL_FOG);
2121 checkGLcall("glDisable GL_FOG");
2122 glDisable(GL_BLEND);
2123 checkGLcall("glDisable GL_BLEND");
2124 glDisable(GL_CULL_FACE);
2125 checkGLcall("glDisable GL_CULL_FACE");
2126 glDisable(GL_STENCIL_TEST);
2127 checkGLcall("glDisable GL_STENCIL_TEST");
2129 /* Ok, we need 2d textures, but not 1D or 3D */
2130 glDisable(GL_TEXTURE_1D);
2131 checkGLcall("glDisable GL_TEXTURE_1D");
2132 glEnable(GL_TEXTURE_2D);
2133 checkGLcall("glEnable GL_TEXTURE_2D");
2134 glDisable(GL_TEXTURE_3D);
2135 checkGLcall("glDisable GL_TEXTURE_3D");
2137 /* Bind the texture */
2138 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2139 checkGLcall("glBindTexture");
2141 glEnable(GL_SCISSOR_TEST);
2143 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2145 /* No filtering for blts */
2146 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2147 GL_NEAREST);
2148 checkGLcall("glTexParameteri");
2149 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2150 GL_NEAREST);
2151 checkGLcall("glTexParameteri");
2152 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2153 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2154 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2155 checkGLcall("glTexEnvi");
2157 /* This is for color keying */
2158 if(Flags & DDBLT_KEYSRC) {
2159 glEnable(GL_ALPHA_TEST);
2160 checkGLcall("glEnable GL_ALPHA_TEST");
2161 glAlphaFunc(GL_NOTEQUAL, 0.0);
2162 checkGLcall("glAlphaFunc\n");
2163 } else {
2164 glDisable(GL_ALPHA_TEST);
2165 checkGLcall("glDisable GL_ALPHA_TEST");
2168 /* Draw a textured quad
2170 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2172 glBegin(GL_QUADS);
2174 glColor3d(1.0f, 1.0f, 1.0f);
2175 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2176 glVertex3f(rect.x1,
2177 rect.y1,
2178 0.0);
2180 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2181 glVertex3f(rect.x1, rect.y2, 0.0);
2183 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2184 glVertex3f(rect.x2,
2185 rect.y2,
2186 0.0);
2188 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2189 glVertex3f(rect.x2,
2190 rect.y1,
2191 0.0);
2192 glEnd();
2193 checkGLcall("glEnd");
2195 /* Unbind the texture */
2196 glBindTexture(GL_TEXTURE_2D, 0);
2197 checkGLcall("glEnable glBindTexture");
2199 /* Restore the old settings */
2200 if(oldLight) {
2201 glEnable(GL_LIGHTING);
2202 checkGLcall("glEnable GL_LIGHTING");
2204 if(oldFog) {
2205 glEnable(GL_FOG);
2206 checkGLcall("glEnable GL_FOG");
2208 if(oldDepth) {
2209 glEnable(GL_DEPTH_TEST);
2210 checkGLcall("glEnable GL_DEPTH_TEST");
2212 if(oldBlend) {
2213 glEnable(GL_BLEND);
2214 checkGLcall("glEnable GL_BLEND");
2216 if(oldCull) {
2217 glEnable(GL_CULL_FACE);
2218 checkGLcall("glEnable GL_CULL_FACE");
2220 if(oldStencil) {
2221 glEnable(GL_STENCIL_TEST);
2222 checkGLcall("glEnable GL_STENCIL_TEST");
2224 if(!oldAlpha) {
2225 glDisable(GL_ALPHA_TEST);
2226 checkGLcall("glDisable GL_ALPHA_TEST");
2227 } else {
2228 glEnable(GL_ALPHA_TEST);
2229 checkGLcall("glEnable GL_ALPHA_TEST");
2232 glAlphaFunc(alphafunc, alpharef);
2233 checkGLcall("glAlphaFunc\n");
2235 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2236 glDrawBuffer(oldDraw);
2239 /* Restore the color key */
2240 if(oldCKey != Src->CKeyFlags) {
2241 Src->CKeyFlags = oldCKey;
2242 Src->Flags |= SFLAG_DIRTY;
2245 LEAVE_GL();
2247 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2248 This->Flags |= SFLAG_GLDIRTY;
2250 return WINED3D_OK;
2254 /* Blt from rendertarget to texture? */
2255 if( (SrcSurface == swapchain->frontBuffer) ||
2256 (SrcSurface == swapchain->backBuffer) ) {
2257 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2258 ( (IWineD3DSurface *) This != swapchain->backBuffer) ) {
2259 UINT row;
2260 D3DRECT srect;
2261 float xrel, yrel;
2263 TRACE("Blt from rendertarget to texture\n");
2265 /* Call preload for the surface to make sure it isn't dirty */
2266 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2268 if(SrcRect) {
2269 srect.x1 = SrcRect->left;
2270 srect.y1 = SrcRect->top;
2271 srect.x2 = SrcRect->right;
2272 srect.y2 = SrcRect->bottom;
2273 } else {
2274 srect.x1 = 0;
2275 srect.y1 = 0;
2276 srect.x2 = Src->currentDesc.Width;
2277 srect.y2 = Src->currentDesc.Height;
2280 ENTER_GL();
2282 /* Bind the target texture */
2283 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2284 checkGLcall("glBindTexture");
2285 if(SrcSurface == swapchain->backBuffer) {
2286 glReadBuffer(GL_BACK);
2287 } else {
2288 glReadBuffer(GL_FRONT);
2290 checkGLcall("glReadBuffer");
2292 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2293 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2295 /* I have to process this row by row to swap the image,
2296 * otherwise it would be upside down, so streching in y direction
2297 * doesn't cost extra time
2299 * However, streching in x direction can be avoided if not necessary
2301 for(row = rect.y1; row < rect.y2; row++) {
2302 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2303 /* Well, that stuff works, but it's very slow.
2304 * find a better way instead
2306 UINT col;
2307 for(col = rect.x1; col < rect.x2; col++) {
2308 glCopyTexSubImage2D(GL_TEXTURE_2D,
2309 0, /* level */
2310 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2311 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2312 1, 1);
2314 } else {
2315 glCopyTexSubImage2D(GL_TEXTURE_2D,
2316 0, /* level */
2317 rect.x1, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2318 srect.x1, Src->currentDesc.Height - srect.y2 + row * yrel,
2319 rect.x2, 1);
2323 vcheckGLcall("glCopyTexSubImage2D");
2324 LEAVE_GL();
2326 if(!(This->Flags & SFLAG_DONOTFREE)) {
2327 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2328 This->resource.allocatedMemory = NULL;
2329 } else {
2330 This->Flags |= SFLAG_GLDIRTY;
2333 return WINED3D_OK;
2338 if (Flags & DDBLT_COLORFILL) {
2339 /* This is easy to handle for the D3D Device... */
2340 DWORD color;
2341 IWineD3DSwapChainImpl *implSwapChain;
2342 GLint prev_draw;
2344 TRACE("Colorfill\n");
2346 /* The color as given in the Blt function is in the format of the frame-buffer...
2347 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2349 if (This->resource.format == WINED3DFMT_P8) {
2350 if (This->palette) {
2351 color = ((0xFF000000) |
2352 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2353 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2354 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2355 } else {
2356 color = 0xFF000000;
2359 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2360 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2361 color = 0xFFFFFFFF;
2362 } else {
2363 color = ((0xFF000000) |
2364 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2365 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2366 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2369 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2370 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2371 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2373 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2374 color = DDBltFx->u5.dwFillColor;
2376 else {
2377 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2378 return WINED3DERR_INVALIDCALL;
2381 /* Are we drawing to the Front buffer or the back buffer? */
2382 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
2383 vcheckGLcall("glIntegerv");
2385 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2386 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2387 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2388 if(This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer) {
2389 glDrawBuffer(GL_BACK);
2390 checkGLcall("glDrawBuffer(GL_BACK)");
2392 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2393 glDrawBuffer(GL_FRONT);
2394 checkGLcall("glDrawBuffer(GL_FRONT)");
2396 else {
2397 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2398 return WINED3DERR_INVALIDCALL;
2401 TRACE("(%p) executing Render Target override, color = %lx\n", This, color);
2403 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2404 1 /* Number of rectangles */,
2405 &rect,
2406 D3DCLEAR_TARGET,
2407 color,
2408 0.0 /* Z */,
2409 0 /* Stencil */);
2411 /* Restore the original draw buffer */
2412 glDrawBuffer(prev_draw);
2413 vcheckGLcall("glDrawBuffer");
2415 return WINED3D_OK;
2418 /* Default: Fall back to the generic blt */
2419 return WINED3DERR_INVALIDCALL;
2422 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2423 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2424 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2425 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2426 TRACE("(%p): Usage is %08lx\n", This, This->resource.usage);
2428 /* Special cases for RenderTargets */
2429 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2430 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2431 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2434 /* For the rest call the X11 surface implementation.
2435 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2436 * other Blts are rather rare
2438 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2441 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2442 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2443 TRACE("(%p)->(%lx)\n", This, Flags);
2445 switch (Flags)
2447 case DDGBS_CANBLT:
2448 case DDGBS_ISBLTDONE:
2449 return DD_OK;
2451 default:
2452 return DDERR_INVALIDPARAMS;
2456 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2457 /* XXX: DDERR_INVALIDSURFACETYPE */
2459 TRACE("(%p)->(%08lx)\n",iface,Flags);
2460 switch (Flags) {
2461 case DDGFS_CANFLIP:
2462 case DDGFS_ISFLIPDONE:
2463 return DD_OK;
2465 default:
2466 return DDERR_INVALIDPARAMS;
2470 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2471 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2472 TRACE("(%p)\n", This);
2474 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2477 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2478 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2479 TRACE("(%p)\n", This);
2481 /* So far we don't lose anything :) */
2482 This->Flags &= ~SFLAG_LOST;
2483 return WINED3D_OK;
2486 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2487 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2488 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2489 TRACE("(%p)->(%ld, %ld, %p, %p, %08lx\n", iface, dstx, dsty, Source, rsrc, trans);
2491 /* Special cases for RenderTargets */
2492 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2493 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2495 RECT SrcRect, DstRect;
2497 if(rsrc) {
2498 SrcRect.left = rsrc->left;
2499 SrcRect.top= rsrc->top;
2500 SrcRect.bottom = rsrc->bottom;
2501 SrcRect.right = rsrc->right;
2502 } else {
2503 SrcRect.left = 0;
2504 SrcRect.top = 0;
2505 SrcRect.right = srcImpl->currentDesc.Width;
2506 SrcRect.bottom = srcImpl->currentDesc.Height;
2509 DstRect.left = dstx;
2510 DstRect.top=dsty;
2511 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2512 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2514 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, 0, NULL) == WINED3D_OK) return WINED3D_OK;
2518 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2521 HRESULT WINAPI IWineD3DSurfaceImpl_SetPixelFormat(IWineD3DSurface *iface, WINED3DFORMAT Format, BYTE *Surface, DWORD Size) {
2522 FIXME("This is unimplemented for now(d3d7 merge)\n");
2523 return WINED3DERR_INVALIDCALL;
2526 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2527 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2528 TRACE("(%p)->(%p)\n", This, Pal);
2530 *Pal = (IWineD3DPalette *) This->palette;
2531 return DD_OK;
2534 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2535 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2536 RGBQUAD col[256];
2537 IWineD3DPaletteImpl *pal = This->palette;
2538 unsigned int n;
2539 TRACE("(%p)\n", This);
2541 if(This->resource.format == WINED3DFMT_P8 ||
2542 This->resource.format == WINED3DFMT_A8P8)
2544 TRACE("Dirtifying surface\n");
2545 This->Flags |= SFLAG_DIRTY;
2548 if(This->Flags & SFLAG_DIBSECTION) {
2549 TRACE("(%p): Updating the hdc's palette\n", This);
2550 for (n=0; n<256; n++) {
2551 if(pal) {
2552 col[n].rgbRed = pal->palents[n].peRed;
2553 col[n].rgbGreen = pal->palents[n].peGreen;
2554 col[n].rgbBlue = pal->palents[n].peBlue;
2555 } else {
2556 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2557 /* Use the default device palette */
2558 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2559 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2560 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2562 col[n].rgbReserved = 0;
2564 SetDIBColorTable(This->hDC, 0, 256, col);
2567 return WINED3D_OK;
2570 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2571 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2572 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2573 TRACE("(%p)->(%p)\n", This, Pal);
2575 if(This->palette != NULL)
2576 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2577 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2579 if(PalImpl != NULL) {
2580 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2581 /* Set the device's main palette if the palette
2582 * wasn't a primary palette before
2584 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2585 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2586 unsigned int i;
2588 for(i=0; i < 256; i++) {
2589 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2593 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2596 This->palette = PalImpl;
2598 return IWineD3DSurface_RealizePalette(iface);
2601 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2602 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2603 BOOL dirtify = FALSE;
2604 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
2606 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2607 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
2608 return DDERR_INVALIDPARAMS;
2611 /* Dirtify the surface, but only if a key was changed */
2612 if(CKey) {
2613 switch (Flags & ~DDCKEY_COLORSPACE) {
2614 case DDCKEY_DESTBLT:
2615 if(!(This->CKeyFlags & DDSD_CKDESTBLT)) {
2616 dirtify = TRUE;
2617 } else {
2618 dirtify = memcmp(&This->DestBltCKey, CKey, sizeof(*CKey) ) != 0;
2620 This->DestBltCKey = *CKey;
2621 This->CKeyFlags |= DDSD_CKDESTBLT;
2622 break;
2624 case DDCKEY_DESTOVERLAY:
2625 if(!(This->CKeyFlags & DDSD_CKDESTOVERLAY)) {
2626 dirtify = TRUE;
2627 } else {
2628 dirtify = memcmp(&This->DestOverlayCKey, CKey, sizeof(*CKey)) != 0;
2630 This->DestOverlayCKey = *CKey;
2631 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2632 break;
2634 case DDCKEY_SRCOVERLAY:
2635 if(!(This->CKeyFlags & DDSD_CKSRCOVERLAY)) {
2636 dirtify = TRUE;
2637 } else {
2638 dirtify = memcmp(&This->SrcOverlayCKey, CKey, sizeof(*CKey)) != 0;
2640 This->SrcOverlayCKey = *CKey;
2641 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2642 break;
2644 case DDCKEY_SRCBLT:
2645 if(!(This->CKeyFlags & DDSD_CKSRCBLT)) {
2646 dirtify = TRUE;
2647 } else {
2648 dirtify = memcmp(&This->SrcBltCKey, CKey, sizeof(*CKey)) != 0;
2650 This->SrcBltCKey = *CKey;
2651 This->CKeyFlags |= DDSD_CKSRCBLT;
2652 break;
2655 else {
2656 switch (Flags & ~DDCKEY_COLORSPACE) {
2657 case DDCKEY_DESTBLT:
2658 dirtify = This->CKeyFlags & DDSD_CKDESTBLT;
2659 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2660 break;
2662 case DDCKEY_DESTOVERLAY:
2663 dirtify = This->CKeyFlags & DDSD_CKDESTOVERLAY;
2664 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2665 break;
2667 case DDCKEY_SRCOVERLAY:
2668 dirtify = This->CKeyFlags & DDSD_CKSRCOVERLAY;
2669 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2670 break;
2672 case DDCKEY_SRCBLT:
2673 dirtify = This->CKeyFlags & DDSD_CKSRCBLT;
2674 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2675 break;
2679 if(dirtify) {
2680 TRACE("Color key changed, dirtifying surface\n");
2681 This->Flags |= SFLAG_DIRTY;
2684 return WINED3D_OK;
2687 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2688 /** Check against the maximum texture sizes supported by the video card **/
2689 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2691 TRACE("%p\n", This);
2692 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2693 /* one of three options
2694 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)
2695 2: Set the texture to the maxium size (bad idea)
2696 3: WARN and return WINED3DERR_NOTAVAILABLE;
2697 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.
2699 WARN("(%p) Creating an oversized surface\n", This);
2700 This->Flags |= SFLAG_OVERSIZE;
2702 /* This will be initialized on the first blt */
2703 This->glRect.left = 0;
2704 This->glRect.top = 0;
2705 This->glRect.right = 0;
2706 This->glRect.bottom = 0;
2707 } else {
2708 /* No oversize, gl rect is the full texture size */
2709 This->Flags &= ~SFLAG_OVERSIZE;
2710 This->glRect.left = 0;
2711 This->glRect.top = 0;
2712 This->glRect.right = This->pow2Width;
2713 This->glRect.bottom = This->pow2Height;
2716 return WINED3D_OK;
2719 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
2720 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2721 DWORD ret;
2722 TRACE("(%p)\n", This);
2724 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
2725 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
2726 ie pitch = (width/4) * bytes per block */
2727 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
2728 ret = (This->currentDesc.Width >> 2) << 3;
2729 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
2730 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
2731 ret = (This->currentDesc.Width >> 2) << 4;
2732 else {
2733 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2734 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
2735 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
2736 } else {
2737 ret = This->bytesPerPixel * This->pow2Width;
2740 TRACE("(%p) Returning %ld\n", This, ret);
2741 return ret;
2744 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
2746 /* IUnknown */
2747 IWineD3DSurfaceImpl_QueryInterface,
2748 IWineD3DSurfaceImpl_AddRef,
2749 IWineD3DSurfaceImpl_Release,
2750 /* IWineD3DResource */
2751 IWineD3DSurfaceImpl_GetParent,
2752 IWineD3DSurfaceImpl_GetDevice,
2753 IWineD3DSurfaceImpl_SetPrivateData,
2754 IWineD3DSurfaceImpl_GetPrivateData,
2755 IWineD3DSurfaceImpl_FreePrivateData,
2756 IWineD3DSurfaceImpl_SetPriority,
2757 IWineD3DSurfaceImpl_GetPriority,
2758 IWineD3DSurfaceImpl_PreLoad,
2759 IWineD3DSurfaceImpl_GetType,
2760 /* IWineD3DSurface */
2761 IWineD3DSurfaceImpl_GetContainerParent,
2762 IWineD3DSurfaceImpl_GetContainer,
2763 IWineD3DSurfaceImpl_GetDesc,
2764 IWineD3DSurfaceImpl_LockRect,
2765 IWineD3DSurfaceImpl_UnlockRect,
2766 IWineD3DSurfaceImpl_GetDC,
2767 IWineD3DSurfaceImpl_ReleaseDC,
2768 IWineD3DSurfaceImpl_Flip,
2769 IWineD3DSurfaceImpl_Blt,
2770 IWineD3DSurfaceImpl_GetBltStatus,
2771 IWineD3DSurfaceImpl_GetFlipStatus,
2772 IWineD3DSurfaceImpl_IsLost,
2773 IWineD3DSurfaceImpl_Restore,
2774 IWineD3DSurfaceImpl_BltFast,
2775 IWineD3DSurfaceImpl_SetPixelFormat,
2776 IWineD3DSurfaceImpl_GetPalette,
2777 IWineD3DSurfaceImpl_SetPalette,
2778 IWineD3DSurfaceImpl_RealizePalette,
2779 IWineD3DSurfaceImpl_SetColorKey,
2780 IWineD3DSurfaceImpl_GetPitch,
2781 /* Internal use: */
2782 IWineD3DSurfaceImpl_CleanDirtyRect,
2783 IWineD3DSurfaceImpl_AddDirtyRect,
2784 IWineD3DSurfaceImpl_LoadTexture,
2785 IWineD3DSurfaceImpl_SaveSnapshot,
2786 IWineD3DSurfaceImpl_SetContainer,
2787 IWineD3DSurfaceImpl_SetPBufferState,
2788 IWineD3DSurfaceImpl_SetGlTextureDesc,
2789 IWineD3DSurfaceImpl_GetGlDesc,
2790 IWineD3DSurfaceImpl_GetData,
2791 IWineD3DSurfaceImpl_SetFormat,
2792 IWineD3DSurfaceImpl_PrivateSetup