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
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);
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);
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);
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);
69 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
70 TRACE("(%p) : cleaning up\n", This);
71 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
73 TRACE("Deleting texture %d\n", This->glDescription.textureName);
74 glDeleteTextures(1, &This->glDescription.textureName);
78 if(This->Flags & SFLAG_DIBSECTION) {
80 SelectObject(This->hDC, This->dib.holdbitmap);
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);
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);
140 TRACE("(%p) : About to load surface\n", This);
142 #if 0 /* TODO: context manager support */
143 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
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 */
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) */
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) */);
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 */
211 *ppContainerParent = NULL;
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);
224 ERR("Called without a valid ppContainer.\n");
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;
235 container = (IWineD3DBase *)This->resource.wineD3DDevice;
238 TRACE("Relaying to QueryInterface\n");
239 return IUnknown_QueryInterface(container, riid, ppContainer);
242 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
243 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
245 TRACE("(%p) : copying into %p\n", This, pDesc);
246 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
247 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
248 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
249 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
250 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
251 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
252 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
253 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
254 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
258 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
259 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
260 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
261 if (This->glDescription.textureName == 0 && textureName != 0) {
262 This->Flags |= SFLAG_DIRTY;
263 IWineD3DSurface_AddDirtyRect(iface, NULL);
265 This->glDescription.textureName = textureName;
266 This->glDescription.target = target;
269 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
270 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
271 TRACE("(%p) : returning %p\n", This, &This->glDescription);
272 *glDescription = &This->glDescription;
275 /* TODO: think about moving this down to resource? */
276 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
277 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
278 /* This should only be called for sysmem textures, it may be a good idea to extend this to all pools at some point in the futture */
279 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
280 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
282 return (CONST void*)(This->resource.allocatedMemory);
285 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
286 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
287 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
288 IWineD3DSwapChainImpl *swapchain = NULL;
289 static UINT messages = 0; /* holds flags to disable fixme messages */
291 /* fixme: should we really lock as such? */
292 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
293 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
294 FIXME("Warning: Surface is in texture memory or pbuffer\n");
295 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
298 if (!(This->Flags & SFLAG_LOCKABLE)) {
299 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
300 texture regions, and since the destination is an unlockable region we need
302 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
303 /*return WINED3DERR_INVALIDCALL; */
306 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
307 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
309 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
310 if (swapchain != NULL && iface == swapchain->backBuffer) {
311 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
312 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
313 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
314 } else if (iface == myDevice->renderTarget) {
315 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
316 } else if (iface == myDevice->depthStencilBuffer) {
317 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
320 if (NULL != swapchain) {
321 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
326 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
329 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
332 pLockedRect->pBits = This->resource.allocatedMemory;
333 This->lockedRect.left = 0;
334 This->lockedRect.top = 0;
335 This->lockedRect.right = This->currentDesc.Width;
336 This->lockedRect.bottom = This->currentDesc.Height;
337 TRACE("Locked Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
339 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
341 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
342 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
344 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
346 This->lockedRect.left = pRect->left;
347 This->lockedRect.top = pRect->top;
348 This->lockedRect.right = pRect->right;
349 This->lockedRect.bottom = pRect->bottom;
352 if (This->Flags & SFLAG_NONPOW2) {
353 TRACE("Locking non-power 2 texture\n");
356 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
357 /* classic surface TODO: non 2d surfaces?
358 These resources may be POOL_SYSTEMMEM, so they must not access the device */
359 TRACE("locking an ordinarary surface\n");
360 /* Check to see if memory has already been allocated from the surface*/
361 if ((NULL == This->resource.allocatedMemory) ||
362 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
363 /* Non-system memory surfaces */
365 This->Flags &= ~SFLAG_GLDIRTY;
367 /*Surface has no memory currently allocated to it!*/
368 TRACE("(%p) Locking rect\n" , This);
369 if(!This->resource.allocatedMemory) {
370 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
372 if (0 != This->glDescription.textureName) {
373 /* Now I have to copy thing bits back */
374 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
375 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
378 /* Make sure that the texture is loaded */
379 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
381 TRACE("(%p) glGetTexImage level(%d), fmt(%d), typ(%d), mem(%p)\n" , This, This->glDescription.level, This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
383 if (This->resource.format == WINED3DFMT_DXT1 ||
384 This->resource.format == WINED3DFMT_DXT2 ||
385 This->resource.format == WINED3DFMT_DXT3 ||
386 This->resource.format == WINED3DFMT_DXT4 ||
387 This->resource.format == WINED3DFMT_DXT5) {
388 TRACE("Locking a compressed texture\n");
389 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
390 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
391 This->glDescription.level,
392 This->resource.allocatedMemory);
395 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
398 glGetTexImage(This->glDescription.target,
399 This->glDescription.level,
400 This->glDescription.glFormat,
401 This->glDescription.glType,
402 This->resource.allocatedMemory);
403 vcheckGLcall("glGetTexImage");
404 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
405 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
406 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
407 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
411 instead of boxing the texture :
412 |<-texture width ->| -->pow2width| /\
413 |111111111111111111| | |
414 |222 Texture 222222| boxed empty | texture height
415 |3333 Data 33333333| | |
416 |444444444444444444| | \/
417 ----------------------------------- |
418 | boxed empty | boxed empty | pow2height
420 -----------------------------------
423 were repacking the data to the expected texture width
425 |<-texture width ->| -->pow2width| /\
426 |111111111111111111222222222222222| |
427 |222333333333333333333444444444444| texture height
433 -----------------------------------
437 |<-texture width ->| /\
439 |222222222222222222|texture height
441 |444444444444444444| \/
444 this also means that any references to allocatedMemory should work with the data as if were a standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
446 internally the texture is still stored in a boxed format so any references to textureName will get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
448 if (This->Flags & SFLAG_NONPOW2) {
450 int pitcha = 0, pitchb = 0;
452 pitcha = This->bytesPerPixel * This->currentDesc.Width;
453 pitchb = This->bytesPerPixel * This->pow2Width;
454 datab = dataa = This->resource.allocatedMemory;
455 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
456 for (y = 1 ; y < This->currentDesc.Height; y++) {
457 dataa += pitcha; /* skip the first row */
459 memcpy(dataa, datab, pitcha);
466 } else { /* Nothing to do */
467 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
471 pLockedRect->pBits = This->resource.allocatedMemory;
473 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
474 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
476 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
480 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
481 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
484 BOOL notInContext = FALSE;
485 IWineD3DSwapChainImpl *targetSwapChain = NULL;
491 * for render->surface copy begin to begin of allocatedMemory
492 * unlock can be more easy
495 TRACE("locking a render target\n");
497 if (This->resource.allocatedMemory == NULL)
498 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
500 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
501 pLockedRect->pBits = This->resource.allocatedMemory;
504 vcheckGLcall("glFlush");
505 glGetIntegerv(GL_READ_BUFFER, &prev_read);
506 vcheckGLcall("glIntegerv");
507 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
508 vcheckGLcall("glIntegerv");
510 /* Here's what we have to do:
511 See if the swapchain has the same context as the renderTarget or the surface is the render target.
512 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
513 and use the front back buffer as required.
514 if not, we need to switch contexts and then switchback at the end.
516 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
517 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
519 /* NOTE: In a shared context environment the renderTarget will use the same context as the implicit swapchain (we're not in a shared environment yet! */
520 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
521 if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) {
522 TRACE("locking back buffer\n");
523 glReadBuffer(GL_BACK);
524 } else if (iface == swapchain->frontBuffer) {
525 TRACE("locking front\n");
526 glReadBuffer(GL_FRONT);
527 } else if (iface == myDevice->depthStencilBuffer) {
528 FIXME("Stencil Buffer lock unsupported for now\n");
530 FIXME("(%p) Shouldn't have got here!\n", This);
531 glReadBuffer(GL_BACK);
533 } else if (swapchain != NULL) {
534 IWineD3DSwapChainImpl *implSwapChain;
535 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
536 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
537 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
538 if (iface == swapchain->backBuffer) {
539 glReadBuffer(GL_BACK);
540 } else if (iface == swapchain->frontBuffer) {
541 glReadBuffer(GL_FRONT);
542 } else if (iface == myDevice->depthStencilBuffer) {
543 FIXME("Stencil Buffer lock unsupported for now\n");
545 FIXME("Should have got here!\n");
546 glReadBuffer(GL_BACK);
549 /* We need to switch contexts to be able to read the buffer!!! */
550 FIXME("The buffer requested isn't in the current openGL context\n");
552 /* TODO: check the contexts, to see if were shared with the current context */
554 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
556 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
557 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
559 /** the depth stencil in openGL has a format of GL_FLOAT
560 * which should be good for WINED3DFMT_D16_LOCKABLE
562 * it is unclear what format the stencil buffer is in except.
563 * 'Each index is converted to fixed point...
564 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
565 * mappings in the table GL_PIXEL_MAP_S_TO_S.
566 * glReadPixels(This->lockedRect.left,
567 * This->lockedRect.bottom - j - 1,
568 * This->lockedRect.right - This->lockedRect.left,
570 * GL_DEPTH_COMPONENT,
572 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
573 *****************************************/
574 if (!notInContext) { /* Only read the buffer if it's in the current context */
578 /* Bizarly it takes 120 millseconds to get an 800x600 region a line at a time, but only 10 to get the whole lot every time,
579 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
580 * run ten times faster!
581 * ************************************/
582 BOOL ati_performance_hack = FALSE;
583 ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
585 if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
586 This->lockedRect.right == This->currentDesc.Width
587 && This->lockedRect.bottom == This->currentDesc.Height)) {
588 BYTE *row, *top, *bottom;
592 This->currentDesc.Width,
593 This->currentDesc.Height,
594 This->glDescription.glFormat,
595 This->glDescription.glType,
596 (char *)pLockedRect->pBits);
598 /* glReadPixels returns the image upside down, and there is no way to prevent this.
599 Flip the lines in software*/
600 row = HeapAlloc(GetProcessHeap(), 0, pLockedRect->Pitch);
602 ERR("Out of memory\n");
603 return E_OUTOFMEMORY;
605 top = This->resource.allocatedMemory;
606 bottom = ( (BYTE *) This->resource.allocatedMemory) + pLockedRect->Pitch * ( This->currentDesc.Height - 1);
607 for(i = 0; i < This->currentDesc.Height / 2; i++) {
608 memcpy(row, top, pLockedRect->Pitch);
609 memcpy(top, bottom, pLockedRect->Pitch);
610 memcpy(bottom, row, pLockedRect->Pitch);
611 top += pLockedRect->Pitch;
612 bottom -= pLockedRect->Pitch;
614 HeapFree(GetProcessHeap(), 0, row);
616 This->Flags &= ~SFLAG_GLDIRTY;
618 } else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
620 This->lockedRect.top,
621 This->currentDesc.Width,
622 This->currentDesc.Height,
623 This->glDescription.glFormat,
624 This->glDescription.glType,
625 (char *)pLockedRect->pBits);
628 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
629 glReadPixels(This->lockedRect.left,
630 This->lockedRect.bottom - j - 1,
631 This->lockedRect.right - This->lockedRect.left,
633 This->glDescription.glFormat,
634 This->glDescription.glType,
635 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
640 vcheckGLcall("glReadPixels");
641 TRACE("Resetting buffer\n");
642 glReadBuffer(prev_read);
643 vcheckGLcall("glReadBuffer");
647 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
650 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
653 glReadPixels(This->lockedRect.left,
654 This->lockedRect.bottom - j - 1,
655 This->lockedRect.right - This->lockedRect.left,
657 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
664 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
667 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
670 IWineD3DBaseTexture *pBaseTexture;
673 * as seen in msdn docs
675 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
677 /** Dirtify Container if needed */
678 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
679 TRACE("Making container dirty\n");
680 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
681 IWineD3DBaseTexture_Release(pBaseTexture);
683 TRACE("Surface is standalone, no need to dirty the container\n");
687 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
689 This->Flags |= SFLAG_LOCKED;
693 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
695 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
696 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
697 const char *buffername = "";
698 IWineD3DSwapChainImpl *swapchain = NULL;
700 if (!(This->Flags & SFLAG_LOCKED)) {
701 WARN("trying to Unlock an unlocked surf@%p\n", This);
702 return WINED3DERR_INVALIDCALL;
705 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
706 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
708 if ((swapchain != NULL) && iface == swapchain->backBuffer) {
709 buffername = "backBuffer";
710 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
711 buffername = "frontBuffer";
712 } else if (iface == myDevice->depthStencilBuffer) {
713 buffername = "depthStencilBuffer";
714 } else if (iface == myDevice->renderTarget) {
715 buffername = "renderTarget";
719 if (swapchain != NULL) {
720 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
723 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
725 if (!(This->Flags & SFLAG_DIRTY)) {
726 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
730 if (0 == This->resource.usage) { /* classic surface */
733 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
735 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
737 /****************************
738 * TODO: Render targets are 'special' and
739 * ?some? locking needs to be passed onto the context manager
740 * so that it becomes possible to use auxiliary buffers, pbuffers
741 * render-to-texture, shared, cached contexts etc...
742 * ****************************/
743 IWineD3DSwapChainImpl *implSwapChain;
744 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
746 if (iface == implSwapChain->backBuffer || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
749 GLint prev_depth_test;
750 GLint prev_rasterpos[4];
752 /* Some drivers(radeon dri, others?) don't like exceptions during
753 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
754 * after ReleaseDC. Reading it will cause an exception, which x11drv will
755 * catch to put the dib section in InSync mode, which leads to a crash
756 * and a blocked x server on my radeon card.
758 * The following lines read the dib section so it is put in inSync mode
759 * before glDrawPixels is called and the crash is prevented. There won't
760 * be any interfering gdi accesses, because UnlockRect is called from
761 * ReleaseDC, and the app won't use the dc any more afterwards.
763 if(This->Flags & SFLAG_DIBSECTION) {
765 read = This->resource.allocatedMemory[0];
771 vcheckGLcall("glFlush");
772 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
773 vcheckGLcall("glIntegerv");
774 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
775 vcheckGLcall("glIntegerv");
776 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
777 vcheckGLcall("glIntegerv");
778 glPixelZoom(1.0, -1.0);
779 vcheckGLcall("glPixelZoom");
780 prev_depth_test = glIsEnabled(GL_DEPTH_TEST);
782 /* glDrawPixels transforms the raster position as though it was a vertex -
783 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
784 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
785 d3ddevice_set_ortho(This->resource.wineD3DDevice);
787 if (iface == implSwapChain->frontBuffer) {
788 glDrawBuffer(GL_FRONT);
789 checkGLcall("glDrawBuffer GL_FRONT");
790 } else if (iface == implSwapChain->backBuffer || iface == myDevice->renderTarget) {
791 glDrawBuffer(GL_BACK);
792 checkGLcall("glDrawBuffer GL_BACK");
795 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
796 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
797 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
799 /* And back buffers are not blended */
801 glDisable(GL_DEPTH_TEST);
803 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
804 vcheckGLcall("glRasterPos2f");
805 switch (This->resource.format) {
806 case WINED3DFMT_X4R4G4B4:
809 unsigned short *data;
810 data = (unsigned short *)This->resource.allocatedMemory;
811 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
818 case WINED3DFMT_A4R4G4B4:
820 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
821 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
822 vcheckGLcall("glDrawPixels");
825 case WINED3DFMT_R5G6B5:
827 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
828 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
829 vcheckGLcall("glDrawPixels");
832 case WINED3DFMT_X1R5G5B5:
835 unsigned short *data;
836 data = (unsigned short *)This->resource.allocatedMemory;
837 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
844 case WINED3DFMT_A1R5G5B5:
846 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
847 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
848 vcheckGLcall("glDrawPixels");
851 case WINED3DFMT_R8G8B8:
853 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
854 GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
855 vcheckGLcall("glDrawPixels");
858 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
859 could be any random value this fixes the intro move in Pirates! */
863 data = (unsigned int *)This->resource.allocatedMemory;
864 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
871 case WINED3DFMT_A8R8G8B8:
873 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
874 vcheckGLcall("glPixelStorei");
875 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
876 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
877 vcheckGLcall("glDrawPixels");
878 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
879 vcheckGLcall("glPixelStorei");
882 case WINED3DFMT_A2R10G10B10:
884 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
885 vcheckGLcall("glPixelStorei");
886 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
887 GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
888 vcheckGLcall("glDrawPixels");
889 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
890 vcheckGLcall("glPixelStorei");
894 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
897 glPixelZoom(1.0,1.0);
898 vcheckGLcall("glPixelZoom");
899 glDrawBuffer(prev_draw);
900 vcheckGLcall("glDrawBuffer");
901 glRasterPos3iv(&prev_rasterpos[0]);
902 vcheckGLcall("glRasterPos3iv");
903 if(prev_depth_test) glEnable(GL_DEPTH_TEST);
905 /* Reset to previous pack row length / blending state */
906 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
907 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
911 /** restore clean dirty state */
912 IWineD3DSurface_CleanDirtyRect(iface);
915 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
917 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
919 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
921 if (iface == myDevice->depthStencilBuffer) {
922 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
924 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
928 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
932 This->Flags &= ~SFLAG_LOCKED;
933 memset(&This->lockedRect, 0, sizeof(RECT));
937 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
938 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
939 WINED3DLOCKED_RECT lock;
947 TRACE("(%p)->(%p)\n",This,pHDC);
949 /* Give more detailed info for ddraw */
950 if (This->Flags & SFLAG_DCINUSE)
951 return DDERR_DCALREADYCREATED;
953 /* Can't GetDC if the surface is locked */
954 if (This->Flags & SFLAG_LOCKED)
955 return WINED3DERR_INVALIDCALL;
957 memset(&lock, 0, sizeof(lock)); /* To be sure */
959 /* Create a DIB section if there isn't a hdc yet */
961 if(This->Flags & SFLAG_ACTIVELOCK) {
962 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
965 switch (This->bytesPerPixel) {
968 /* Allocate extra space to store the RGB bit masks. */
969 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
973 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
977 /* Allocate extra space for a palette. */
978 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
979 sizeof(BITMAPINFOHEADER)
981 * (1 << (This->bytesPerPixel * 8)));
985 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
986 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
987 b_info->bmiHeader.biWidth = This->currentDesc.Width;
988 b_info->bmiHeader.biHeight = -This->currentDesc.Height;
989 /* Use the full pow2 image size(assigned below) because LockRect
990 * will need it for a full glGetTexImage call
993 b_info->bmiHeader.biWidth = This->pow2Width;
994 b_info->bmiHeader.biHeight = -This->pow2Height;
996 b_info->bmiHeader.biPlanes = 1;
997 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
999 b_info->bmiHeader.biSizeImage = This->resource.size;
1001 b_info->bmiHeader.biXPelsPerMeter = 0;
1002 b_info->bmiHeader.biYPelsPerMeter = 0;
1003 b_info->bmiHeader.biClrUsed = 0;
1004 b_info->bmiHeader.biClrImportant = 0;
1006 /* Get the bit masks */
1007 masks = (DWORD *) &(b_info->bmiColors);
1008 switch (This->resource.format) {
1009 case WINED3DFMT_R8G8B8:
1010 usage = DIB_RGB_COLORS;
1011 b_info->bmiHeader.biCompression = BI_RGB;
1014 case WINED3DFMT_X1R5G5B5:
1015 case WINED3DFMT_A1R5G5B5:
1016 case WINED3DFMT_A4R4G4B4:
1017 case WINED3DFMT_X4R4G4B4:
1018 case WINED3DFMT_R3G3B2:
1019 case WINED3DFMT_A8R3G3B2:
1020 case WINED3DFMT_A2B10G10R10:
1021 case WINED3DFMT_A8B8G8R8:
1022 case WINED3DFMT_X8B8G8R8:
1023 case WINED3DFMT_A2R10G10B10:
1024 case WINED3DFMT_R5G6B5:
1025 case WINED3DFMT_A16B16G16R16:
1027 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1028 masks[0] = get_bitmask_red(This->resource.format);
1029 masks[1] = get_bitmask_green(This->resource.format);
1030 masks[2] = get_bitmask_blue(This->resource.format);
1034 /* Don't know palette */
1035 b_info->bmiHeader.biCompression = BI_RGB;
1040 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1042 HeapFree(GetProcessHeap(), 0, b_info);
1043 return HRESULT_FROM_WIN32(GetLastError());
1046 TRACE("Creating a DIB section with size %ldx%ldx%d, size=%ld\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
1047 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1050 if (!This->dib.DIBsection) {
1051 ERR("CreateDIBSection failed!\n");
1052 return HRESULT_FROM_WIN32(GetLastError());
1054 HeapFree(GetProcessHeap(), 0, b_info);
1056 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1058 /* copy the existing surface to the dib section */
1059 if(This->resource.allocatedMemory) {
1060 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->resource.size);
1061 /* We won't need that any more */
1062 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1064 /* This is to make LockRect read the gl Texture although memory is allocated */
1065 This->Flags |= SFLAG_GLDIRTY;
1068 /* Use the dib section from now on */
1069 This->resource.allocatedMemory = This->dib.bitmap_data;
1071 /* Now allocate a HDC */
1072 This->hDC = CreateCompatibleDC(0);
1073 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1074 TRACE("using wined3d palette %p\n", This->palette);
1075 SelectPalette(This->hDC,
1076 This->palette ? This->palette->hpal : 0,
1079 This->Flags |= SFLAG_DIBSECTION;
1082 /* Lock the surface */
1083 hr = IWineD3DSurface_LockRect(iface,
1088 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1089 /* keep the dib section */
1093 if(This->resource.format == WINED3DFMT_P8 ||
1094 This->resource.format == WINED3DFMT_A8P8) {
1097 PALETTEENTRY ent[256];
1099 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1100 for (n=0; n<256; n++) {
1101 col[n].rgbRed = ent[n].peRed;
1102 col[n].rgbGreen = ent[n].peGreen;
1103 col[n].rgbBlue = ent[n].peBlue;
1104 col[n].rgbReserved = 0;
1107 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1109 for (n=0; n<256; n++) {
1110 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1111 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1112 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1113 col[n].rgbReserved = 0;
1117 SetDIBColorTable(This->hDC, 0, 256, col);
1121 TRACE("returning %p\n",*pHDC);
1122 This->Flags |= SFLAG_DCINUSE;
1127 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1128 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1130 TRACE("(%p)->(%p)\n",This,hDC);
1132 if (!(This->Flags & SFLAG_DCINUSE))
1133 return D3DERR_INVALIDCALL;
1135 /* we locked first, so unlock now */
1136 IWineD3DSurface_UnlockRect(iface);
1138 This->Flags &= ~SFLAG_DCINUSE;
1143 /* ******************************************************
1144 IWineD3DSurface Internal (No mapping to directx api) parts follow
1145 ****************************************************** */
1150 CONVERT_PALETTED_CK,
1154 CONVERT_CK_4444_ARGB,
1159 CONVERT_CK_8888_ARGB,
1163 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp) {
1164 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1166 /* Default values: From the surface */
1167 *format = D3DFmt2GLFmt(This->resource.wineD3DDevice,
1168 This->resource.format);
1169 *internal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice,
1170 This->resource.format);
1171 *type = D3DFmt2GLType(This->resource.wineD3DDevice,
1172 This->resource.format);
1173 *convert = NO_CONVERSION;
1174 *target_bpp = This->bytesPerPixel;
1176 /* Ok, now look if we have to do any conversion */
1177 switch(This->resource.format) {
1182 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active) {
1184 *internal = GL_RGBA;
1185 *type = GL_UNSIGNED_BYTE;
1187 if(colorkey_active) {
1188 *convert = CONVERT_PALETTED;
1190 *convert = CONVERT_PALETTED_CK;
1196 case WINED3DFMT_R3G3B2:
1197 /* **********************
1198 GL_UNSIGNED_BYTE_3_3_2
1199 ********************** */
1200 if (colorkey_active) {
1201 /* This texture format will never be used.. So do not care about color keying
1202 up until the point in time it will be needed :-) */
1203 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1207 case WINED3DFMT_R5G6B5:
1208 if (colorkey_active) {
1209 *convert = CONVERT_CK_565;
1211 *internal = GL_RGBA;
1212 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1216 case WINED3DFMT_R8G8B8:
1217 if (colorkey_active) {
1218 *convert = CONVERT_CK_RGB24;
1220 *internal = GL_RGBA;
1221 *type = GL_UNSIGNED_INT_8_8_8_8;
1226 case WINED3DFMT_X8R8G8B8:
1227 if (colorkey_active) {
1228 *convert = CONVERT_RGB32_888;
1230 *internal = GL_RGBA;
1231 *type = GL_UNSIGNED_INT_8_8_8_8;
1235 /* Not sure if we should do color keying on Alpha-Enabled surfaces */
1236 case WINED3DFMT_A4R4G4B4:
1237 if (colorkey_active)
1239 *convert = CONVERT_CK_4444_ARGB;
1241 *internal = GL_RGBA;
1242 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1246 case WINED3DFMT_A1R5G5B5:
1247 if (colorkey_active)
1249 *convert = CONVERT_CK_1555;
1252 case WINED3DFMT_A8R8G8B8:
1253 if (colorkey_active)
1255 *convert = CONVERT_CK_8888_ARGB;
1257 *internal = GL_RGBA;
1258 *type = GL_UNSIGNED_INT_8_8_8_8;
1269 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1270 TRACE("(%p)->(%p),(%ld,%d,%p)\n", src, dst, len, convert, surf);
1275 memcpy(dst, src, len * surf->bytesPerPixel);
1278 case CONVERT_PALETTED:
1279 case CONVERT_PALETTED_CK:
1281 IWineD3DPaletteImpl* pal = surf->palette;
1287 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1291 /* Still no palette? Use the device's palette */
1292 /* Get the surface's palette */
1293 for (i = 0; i < 256; i++) {
1294 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1296 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1297 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1298 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1299 if ((convert == CONVERT_PALETTED_CK) &&
1300 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1301 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1302 /* We should maybe here put a more 'neutral' color than the standard bright purple
1303 one often used by application to prevent the nice purple borders when bi-linear
1311 TRACE("Using surface palette %p\n", pal);
1312 /* Get the surface's palette */
1313 for (i = 0; i < 256; i++) {
1314 table[i][0] = pal->palents[i].peRed;
1315 table[i][1] = pal->palents[i].peGreen;
1316 table[i][2] = pal->palents[i].peBlue;
1317 if ((convert == CONVERT_PALETTED_CK) &&
1318 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1319 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1320 /* We should maybe here put a more 'neutral' color than the standard bright purple
1321 one often used by application to prevent the nice purple borders when bi-linear
1330 for (x = 0; x < len; x++) {
1331 BYTE color = *src++;
1332 *dst++ = table[color][0];
1333 *dst++ = table[color][1];
1334 *dst++ = table[color][2];
1335 *dst++ = table[color][3];
1340 case CONVERT_CK_565:
1342 /* Converting the 565 format in 5551 packed to emulate color-keying.
1344 Note : in all these conversion, it would be best to average the averaging
1345 pixels to get the color of the pixel that will be color-keyed to
1346 prevent 'color bleeding'. This will be done later on if ever it is
1349 Note2: when using color-keying + alpha, are the alpha bits part of the
1350 color-space or not ?
1353 WORD *Source = (WORD *) src;
1354 WORD *Dest = (WORD *) dst;
1356 TRACE("Color keyed 565\n");
1358 for (x = 0; x < len; x++ ) {
1359 WORD color = *Source++;
1360 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1361 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1362 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1370 case CONVERT_CK_1555:
1373 WORD *Source = (WORD *) src;
1374 WORD *Dest = (WORD *) dst;
1376 for (x = 0; x < len * sizeof(WORD); x+=sizeof(WORD)) {
1377 WORD color = *Source++;
1378 *Dest = (color & 0x7FFF);
1379 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1380 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1381 *Dest |= (color & 0x8000);
1387 case CONVERT_CK_4444_ARGB:
1389 /* Move the four Alpha bits... */
1391 WORD *Source = (WORD *) src;
1392 WORD *Dest = (WORD *) dst;
1394 for (x = 0; x < len; x++) {
1395 WORD color = *Source++;
1396 *dst = (color & 0x0FFF) << 4;
1397 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1398 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1399 *Dest |= (color & 0xF000) >> 12;
1405 ERR("Unsupported conversation type %d\n", convert);
1411 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1412 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1414 if (This->Flags & SFLAG_INTEXTURE) {
1415 TRACE("Surface already in texture\n");
1418 if (!(This->Flags & SFLAG_DIRTY)) {
1419 TRACE("surface isn't dirty\n");
1423 This->Flags &= ~SFLAG_DIRTY;
1425 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1426 * These resources are not bound by device size or format restrictions. Because of this,
1427 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1428 * However, these resources can always be created, locked, and copied.
1430 if (This->resource.pool == WINED3DPOOL_SCRATCH)
1432 FIXME("(%p) Operation not supported for scratch textures\n",This);
1433 return WINED3DERR_INVALIDCALL;
1436 if (This->Flags & SFLAG_INPBUFFER) {
1439 if (This->glDescription.level != 0)
1440 FIXME("Surface in texture is only supported for level 0\n");
1441 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1442 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1443 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1444 This->resource.format == WINED3DFMT_DXT5)
1445 FIXME("Format %d not supported\n", This->resource.format);
1448 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1449 vcheckGLcall("glGetIntegerv");
1450 glReadBuffer(GL_BACK);
1451 vcheckGLcall("glReadBuffer");
1453 glCopyTexImage2D(This->glDescription.target,
1454 This->glDescription.level,
1455 This->glDescription.glFormatInternal,
1458 This->currentDesc.Width,
1459 This->currentDesc.Height,
1462 checkGLcall("glCopyTexImage2D");
1463 glReadBuffer(prevRead);
1464 vcheckGLcall("glReadBuffer");
1465 TRACE("Updating target %d\n", This->glDescription.target);
1466 This->Flags |= SFLAG_INTEXTURE;
1472 /* TODO: Compressed non-power 2 support */
1474 if (This->resource.format == WINED3DFMT_DXT1 ||
1475 This->resource.format == WINED3DFMT_DXT2 ||
1476 This->resource.format == WINED3DFMT_DXT3 ||
1477 This->resource.format == WINED3DFMT_DXT4 ||
1478 This->resource.format == WINED3DFMT_DXT5) {
1479 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1480 FIXME("Using DXT1/3/5 without advertized support\n");
1481 } else if (This->resource.allocatedMemory) {
1482 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1483 This->glDescription.target,
1484 This->glDescription.level,
1485 This->glDescription.glFormatInternal,
1486 This->currentDesc.Width,
1487 This->currentDesc.Height,
1489 This->resource.size,
1490 This->resource.allocatedMemory);
1494 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1495 This->glDescription.level,
1496 This->glDescription.glFormatInternal,
1497 This->currentDesc.Width,
1498 This->currentDesc.Height,
1500 This->resource.size,
1501 This->resource.allocatedMemory);
1502 checkGLcall("glCommpressedTexImage2D");
1506 if(!(This->Flags & SFLAG_DONOTFREE)){
1507 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1508 This->resource.allocatedMemory = NULL;
1512 GLenum format, internal, type;
1513 CONVERT_TYPES convert;
1517 d3dfmt_get_conv(This, TRUE /* We need color keying */, &format, &internal, &type, &convert, &bpp);
1519 if((convert != NO_CONVERSION) &&
1520 This->resource.allocatedMemory) {
1521 int width = This->glRect.right - This->glRect.left;
1522 int height = This->glRect.bottom - This->glRect.top;
1525 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
1527 ERR("Out of memory %d, %d!\n", width, height);
1528 return WINED3DERR_OUTOFVIDEOMEMORY;
1531 for(row = This->glRect.top; row < This->glRect.bottom; row++) {
1532 BYTE *cur = This->resource.allocatedMemory + row * This->pow2Width * This->bytesPerPixel;
1533 d3dfmt_convert_surface(cur + This->glRect.left * This->bytesPerPixel,
1534 mem + row * width * bpp,
1539 This->Flags |= SFLAG_CONVERTED;
1541 This->Flags &= ~SFLAG_CONVERTED;
1542 mem = This->resource.allocatedMemory;
1545 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1546 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE) ) {
1549 TRACE("non power of two support\n");
1551 TRACE("(%p) Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n", This,
1552 This->glDescription.target,
1553 This->glDescription.level,
1554 debug_d3dformat(This->resource.format),
1555 This->glDescription.glFormatInternal,
1559 This->glDescription.glFormat,
1560 This->glDescription.glType,
1563 glTexImage2D(This->glDescription.target,
1564 This->glDescription.level,
1565 This->glDescription.glFormatInternal,
1569 This->glDescription.glFormat,
1570 This->glDescription.glType,
1573 checkGLcall("glTexImage2D");
1574 if (This->resource.allocatedMemory != NULL) {
1575 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1576 /* And map the non-power two data into the top left corner */
1578 This->glDescription.target,
1579 This->glDescription.level,
1582 This->currentDesc.Width,
1583 This->currentDesc.Height,
1584 This->glDescription.glFormat,
1585 This->glDescription.glType,
1586 This->resource.allocatedMemory
1588 checkGLcall("glTexSubImage2D");
1594 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%ld, h=%ld,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1595 This->glDescription.target,
1596 This->glDescription.level,
1597 debug_d3dformat(This->resource.format),
1598 This->glDescription.glFormatInternal,
1599 This->glRect.right - This->glRect.left,
1600 This->glRect.bottom - This->glRect.top,
1602 This->glDescription.glFormat,
1603 This->glDescription.glType,
1608 /* OK, create the texture */
1609 glTexImage2D(This->glDescription.target,
1610 This->glDescription.level,
1612 This->glRect.right - This->glRect.left,
1613 This->glRect.bottom - This->glRect.top,
1619 checkGLcall("glTexImage2D");
1623 if(mem != This->resource.allocatedMemory)
1624 HeapFree(GetProcessHeap(), 0, mem);
1628 static unsigned int gen = 0;
1631 if ((gen % 10) == 0) {
1632 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1633 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1636 * debugging crash code
1644 if(!(This->Flags & SFLAG_DONOTFREE)){
1645 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1646 This->resource.allocatedMemory = NULL;
1656 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1659 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1660 char *allocatedMemory;
1662 IWineD3DSwapChain *swapChain = NULL;
1667 Textures my not be stored in ->allocatedgMemory and a GlTexture
1668 so we should lock the surface before saving a snapshot, or at least check that
1670 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1671 by calling GetTexImage and in compressed form by calling
1672 GetCompressedTexImageARB. Queried compressed images can be saved and
1673 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1674 texture images do not need to be processed by the GL and should
1675 significantly improve texture loading performance relative to uncompressed
1678 /* Setup the width and height to be the internal texture width and height. */
1679 width = This->pow2Width;
1680 height = This->pow2Height;
1681 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1682 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1684 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1685 /* we don't want to interfere with the back buffer so read the data into a temporary texture and then save the data out of the temporary texture */
1688 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1689 glEnable(GL_TEXTURE_2D);
1691 glGenTextures(1, &tmpTexture);
1692 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1694 glTexImage2D(GL_TEXTURE_2D,
1701 GL_UNSIGNED_INT_8_8_8_8_REV,
1704 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1705 vcheckGLcall("glGetIntegerv");
1706 glReadBuffer(GL_BACK);
1707 vcheckGLcall("glReadBuffer");
1708 glCopyTexImage2D(GL_TEXTURE_2D,
1717 checkGLcall("glCopyTexImage2D");
1718 glReadBuffer(prevRead);
1721 } else { /* bind the real texture */
1722 IWineD3DSurface_PreLoad(iface);
1724 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1726 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1727 glGetTexImage(GL_TEXTURE_2D,
1728 This->glDescription.level,
1730 GL_UNSIGNED_INT_8_8_8_8_REV,
1732 checkGLcall("glTexImage2D");
1734 glBindTexture(GL_TEXTURE_2D, 0);
1735 glDeleteTextures(1, &tmpTexture);
1739 f = fopen(filename, "w+");
1741 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1742 return WINED3DERR_INVALIDCALL;
1744 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1745 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1760 fwrite(&width,2,1,f);
1762 fwrite(&height,2,1,f);
1767 /* if the data is upside down if we've fetched it from a back buffer, so it needs flipping again to make it the correct way up*/
1769 textureRow = allocatedMemory + (width * (height - 1) *4);
1771 textureRow = allocatedMemory;
1772 for (y = 0 ; y < height; y++) {
1773 for (i = 0; i < width; i++) {
1774 color = *((DWORD*)textureRow);
1775 fputc((color >> 16) & 0xFF, f); /* B */
1776 fputc((color >> 8) & 0xFF, f); /* G */
1777 fputc((color >> 0) & 0xFF, f); /* R */
1778 fputc((color >> 24) & 0xFF, f); /* A */
1781 /* take two rows of the pointer to the texture memory */
1783 (textureRow-= width << 3);
1786 TRACE("Closing file\n");
1790 IWineD3DSwapChain_Release(swapChain);
1792 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1796 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1797 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1798 This->Flags &= ~SFLAG_DIRTY;
1799 This->dirtyRect.left = This->currentDesc.Width;
1800 This->dirtyRect.top = This->currentDesc.Height;
1801 This->dirtyRect.right = 0;
1802 This->dirtyRect.bottom = 0;
1803 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1804 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1809 * Slightly inefficient way to handle multiple dirty rects but it works :)
1811 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1812 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1813 IWineD3DBaseTexture *baseTexture = NULL;
1814 This->Flags |= SFLAG_DIRTY;
1815 if (NULL != pDirtyRect) {
1816 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1817 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1818 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1819 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1821 This->dirtyRect.left = 0;
1822 This->dirtyRect.top = 0;
1823 This->dirtyRect.right = This->currentDesc.Width;
1824 This->dirtyRect.bottom = This->currentDesc.Height;
1826 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
1827 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1828 /* if the container is a basetexture then mark it dirty. */
1829 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1830 TRACE("Passing to conatiner\n");
1831 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1832 IWineD3DBaseTexture_Release(baseTexture);
1837 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1838 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1840 TRACE("This %p, container %p\n", This, container);
1842 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1844 TRACE("Setting container to %p from %p\n", container, This->container);
1845 This->container = container;
1850 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1851 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1853 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1854 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1855 return WINED3DERR_INVALIDCALL;
1858 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1859 if (format == WINED3DFMT_UNKNOWN) {
1860 This->resource.size = 0;
1861 } else if (format == WINED3DFMT_DXT1) {
1862 /* DXT1 is half byte per pixel */
1863 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1865 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1866 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1867 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1869 This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1873 /* Setup some glformat defaults */
1874 if (format != WINED3DFMT_UNKNOWN) {
1875 This->glDescription.glFormat = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1876 This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1877 This->glDescription.glType = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1879 This->glDescription.glFormat = 0;
1880 This->glDescription.glFormatInternal = 0;
1881 This->glDescription.glType = 0;
1884 if (format != WINED3DFMT_UNKNOWN) {
1885 This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1886 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1888 This->bytesPerPixel = 0;
1892 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
1894 This->resource.format = format;
1896 TRACE("(%p) : Size %d, pow2Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This, This->resource.size, This->pow2Size, This->bytesPerPixel, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType);
1901 /* TODO: replace this function with context management routines */
1902 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1903 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1906 This->Flags |= SFLAG_INPBUFFER;
1908 This->Flags &= ~SFLAG_INPBUFFER;
1912 This->Flags |= SFLAG_INTEXTURE;
1914 This->Flags &= ~SFLAG_INTEXTURE;
1920 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
1921 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1922 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
1923 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
1925 /* Flipping is only supported on RenderTargets */
1926 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
1929 /* DDraw sets this for the X11 surfaces, so don't confuse the user
1930 * FIXME("(%p) Target override is not supported by now\n", This);
1931 * Additionally, it isn't really possible to support triple-buffering
1932 * properly on opengl at all
1936 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
1937 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
1940 /* Not called from the VTable */
1941 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
1943 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1944 IWineD3DSwapChainImpl *swapchain = NULL;
1945 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
1948 TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
1950 /* Get the swapchain. One of the surfaces has to be a primary surface */
1951 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
1952 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1954 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
1955 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1956 else return WINED3DERR_INVALIDCALL;
1962 rect.x1 = DestRect->left;
1963 rect.y1 = DestRect->top;
1964 rect.x2 = DestRect->right;
1965 rect.y2 = DestRect->bottom;
1969 rect.x2 = This->currentDesc.Width;
1970 rect.y2 = This->currentDesc.Height;
1973 /* Half-life does a Blt from the back buffer to the front buffer,
1974 * Full surface size, no flags... Use present instead
1978 /* First, check if we can do a Flip */
1980 /* Check rects - IWineD3DDevice_Present doesn't handle them */
1982 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
1983 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
1990 /* Check the Destination rect and the surface sizes */
1992 (rect.x1 == 0) && (rect.y1 == 0) &&
1993 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
1994 (This->currentDesc.Width == Src->currentDesc.Width) &&
1995 (This->currentDesc.Height == Src->currentDesc.Height)) {
1996 /* These flags are unimportant for the flag check, remove them */
1998 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
1999 if( ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer) ) {
2001 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2003 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2004 * take very long, while a flip is fast.
2005 * This applies to Half-Life, which does such Blts every time it finished
2006 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2007 * menu. This is also used by all apps when they do windowed rendering
2009 * The problem is that flipping is not really the same as copying. After a
2010 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2011 * untouched. Therefore it's necessary to override the swap effect
2012 * and to set it back after the flip.
2015 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2017 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2018 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2019 NULL, NULL, 0, NULL);
2021 swapchain->presentParms.SwapEffect = orig_swap;
2028 /* Blt from texture to rendertarget? */
2029 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2030 ((IWineD3DSurface *) This == swapchain->backBuffer) )
2032 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2033 ( (IWineD3DSurface *) Src != swapchain->backBuffer) ) ) {
2034 float glTexCoord[4];
2036 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2040 RECT SourceRectangle;
2043 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2046 SourceRectangle.left = SrcRect->left;
2047 SourceRectangle.right = SrcRect->right;
2048 SourceRectangle.top = SrcRect->top;
2049 SourceRectangle.bottom = SrcRect->bottom;
2051 SourceRectangle.left = 0;
2052 SourceRectangle.right = Src->currentDesc.Width;
2053 SourceRectangle.top = 0;
2054 SourceRectangle.bottom = Src->currentDesc.Height;
2057 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2058 /* Fall back to software */
2059 WARN("(%p) Source texture area (%ld,%ld)-(%ld,%ld) is too big\n", Src,
2060 SourceRectangle.left, SourceRectangle.top,
2061 SourceRectangle.right, SourceRectangle.bottom);
2062 return WINED3DERR_INVALIDCALL;
2065 /* Color keying: Check if we have to do a color keyed blt,
2066 * and if not check if a color key is activated.
2068 oldCKey = Src->CKeyFlags;
2069 if(!(Flags & DDBLT_KEYSRC) &&
2070 Src->CKeyFlags & DDSD_CKSRCBLT) {
2071 /* Ok, the surface has a color key, but we shall not use it -
2072 * Deactivate it for now and dirtify the surface to reload it
2074 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2075 Src->Flags |= SFLAG_DIRTY;
2078 /* Now load the surface */
2079 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2083 /* Save all the old stuff until we have a proper opengl state manager */
2084 oldLight = glIsEnabled(GL_LIGHTING);
2085 oldFog = glIsEnabled(GL_FOG);
2086 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2087 oldBlend = glIsEnabled(GL_BLEND);
2088 oldCull = glIsEnabled(GL_CULL_FACE);
2089 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2090 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2092 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2093 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2094 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2095 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2097 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2098 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2099 TRACE("Drawing to front buffer\n");
2100 glDrawBuffer(GL_FRONT);
2101 checkGLcall("glDrawBuffer GL_FRONT");
2104 /* Unbind the old texture */
2105 glBindTexture(GL_TEXTURE_2D, 0);
2107 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2108 /* We use texture unit 0 for blts */
2109 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2110 checkGLcall("glActiveTextureARB");
2112 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2115 /* Disable some fancy graphics effects */
2116 glDisable(GL_LIGHTING);
2117 checkGLcall("glDisable GL_LIGHTING");
2118 glDisable(GL_DEPTH_TEST);
2119 checkGLcall("glDisable GL_DEPTH_TEST");
2121 checkGLcall("glDisable GL_FOG");
2122 glDisable(GL_BLEND);
2123 checkGLcall("glDisable GL_BLEND");
2124 glDisable(GL_CULL_FACE);
2125 checkGLcall("glDisable GL_CULL_FACE");
2126 glDisable(GL_STENCIL_TEST);
2127 checkGLcall("glDisable GL_STENCIL_TEST");
2129 /* Ok, we need 2d textures, but not 1D or 3D */
2130 glDisable(GL_TEXTURE_1D);
2131 checkGLcall("glDisable GL_TEXTURE_1D");
2132 glEnable(GL_TEXTURE_2D);
2133 checkGLcall("glEnable GL_TEXTURE_2D");
2134 glDisable(GL_TEXTURE_3D);
2135 checkGLcall("glDisable GL_TEXTURE_3D");
2137 /* Bind the texture */
2138 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2139 checkGLcall("glBindTexture");
2141 glEnable(GL_SCISSOR_TEST);
2143 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2145 /* No filtering for blts */
2146 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2148 checkGLcall("glTexParameteri");
2149 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2151 checkGLcall("glTexParameteri");
2152 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2153 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2154 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2155 checkGLcall("glTexEnvi");
2157 /* This is for color keying */
2158 if(Flags & DDBLT_KEYSRC) {
2159 glEnable(GL_ALPHA_TEST);
2160 checkGLcall("glEnable GL_ALPHA_TEST");
2161 glAlphaFunc(GL_NOTEQUAL, 0.0);
2162 checkGLcall("glAlphaFunc\n");
2164 glDisable(GL_ALPHA_TEST);
2165 checkGLcall("glDisable GL_ALPHA_TEST");
2168 /* Draw a textured quad
2170 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2174 glColor3d(1.0f, 1.0f, 1.0f);
2175 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2180 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2181 glVertex3f(rect.x1, rect.y2, 0.0);
2183 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2188 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2193 checkGLcall("glEnd");
2195 /* Unbind the texture */
2196 glBindTexture(GL_TEXTURE_2D, 0);
2197 checkGLcall("glEnable glBindTexture");
2199 /* Restore the old settings */
2201 glEnable(GL_LIGHTING);
2202 checkGLcall("glEnable GL_LIGHTING");
2206 checkGLcall("glEnable GL_FOG");
2209 glEnable(GL_DEPTH_TEST);
2210 checkGLcall("glEnable GL_DEPTH_TEST");
2214 checkGLcall("glEnable GL_BLEND");
2217 glEnable(GL_CULL_FACE);
2218 checkGLcall("glEnable GL_CULL_FACE");
2221 glEnable(GL_STENCIL_TEST);
2222 checkGLcall("glEnable GL_STENCIL_TEST");
2225 glDisable(GL_ALPHA_TEST);
2226 checkGLcall("glDisable GL_ALPHA_TEST");
2228 glEnable(GL_ALPHA_TEST);
2229 checkGLcall("glEnable GL_ALPHA_TEST");
2232 glAlphaFunc(alphafunc, alpharef);
2233 checkGLcall("glAlphaFunc\n");
2235 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2236 glDrawBuffer(oldDraw);
2239 /* Restore the color key */
2240 if(oldCKey != Src->CKeyFlags) {
2241 Src->CKeyFlags = oldCKey;
2242 Src->Flags |= SFLAG_DIRTY;
2247 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2248 This->Flags |= SFLAG_GLDIRTY;
2254 /* Blt from rendertarget to texture? */
2255 if( (SrcSurface == swapchain->frontBuffer) ||
2256 (SrcSurface == swapchain->backBuffer) ) {
2257 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2258 ( (IWineD3DSurface *) This != swapchain->backBuffer) ) {
2263 TRACE("Blt from rendertarget to texture\n");
2265 /* Call preload for the surface to make sure it isn't dirty */
2266 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2269 srect.x1 = SrcRect->left;
2270 srect.y1 = SrcRect->top;
2271 srect.x2 = SrcRect->right;
2272 srect.y2 = SrcRect->bottom;
2276 srect.x2 = Src->currentDesc.Width;
2277 srect.y2 = Src->currentDesc.Height;
2282 /* Bind the target texture */
2283 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2284 checkGLcall("glBindTexture");
2285 if(SrcSurface == swapchain->backBuffer) {
2286 glReadBuffer(GL_BACK);
2288 glReadBuffer(GL_FRONT);
2290 checkGLcall("glReadBuffer");
2292 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2293 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2295 /* I have to process this row by row to swap the image,
2296 * otherwise it would be upside down, so streching in y direction
2297 * doesn't cost extra time
2299 * However, streching in x direction can be avoided if not necessary
2301 for(row = rect.y1; row < rect.y2; row++) {
2302 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2303 /* Well, that stuff works, but it's very slow.
2304 * find a better way instead
2307 for(col = rect.x1; col < rect.x2; col++) {
2308 glCopyTexSubImage2D(GL_TEXTURE_2D,
2310 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2311 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2315 glCopyTexSubImage2D(GL_TEXTURE_2D,
2317 rect.x1, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2318 srect.x1, Src->currentDesc.Height - srect.y2 + row * yrel,
2323 vcheckGLcall("glCopyTexSubImage2D");
2326 if(!(This->Flags & SFLAG_DONOTFREE)) {
2327 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2328 This->resource.allocatedMemory = NULL;
2330 This->Flags |= SFLAG_GLDIRTY;
2338 if (Flags & DDBLT_COLORFILL) {
2339 /* This is easy to handle for the D3D Device... */
2341 IWineD3DSwapChainImpl *implSwapChain;
2344 TRACE("Colorfill\n");
2346 /* The color as given in the Blt function is in the format of the frame-buffer...
2347 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2349 if (This->resource.format == WINED3DFMT_P8) {
2350 if (This->palette) {
2351 color = ((0xFF000000) |
2352 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2353 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2354 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2359 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2360 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2363 color = ((0xFF000000) |
2364 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2365 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2366 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2369 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2370 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2371 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2373 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2374 color = DDBltFx->u5.dwFillColor;
2377 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2378 return WINED3DERR_INVALIDCALL;
2381 /* Are we drawing to the Front buffer or the back buffer? */
2382 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
2383 vcheckGLcall("glIntegerv");
2385 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2386 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2387 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2388 if(This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer) {
2389 glDrawBuffer(GL_BACK);
2390 checkGLcall("glDrawBuffer(GL_BACK)");
2392 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2393 glDrawBuffer(GL_FRONT);
2394 checkGLcall("glDrawBuffer(GL_FRONT)");
2397 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2398 return WINED3DERR_INVALIDCALL;
2401 TRACE("(%p) executing Render Target override, color = %lx\n", This, color);
2403 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2404 1 /* Number of rectangles */,
2411 /* Restore the original draw buffer */
2412 glDrawBuffer(prev_draw);
2413 vcheckGLcall("glDrawBuffer");
2418 /* Default: Fall back to the generic blt */
2419 return WINED3DERR_INVALIDCALL;
2422 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2423 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2424 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2425 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2426 TRACE("(%p): Usage is %08lx\n", This, This->resource.usage);
2428 /* Special cases for RenderTargets */
2429 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2430 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2431 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2434 /* For the rest call the X11 surface implementation.
2435 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2436 * other Blts are rather rare
2438 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2441 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2442 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2443 TRACE("(%p)->(%lx)\n", This, Flags);
2448 case DDGBS_ISBLTDONE:
2452 return DDERR_INVALIDPARAMS;
2456 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2457 /* XXX: DDERR_INVALIDSURFACETYPE */
2459 TRACE("(%p)->(%08lx)\n",iface,Flags);
2462 case DDGFS_ISFLIPDONE:
2466 return DDERR_INVALIDPARAMS;
2470 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2471 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2472 TRACE("(%p)\n", This);
2474 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2477 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2478 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2479 TRACE("(%p)\n", This);
2481 /* So far we don't lose anything :) */
2482 This->Flags &= ~SFLAG_LOST;
2486 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2487 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2488 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2489 TRACE("(%p)->(%ld, %ld, %p, %p, %08lx\n", iface, dstx, dsty, Source, rsrc, trans);
2491 /* Special cases for RenderTargets */
2492 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2493 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2495 RECT SrcRect, DstRect;
2498 SrcRect.left = rsrc->left;
2499 SrcRect.top= rsrc->top;
2500 SrcRect.bottom = rsrc->bottom;
2501 SrcRect.right = rsrc->right;
2505 SrcRect.right = srcImpl->currentDesc.Width;
2506 SrcRect.bottom = srcImpl->currentDesc.Height;
2509 DstRect.left = dstx;
2511 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2512 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2514 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, 0, NULL) == WINED3D_OK) return WINED3D_OK;
2518 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2521 HRESULT WINAPI IWineD3DSurfaceImpl_SetPixelFormat(IWineD3DSurface *iface, WINED3DFORMAT Format, BYTE *Surface, DWORD Size) {
2522 FIXME("This is unimplemented for now(d3d7 merge)\n");
2523 return WINED3DERR_INVALIDCALL;
2526 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2527 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2528 TRACE("(%p)->(%p)\n", This, Pal);
2530 *Pal = (IWineD3DPalette *) This->palette;
2534 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2535 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2537 IWineD3DPaletteImpl *pal = This->palette;
2539 TRACE("(%p)\n", This);
2541 if(This->resource.format == WINED3DFMT_P8 ||
2542 This->resource.format == WINED3DFMT_A8P8)
2544 TRACE("Dirtifying surface\n");
2545 This->Flags |= SFLAG_DIRTY;
2548 if(This->Flags & SFLAG_DIBSECTION) {
2549 TRACE("(%p): Updating the hdc's palette\n", This);
2550 for (n=0; n<256; n++) {
2552 col[n].rgbRed = pal->palents[n].peRed;
2553 col[n].rgbGreen = pal->palents[n].peGreen;
2554 col[n].rgbBlue = pal->palents[n].peBlue;
2556 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2557 /* Use the default device palette */
2558 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2559 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2560 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2562 col[n].rgbReserved = 0;
2564 SetDIBColorTable(This->hDC, 0, 256, col);
2570 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2571 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2572 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2573 TRACE("(%p)->(%p)\n", This, Pal);
2575 if(This->palette != NULL)
2576 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2577 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2579 if(PalImpl != NULL) {
2580 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2581 /* Set the device's main palette if the palette
2582 * wasn't a primary palette before
2584 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2585 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2588 for(i=0; i < 256; i++) {
2589 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2593 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2596 This->palette = PalImpl;
2598 return IWineD3DSurface_RealizePalette(iface);
2601 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2602 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2603 BOOL dirtify = FALSE;
2604 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
2606 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2607 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
2608 return DDERR_INVALIDPARAMS;
2611 /* Dirtify the surface, but only if a key was changed */
2613 switch (Flags & ~DDCKEY_COLORSPACE) {
2614 case DDCKEY_DESTBLT:
2615 if(!(This->CKeyFlags & DDSD_CKDESTBLT)) {
2618 dirtify = memcmp(&This->DestBltCKey, CKey, sizeof(*CKey) ) != 0;
2620 This->DestBltCKey = *CKey;
2621 This->CKeyFlags |= DDSD_CKDESTBLT;
2624 case DDCKEY_DESTOVERLAY:
2625 if(!(This->CKeyFlags & DDSD_CKDESTOVERLAY)) {
2628 dirtify = memcmp(&This->DestOverlayCKey, CKey, sizeof(*CKey)) != 0;
2630 This->DestOverlayCKey = *CKey;
2631 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2634 case DDCKEY_SRCOVERLAY:
2635 if(!(This->CKeyFlags & DDSD_CKSRCOVERLAY)) {
2638 dirtify = memcmp(&This->SrcOverlayCKey, CKey, sizeof(*CKey)) != 0;
2640 This->SrcOverlayCKey = *CKey;
2641 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2645 if(!(This->CKeyFlags & DDSD_CKSRCBLT)) {
2648 dirtify = memcmp(&This->SrcBltCKey, CKey, sizeof(*CKey)) != 0;
2650 This->SrcBltCKey = *CKey;
2651 This->CKeyFlags |= DDSD_CKSRCBLT;
2656 switch (Flags & ~DDCKEY_COLORSPACE) {
2657 case DDCKEY_DESTBLT:
2658 dirtify = This->CKeyFlags & DDSD_CKDESTBLT;
2659 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2662 case DDCKEY_DESTOVERLAY:
2663 dirtify = This->CKeyFlags & DDSD_CKDESTOVERLAY;
2664 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2667 case DDCKEY_SRCOVERLAY:
2668 dirtify = This->CKeyFlags & DDSD_CKSRCOVERLAY;
2669 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2673 dirtify = This->CKeyFlags & DDSD_CKSRCBLT;
2674 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2680 TRACE("Color key changed, dirtifying surface\n");
2681 This->Flags |= SFLAG_DIRTY;
2687 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2688 /** Check against the maximum texture sizes supported by the video card **/
2689 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2691 TRACE("%p\n", This);
2692 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2693 /* one of three options
2694 1: Do the same as we do with nonpow 2 and scale the texture, (any texture ops would require the texture to be scaled which is potentially slow)
2695 2: Set the texture to the maxium size (bad idea)
2696 3: WARN and return WINED3DERR_NOTAVAILABLE;
2697 4: Create the surface, but allow it to be used only for DirectDraw Blts. Some apps(e.g. Swat 3) create textures with a Height of 16 and a Width > 3000 and blt 16x16 letter areas from them to the render target.
2699 WARN("(%p) Creating an oversized surface\n", This);
2700 This->Flags |= SFLAG_OVERSIZE;
2702 /* This will be initialized on the first blt */
2703 This->glRect.left = 0;
2704 This->glRect.top = 0;
2705 This->glRect.right = 0;
2706 This->glRect.bottom = 0;
2708 /* No oversize, gl rect is the full texture size */
2709 This->Flags &= ~SFLAG_OVERSIZE;
2710 This->glRect.left = 0;
2711 This->glRect.top = 0;
2712 This->glRect.right = This->pow2Width;
2713 This->glRect.bottom = This->pow2Height;
2719 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
2720 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2722 TRACE("(%p)\n", This);
2724 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
2725 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
2726 ie pitch = (width/4) * bytes per block */
2727 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
2728 ret = (This->currentDesc.Width >> 2) << 3;
2729 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
2730 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
2731 ret = (This->currentDesc.Width >> 2) << 4;
2733 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2734 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
2735 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
2737 ret = This->bytesPerPixel * This->pow2Width;
2740 TRACE("(%p) Returning %ld\n", This, ret);
2744 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
2747 IWineD3DSurfaceImpl_QueryInterface,
2748 IWineD3DSurfaceImpl_AddRef,
2749 IWineD3DSurfaceImpl_Release,
2750 /* IWineD3DResource */
2751 IWineD3DSurfaceImpl_GetParent,
2752 IWineD3DSurfaceImpl_GetDevice,
2753 IWineD3DSurfaceImpl_SetPrivateData,
2754 IWineD3DSurfaceImpl_GetPrivateData,
2755 IWineD3DSurfaceImpl_FreePrivateData,
2756 IWineD3DSurfaceImpl_SetPriority,
2757 IWineD3DSurfaceImpl_GetPriority,
2758 IWineD3DSurfaceImpl_PreLoad,
2759 IWineD3DSurfaceImpl_GetType,
2760 /* IWineD3DSurface */
2761 IWineD3DSurfaceImpl_GetContainerParent,
2762 IWineD3DSurfaceImpl_GetContainer,
2763 IWineD3DSurfaceImpl_GetDesc,
2764 IWineD3DSurfaceImpl_LockRect,
2765 IWineD3DSurfaceImpl_UnlockRect,
2766 IWineD3DSurfaceImpl_GetDC,
2767 IWineD3DSurfaceImpl_ReleaseDC,
2768 IWineD3DSurfaceImpl_Flip,
2769 IWineD3DSurfaceImpl_Blt,
2770 IWineD3DSurfaceImpl_GetBltStatus,
2771 IWineD3DSurfaceImpl_GetFlipStatus,
2772 IWineD3DSurfaceImpl_IsLost,
2773 IWineD3DSurfaceImpl_Restore,
2774 IWineD3DSurfaceImpl_BltFast,
2775 IWineD3DSurfaceImpl_SetPixelFormat,
2776 IWineD3DSurfaceImpl_GetPalette,
2777 IWineD3DSurfaceImpl_SetPalette,
2778 IWineD3DSurfaceImpl_RealizePalette,
2779 IWineD3DSurfaceImpl_SetColorKey,
2780 IWineD3DSurfaceImpl_GetPitch,
2782 IWineD3DSurfaceImpl_CleanDirtyRect,
2783 IWineD3DSurfaceImpl_AddDirtyRect,
2784 IWineD3DSurfaceImpl_LoadTexture,
2785 IWineD3DSurfaceImpl_SaveSnapshot,
2786 IWineD3DSurfaceImpl_SetContainer,
2787 IWineD3DSurfaceImpl_SetPBufferState,
2788 IWineD3DSurfaceImpl_SetGlTextureDesc,
2789 IWineD3DSurfaceImpl_GetGlDesc,
2790 IWineD3DSurfaceImpl_GetData,
2791 IWineD3DSurfaceImpl_SetFormat,
2792 IWineD3DSurfaceImpl_PrivateSetup