wined3d: Render target locking fixes.
[wine/gsoc_dplay.git] / dlls / wined3d / surface.c
blobe270701a1abe6629d03701ab0f9cc00eb00a1a4a
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 if (IUnknown_QueryInterface(container, riid, ppContainer) != S_OK)
240 return WINED3DERR_INVALIDCALL;
242 return WINED3D_OK;
245 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
246 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
248 TRACE("(%p) : copying into %p\n", This, pDesc);
249 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
250 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
251 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
252 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
253 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
254 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
255 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
256 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
257 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
258 return WINED3D_OK;
261 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
262 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
263 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
264 if (This->glDescription.textureName == 0 && textureName != 0) {
265 This->Flags |= SFLAG_DIRTY;
266 IWineD3DSurface_AddDirtyRect(iface, NULL);
268 This->glDescription.textureName = textureName;
269 This->glDescription.target = target;
272 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
273 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
274 TRACE("(%p) : returning %p\n", This, &This->glDescription);
275 *glDescription = &This->glDescription;
278 /* TODO: think about moving this down to resource? */
279 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
280 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
281 /* 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 */
282 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
283 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
285 return (CONST void*)(This->resource.allocatedMemory);
288 HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
289 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
290 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
291 IWineD3DSwapChainImpl *swapchain = NULL;
292 static UINT messages = 0; /* holds flags to disable fixme messages */
294 /* fixme: should we really lock as such? */
295 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
296 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
297 FIXME("Warning: Surface is in texture memory or pbuffer\n");
298 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
301 if (!(This->Flags & SFLAG_LOCKABLE)) {
302 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
303 texture regions, and since the destination is an unlockable region we need
304 to tolerate this */
305 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
306 /*return WINED3DERR_INVALIDCALL; */
309 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
310 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
312 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
313 if (swapchain != NULL && iface == swapchain->backBuffer) {
314 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
315 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
316 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
317 } else if (iface == myDevice->renderTarget) {
318 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
319 } else if (iface == myDevice->depthStencilBuffer) {
320 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
323 if (NULL != swapchain) {
324 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
326 swapchain = NULL;
328 } else {
329 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
332 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
334 if (NULL == pRect) {
335 pLockedRect->pBits = This->resource.allocatedMemory;
336 This->lockedRect.left = 0;
337 This->lockedRect.top = 0;
338 This->lockedRect.right = This->currentDesc.Width;
339 This->lockedRect.bottom = This->currentDesc.Height;
340 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);
341 } else {
342 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
344 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
345 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
346 } else {
347 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
349 This->lockedRect.left = pRect->left;
350 This->lockedRect.top = pRect->top;
351 This->lockedRect.right = pRect->right;
352 This->lockedRect.bottom = pRect->bottom;
355 if (This->Flags & SFLAG_NONPOW2) {
356 TRACE("Locking non-power 2 texture\n");
359 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
360 /* classic surface TODO: non 2d surfaces?
361 These resources may be POOL_SYSTEMMEM, so they must not access the device */
362 TRACE("locking an ordinarary surface\n");
363 /* Check to see if memory has already been allocated from the surface*/
364 if ((NULL == This->resource.allocatedMemory) ||
365 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
366 /* Non-system memory surfaces */
368 This->Flags &= ~SFLAG_GLDIRTY;
370 /*Surface has no memory currently allocated to it!*/
371 TRACE("(%p) Locking rect\n" , This);
372 if(!This->resource.allocatedMemory) {
373 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
375 if (0 != This->glDescription.textureName) {
376 /* Now I have to copy thing bits back */
377 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
378 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
379 ENTER_GL();
381 /* Make sure that the texture is loaded */
382 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
384 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);
386 if (This->resource.format == WINED3DFMT_DXT1 ||
387 This->resource.format == WINED3DFMT_DXT2 ||
388 This->resource.format == WINED3DFMT_DXT3 ||
389 This->resource.format == WINED3DFMT_DXT4 ||
390 This->resource.format == WINED3DFMT_DXT5) {
391 TRACE("Locking a compressed texture\n");
392 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
393 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
394 This->glDescription.level,
395 This->resource.allocatedMemory);
397 } else {
398 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
400 } else {
401 glGetTexImage(This->glDescription.target,
402 This->glDescription.level,
403 This->glDescription.glFormat,
404 This->glDescription.glType,
405 This->resource.allocatedMemory);
406 vcheckGLcall("glGetTexImage");
407 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
408 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
409 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
410 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
412 Were doing this...
414 instead of boxing the texture :
415 |<-texture width ->| -->pow2width| /\
416 |111111111111111111| | |
417 |222 Texture 222222| boxed empty | texture height
418 |3333 Data 33333333| | |
419 |444444444444444444| | \/
420 ----------------------------------- |
421 | boxed empty | boxed empty | pow2height
422 | | | \/
423 -----------------------------------
426 were repacking the data to the expected texture width
428 |<-texture width ->| -->pow2width| /\
429 |111111111111111111222222222222222| |
430 |222333333333333333333444444444444| texture height
431 |444444 | |
432 | | \/
433 | | |
434 | empty | pow2height
435 | | \/
436 -----------------------------------
438 == is the same as
440 |<-texture width ->| /\
441 |111111111111111111|
442 |222222222222222222|texture height
443 |333333333333333333|
444 |444444444444444444| \/
445 --------------------
447 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.
449 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.
451 if (This->Flags & SFLAG_NONPOW2) {
452 BYTE* dataa, *datab;
453 int pitcha = 0, pitchb = 0;
454 int y;
455 pitcha = This->bytesPerPixel * This->currentDesc.Width;
456 pitchb = This->bytesPerPixel * This->pow2Width;
457 datab = dataa = This->resource.allocatedMemory;
458 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
459 for (y = 1 ; y < This->currentDesc.Height; y++) {
460 dataa += pitcha; /* skip the first row */
461 datab += pitchb;
462 memcpy(dataa, datab, pitcha);
467 LEAVE_GL();
469 } else { /* Nothing to do */
470 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
473 if (NULL == pRect) {
474 pLockedRect->pBits = This->resource.allocatedMemory;
475 } else{
476 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
477 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
478 } else {
479 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
483 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
484 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
485 GLint prev_store;
486 GLint prev_read;
487 BOOL notInContext = FALSE;
488 IWineD3DSwapChainImpl *targetSwapChain = NULL;
491 ENTER_GL();
494 * for render->surface copy begin to begin of allocatedMemory
495 * unlock can be more easy
498 TRACE("locking a render target\n");
500 if (This->resource.allocatedMemory == NULL)
501 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
503 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
504 pLockedRect->pBits = This->resource.allocatedMemory;
506 glFlush();
507 vcheckGLcall("glFlush");
508 glGetIntegerv(GL_READ_BUFFER, &prev_read);
509 vcheckGLcall("glIntegerv");
510 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
511 vcheckGLcall("glIntegerv");
513 /* Here's what we have to do:
514 See if the swapchain has the same context as the renderTarget or the surface is the render target.
515 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
516 and use the front back buffer as required.
517 if not, we need to switch contexts and then switchback at the end.
519 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
520 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
522 /* 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! */
523 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
524 if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) {
525 TRACE("locking back buffer\n");
526 glReadBuffer(GL_BACK);
527 } else if (iface == swapchain->frontBuffer) {
528 TRACE("locking front\n");
529 glReadBuffer(GL_FRONT);
530 } else if (iface == myDevice->depthStencilBuffer) {
531 FIXME("Stencil Buffer lock unsupported for now\n");
532 } else {
533 FIXME("(%p) Shouldn't have got here!\n", This);
534 glReadBuffer(GL_BACK);
536 } else if (swapchain != NULL) {
537 IWineD3DSwapChainImpl *implSwapChain;
538 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
539 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
540 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
541 if (iface == swapchain->backBuffer) {
542 glReadBuffer(GL_BACK);
543 } else if (iface == swapchain->frontBuffer) {
544 glReadBuffer(GL_FRONT);
545 } else if (iface == myDevice->depthStencilBuffer) {
546 FIXME("Stencil Buffer lock unsupported for now\n");
547 } else {
548 FIXME("Should have got here!\n");
549 glReadBuffer(GL_BACK);
551 } else {
552 /* We need to switch contexts to be able to read the buffer!!! */
553 FIXME("The buffer requested isn't in the current openGL context\n");
554 notInContext = TRUE;
555 /* TODO: check the contexts, to see if were shared with the current context */
557 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
559 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
560 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
562 /** the depth stencil in openGL has a format of GL_FLOAT
563 * which should be good for WINED3DFMT_D16_LOCKABLE
564 * and WINED3DFMT_D16
565 * it is unclear what format the stencil buffer is in except.
566 * 'Each index is converted to fixed point...
567 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
568 * mappings in the table GL_PIXEL_MAP_S_TO_S.
569 * glReadPixels(This->lockedRect.left,
570 * This->lockedRect.bottom - j - 1,
571 * This->lockedRect.right - This->lockedRect.left,
572 * 1,
573 * GL_DEPTH_COMPONENT,
574 * type,
575 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
576 *****************************************/
577 if (!notInContext) { /* Only read the buffer if it's in the current context */
578 long j;
580 #if 0
581 /* 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,
582 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
583 * run ten times faster!
584 * ************************************/
585 BOOL ati_performance_hack = FALSE;
586 ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
587 #endif
588 if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
589 This->lockedRect.right == This->currentDesc.Width
590 && This->lockedRect.bottom == This->currentDesc.Height)) {
591 BYTE *row, *top, *bottom;
592 int i;
594 glReadPixels(0, 0,
595 This->currentDesc.Width,
596 This->currentDesc.Height,
597 This->glDescription.glFormat,
598 This->glDescription.glType,
599 (char *)pLockedRect->pBits);
601 /* glReadPixels returns the image upside down, and there is no way to prevent this.
602 Flip the lines in software*/
603 row = HeapAlloc(GetProcessHeap(), 0, pLockedRect->Pitch);
604 if(!row) {
605 ERR("Out of memory\n");
606 return E_OUTOFMEMORY;
608 top = This->resource.allocatedMemory;
609 bottom = ( (BYTE *) This->resource.allocatedMemory) + pLockedRect->Pitch * ( This->currentDesc.Height - 1);
610 for(i = 0; i < This->currentDesc.Height / 2; i++) {
611 memcpy(row, top, pLockedRect->Pitch);
612 memcpy(top, bottom, pLockedRect->Pitch);
613 memcpy(bottom, row, pLockedRect->Pitch);
614 top += pLockedRect->Pitch;
615 bottom -= pLockedRect->Pitch;
617 HeapFree(GetProcessHeap(), 0, row);
619 This->Flags &= ~SFLAG_GLDIRTY;
621 } else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
622 glReadPixels(0,
623 This->lockedRect.top,
624 This->currentDesc.Width,
625 This->currentDesc.Height,
626 This->glDescription.glFormat,
627 This->glDescription.glType,
628 (char *)pLockedRect->pBits);
629 } else{
631 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
632 glReadPixels(This->lockedRect.left,
633 This->lockedRect.bottom - j - 1,
634 This->lockedRect.right - This->lockedRect.left,
636 This->glDescription.glFormat,
637 This->glDescription.glType,
638 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
643 vcheckGLcall("glReadPixels");
644 TRACE("Resetting buffer\n");
645 glReadBuffer(prev_read);
646 vcheckGLcall("glReadBuffer");
648 LEAVE_GL();
650 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
652 if (!messages & 1) {
653 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
656 glReadPixels(This->lockedRect.left,
657 This->lockedRect.bottom - j - 1,
658 This->lockedRect.right - This->lockedRect.left,
660 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
664 messages |= 1;
666 } else {
667 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
670 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
671 /* Don't dirtify */
672 } else {
673 IWineD3DBaseTexture *pBaseTexture;
675 * Dirtify on lock
676 * as seen in msdn docs
678 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
680 /** Dirtify Container if needed */
681 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
682 TRACE("Making container dirty\n");
683 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
684 IWineD3DBaseTexture_Release(pBaseTexture);
685 } else {
686 TRACE("Surface is standalone, no need to dirty the container\n");
690 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
692 This->Flags |= SFLAG_LOCKED;
693 return WINED3D_OK;
696 HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
697 GLint skipBytes = 0;
698 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
699 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
700 const char *buffername = "";
701 IWineD3DSwapChainImpl *swapchain = NULL;
703 if (!(This->Flags & SFLAG_LOCKED)) {
704 WARN("trying to Unlock an unlocked surf@%p\n", This);
705 return WINED3DERR_INVALIDCALL;
708 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
709 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
711 if ((swapchain != NULL) && iface == swapchain->backBuffer) {
712 buffername = "backBuffer";
713 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
714 buffername = "frontBuffer";
715 } else if (iface == myDevice->depthStencilBuffer) {
716 buffername = "depthStencilBuffer";
717 } else if (iface == myDevice->renderTarget) {
718 buffername = "renderTarget";
722 if (swapchain != NULL) {
723 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
726 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
728 if (!(This->Flags & SFLAG_DIRTY)) {
729 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
730 goto unlock_end;
733 if (0 == This->resource.usage) { /* classic surface */
735 * nothing to do
736 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
738 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
740 /****************************
741 * TODO: Render targets are 'special' and
742 * ?some? locking needs to be passed onto the context manager
743 * so that it becomes possible to use auxiliary buffers, pbuffers
744 * render-to-texture, shared, cached contexts etc...
745 * ****************************/
746 IWineD3DSwapChainImpl *implSwapChain;
747 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
749 if (iface == implSwapChain->backBuffer || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
750 GLint prev_store;
751 GLint prev_draw;
752 GLint prev_depth_test;
753 GLint prev_rasterpos[4];
755 /* Some drivers(radeon dri, others?) don't like exceptions during
756 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
757 * after ReleaseDC. Reading it will cause an exception, which x11drv will
758 * catch to put the dib section in InSync mode, which leads to a crash
759 * and a blocked x server on my radeon card.
761 * The following lines read the dib section so it is put in inSync mode
762 * before glDrawPixels is called and the crash is prevented. There won't
763 * be any interfering gdi accesses, because UnlockRect is called from
764 * ReleaseDC, and the app won't use the dc any more afterwards.
766 if(This->Flags & SFLAG_DIBSECTION) {
767 volatile BYTE read;
768 read = This->resource.allocatedMemory[0];
771 ENTER_GL();
773 glFlush();
774 vcheckGLcall("glFlush");
775 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
776 vcheckGLcall("glIntegerv");
777 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
778 vcheckGLcall("glIntegerv");
779 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
780 vcheckGLcall("glIntegerv");
781 glPixelZoom(1.0, -1.0);
782 vcheckGLcall("glPixelZoom");
783 prev_depth_test = glIsEnabled(GL_DEPTH_TEST);
785 /* glDrawPixels transforms the raster position as though it was a vertex -
786 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
787 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
788 d3ddevice_set_ortho(This->resource.wineD3DDevice);
790 if (iface == implSwapChain->frontBuffer) {
791 glDrawBuffer(GL_FRONT);
792 checkGLcall("glDrawBuffer GL_FRONT");
793 } else if (iface == implSwapChain->backBuffer || iface == myDevice->renderTarget) {
794 glDrawBuffer(GL_BACK);
795 checkGLcall("glDrawBuffer GL_BACK");
798 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
799 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
800 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
802 /* And back buffers are not blended */
803 glDisable(GL_BLEND);
804 glDisable(GL_DEPTH_TEST);
806 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
807 vcheckGLcall("glRasterPos2f");
808 switch (This->resource.format) {
809 case WINED3DFMT_X4R4G4B4:
811 int size;
812 unsigned short *data;
813 data = (unsigned short *)This->resource.allocatedMemory;
814 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
815 while(size > 0) {
816 *data |= 0xF000;
817 data++;
818 size--;
821 case WINED3DFMT_A4R4G4B4:
823 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
824 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
825 vcheckGLcall("glDrawPixels");
827 break;
828 case WINED3DFMT_R5G6B5:
830 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
831 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
832 vcheckGLcall("glDrawPixels");
834 break;
835 case WINED3DFMT_X1R5G5B5:
837 int size;
838 unsigned short *data;
839 data = (unsigned short *)This->resource.allocatedMemory;
840 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
841 while(size > 0) {
842 *data |= 0x8000;
843 data++;
844 size--;
847 case WINED3DFMT_A1R5G5B5:
849 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
850 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
851 vcheckGLcall("glDrawPixels");
853 break;
854 case WINED3DFMT_R8G8B8:
856 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
857 GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
858 vcheckGLcall("glDrawPixels");
860 break;
861 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
862 could be any random value this fixes the intro move in Pirates! */
864 int size;
865 unsigned int *data;
866 data = (unsigned int *)This->resource.allocatedMemory;
867 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
868 while(size > 0) {
869 *data |= 0xFF000000;
870 data++;
871 size--;
874 case WINED3DFMT_A8R8G8B8:
876 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
877 vcheckGLcall("glPixelStorei");
878 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
879 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
880 vcheckGLcall("glDrawPixels");
881 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
882 vcheckGLcall("glPixelStorei");
884 break;
885 case WINED3DFMT_A2R10G10B10:
887 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
888 vcheckGLcall("glPixelStorei");
889 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
890 GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
891 vcheckGLcall("glDrawPixels");
892 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
893 vcheckGLcall("glPixelStorei");
895 break;
896 default:
897 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
900 glPixelZoom(1.0,1.0);
901 vcheckGLcall("glPixelZoom");
902 glDrawBuffer(prev_draw);
903 vcheckGLcall("glDrawBuffer");
904 glRasterPos3iv(&prev_rasterpos[0]);
905 vcheckGLcall("glRasterPos3iv");
906 if(prev_depth_test) glEnable(GL_DEPTH_TEST);
908 /* Reset to previous pack row length / blending state */
909 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
910 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
912 LEAVE_GL();
914 /** restore clean dirty state */
915 IWineD3DSurface_CleanDirtyRect(iface);
917 } else {
918 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
920 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
922 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
924 if (iface == myDevice->depthStencilBuffer) {
925 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
926 } else {
927 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
930 } else {
931 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
934 unlock_end:
935 This->Flags &= ~SFLAG_LOCKED;
936 memset(&This->lockedRect, 0, sizeof(RECT));
937 return WINED3D_OK;
940 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
941 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
942 WINED3DLOCKED_RECT lock;
943 UINT usage;
944 BITMAPINFO* b_info;
945 HDC ddc;
946 DWORD *masks;
947 HRESULT hr;
948 RGBQUAD col[256];
950 TRACE("(%p)->(%p)\n",This,pHDC);
952 /* Give more detailed info for ddraw */
953 if (This->Flags & SFLAG_DCINUSE)
954 return DDERR_DCALREADYCREATED;
956 /* Can't GetDC if the surface is locked */
957 if (This->Flags & SFLAG_LOCKED)
958 return WINED3DERR_INVALIDCALL;
960 memset(&lock, 0, sizeof(lock)); /* To be sure */
962 /* Create a DIB section if there isn't a hdc yet */
963 if(!This->hDC) {
964 if(This->Flags & SFLAG_ACTIVELOCK) {
965 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
968 switch (This->bytesPerPixel) {
969 case 2:
970 case 4:
971 /* Allocate extra space to store the RGB bit masks. */
972 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
973 break;
975 case 3:
976 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
977 break;
979 default:
980 /* Allocate extra space for a palette. */
981 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
982 sizeof(BITMAPINFOHEADER)
983 + sizeof(RGBQUAD)
984 * (1 << (This->bytesPerPixel * 8)));
985 break;
988 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
989 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
990 b_info->bmiHeader.biWidth = This->currentDesc.Width;
991 b_info->bmiHeader.biHeight = -This->currentDesc.Height;
992 /* Use the full pow2 image size(assigned below) because LockRect
993 * will need it for a full glGetTexImage call
995 } else {
996 b_info->bmiHeader.biWidth = This->pow2Width;
997 b_info->bmiHeader.biHeight = -This->pow2Height;
999 b_info->bmiHeader.biPlanes = 1;
1000 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1002 b_info->bmiHeader.biSizeImage = This->resource.size;
1004 b_info->bmiHeader.biXPelsPerMeter = 0;
1005 b_info->bmiHeader.biYPelsPerMeter = 0;
1006 b_info->bmiHeader.biClrUsed = 0;
1007 b_info->bmiHeader.biClrImportant = 0;
1009 /* Get the bit masks */
1010 masks = (DWORD *) &(b_info->bmiColors);
1011 switch (This->resource.format) {
1012 case WINED3DFMT_R8G8B8:
1013 usage = DIB_RGB_COLORS;
1014 b_info->bmiHeader.biCompression = BI_RGB;
1015 break;
1017 case WINED3DFMT_X1R5G5B5:
1018 case WINED3DFMT_A1R5G5B5:
1019 case WINED3DFMT_A4R4G4B4:
1020 case WINED3DFMT_X4R4G4B4:
1021 case WINED3DFMT_R3G3B2:
1022 case WINED3DFMT_A8R3G3B2:
1023 case WINED3DFMT_A2B10G10R10:
1024 case WINED3DFMT_A8B8G8R8:
1025 case WINED3DFMT_X8B8G8R8:
1026 case WINED3DFMT_A2R10G10B10:
1027 case WINED3DFMT_R5G6B5:
1028 case WINED3DFMT_A16B16G16R16:
1029 usage = 0;
1030 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1031 masks[0] = get_bitmask_red(This->resource.format);
1032 masks[1] = get_bitmask_green(This->resource.format);
1033 masks[2] = get_bitmask_blue(This->resource.format);
1034 break;
1036 default:
1037 /* Don't know palette */
1038 b_info->bmiHeader.biCompression = BI_RGB;
1039 usage = 0;
1040 break;
1043 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1044 if (ddc == 0) {
1045 HeapFree(GetProcessHeap(), 0, b_info);
1046 return HRESULT_FROM_WIN32(GetLastError());
1049 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);
1050 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1051 DeleteDC(ddc);
1053 if (!This->dib.DIBsection) {
1054 ERR("CreateDIBSection failed!\n");
1055 return HRESULT_FROM_WIN32(GetLastError());
1057 HeapFree(GetProcessHeap(), 0, b_info);
1059 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1061 /* copy the existing surface to the dib section */
1062 if(This->resource.allocatedMemory) {
1063 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->resource.size);
1064 /* We won't need that any more */
1065 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1066 } else {
1067 /* This is to make LockRect read the gl Texture although memory is allocated */
1068 This->Flags |= SFLAG_GLDIRTY;
1071 /* Use the dib section from now on */
1072 This->resource.allocatedMemory = This->dib.bitmap_data;
1074 /* Now allocate a HDC */
1075 This->hDC = CreateCompatibleDC(0);
1076 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1077 TRACE("using wined3d palette %p\n", This->palette);
1078 SelectPalette(This->hDC,
1079 This->palette ? This->palette->hpal : 0,
1080 FALSE);
1082 This->Flags |= SFLAG_DIBSECTION;
1085 /* Lock the surface */
1086 hr = IWineD3DSurface_LockRect(iface,
1087 &lock,
1088 NULL,
1090 if(FAILED(hr)) {
1091 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1092 /* keep the dib section */
1093 return hr;
1096 if(This->resource.format == WINED3DFMT_P8 ||
1097 This->resource.format == WINED3DFMT_A8P8) {
1098 unsigned int n;
1099 if(This->palette) {
1100 PALETTEENTRY ent[256];
1102 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1103 for (n=0; n<256; n++) {
1104 col[n].rgbRed = ent[n].peRed;
1105 col[n].rgbGreen = ent[n].peGreen;
1106 col[n].rgbBlue = ent[n].peBlue;
1107 col[n].rgbReserved = 0;
1109 } else {
1110 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1112 for (n=0; n<256; n++) {
1113 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1114 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1115 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1116 col[n].rgbReserved = 0;
1120 SetDIBColorTable(This->hDC, 0, 256, col);
1123 *pHDC = This->hDC;
1124 TRACE("returning %p\n",*pHDC);
1125 This->Flags |= SFLAG_DCINUSE;
1127 return WINED3D_OK;
1130 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1131 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1133 TRACE("(%p)->(%p)\n",This,hDC);
1135 if (!(This->Flags & SFLAG_DCINUSE))
1136 return D3DERR_INVALIDCALL;
1138 /* we locked first, so unlock now */
1139 IWineD3DSurface_UnlockRect(iface);
1141 This->Flags &= ~SFLAG_DCINUSE;
1143 return WINED3D_OK;
1146 /* ******************************************************
1147 IWineD3DSurface Internal (No mapping to directx api) parts follow
1148 ****************************************************** */
1150 typedef enum {
1151 NO_CONVERSION,
1152 CONVERT_PALETTED,
1153 CONVERT_PALETTED_CK,
1154 CONVERT_CK_565,
1155 CONVERT_CK_5551,
1156 CONVERT_CK_4444,
1157 CONVERT_CK_4444_ARGB,
1158 CONVERT_CK_1555,
1159 CONVERT_555,
1160 CONVERT_CK_RGB24,
1161 CONVERT_CK_8888,
1162 CONVERT_CK_8888_ARGB,
1163 CONVERT_RGB32_888
1164 } CONVERT_TYPES;
1166 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp) {
1167 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1169 /* Default values: From the surface */
1170 *format = D3DFmt2GLFmt(This->resource.wineD3DDevice,
1171 This->resource.format);
1172 *internal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice,
1173 This->resource.format);
1174 *type = D3DFmt2GLType(This->resource.wineD3DDevice,
1175 This->resource.format);
1176 *convert = NO_CONVERSION;
1177 *target_bpp = This->bytesPerPixel;
1179 /* Ok, now look if we have to do any conversion */
1180 switch(This->resource.format) {
1181 case WINED3DFMT_P8:
1182 /* ****************
1183 Paletted Texture
1184 **************** */
1185 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active) {
1186 *format = GL_RGBA;
1187 *internal = GL_RGBA;
1188 *type = GL_UNSIGNED_BYTE;
1189 *target_bpp = 4;
1190 if(colorkey_active) {
1191 *convert = CONVERT_PALETTED;
1192 } else {
1193 *convert = CONVERT_PALETTED_CK;
1197 break;
1199 case WINED3DFMT_R3G3B2:
1200 /* **********************
1201 GL_UNSIGNED_BYTE_3_3_2
1202 ********************** */
1203 if (colorkey_active) {
1204 /* This texture format will never be used.. So do not care about color keying
1205 up until the point in time it will be needed :-) */
1206 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1208 break;
1210 case WINED3DFMT_R5G6B5:
1211 if (colorkey_active) {
1212 *convert = CONVERT_CK_565;
1213 *format = GL_RGBA;
1214 *internal = GL_RGBA;
1215 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1217 break;
1219 case WINED3DFMT_R8G8B8:
1220 if (colorkey_active) {
1221 *convert = CONVERT_CK_RGB24;
1222 *format = GL_RGBA;
1223 *internal = GL_RGBA;
1224 *type = GL_UNSIGNED_INT_8_8_8_8;
1225 *target_bpp = 4;
1227 break;
1229 case WINED3DFMT_X8R8G8B8:
1230 if (colorkey_active) {
1231 *convert = CONVERT_RGB32_888;
1232 *format = GL_RGBA;
1233 *internal = GL_RGBA;
1234 *type = GL_UNSIGNED_INT_8_8_8_8;
1236 break;
1237 #if 0
1238 /* Not sure if we should do color keying on Alpha-Enabled surfaces */
1239 case WINED3DFMT_A4R4G4B4:
1240 if (colorkey_active)
1242 *convert = CONVERT_CK_4444_ARGB;
1243 *format = GL_RGBA;
1244 *internal = GL_RGBA;
1245 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1247 break;
1249 case WINED3DFMT_A1R5G5B5:
1250 if (colorkey_active)
1252 *convert = CONVERT_CK_1555;
1255 case WINED3DFMT_A8R8G8B8:
1256 if (colorkey_active)
1258 *convert = CONVERT_CK_8888_ARGB;
1259 *format = GL_RGBA;
1260 *internal = GL_RGBA;
1261 *type = GL_UNSIGNED_INT_8_8_8_8;
1263 break;
1264 #endif
1265 default:
1266 break;
1269 return WINED3D_OK;
1272 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1273 TRACE("(%p)->(%p),(%ld,%d,%p)\n", src, dst, len, convert, surf);
1275 switch (convert) {
1276 case NO_CONVERSION:
1278 memcpy(dst, src, len * surf->bytesPerPixel);
1279 break;
1281 case CONVERT_PALETTED:
1282 case CONVERT_PALETTED_CK:
1284 IWineD3DPaletteImpl* pal = surf->palette;
1285 BYTE table[256][4];
1286 unsigned int i;
1287 unsigned int x;
1289 if( pal == NULL) {
1290 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1293 if (pal == NULL) {
1294 /* Still no palette? Use the device's palette */
1295 /* Get the surface's palette */
1296 for (i = 0; i < 256; i++) {
1297 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1299 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1300 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1301 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1302 if ((convert == CONVERT_PALETTED_CK) &&
1303 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1304 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1305 /* We should maybe here put a more 'neutral' color than the standard bright purple
1306 one often used by application to prevent the nice purple borders when bi-linear
1307 filtering is on */
1308 table[i][3] = 0x00;
1309 } else {
1310 table[i][3] = 0xFF;
1313 } else {
1314 TRACE("Using surface palette %p\n", pal);
1315 /* Get the surface's palette */
1316 for (i = 0; i < 256; i++) {
1317 table[i][0] = pal->palents[i].peRed;
1318 table[i][1] = pal->palents[i].peGreen;
1319 table[i][2] = pal->palents[i].peBlue;
1320 if ((convert == CONVERT_PALETTED_CK) &&
1321 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1322 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1323 /* We should maybe here put a more 'neutral' color than the standard bright purple
1324 one often used by application to prevent the nice purple borders when bi-linear
1325 filtering is on */
1326 table[i][3] = 0x00;
1327 } else {
1328 table[i][3] = 0xFF;
1333 for (x = 0; x < len; x++) {
1334 BYTE color = *src++;
1335 *dst++ = table[color][0];
1336 *dst++ = table[color][1];
1337 *dst++ = table[color][2];
1338 *dst++ = table[color][3];
1341 break;
1343 case CONVERT_CK_565:
1345 /* Converting the 565 format in 5551 packed to emulate color-keying.
1347 Note : in all these conversion, it would be best to average the averaging
1348 pixels to get the color of the pixel that will be color-keyed to
1349 prevent 'color bleeding'. This will be done later on if ever it is
1350 too visible.
1352 Note2: when using color-keying + alpha, are the alpha bits part of the
1353 color-space or not ?
1355 unsigned int x;
1356 WORD *Source = (WORD *) src;
1357 WORD *Dest = (WORD *) dst;
1359 TRACE("Color keyed 565\n");
1361 for (x = 0; x < len; x++ ) {
1362 WORD color = *Source++;
1363 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1364 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1365 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1366 *Dest |= 0x0001;
1368 Dest++;
1371 break;
1373 case CONVERT_CK_1555:
1375 unsigned int x;
1376 WORD *Source = (WORD *) src;
1377 WORD *Dest = (WORD *) dst;
1379 for (x = 0; x < len * sizeof(WORD); x+=sizeof(WORD)) {
1380 WORD color = *Source++;
1381 *Dest = (color & 0x7FFF);
1382 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1383 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1384 *Dest |= (color & 0x8000);
1385 Dest++;
1388 break;
1390 case CONVERT_CK_4444_ARGB:
1392 /* Move the four Alpha bits... */
1393 unsigned int x;
1394 WORD *Source = (WORD *) src;
1395 WORD *Dest = (WORD *) dst;
1397 for (x = 0; x < len; x++) {
1398 WORD color = *Source++;
1399 *dst = (color & 0x0FFF) << 4;
1400 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1401 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1402 *Dest |= (color & 0xF000) >> 12;
1403 Dest++;
1405 } break;
1407 default:
1408 ERR("Unsupported conversation type %d\n", convert);
1411 return WINED3D_OK;
1414 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1415 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1417 if (This->Flags & SFLAG_INTEXTURE) {
1418 TRACE("Surface already in texture\n");
1419 return WINED3D_OK;
1421 if (!(This->Flags & SFLAG_DIRTY)) {
1422 TRACE("surface isn't dirty\n");
1423 return WINED3D_OK;
1426 This->Flags &= ~SFLAG_DIRTY;
1428 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1429 * These resources are not bound by device size or format restrictions. Because of this,
1430 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1431 * However, these resources can always be created, locked, and copied.
1433 if (This->resource.pool == WINED3DPOOL_SCRATCH)
1435 FIXME("(%p) Operation not supported for scratch textures\n",This);
1436 return WINED3DERR_INVALIDCALL;
1439 if (This->Flags & SFLAG_INPBUFFER) {
1440 ENTER_GL();
1442 if (This->glDescription.level != 0)
1443 FIXME("Surface in texture is only supported for level 0\n");
1444 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1445 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1446 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1447 This->resource.format == WINED3DFMT_DXT5)
1448 FIXME("Format %d not supported\n", This->resource.format);
1449 else {
1450 GLint prevRead;
1451 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1452 vcheckGLcall("glGetIntegerv");
1453 glReadBuffer(GL_BACK);
1454 vcheckGLcall("glReadBuffer");
1456 glCopyTexImage2D(This->glDescription.target,
1457 This->glDescription.level,
1458 This->glDescription.glFormatInternal,
1461 This->currentDesc.Width,
1462 This->currentDesc.Height,
1465 checkGLcall("glCopyTexImage2D");
1466 glReadBuffer(prevRead);
1467 vcheckGLcall("glReadBuffer");
1468 TRACE("Updating target %d\n", This->glDescription.target);
1469 This->Flags |= SFLAG_INTEXTURE;
1471 LEAVE_GL();
1472 return WINED3D_OK;
1475 /* TODO: Compressed non-power 2 support */
1477 if (This->resource.format == WINED3DFMT_DXT1 ||
1478 This->resource.format == WINED3DFMT_DXT2 ||
1479 This->resource.format == WINED3DFMT_DXT3 ||
1480 This->resource.format == WINED3DFMT_DXT4 ||
1481 This->resource.format == WINED3DFMT_DXT5) {
1482 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1483 FIXME("Using DXT1/3/5 without advertized support\n");
1484 } else if (This->resource.allocatedMemory) {
1485 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1486 This->glDescription.target,
1487 This->glDescription.level,
1488 This->glDescription.glFormatInternal,
1489 This->currentDesc.Width,
1490 This->currentDesc.Height,
1492 This->resource.size,
1493 This->resource.allocatedMemory);
1495 ENTER_GL();
1497 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1498 This->glDescription.level,
1499 This->glDescription.glFormatInternal,
1500 This->currentDesc.Width,
1501 This->currentDesc.Height,
1503 This->resource.size,
1504 This->resource.allocatedMemory);
1505 checkGLcall("glCommpressedTexImage2D");
1507 LEAVE_GL();
1509 if(!(This->Flags & SFLAG_DONOTFREE)){
1510 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1511 This->resource.allocatedMemory = NULL;
1514 } else {
1515 GLenum format, internal, type;
1516 CONVERT_TYPES convert;
1517 int bpp;
1518 BYTE *mem;
1520 d3dfmt_get_conv(This, TRUE /* We need color keying */, &format, &internal, &type, &convert, &bpp);
1522 if((convert != NO_CONVERSION) &&
1523 This->resource.allocatedMemory) {
1524 int width = This->glRect.right - This->glRect.left;
1525 int height = This->glRect.bottom - This->glRect.top;
1526 int row;
1528 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
1529 if(!mem) {
1530 ERR("Out of memory %d, %d!\n", width, height);
1531 return WINED3DERR_OUTOFVIDEOMEMORY;
1534 for(row = This->glRect.top; row < This->glRect.bottom; row++) {
1535 BYTE *cur = This->resource.allocatedMemory + row * This->pow2Width * This->bytesPerPixel;
1536 d3dfmt_convert_surface(cur + This->glRect.left * This->bytesPerPixel,
1537 mem + row * width * bpp,
1538 width,
1539 convert,
1540 This);
1542 This->Flags |= SFLAG_CONVERTED;
1543 } else {
1544 This->Flags &= ~SFLAG_CONVERTED;
1545 mem = This->resource.allocatedMemory;
1548 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1549 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE) ) {
1552 TRACE("non power of two support\n");
1553 ENTER_GL();
1554 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,
1555 This->glDescription.target,
1556 This->glDescription.level,
1557 debug_d3dformat(This->resource.format),
1558 This->glDescription.glFormatInternal,
1559 This->pow2Width,
1560 This->pow2Height,
1562 This->glDescription.glFormat,
1563 This->glDescription.glType,
1564 NULL);
1566 glTexImage2D(This->glDescription.target,
1567 This->glDescription.level,
1568 This->glDescription.glFormatInternal,
1569 This->pow2Width,
1570 This->pow2Height,
1571 0/*border*/,
1572 This->glDescription.glFormat,
1573 This->glDescription.glType,
1574 NULL);
1576 checkGLcall("glTexImage2D");
1577 if (This->resource.allocatedMemory != NULL) {
1578 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1579 /* And map the non-power two data into the top left corner */
1580 glTexSubImage2D(
1581 This->glDescription.target,
1582 This->glDescription.level,
1583 0 /* xoffset */,
1584 0 /* ysoffset */ ,
1585 This->currentDesc.Width,
1586 This->currentDesc.Height,
1587 This->glDescription.glFormat,
1588 This->glDescription.glType,
1589 This->resource.allocatedMemory
1591 checkGLcall("glTexSubImage2D");
1593 LEAVE_GL();
1595 } else {
1597 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%ld, h=%ld,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1598 This->glDescription.target,
1599 This->glDescription.level,
1600 debug_d3dformat(This->resource.format),
1601 This->glDescription.glFormatInternal,
1602 This->glRect.right - This->glRect.left,
1603 This->glRect.bottom - This->glRect.top,
1605 This->glDescription.glFormat,
1606 This->glDescription.glType,
1607 mem);
1609 ENTER_GL();
1611 /* OK, create the texture */
1612 glTexImage2D(This->glDescription.target,
1613 This->glDescription.level,
1614 internal,
1615 This->glRect.right - This->glRect.left,
1616 This->glRect.bottom - This->glRect.top,
1617 0 /* border */,
1618 format,
1619 type,
1620 mem);
1622 checkGLcall("glTexImage2D");
1624 LEAVE_GL();
1626 if(mem != This->resource.allocatedMemory)
1627 HeapFree(GetProcessHeap(), 0, mem);
1629 #if 0
1631 static unsigned int gen = 0;
1632 char buffer[4096];
1633 ++gen;
1634 if ((gen % 10) == 0) {
1635 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1636 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1639 * debugging crash code
1640 if (gen == 250) {
1641 void** test = NULL;
1642 *test = 0;
1646 #endif
1647 if(!(This->Flags & SFLAG_DONOTFREE)){
1648 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1649 This->resource.allocatedMemory = NULL;
1654 return WINED3D_OK;
1657 #include <errno.h>
1658 #include <stdio.h>
1659 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1660 FILE* f = NULL;
1661 UINT i, y;
1662 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1663 char *allocatedMemory;
1664 char *textureRow;
1665 IWineD3DSwapChain *swapChain = NULL;
1666 int width, height;
1667 GLuint tmpTexture;
1668 DWORD color;
1669 /*FIXME:
1670 Textures my not be stored in ->allocatedgMemory and a GlTexture
1671 so we should lock the surface before saving a snapshot, or at least check that
1673 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1674 by calling GetTexImage and in compressed form by calling
1675 GetCompressedTexImageARB. Queried compressed images can be saved and
1676 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1677 texture images do not need to be processed by the GL and should
1678 significantly improve texture loading performance relative to uncompressed
1679 images. */
1681 /* Setup the width and height to be the internal texture width and height. */
1682 width = This->pow2Width;
1683 height = This->pow2Height;
1684 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1685 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1687 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1688 /* 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 */
1689 GLint prevRead;
1690 ENTER_GL();
1691 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1692 glEnable(GL_TEXTURE_2D);
1694 glGenTextures(1, &tmpTexture);
1695 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1697 glTexImage2D(GL_TEXTURE_2D,
1699 GL_RGBA,
1700 width,
1701 height,
1702 0/*border*/,
1703 GL_RGBA,
1704 GL_UNSIGNED_INT_8_8_8_8_REV,
1705 NULL);
1707 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1708 vcheckGLcall("glGetIntegerv");
1709 glReadBuffer(GL_BACK);
1710 vcheckGLcall("glReadBuffer");
1711 glCopyTexImage2D(GL_TEXTURE_2D,
1713 GL_RGBA,
1716 width,
1717 height,
1720 checkGLcall("glCopyTexImage2D");
1721 glReadBuffer(prevRead);
1722 LEAVE_GL();
1724 } else { /* bind the real texture */
1725 IWineD3DSurface_PreLoad(iface);
1727 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1728 ENTER_GL();
1729 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1730 glGetTexImage(GL_TEXTURE_2D,
1731 This->glDescription.level,
1732 GL_RGBA,
1733 GL_UNSIGNED_INT_8_8_8_8_REV,
1734 allocatedMemory);
1735 checkGLcall("glTexImage2D");
1736 if (tmpTexture) {
1737 glBindTexture(GL_TEXTURE_2D, 0);
1738 glDeleteTextures(1, &tmpTexture);
1740 LEAVE_GL();
1742 f = fopen(filename, "w+");
1743 if (NULL == f) {
1744 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1745 return WINED3DERR_INVALIDCALL;
1747 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1748 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1749 /* TGA header */
1750 fputc(0,f);
1751 fputc(0,f);
1752 fputc(2,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 fputc(0,f);
1760 fputc(0,f);
1761 fputc(0,f);
1762 /* short width*/
1763 fwrite(&width,2,1,f);
1764 /* short height */
1765 fwrite(&height,2,1,f);
1766 /* format rgba */
1767 fputc(0x20,f);
1768 fputc(0x28,f);
1769 /* raw data */
1770 /* 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*/
1771 if(swapChain)
1772 textureRow = allocatedMemory + (width * (height - 1) *4);
1773 else
1774 textureRow = allocatedMemory;
1775 for (y = 0 ; y < height; y++) {
1776 for (i = 0; i < width; i++) {
1777 color = *((DWORD*)textureRow);
1778 fputc((color >> 16) & 0xFF, f); /* B */
1779 fputc((color >> 8) & 0xFF, f); /* G */
1780 fputc((color >> 0) & 0xFF, f); /* R */
1781 fputc((color >> 24) & 0xFF, f); /* A */
1782 textureRow += 4;
1784 /* take two rows of the pointer to the texture memory */
1785 if(swapChain)
1786 (textureRow-= width << 3);
1789 TRACE("Closing file\n");
1790 fclose(f);
1792 if(swapChain) {
1793 IWineD3DSwapChain_Release(swapChain);
1795 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1796 return WINED3D_OK;
1799 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1800 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1801 This->Flags &= ~SFLAG_DIRTY;
1802 This->dirtyRect.left = This->currentDesc.Width;
1803 This->dirtyRect.top = This->currentDesc.Height;
1804 This->dirtyRect.right = 0;
1805 This->dirtyRect.bottom = 0;
1806 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1807 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1808 return WINED3D_OK;
1812 * Slightly inefficient way to handle multiple dirty rects but it works :)
1814 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1815 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1816 IWineD3DBaseTexture *baseTexture = NULL;
1817 This->Flags |= SFLAG_DIRTY;
1818 if (NULL != pDirtyRect) {
1819 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1820 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1821 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1822 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1823 } else {
1824 This->dirtyRect.left = 0;
1825 This->dirtyRect.top = 0;
1826 This->dirtyRect.right = This->currentDesc.Width;
1827 This->dirtyRect.bottom = This->currentDesc.Height;
1829 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
1830 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1831 /* if the container is a basetexture then mark it dirty. */
1832 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1833 TRACE("Passing to conatiner\n");
1834 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1835 IWineD3DBaseTexture_Release(baseTexture);
1837 return WINED3D_OK;
1840 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1841 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1843 TRACE("This %p, container %p\n", This, container);
1845 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1847 TRACE("Setting container to %p from %p\n", container, This->container);
1848 This->container = container;
1850 return WINED3D_OK;
1853 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1854 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1856 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1857 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1858 return WINED3DERR_INVALIDCALL;
1861 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1862 if (format == WINED3DFMT_UNKNOWN) {
1863 This->resource.size = 0;
1864 } else if (format == WINED3DFMT_DXT1) {
1865 /* DXT1 is half byte per pixel */
1866 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1868 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1869 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1870 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1871 } else {
1872 This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1876 /* Setup some glformat defaults */
1877 if (format != WINED3DFMT_UNKNOWN) {
1878 This->glDescription.glFormat = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1879 This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1880 This->glDescription.glType = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1881 } else {
1882 This->glDescription.glFormat = 0;
1883 This->glDescription.glFormatInternal = 0;
1884 This->glDescription.glType = 0;
1887 if (format != WINED3DFMT_UNKNOWN) {
1888 This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1889 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1890 } else {
1891 This->bytesPerPixel = 0;
1892 This->pow2Size = 0;
1895 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
1897 This->resource.format = format;
1899 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);
1901 return WINED3D_OK;
1904 /* TODO: replace this function with context management routines */
1905 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1906 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1908 if(inPBuffer) {
1909 This->Flags |= SFLAG_INPBUFFER;
1910 } else {
1911 This->Flags &= ~SFLAG_INPBUFFER;
1914 if(inTexture) {
1915 This->Flags |= SFLAG_INTEXTURE;
1916 } else {
1917 This->Flags &= ~SFLAG_INTEXTURE;
1920 return WINED3D_OK;
1923 HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
1924 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1925 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
1926 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
1928 /* Flipping is only supported on RenderTargets */
1929 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
1931 if(override) {
1932 /* DDraw sets this for the X11 surfaces, so don't confuse the user
1933 * FIXME("(%p) Target override is not supported by now\n", This);
1934 * Additionally, it isn't really possible to support triple-buffering
1935 * properly on opengl at all
1939 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
1940 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
1943 /* Not called from the VTable */
1944 HRESULT WINAPI IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
1945 D3DRECT rect;
1946 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1947 IWineD3DSwapChainImpl *swapchain = NULL;
1948 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
1949 BOOL SrcOK = TRUE;
1951 TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
1953 /* Get the swapchain. One of the surfaces has to be a primary surface */
1954 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
1955 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1956 else if(Src) {
1957 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
1958 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1959 else return WINED3DERR_INVALIDCALL;
1960 } else {
1961 swapchain = NULL;
1964 if (DestRect) {
1965 rect.x1 = DestRect->left;
1966 rect.y1 = DestRect->top;
1967 rect.x2 = DestRect->right;
1968 rect.y2 = DestRect->bottom;
1969 } else {
1970 rect.x1 = 0;
1971 rect.y1 = 0;
1972 rect.x2 = This->currentDesc.Width;
1973 rect.y2 = This->currentDesc.Height;
1976 /* Half-life does a Blt from the back buffer to the front buffer,
1977 * Full surface size, no flags... Use present instead
1979 if(Src)
1981 /* First, check if we can do a Flip */
1983 /* Check rects - IWineD3DDevice_Present doesn't handle them */
1984 if( SrcRect ) {
1985 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
1986 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
1987 SrcOK = TRUE;
1989 } else {
1990 SrcOK = TRUE;
1993 /* Check the Destination rect and the surface sizes */
1994 if(SrcOK &&
1995 (rect.x1 == 0) && (rect.y1 == 0) &&
1996 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
1997 (This->currentDesc.Width == Src->currentDesc.Width) &&
1998 (This->currentDesc.Height == Src->currentDesc.Height)) {
1999 /* These flags are unimportant for the flag check, remove them */
2001 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2002 if( ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer) ) {
2004 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2006 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2007 * take very long, while a flip is fast.
2008 * This applies to Half-Life, which does such Blts every time it finished
2009 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2010 * menu. This is also used by all apps when they do windowed rendering
2012 * The problem is that flipping is not really the same as copying. After a
2013 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2014 * untouched. Therefore it's necessary to override the swap effect
2015 * and to set it back after the flip.
2018 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2020 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2021 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2022 NULL, NULL, 0, NULL);
2024 swapchain->presentParms.SwapEffect = orig_swap;
2026 return WINED3D_OK;
2031 /* Blt from texture to rendertarget? */
2032 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2033 ((IWineD3DSurface *) This == swapchain->backBuffer) )
2035 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2036 ( (IWineD3DSurface *) Src != swapchain->backBuffer) ) ) {
2037 float glTexCoord[4];
2038 DWORD oldCKey;
2039 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2040 GLint alphafunc;
2041 GLclampf alpharef;
2042 GLint oldStencil;
2043 RECT SourceRectangle;
2044 GLint oldDraw;
2046 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2048 if(SrcRect) {
2049 SourceRectangle.left = SrcRect->left;
2050 SourceRectangle.right = SrcRect->right;
2051 SourceRectangle.top = SrcRect->top;
2052 SourceRectangle.bottom = SrcRect->bottom;
2053 } else {
2054 SourceRectangle.left = 0;
2055 SourceRectangle.right = Src->currentDesc.Width;
2056 SourceRectangle.top = 0;
2057 SourceRectangle.bottom = Src->currentDesc.Height;
2060 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2061 /* Fall back to software */
2062 WARN("(%p) Source texture area (%ld,%ld)-(%ld,%ld) is too big\n", Src,
2063 SourceRectangle.left, SourceRectangle.top,
2064 SourceRectangle.right, SourceRectangle.bottom);
2065 return WINED3DERR_INVALIDCALL;
2068 /* Color keying: Check if we have to do a color keyed blt,
2069 * and if not check if a color key is activated.
2071 oldCKey = Src->CKeyFlags;
2072 if(!(Flags & DDBLT_KEYSRC) &&
2073 Src->CKeyFlags & DDSD_CKSRCBLT) {
2074 /* Ok, the surface has a color key, but we shall not use it -
2075 * Deactivate it for now and dirtify the surface to reload it
2077 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2078 Src->Flags |= SFLAG_DIRTY;
2081 /* Now load the surface */
2082 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2084 ENTER_GL();
2086 /* Save all the old stuff until we have a proper opengl state manager */
2087 oldLight = glIsEnabled(GL_LIGHTING);
2088 oldFog = glIsEnabled(GL_FOG);
2089 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2090 oldBlend = glIsEnabled(GL_BLEND);
2091 oldCull = glIsEnabled(GL_CULL_FACE);
2092 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2093 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2095 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2096 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2097 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2098 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2100 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2101 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2102 TRACE("Drawing to front buffer\n");
2103 glDrawBuffer(GL_FRONT);
2104 checkGLcall("glDrawBuffer GL_FRONT");
2107 /* Unbind the old texture */
2108 glBindTexture(GL_TEXTURE_2D, 0);
2110 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2111 /* We use texture unit 0 for blts */
2112 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2113 checkGLcall("glActiveTextureARB");
2114 } else {
2115 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2118 /* Disable some fancy graphics effects */
2119 glDisable(GL_LIGHTING);
2120 checkGLcall("glDisable GL_LIGHTING");
2121 glDisable(GL_DEPTH_TEST);
2122 checkGLcall("glDisable GL_DEPTH_TEST");
2123 glDisable(GL_FOG);
2124 checkGLcall("glDisable GL_FOG");
2125 glDisable(GL_BLEND);
2126 checkGLcall("glDisable GL_BLEND");
2127 glDisable(GL_CULL_FACE);
2128 checkGLcall("glDisable GL_CULL_FACE");
2129 glDisable(GL_STENCIL_TEST);
2130 checkGLcall("glDisable GL_STENCIL_TEST");
2132 /* Ok, we need 2d textures, but not 1D or 3D */
2133 glDisable(GL_TEXTURE_1D);
2134 checkGLcall("glDisable GL_TEXTURE_1D");
2135 glEnable(GL_TEXTURE_2D);
2136 checkGLcall("glEnable GL_TEXTURE_2D");
2137 glDisable(GL_TEXTURE_3D);
2138 checkGLcall("glDisable GL_TEXTURE_3D");
2140 /* Bind the texture */
2141 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2142 checkGLcall("glBindTexture");
2144 glEnable(GL_SCISSOR_TEST);
2146 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2148 /* No filtering for blts */
2149 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2150 GL_NEAREST);
2151 checkGLcall("glTexParameteri");
2152 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2153 GL_NEAREST);
2154 checkGLcall("glTexParameteri");
2155 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2156 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2157 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2158 checkGLcall("glTexEnvi");
2160 /* This is for color keying */
2161 if(Flags & DDBLT_KEYSRC) {
2162 glEnable(GL_ALPHA_TEST);
2163 checkGLcall("glEnable GL_ALPHA_TEST");
2164 glAlphaFunc(GL_NOTEQUAL, 0.0);
2165 checkGLcall("glAlphaFunc\n");
2166 } else {
2167 glDisable(GL_ALPHA_TEST);
2168 checkGLcall("glDisable GL_ALPHA_TEST");
2171 /* Draw a textured quad
2173 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2175 glBegin(GL_QUADS);
2177 glColor3d(1.0f, 1.0f, 1.0f);
2178 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2179 glVertex3f(rect.x1,
2180 rect.y1,
2181 0.0);
2183 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2184 glVertex3f(rect.x1, rect.y2, 0.0);
2186 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2187 glVertex3f(rect.x2,
2188 rect.y2,
2189 0.0);
2191 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2192 glVertex3f(rect.x2,
2193 rect.y1,
2194 0.0);
2195 glEnd();
2196 checkGLcall("glEnd");
2198 /* Unbind the texture */
2199 glBindTexture(GL_TEXTURE_2D, 0);
2200 checkGLcall("glEnable glBindTexture");
2202 /* Restore the old settings */
2203 if(oldLight) {
2204 glEnable(GL_LIGHTING);
2205 checkGLcall("glEnable GL_LIGHTING");
2207 if(oldFog) {
2208 glEnable(GL_FOG);
2209 checkGLcall("glEnable GL_FOG");
2211 if(oldDepth) {
2212 glEnable(GL_DEPTH_TEST);
2213 checkGLcall("glEnable GL_DEPTH_TEST");
2215 if(oldBlend) {
2216 glEnable(GL_BLEND);
2217 checkGLcall("glEnable GL_BLEND");
2219 if(oldCull) {
2220 glEnable(GL_CULL_FACE);
2221 checkGLcall("glEnable GL_CULL_FACE");
2223 if(oldStencil) {
2224 glEnable(GL_STENCIL_TEST);
2225 checkGLcall("glEnable GL_STENCIL_TEST");
2227 if(!oldAlpha) {
2228 glDisable(GL_ALPHA_TEST);
2229 checkGLcall("glDisable GL_ALPHA_TEST");
2230 } else {
2231 glEnable(GL_ALPHA_TEST);
2232 checkGLcall("glEnable GL_ALPHA_TEST");
2235 glAlphaFunc(alphafunc, alpharef);
2236 checkGLcall("glAlphaFunc\n");
2238 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2239 glDrawBuffer(oldDraw);
2242 /* Restore the color key */
2243 if(oldCKey != Src->CKeyFlags) {
2244 Src->CKeyFlags = oldCKey;
2245 Src->Flags |= SFLAG_DIRTY;
2248 LEAVE_GL();
2250 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2251 This->Flags |= SFLAG_GLDIRTY;
2253 return WINED3D_OK;
2257 /* Blt from rendertarget to texture? */
2258 if( (SrcSurface == swapchain->frontBuffer) ||
2259 (SrcSurface == swapchain->backBuffer) ) {
2260 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2261 ( (IWineD3DSurface *) This != swapchain->backBuffer) ) {
2262 UINT row;
2263 D3DRECT srect;
2264 float xrel, yrel;
2266 TRACE("Blt from rendertarget to texture\n");
2268 /* Call preload for the surface to make sure it isn't dirty */
2269 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2271 if(SrcRect) {
2272 srect.x1 = SrcRect->left;
2273 srect.y1 = SrcRect->top;
2274 srect.x2 = SrcRect->right;
2275 srect.y2 = SrcRect->bottom;
2276 } else {
2277 srect.x1 = 0;
2278 srect.y1 = 0;
2279 srect.x2 = Src->currentDesc.Width;
2280 srect.y2 = Src->currentDesc.Height;
2283 ENTER_GL();
2285 /* Bind the target texture */
2286 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2287 checkGLcall("glBindTexture");
2288 if(SrcSurface == swapchain->backBuffer) {
2289 glReadBuffer(GL_BACK);
2290 } else {
2291 glReadBuffer(GL_FRONT);
2293 checkGLcall("glReadBuffer");
2295 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2296 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2298 /* I have to process this row by row to swap the image,
2299 * otherwise it would be upside down, so streching in y direction
2300 * doesn't cost extra time
2302 * However, streching in x direction can be avoided if not necessary
2304 for(row = rect.y1; row < rect.y2; row++) {
2305 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2306 /* Well, that stuff works, but it's very slow.
2307 * find a better way instead
2309 UINT col;
2310 for(col = rect.x1; col < rect.x2; col++) {
2311 glCopyTexSubImage2D(GL_TEXTURE_2D,
2312 0, /* level */
2313 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2314 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2315 1, 1);
2317 } else {
2318 glCopyTexSubImage2D(GL_TEXTURE_2D,
2319 0, /* level */
2320 rect.x1, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2321 srect.x1, Src->currentDesc.Height - srect.y2 + row * yrel,
2322 rect.x2, 1);
2326 vcheckGLcall("glCopyTexSubImage2D");
2327 LEAVE_GL();
2329 if(!(This->Flags & SFLAG_DONOTFREE)) {
2330 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2331 This->resource.allocatedMemory = NULL;
2332 } else {
2333 This->Flags |= SFLAG_GLDIRTY;
2336 return WINED3D_OK;
2341 if (Flags & DDBLT_COLORFILL) {
2342 /* This is easy to handle for the D3D Device... */
2343 DWORD color;
2344 IWineD3DSwapChainImpl *implSwapChain;
2345 GLint prev_draw;
2347 TRACE("Colorfill\n");
2349 /* The color as given in the Blt function is in the format of the frame-buffer...
2350 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2352 if (This->resource.format == WINED3DFMT_P8) {
2353 if (This->palette) {
2354 color = ((0xFF000000) |
2355 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2356 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2357 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2358 } else {
2359 color = 0xFF000000;
2362 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2363 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2364 color = 0xFFFFFFFF;
2365 } else {
2366 color = ((0xFF000000) |
2367 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2368 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2369 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2372 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2373 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2374 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2376 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2377 color = DDBltFx->u5.dwFillColor;
2379 else {
2380 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2381 return WINED3DERR_INVALIDCALL;
2384 /* Are we drawing to the Front buffer or the back buffer? */
2385 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
2386 vcheckGLcall("glIntegerv");
2388 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2389 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2390 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2391 if(This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer) {
2392 glDrawBuffer(GL_BACK);
2393 checkGLcall("glDrawBuffer(GL_BACK)");
2395 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2396 glDrawBuffer(GL_FRONT);
2397 checkGLcall("glDrawBuffer(GL_FRONT)");
2399 else {
2400 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2401 return WINED3DERR_INVALIDCALL;
2404 TRACE("(%p) executing Render Target override, color = %lx\n", This, color);
2406 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2407 1 /* Number of rectangles */,
2408 &rect,
2409 D3DCLEAR_TARGET,
2410 color,
2411 0.0 /* Z */,
2412 0 /* Stencil */);
2414 /* Restore the original draw buffer */
2415 glDrawBuffer(prev_draw);
2416 vcheckGLcall("glDrawBuffer");
2418 return WINED3D_OK;
2421 /* Default: Fall back to the generic blt */
2422 return WINED3DERR_INVALIDCALL;
2425 HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2426 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2427 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2428 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2429 TRACE("(%p): Usage is %08lx\n", This, This->resource.usage);
2431 /* Special cases for RenderTargets */
2432 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2433 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2434 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2437 /* For the rest call the X11 surface implementation.
2438 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2439 * other Blts are rather rare
2441 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2444 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2445 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2446 TRACE("(%p)->(%lx)\n", This, Flags);
2448 switch (Flags)
2450 case DDGBS_CANBLT:
2451 case DDGBS_ISBLTDONE:
2452 return DD_OK;
2454 default:
2455 return DDERR_INVALIDPARAMS;
2459 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2460 /* XXX: DDERR_INVALIDSURFACETYPE */
2462 TRACE("(%p)->(%08lx)\n",iface,Flags);
2463 switch (Flags) {
2464 case DDGFS_CANFLIP:
2465 case DDGFS_ISFLIPDONE:
2466 return DD_OK;
2468 default:
2469 return DDERR_INVALIDPARAMS;
2473 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2474 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2475 TRACE("(%p)\n", This);
2477 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2480 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2481 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2482 TRACE("(%p)\n", This);
2484 /* So far we don't lose anything :) */
2485 This->Flags &= ~SFLAG_LOST;
2486 return WINED3D_OK;
2489 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2490 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2491 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2492 TRACE("(%p)->(%ld, %ld, %p, %p, %08lx\n", iface, dstx, dsty, Source, rsrc, trans);
2494 /* Special cases for RenderTargets */
2495 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2496 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2498 RECT SrcRect, DstRect;
2500 if(rsrc) {
2501 SrcRect.left = rsrc->left;
2502 SrcRect.top= rsrc->top;
2503 SrcRect.bottom = rsrc->bottom;
2504 SrcRect.right = rsrc->right;
2505 } else {
2506 SrcRect.left = 0;
2507 SrcRect.top = 0;
2508 SrcRect.right = srcImpl->currentDesc.Width;
2509 SrcRect.bottom = srcImpl->currentDesc.Height;
2512 DstRect.left = dstx;
2513 DstRect.top=dsty;
2514 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2515 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2517 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, 0, NULL) == WINED3D_OK) return WINED3D_OK;
2521 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2524 HRESULT WINAPI IWineD3DSurfaceImpl_SetPixelFormat(IWineD3DSurface *iface, WINED3DFORMAT Format, BYTE *Surface, DWORD Size) {
2525 FIXME("This is unimplemented for now(d3d7 merge)\n");
2526 return WINED3DERR_INVALIDCALL;
2529 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2530 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2531 TRACE("(%p)->(%p)\n", This, Pal);
2533 *Pal = (IWineD3DPalette *) This->palette;
2534 return DD_OK;
2537 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2538 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2539 RGBQUAD col[256];
2540 IWineD3DPaletteImpl *pal = This->palette;
2541 unsigned int n;
2542 TRACE("(%p)\n", This);
2544 if(This->resource.format == WINED3DFMT_P8 ||
2545 This->resource.format == WINED3DFMT_A8P8)
2547 TRACE("Dirtifying surface\n");
2548 This->Flags |= SFLAG_DIRTY;
2551 if(This->Flags & SFLAG_DIBSECTION) {
2552 TRACE("(%p): Updating the hdc's palette\n", This);
2553 for (n=0; n<256; n++) {
2554 if(pal) {
2555 col[n].rgbRed = pal->palents[n].peRed;
2556 col[n].rgbGreen = pal->palents[n].peGreen;
2557 col[n].rgbBlue = pal->palents[n].peBlue;
2558 } else {
2559 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2560 /* Use the default device palette */
2561 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2562 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2563 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2565 col[n].rgbReserved = 0;
2567 SetDIBColorTable(This->hDC, 0, 256, col);
2570 return WINED3D_OK;
2573 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2574 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2575 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2576 TRACE("(%p)->(%p)\n", This, Pal);
2578 if(This->palette != NULL)
2579 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2580 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2582 if(PalImpl != NULL) {
2583 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2584 /* Set the device's main palette if the palette
2585 * wasn't a primary palette before
2587 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2588 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2589 unsigned int i;
2591 for(i=0; i < 256; i++) {
2592 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2596 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2599 This->palette = PalImpl;
2601 return IWineD3DSurface_RealizePalette(iface);
2604 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2605 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2606 BOOL dirtify = FALSE;
2607 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
2609 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2610 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
2611 return DDERR_INVALIDPARAMS;
2614 /* Dirtify the surface, but only if a key was changed */
2615 if(CKey) {
2616 switch (Flags & ~DDCKEY_COLORSPACE) {
2617 case DDCKEY_DESTBLT:
2618 if(!(This->CKeyFlags & DDSD_CKDESTBLT)) {
2619 dirtify = TRUE;
2620 } else {
2621 dirtify = memcmp(&This->DestBltCKey, CKey, sizeof(*CKey) ) != 0;
2623 This->DestBltCKey = *CKey;
2624 This->CKeyFlags |= DDSD_CKDESTBLT;
2625 break;
2627 case DDCKEY_DESTOVERLAY:
2628 if(!(This->CKeyFlags & DDSD_CKDESTOVERLAY)) {
2629 dirtify = TRUE;
2630 } else {
2631 dirtify = memcmp(&This->DestOverlayCKey, CKey, sizeof(*CKey)) != 0;
2633 This->DestOverlayCKey = *CKey;
2634 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2635 break;
2637 case DDCKEY_SRCOVERLAY:
2638 if(!(This->CKeyFlags & DDSD_CKSRCOVERLAY)) {
2639 dirtify = TRUE;
2640 } else {
2641 dirtify = memcmp(&This->SrcOverlayCKey, CKey, sizeof(*CKey)) != 0;
2643 This->SrcOverlayCKey = *CKey;
2644 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2645 break;
2647 case DDCKEY_SRCBLT:
2648 if(!(This->CKeyFlags & DDSD_CKSRCBLT)) {
2649 dirtify = TRUE;
2650 } else {
2651 dirtify = memcmp(&This->SrcBltCKey, CKey, sizeof(*CKey)) != 0;
2653 This->SrcBltCKey = *CKey;
2654 This->CKeyFlags |= DDSD_CKSRCBLT;
2655 break;
2658 else {
2659 switch (Flags & ~DDCKEY_COLORSPACE) {
2660 case DDCKEY_DESTBLT:
2661 dirtify = This->CKeyFlags & DDSD_CKDESTBLT;
2662 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2663 break;
2665 case DDCKEY_DESTOVERLAY:
2666 dirtify = This->CKeyFlags & DDSD_CKDESTOVERLAY;
2667 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2668 break;
2670 case DDCKEY_SRCOVERLAY:
2671 dirtify = This->CKeyFlags & DDSD_CKSRCOVERLAY;
2672 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2673 break;
2675 case DDCKEY_SRCBLT:
2676 dirtify = This->CKeyFlags & DDSD_CKSRCBLT;
2677 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2678 break;
2682 if(dirtify) {
2683 TRACE("Color key changed, dirtifying surface\n");
2684 This->Flags |= SFLAG_DIRTY;
2687 return WINED3D_OK;
2690 HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2691 /** Check against the maximum texture sizes supported by the video card **/
2692 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2694 TRACE("%p\n", This);
2695 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2696 /* one of three options
2697 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)
2698 2: Set the texture to the maxium size (bad idea)
2699 3: WARN and return WINED3DERR_NOTAVAILABLE;
2700 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.
2702 WARN("(%p) Creating an oversized surface\n", This);
2703 This->Flags |= SFLAG_OVERSIZE;
2705 /* This will be initialized on the first blt */
2706 This->glRect.left = 0;
2707 This->glRect.top = 0;
2708 This->glRect.right = 0;
2709 This->glRect.bottom = 0;
2710 } else {
2711 /* No oversize, gl rect is the full texture size */
2712 This->Flags &= ~SFLAG_OVERSIZE;
2713 This->glRect.left = 0;
2714 This->glRect.top = 0;
2715 This->glRect.right = This->pow2Width;
2716 This->glRect.bottom = This->pow2Height;
2719 return WINED3D_OK;
2722 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
2723 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2724 DWORD ret;
2725 TRACE("(%p)\n", This);
2727 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
2728 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
2729 ie pitch = (width/4) * bytes per block */
2730 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
2731 ret = (This->currentDesc.Width >> 2) << 3;
2732 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
2733 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
2734 ret = (This->currentDesc.Width >> 2) << 4;
2735 else {
2736 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2737 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
2738 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
2739 } else {
2740 ret = This->bytesPerPixel * This->pow2Width;
2743 TRACE("(%p) Returning %ld\n", This, ret);
2744 return ret;
2747 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
2749 /* IUnknown */
2750 IWineD3DSurfaceImpl_QueryInterface,
2751 IWineD3DSurfaceImpl_AddRef,
2752 IWineD3DSurfaceImpl_Release,
2753 /* IWineD3DResource */
2754 IWineD3DSurfaceImpl_GetParent,
2755 IWineD3DSurfaceImpl_GetDevice,
2756 IWineD3DSurfaceImpl_SetPrivateData,
2757 IWineD3DSurfaceImpl_GetPrivateData,
2758 IWineD3DSurfaceImpl_FreePrivateData,
2759 IWineD3DSurfaceImpl_SetPriority,
2760 IWineD3DSurfaceImpl_GetPriority,
2761 IWineD3DSurfaceImpl_PreLoad,
2762 IWineD3DSurfaceImpl_GetType,
2763 /* IWineD3DSurface */
2764 IWineD3DSurfaceImpl_GetContainerParent,
2765 IWineD3DSurfaceImpl_GetContainer,
2766 IWineD3DSurfaceImpl_GetDesc,
2767 IWineD3DSurfaceImpl_LockRect,
2768 IWineD3DSurfaceImpl_UnlockRect,
2769 IWineD3DSurfaceImpl_GetDC,
2770 IWineD3DSurfaceImpl_ReleaseDC,
2771 IWineD3DSurfaceImpl_Flip,
2772 IWineD3DSurfaceImpl_Blt,
2773 IWineD3DSurfaceImpl_GetBltStatus,
2774 IWineD3DSurfaceImpl_GetFlipStatus,
2775 IWineD3DSurfaceImpl_IsLost,
2776 IWineD3DSurfaceImpl_Restore,
2777 IWineD3DSurfaceImpl_BltFast,
2778 IWineD3DSurfaceImpl_SetPixelFormat,
2779 IWineD3DSurfaceImpl_GetPalette,
2780 IWineD3DSurfaceImpl_SetPalette,
2781 IWineD3DSurfaceImpl_RealizePalette,
2782 IWineD3DSurfaceImpl_SetColorKey,
2783 IWineD3DSurfaceImpl_GetPitch,
2784 /* Internal use: */
2785 IWineD3DSurfaceImpl_CleanDirtyRect,
2786 IWineD3DSurfaceImpl_AddDirtyRect,
2787 IWineD3DSurfaceImpl_LoadTexture,
2788 IWineD3DSurfaceImpl_SaveSnapshot,
2789 IWineD3DSurfaceImpl_SetContainer,
2790 IWineD3DSurfaceImpl_SetPBufferState,
2791 IWineD3DSurfaceImpl_SetGlTextureDesc,
2792 IWineD3DSurfaceImpl_GetGlDesc,
2793 IWineD3DSurfaceImpl_GetData,
2794 IWineD3DSurfaceImpl_SetFormat,
2795 IWineD3DSurfaceImpl_PrivateSetup