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 */
290 BOOL backbuf = FALSE;
292 /* fixme: should we really lock as such? */
293 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
294 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
295 FIXME("Warning: Surface is in texture memory or pbuffer\n");
296 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
299 if (!(This->Flags & SFLAG_LOCKABLE)) {
300 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
301 texture regions, and since the destination is an unlockable region we need
303 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
304 /*return WINED3DERR_INVALIDCALL; */
307 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
308 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
310 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
311 if(swapchain != NULL) {
313 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
314 if(iface == swapchain->backBuffer[i]) {
321 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
322 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
323 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
324 } else if (iface == myDevice->renderTarget) {
325 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
326 } else if (iface == myDevice->depthStencilBuffer) {
327 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
330 if (NULL != swapchain) {
331 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
336 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
339 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
342 pLockedRect->pBits = This->resource.allocatedMemory;
343 This->lockedRect.left = 0;
344 This->lockedRect.top = 0;
345 This->lockedRect.right = This->currentDesc.Width;
346 This->lockedRect.bottom = This->currentDesc.Height;
347 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);
349 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
351 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
352 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
354 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
356 This->lockedRect.left = pRect->left;
357 This->lockedRect.top = pRect->top;
358 This->lockedRect.right = pRect->right;
359 This->lockedRect.bottom = pRect->bottom;
362 if (This->Flags & SFLAG_NONPOW2) {
363 TRACE("Locking non-power 2 texture\n");
366 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
367 /* classic surface TODO: non 2d surfaces?
368 These resources may be POOL_SYSTEMMEM, so they must not access the device */
369 TRACE("locking an ordinarary surface\n");
370 /* Check to see if memory has already been allocated from the surface*/
371 if ((NULL == This->resource.allocatedMemory) ||
372 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
373 /* Non-system memory surfaces */
375 This->Flags &= ~SFLAG_GLDIRTY;
377 /*Surface has no memory currently allocated to it!*/
378 TRACE("(%p) Locking rect\n" , This);
379 if(!This->resource.allocatedMemory) {
380 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
382 if (0 != This->glDescription.textureName) {
383 /* Now I have to copy thing bits back */
384 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
385 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
388 /* Make sure that the texture is loaded */
389 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
391 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);
393 if (This->resource.format == WINED3DFMT_DXT1 ||
394 This->resource.format == WINED3DFMT_DXT2 ||
395 This->resource.format == WINED3DFMT_DXT3 ||
396 This->resource.format == WINED3DFMT_DXT4 ||
397 This->resource.format == WINED3DFMT_DXT5) {
398 TRACE("Locking a compressed texture\n");
399 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
400 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
401 This->glDescription.level,
402 This->resource.allocatedMemory);
405 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
408 glGetTexImage(This->glDescription.target,
409 This->glDescription.level,
410 This->glDescription.glFormat,
411 This->glDescription.glType,
412 This->resource.allocatedMemory);
413 vcheckGLcall("glGetTexImage");
414 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
415 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
416 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
417 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
421 instead of boxing the texture :
422 |<-texture width ->| -->pow2width| /\
423 |111111111111111111| | |
424 |222 Texture 222222| boxed empty | texture height
425 |3333 Data 33333333| | |
426 |444444444444444444| | \/
427 ----------------------------------- |
428 | boxed empty | boxed empty | pow2height
430 -----------------------------------
433 were repacking the data to the expected texture width
435 |<-texture width ->| -->pow2width| /\
436 |111111111111111111222222222222222| |
437 |222333333333333333333444444444444| texture height
443 -----------------------------------
447 |<-texture width ->| /\
449 |222222222222222222|texture height
451 |444444444444444444| \/
454 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.
456 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.
458 if (This->Flags & SFLAG_NONPOW2) {
460 int pitcha = 0, pitchb = 0;
462 pitcha = This->bytesPerPixel * This->currentDesc.Width;
463 pitchb = This->bytesPerPixel * This->pow2Width;
464 datab = dataa = This->resource.allocatedMemory;
465 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
466 for (y = 1 ; y < This->currentDesc.Height; y++) {
467 dataa += pitcha; /* skip the first row */
469 memcpy(dataa, datab, pitcha);
476 } else { /* Nothing to do */
477 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
481 pLockedRect->pBits = This->resource.allocatedMemory;
483 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
484 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
486 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
490 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
491 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
494 BOOL notInContext = FALSE;
495 IWineD3DSwapChainImpl *targetSwapChain = NULL;
501 * for render->surface copy begin to begin of allocatedMemory
502 * unlock can be more easy
505 TRACE("locking a render target\n");
507 if (This->resource.allocatedMemory == NULL)
508 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
510 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
511 pLockedRect->pBits = This->resource.allocatedMemory;
514 vcheckGLcall("glFlush");
515 glGetIntegerv(GL_READ_BUFFER, &prev_read);
516 vcheckGLcall("glIntegerv");
517 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
518 vcheckGLcall("glIntegerv");
520 /* Here's what we have to do:
521 See if the swapchain has the same context as the renderTarget or the surface is the render target.
522 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
523 and use the front back buffer as required.
524 if not, we need to switch contexts and then switchback at the end.
526 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
527 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
529 /* 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! */
530 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
531 if (iface == swapchain->frontBuffer) {
532 TRACE("locking front\n");
533 glReadBuffer(GL_FRONT);
535 else if (iface == myDevice->renderTarget || backbuf) {
536 TRACE("locking back buffer\n");
537 glReadBuffer(GL_BACK);
538 } else if (iface == myDevice->depthStencilBuffer) {
539 FIXME("Stencil Buffer lock unsupported for now\n");
541 FIXME("(%p) Shouldn't have got here!\n", This);
542 glReadBuffer(GL_BACK);
544 } else if (swapchain != NULL) {
545 IWineD3DSwapChainImpl *implSwapChain;
546 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
547 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
548 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
550 glReadBuffer(GL_BACK);
551 } else if (iface == swapchain->frontBuffer) {
552 glReadBuffer(GL_FRONT);
553 } else if (iface == myDevice->depthStencilBuffer) {
554 FIXME("Stencil Buffer lock unsupported for now\n");
556 FIXME("Should have got here!\n");
557 glReadBuffer(GL_BACK);
560 /* We need to switch contexts to be able to read the buffer!!! */
561 FIXME("The buffer requested isn't in the current openGL context\n");
563 /* TODO: check the contexts, to see if were shared with the current context */
565 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
567 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
568 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
570 /** the depth stencil in openGL has a format of GL_FLOAT
571 * which should be good for WINED3DFMT_D16_LOCKABLE
573 * it is unclear what format the stencil buffer is in except.
574 * 'Each index is converted to fixed point...
575 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
576 * mappings in the table GL_PIXEL_MAP_S_TO_S.
577 * glReadPixels(This->lockedRect.left,
578 * This->lockedRect.bottom - j - 1,
579 * This->lockedRect.right - This->lockedRect.left,
581 * GL_DEPTH_COMPONENT,
583 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
584 *****************************************/
585 if (!notInContext) { /* Only read the buffer if it's in the current context */
589 /* 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,
590 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
591 * run ten times faster!
592 * ************************************/
593 BOOL ati_performance_hack = FALSE;
594 ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
596 if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
597 This->lockedRect.right == This->currentDesc.Width
598 && This->lockedRect.bottom == This->currentDesc.Height)) {
599 BYTE *row, *top, *bottom;
603 This->currentDesc.Width,
604 This->currentDesc.Height,
605 This->glDescription.glFormat,
606 This->glDescription.glType,
607 (char *)pLockedRect->pBits);
609 /* glReadPixels returns the image upside down, and there is no way to prevent this.
610 Flip the lines in software*/
611 row = HeapAlloc(GetProcessHeap(), 0, pLockedRect->Pitch);
613 ERR("Out of memory\n");
614 return E_OUTOFMEMORY;
616 top = This->resource.allocatedMemory;
617 bottom = ( (BYTE *) This->resource.allocatedMemory) + pLockedRect->Pitch * ( This->currentDesc.Height - 1);
618 for(i = 0; i < This->currentDesc.Height / 2; i++) {
619 memcpy(row, top, pLockedRect->Pitch);
620 memcpy(top, bottom, pLockedRect->Pitch);
621 memcpy(bottom, row, pLockedRect->Pitch);
622 top += pLockedRect->Pitch;
623 bottom -= pLockedRect->Pitch;
625 HeapFree(GetProcessHeap(), 0, row);
627 This->Flags &= ~SFLAG_GLDIRTY;
629 } else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
631 This->lockedRect.top,
632 This->currentDesc.Width,
633 This->currentDesc.Height,
634 This->glDescription.glFormat,
635 This->glDescription.glType,
636 (char *)pLockedRect->pBits);
639 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
640 glReadPixels(This->lockedRect.left,
641 This->lockedRect.bottom - j - 1,
642 This->lockedRect.right - This->lockedRect.left,
644 This->glDescription.glFormat,
645 This->glDescription.glType,
646 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
651 vcheckGLcall("glReadPixels");
652 TRACE("Resetting buffer\n");
654 glReadBuffer(prev_read);
655 vcheckGLcall("glReadBuffer");
659 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
662 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
665 glReadPixels(This->lockedRect.left,
666 This->lockedRect.bottom - j - 1,
667 This->lockedRect.right - This->lockedRect.left,
669 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
676 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
679 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
682 IWineD3DBaseTexture *pBaseTexture;
685 * as seen in msdn docs
687 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
689 /** Dirtify Container if needed */
690 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
691 TRACE("Making container dirty\n");
692 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
693 IWineD3DBaseTexture_Release(pBaseTexture);
695 TRACE("Surface is standalone, no need to dirty the container\n");
699 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
701 This->Flags |= SFLAG_LOCKED;
705 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
707 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
708 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
709 const char *buffername = "";
710 IWineD3DSwapChainImpl *swapchain = NULL;
711 BOOL backbuf = FALSE;
713 if (!(This->Flags & SFLAG_LOCKED)) {
714 WARN("trying to Unlock an unlocked surf@%p\n", This);
715 return WINED3DERR_INVALIDCALL;
718 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
719 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
723 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
724 if(iface == swapchain->backBuffer[i]) {
732 buffername = "backBuffer";
733 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
734 buffername = "frontBuffer";
735 } else if (iface == myDevice->depthStencilBuffer) {
736 buffername = "depthStencilBuffer";
737 } else if (iface == myDevice->renderTarget) {
738 buffername = "renderTarget";
742 if (swapchain != NULL) {
743 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
746 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
748 if (!(This->Flags & SFLAG_DIRTY)) {
749 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
753 if (0 == This->resource.usage) { /* classic surface */
756 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
758 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
760 /****************************
761 * TODO: Render targets are 'special' and
762 * ?some? locking needs to be passed onto the context manager
763 * so that it becomes possible to use auxiliary buffers, pbuffers
764 * render-to-texture, shared, cached contexts etc...
765 * ****************************/
766 IWineD3DSwapChainImpl *implSwapChain;
767 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
769 if (backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
772 GLint prev_depth_test;
773 GLint prev_rasterpos[4];
775 /* Some drivers(radeon dri, others?) don't like exceptions during
776 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
777 * after ReleaseDC. Reading it will cause an exception, which x11drv will
778 * catch to put the dib section in InSync mode, which leads to a crash
779 * and a blocked x server on my radeon card.
781 * The following lines read the dib section so it is put in inSync mode
782 * before glDrawPixels is called and the crash is prevented. There won't
783 * be any interfering gdi accesses, because UnlockRect is called from
784 * ReleaseDC, and the app won't use the dc any more afterwards.
786 if(This->Flags & SFLAG_DIBSECTION) {
788 read = This->resource.allocatedMemory[0];
794 vcheckGLcall("glFlush");
795 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
796 vcheckGLcall("glIntegerv");
797 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
798 vcheckGLcall("glIntegerv");
799 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
800 vcheckGLcall("glIntegerv");
801 glPixelZoom(1.0, -1.0);
802 vcheckGLcall("glPixelZoom");
803 prev_depth_test = glIsEnabled(GL_DEPTH_TEST);
805 /* glDrawPixels transforms the raster position as though it was a vertex -
806 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
807 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
808 d3ddevice_set_ortho(This->resource.wineD3DDevice);
810 if (iface == implSwapChain->frontBuffer) {
811 glDrawBuffer(GL_FRONT);
812 checkGLcall("glDrawBuffer GL_FRONT");
813 } else if (backbuf || iface == myDevice->renderTarget) {
814 glDrawBuffer(GL_BACK);
815 checkGLcall("glDrawBuffer GL_BACK");
818 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
819 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
820 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
822 /* And back buffers are not blended */
824 glDisable(GL_DEPTH_TEST);
826 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
827 vcheckGLcall("glRasterPos2f");
829 switch (This->resource.format) {
830 case WINED3DFMT_X4R4G4B4:
833 unsigned short *data;
834 data = (unsigned short *)This->resource.allocatedMemory;
835 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
842 case WINED3DFMT_A4R4G4B4:
844 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
845 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
846 vcheckGLcall("glDrawPixels");
849 case WINED3DFMT_R5G6B5:
851 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
852 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
853 vcheckGLcall("glDrawPixels");
856 case WINED3DFMT_X1R5G5B5:
859 unsigned short *data;
860 data = (unsigned short *)This->resource.allocatedMemory;
861 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
868 case WINED3DFMT_A1R5G5B5:
870 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
871 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
872 vcheckGLcall("glDrawPixels");
875 case WINED3DFMT_R8G8B8:
877 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
878 GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
879 vcheckGLcall("glDrawPixels");
882 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
883 could be any random value this fixes the intro move in Pirates! */
887 data = (unsigned int *)This->resource.allocatedMemory;
888 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
895 case WINED3DFMT_A8R8G8B8:
897 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
898 vcheckGLcall("glPixelStorei");
899 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
900 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
901 vcheckGLcall("glDrawPixels");
902 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
903 vcheckGLcall("glPixelStorei");
906 case WINED3DFMT_A2R10G10B10:
908 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
909 vcheckGLcall("glPixelStorei");
910 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
911 GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
912 vcheckGLcall("glDrawPixels");
913 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
914 vcheckGLcall("glPixelStorei");
918 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
921 glPixelZoom(1.0,1.0);
922 vcheckGLcall("glPixelZoom");
923 glDrawBuffer(prev_draw);
924 vcheckGLcall("glDrawBuffer");
925 glRasterPos3iv(&prev_rasterpos[0]);
926 vcheckGLcall("glRasterPos3iv");
927 if(prev_depth_test) glEnable(GL_DEPTH_TEST);
929 /* Reset to previous pack row length / blending state */
930 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
931 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
935 /** restore clean dirty state */
936 IWineD3DSurface_CleanDirtyRect(iface);
939 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
941 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
943 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
945 if (iface == myDevice->depthStencilBuffer) {
946 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
948 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
952 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
956 This->Flags &= ~SFLAG_LOCKED;
957 memset(&This->lockedRect, 0, sizeof(RECT));
961 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
962 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
963 WINED3DLOCKED_RECT lock;
971 TRACE("(%p)->(%p)\n",This,pHDC);
973 /* Give more detailed info for ddraw */
974 if (This->Flags & SFLAG_DCINUSE)
975 return DDERR_DCALREADYCREATED;
977 /* Can't GetDC if the surface is locked */
978 if (This->Flags & SFLAG_LOCKED)
979 return WINED3DERR_INVALIDCALL;
981 memset(&lock, 0, sizeof(lock)); /* To be sure */
983 /* Create a DIB section if there isn't a hdc yet */
985 if(This->Flags & SFLAG_ACTIVELOCK) {
986 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
989 switch (This->bytesPerPixel) {
992 /* Allocate extra space to store the RGB bit masks. */
993 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
997 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1001 /* Allocate extra space for a palette. */
1002 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1003 sizeof(BITMAPINFOHEADER)
1005 * (1 << (This->bytesPerPixel * 8)));
1009 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1010 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1011 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1012 b_info->bmiHeader.biHeight = -This->currentDesc.Height;
1013 /* Use the full pow2 image size(assigned below) because LockRect
1014 * will need it for a full glGetTexImage call
1017 b_info->bmiHeader.biWidth = This->pow2Width;
1018 b_info->bmiHeader.biHeight = -This->pow2Height;
1020 b_info->bmiHeader.biPlanes = 1;
1021 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1023 b_info->bmiHeader.biSizeImage = This->resource.size;
1025 b_info->bmiHeader.biXPelsPerMeter = 0;
1026 b_info->bmiHeader.biYPelsPerMeter = 0;
1027 b_info->bmiHeader.biClrUsed = 0;
1028 b_info->bmiHeader.biClrImportant = 0;
1030 /* Get the bit masks */
1031 masks = (DWORD *) &(b_info->bmiColors);
1032 switch (This->resource.format) {
1033 case WINED3DFMT_R8G8B8:
1034 usage = DIB_RGB_COLORS;
1035 b_info->bmiHeader.biCompression = BI_RGB;
1038 case WINED3DFMT_X1R5G5B5:
1039 case WINED3DFMT_A1R5G5B5:
1040 case WINED3DFMT_A4R4G4B4:
1041 case WINED3DFMT_X4R4G4B4:
1042 case WINED3DFMT_R3G3B2:
1043 case WINED3DFMT_A8R3G3B2:
1044 case WINED3DFMT_A2B10G10R10:
1045 case WINED3DFMT_A8B8G8R8:
1046 case WINED3DFMT_X8B8G8R8:
1047 case WINED3DFMT_A2R10G10B10:
1048 case WINED3DFMT_R5G6B5:
1049 case WINED3DFMT_A16B16G16R16:
1051 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1052 masks[0] = get_bitmask_red(This->resource.format);
1053 masks[1] = get_bitmask_green(This->resource.format);
1054 masks[2] = get_bitmask_blue(This->resource.format);
1058 /* Don't know palette */
1059 b_info->bmiHeader.biCompression = BI_RGB;
1064 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1066 HeapFree(GetProcessHeap(), 0, b_info);
1067 return HRESULT_FROM_WIN32(GetLastError());
1070 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);
1071 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1074 if (!This->dib.DIBsection) {
1075 ERR("CreateDIBSection failed!\n");
1076 return HRESULT_FROM_WIN32(GetLastError());
1078 HeapFree(GetProcessHeap(), 0, b_info);
1080 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1082 /* copy the existing surface to the dib section */
1083 if(This->resource.allocatedMemory) {
1084 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->resource.size);
1085 /* We won't need that any more */
1086 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1088 /* This is to make LockRect read the gl Texture although memory is allocated */
1089 This->Flags |= SFLAG_GLDIRTY;
1092 /* Use the dib section from now on */
1093 This->resource.allocatedMemory = This->dib.bitmap_data;
1095 /* Now allocate a HDC */
1096 This->hDC = CreateCompatibleDC(0);
1097 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1098 TRACE("using wined3d palette %p\n", This->palette);
1099 SelectPalette(This->hDC,
1100 This->palette ? This->palette->hpal : 0,
1103 This->Flags |= SFLAG_DIBSECTION;
1106 /* Lock the surface */
1107 hr = IWineD3DSurface_LockRect(iface,
1112 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1113 /* keep the dib section */
1117 if(This->resource.format == WINED3DFMT_P8 ||
1118 This->resource.format == WINED3DFMT_A8P8) {
1121 PALETTEENTRY ent[256];
1123 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1124 for (n=0; n<256; n++) {
1125 col[n].rgbRed = ent[n].peRed;
1126 col[n].rgbGreen = ent[n].peGreen;
1127 col[n].rgbBlue = ent[n].peBlue;
1128 col[n].rgbReserved = 0;
1131 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1133 for (n=0; n<256; n++) {
1134 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1135 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1136 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1137 col[n].rgbReserved = 0;
1141 SetDIBColorTable(This->hDC, 0, 256, col);
1145 TRACE("returning %p\n",*pHDC);
1146 This->Flags |= SFLAG_DCINUSE;
1151 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1152 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1154 TRACE("(%p)->(%p)\n",This,hDC);
1156 if (!(This->Flags & SFLAG_DCINUSE))
1157 return D3DERR_INVALIDCALL;
1159 /* we locked first, so unlock now */
1160 IWineD3DSurface_UnlockRect(iface);
1162 This->Flags &= ~SFLAG_DCINUSE;
1167 /* ******************************************************
1168 IWineD3DSurface Internal (No mapping to directx api) parts follow
1169 ****************************************************** */
1174 CONVERT_PALETTED_CK,
1178 CONVERT_CK_4444_ARGB,
1183 CONVERT_CK_8888_ARGB,
1187 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp) {
1188 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1190 /* Default values: From the surface */
1191 *format = D3DFmt2GLFmt(This->resource.wineD3DDevice,
1192 This->resource.format);
1193 *internal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice,
1194 This->resource.format);
1195 *type = D3DFmt2GLType(This->resource.wineD3DDevice,
1196 This->resource.format);
1197 *convert = NO_CONVERSION;
1198 *target_bpp = This->bytesPerPixel;
1200 /* Ok, now look if we have to do any conversion */
1201 switch(This->resource.format) {
1206 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active) {
1208 *internal = GL_RGBA;
1209 *type = GL_UNSIGNED_BYTE;
1211 if(colorkey_active) {
1212 *convert = CONVERT_PALETTED;
1214 *convert = CONVERT_PALETTED_CK;
1220 case WINED3DFMT_R3G3B2:
1221 /* **********************
1222 GL_UNSIGNED_BYTE_3_3_2
1223 ********************** */
1224 if (colorkey_active) {
1225 /* This texture format will never be used.. So do not care about color keying
1226 up until the point in time it will be needed :-) */
1227 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1231 case WINED3DFMT_R5G6B5:
1232 if (colorkey_active) {
1233 *convert = CONVERT_CK_565;
1235 *internal = GL_RGBA;
1236 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1240 case WINED3DFMT_R8G8B8:
1241 if (colorkey_active) {
1242 *convert = CONVERT_CK_RGB24;
1244 *internal = GL_RGBA;
1245 *type = GL_UNSIGNED_INT_8_8_8_8;
1250 case WINED3DFMT_X8R8G8B8:
1251 if (colorkey_active) {
1252 *convert = CONVERT_RGB32_888;
1254 *internal = GL_RGBA;
1255 *type = GL_UNSIGNED_INT_8_8_8_8;
1259 /* Not sure if we should do color keying on Alpha-Enabled surfaces */
1260 case WINED3DFMT_A4R4G4B4:
1261 if (colorkey_active)
1263 *convert = CONVERT_CK_4444_ARGB;
1265 *internal = GL_RGBA;
1266 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1270 case WINED3DFMT_A1R5G5B5:
1271 if (colorkey_active)
1273 *convert = CONVERT_CK_1555;
1276 case WINED3DFMT_A8R8G8B8:
1277 if (colorkey_active)
1279 *convert = CONVERT_CK_8888_ARGB;
1281 *internal = GL_RGBA;
1282 *type = GL_UNSIGNED_INT_8_8_8_8;
1293 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1294 TRACE("(%p)->(%p),(%ld,%d,%p)\n", src, dst, len, convert, surf);
1299 memcpy(dst, src, len * surf->bytesPerPixel);
1302 case CONVERT_PALETTED:
1303 case CONVERT_PALETTED_CK:
1305 IWineD3DPaletteImpl* pal = surf->palette;
1311 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1315 /* Still no palette? Use the device's palette */
1316 /* Get the surface's palette */
1317 for (i = 0; i < 256; i++) {
1318 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1320 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1321 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1322 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1323 if ((convert == CONVERT_PALETTED_CK) &&
1324 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1325 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1326 /* We should maybe here put a more 'neutral' color than the standard bright purple
1327 one often used by application to prevent the nice purple borders when bi-linear
1335 TRACE("Using surface palette %p\n", pal);
1336 /* Get the surface's palette */
1337 for (i = 0; i < 256; i++) {
1338 table[i][0] = pal->palents[i].peRed;
1339 table[i][1] = pal->palents[i].peGreen;
1340 table[i][2] = pal->palents[i].peBlue;
1341 if ((convert == CONVERT_PALETTED_CK) &&
1342 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1343 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1344 /* We should maybe here put a more 'neutral' color than the standard bright purple
1345 one often used by application to prevent the nice purple borders when bi-linear
1354 for (x = 0; x < len; x++) {
1355 BYTE color = *src++;
1356 *dst++ = table[color][0];
1357 *dst++ = table[color][1];
1358 *dst++ = table[color][2];
1359 *dst++ = table[color][3];
1364 case CONVERT_CK_565:
1366 /* Converting the 565 format in 5551 packed to emulate color-keying.
1368 Note : in all these conversion, it would be best to average the averaging
1369 pixels to get the color of the pixel that will be color-keyed to
1370 prevent 'color bleeding'. This will be done later on if ever it is
1373 Note2: when using color-keying + alpha, are the alpha bits part of the
1374 color-space or not ?
1377 WORD *Source = (WORD *) src;
1378 WORD *Dest = (WORD *) dst;
1380 TRACE("Color keyed 565\n");
1382 for (x = 0; x < len; x++ ) {
1383 WORD color = *Source++;
1384 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1385 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1386 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1394 case CONVERT_CK_1555:
1397 WORD *Source = (WORD *) src;
1398 WORD *Dest = (WORD *) dst;
1400 for (x = 0; x < len * sizeof(WORD); x+=sizeof(WORD)) {
1401 WORD color = *Source++;
1402 *Dest = (color & 0x7FFF);
1403 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1404 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1405 *Dest |= (color & 0x8000);
1411 case CONVERT_CK_4444_ARGB:
1413 /* Move the four Alpha bits... */
1415 WORD *Source = (WORD *) src;
1416 WORD *Dest = (WORD *) dst;
1418 for (x = 0; x < len; x++) {
1419 WORD color = *Source++;
1420 *dst = (color & 0x0FFF) << 4;
1421 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1422 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1423 *Dest |= (color & 0xF000) >> 12;
1429 ERR("Unsupported conversation type %d\n", convert);
1435 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1436 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1438 if (This->Flags & SFLAG_INTEXTURE) {
1439 TRACE("Surface already in texture\n");
1442 if (!(This->Flags & SFLAG_DIRTY)) {
1443 TRACE("surface isn't dirty\n");
1447 This->Flags &= ~SFLAG_DIRTY;
1449 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1450 * These resources are not bound by device size or format restrictions. Because of this,
1451 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1452 * However, these resources can always be created, locked, and copied.
1454 if (This->resource.pool == WINED3DPOOL_SCRATCH)
1456 FIXME("(%p) Operation not supported for scratch textures\n",This);
1457 return WINED3DERR_INVALIDCALL;
1460 if (This->Flags & SFLAG_INPBUFFER) {
1463 if (This->glDescription.level != 0)
1464 FIXME("Surface in texture is only supported for level 0\n");
1465 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1466 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1467 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1468 This->resource.format == WINED3DFMT_DXT5)
1469 FIXME("Format %d not supported\n", This->resource.format);
1472 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1473 vcheckGLcall("glGetIntegerv");
1474 glReadBuffer(GL_BACK);
1475 vcheckGLcall("glReadBuffer");
1477 glCopyTexImage2D(This->glDescription.target,
1478 This->glDescription.level,
1479 This->glDescription.glFormatInternal,
1482 This->currentDesc.Width,
1483 This->currentDesc.Height,
1486 checkGLcall("glCopyTexImage2D");
1487 glReadBuffer(prevRead);
1488 vcheckGLcall("glReadBuffer");
1489 TRACE("Updating target %d\n", This->glDescription.target);
1490 This->Flags |= SFLAG_INTEXTURE;
1496 /* TODO: Compressed non-power 2 support */
1498 if (This->resource.format == WINED3DFMT_DXT1 ||
1499 This->resource.format == WINED3DFMT_DXT2 ||
1500 This->resource.format == WINED3DFMT_DXT3 ||
1501 This->resource.format == WINED3DFMT_DXT4 ||
1502 This->resource.format == WINED3DFMT_DXT5) {
1503 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1504 FIXME("Using DXT1/3/5 without advertized support\n");
1505 } else if (This->resource.allocatedMemory) {
1506 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1507 This->glDescription.target,
1508 This->glDescription.level,
1509 This->glDescription.glFormatInternal,
1510 This->currentDesc.Width,
1511 This->currentDesc.Height,
1513 This->resource.size,
1514 This->resource.allocatedMemory);
1518 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1519 This->glDescription.level,
1520 This->glDescription.glFormatInternal,
1521 This->currentDesc.Width,
1522 This->currentDesc.Height,
1524 This->resource.size,
1525 This->resource.allocatedMemory);
1526 checkGLcall("glCommpressedTexImage2D");
1530 if(!(This->Flags & SFLAG_DONOTFREE)){
1531 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1532 This->resource.allocatedMemory = NULL;
1536 GLenum format, internal, type;
1537 CONVERT_TYPES convert;
1541 d3dfmt_get_conv(This, TRUE /* We need color keying */, &format, &internal, &type, &convert, &bpp);
1543 if((convert != NO_CONVERSION) &&
1544 This->resource.allocatedMemory) {
1545 int width = This->glRect.right - This->glRect.left;
1546 int height = This->glRect.bottom - This->glRect.top;
1549 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
1551 ERR("Out of memory %d, %d!\n", width, height);
1552 return WINED3DERR_OUTOFVIDEOMEMORY;
1555 for(row = This->glRect.top; row < This->glRect.bottom; row++) {
1556 BYTE *cur = This->resource.allocatedMemory + row * This->pow2Width * This->bytesPerPixel;
1557 d3dfmt_convert_surface(cur + This->glRect.left * This->bytesPerPixel,
1558 mem + row * width * bpp,
1563 This->Flags |= SFLAG_CONVERTED;
1565 This->Flags &= ~SFLAG_CONVERTED;
1566 mem = This->resource.allocatedMemory;
1569 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1570 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE) ) {
1573 TRACE("non power of two support\n");
1575 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,
1576 This->glDescription.target,
1577 This->glDescription.level,
1578 debug_d3dformat(This->resource.format),
1579 This->glDescription.glFormatInternal,
1583 This->glDescription.glFormat,
1584 This->glDescription.glType,
1587 glTexImage2D(This->glDescription.target,
1588 This->glDescription.level,
1589 This->glDescription.glFormatInternal,
1593 This->glDescription.glFormat,
1594 This->glDescription.glType,
1597 checkGLcall("glTexImage2D");
1598 if (This->resource.allocatedMemory != NULL) {
1599 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1600 /* And map the non-power two data into the top left corner */
1602 This->glDescription.target,
1603 This->glDescription.level,
1606 This->currentDesc.Width,
1607 This->currentDesc.Height,
1608 This->glDescription.glFormat,
1609 This->glDescription.glType,
1610 This->resource.allocatedMemory
1612 checkGLcall("glTexSubImage2D");
1618 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%ld, h=%ld,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1619 This->glDescription.target,
1620 This->glDescription.level,
1621 debug_d3dformat(This->resource.format),
1622 This->glDescription.glFormatInternal,
1623 This->glRect.right - This->glRect.left,
1624 This->glRect.bottom - This->glRect.top,
1626 This->glDescription.glFormat,
1627 This->glDescription.glType,
1632 /* OK, create the texture */
1633 glTexImage2D(This->glDescription.target,
1634 This->glDescription.level,
1636 This->glRect.right - This->glRect.left,
1637 This->glRect.bottom - This->glRect.top,
1643 checkGLcall("glTexImage2D");
1647 if(mem != This->resource.allocatedMemory)
1648 HeapFree(GetProcessHeap(), 0, mem);
1652 static unsigned int gen = 0;
1655 if ((gen % 10) == 0) {
1656 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1657 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1660 * debugging crash code
1668 if(!(This->Flags & SFLAG_DONOTFREE)){
1669 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1670 This->resource.allocatedMemory = NULL;
1680 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1683 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1684 char *allocatedMemory;
1686 IWineD3DSwapChain *swapChain = NULL;
1691 Textures my not be stored in ->allocatedgMemory and a GlTexture
1692 so we should lock the surface before saving a snapshot, or at least check that
1694 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1695 by calling GetTexImage and in compressed form by calling
1696 GetCompressedTexImageARB. Queried compressed images can be saved and
1697 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1698 texture images do not need to be processed by the GL and should
1699 significantly improve texture loading performance relative to uncompressed
1702 /* Setup the width and height to be the internal texture width and height. */
1703 width = This->pow2Width;
1704 height = This->pow2Height;
1705 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1706 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1708 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1709 /* 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 */
1712 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1713 glEnable(GL_TEXTURE_2D);
1715 glGenTextures(1, &tmpTexture);
1716 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1718 glTexImage2D(GL_TEXTURE_2D,
1725 GL_UNSIGNED_INT_8_8_8_8_REV,
1728 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1729 vcheckGLcall("glGetIntegerv");
1730 glReadBuffer(GL_BACK);
1731 vcheckGLcall("glReadBuffer");
1732 glCopyTexImage2D(GL_TEXTURE_2D,
1741 checkGLcall("glCopyTexImage2D");
1742 glReadBuffer(prevRead);
1745 } else { /* bind the real texture */
1746 IWineD3DSurface_PreLoad(iface);
1748 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1750 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1751 glGetTexImage(GL_TEXTURE_2D,
1752 This->glDescription.level,
1754 GL_UNSIGNED_INT_8_8_8_8_REV,
1756 checkGLcall("glTexImage2D");
1758 glBindTexture(GL_TEXTURE_2D, 0);
1759 glDeleteTextures(1, &tmpTexture);
1763 f = fopen(filename, "w+");
1765 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1766 return WINED3DERR_INVALIDCALL;
1768 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1769 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1784 fwrite(&width,2,1,f);
1786 fwrite(&height,2,1,f);
1791 /* 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*/
1793 textureRow = allocatedMemory + (width * (height - 1) *4);
1795 textureRow = allocatedMemory;
1796 for (y = 0 ; y < height; y++) {
1797 for (i = 0; i < width; i++) {
1798 color = *((DWORD*)textureRow);
1799 fputc((color >> 16) & 0xFF, f); /* B */
1800 fputc((color >> 8) & 0xFF, f); /* G */
1801 fputc((color >> 0) & 0xFF, f); /* R */
1802 fputc((color >> 24) & 0xFF, f); /* A */
1805 /* take two rows of the pointer to the texture memory */
1807 (textureRow-= width << 3);
1810 TRACE("Closing file\n");
1814 IWineD3DSwapChain_Release(swapChain);
1816 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1820 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1821 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1822 This->Flags &= ~SFLAG_DIRTY;
1823 This->dirtyRect.left = This->currentDesc.Width;
1824 This->dirtyRect.top = This->currentDesc.Height;
1825 This->dirtyRect.right = 0;
1826 This->dirtyRect.bottom = 0;
1827 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1828 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1833 * Slightly inefficient way to handle multiple dirty rects but it works :)
1835 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1836 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1837 IWineD3DBaseTexture *baseTexture = NULL;
1838 This->Flags |= SFLAG_DIRTY;
1839 if (NULL != pDirtyRect) {
1840 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1841 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1842 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1843 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1845 This->dirtyRect.left = 0;
1846 This->dirtyRect.top = 0;
1847 This->dirtyRect.right = This->currentDesc.Width;
1848 This->dirtyRect.bottom = This->currentDesc.Height;
1850 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
1851 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1852 /* if the container is a basetexture then mark it dirty. */
1853 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1854 TRACE("Passing to conatiner\n");
1855 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1856 IWineD3DBaseTexture_Release(baseTexture);
1861 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1862 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1864 TRACE("This %p, container %p\n", This, container);
1866 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1868 TRACE("Setting container to %p from %p\n", container, This->container);
1869 This->container = container;
1874 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1875 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1877 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1878 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1879 return WINED3DERR_INVALIDCALL;
1882 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1883 if (format == WINED3DFMT_UNKNOWN) {
1884 This->resource.size = 0;
1885 } else if (format == WINED3DFMT_DXT1) {
1886 /* DXT1 is half byte per pixel */
1887 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1889 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1890 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1891 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1893 This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1897 /* Setup some glformat defaults */
1898 if (format != WINED3DFMT_UNKNOWN) {
1899 This->glDescription.glFormat = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1900 This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1901 This->glDescription.glType = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1903 This->glDescription.glFormat = 0;
1904 This->glDescription.glFormatInternal = 0;
1905 This->glDescription.glType = 0;
1908 if (format != WINED3DFMT_UNKNOWN) {
1909 This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1910 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1912 This->bytesPerPixel = 0;
1916 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
1918 This->resource.format = format;
1920 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);
1925 /* TODO: replace this function with context management routines */
1926 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1927 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1930 This->Flags |= SFLAG_INPBUFFER;
1932 This->Flags &= ~SFLAG_INPBUFFER;
1936 This->Flags |= SFLAG_INTEXTURE;
1938 This->Flags &= ~SFLAG_INTEXTURE;
1944 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
1945 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1946 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
1947 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
1949 /* Flipping is only supported on RenderTargets */
1950 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
1953 /* DDraw sets this for the X11 surfaces, so don't confuse the user
1954 * FIXME("(%p) Target override is not supported by now\n", This);
1955 * Additionally, it isn't really possible to support triple-buffering
1956 * properly on opengl at all
1960 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
1961 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
1964 /* Not called from the VTable */
1965 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
1967 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1968 IWineD3DSwapChainImpl *swapchain = NULL;
1969 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
1972 TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
1974 /* Get the swapchain. One of the surfaces has to be a primary surface */
1975 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
1976 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1978 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
1979 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1980 else return WINED3DERR_INVALIDCALL;
1986 rect.x1 = DestRect->left;
1987 rect.y1 = DestRect->top;
1988 rect.x2 = DestRect->right;
1989 rect.y2 = DestRect->bottom;
1993 rect.x2 = This->currentDesc.Width;
1994 rect.y2 = This->currentDesc.Height;
1997 /* Half-life does a Blt from the back buffer to the front buffer,
1998 * Full surface size, no flags... Use present instead
2002 /* First, check if we can do a Flip */
2004 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2006 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2007 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2014 /* Check the Destination rect and the surface sizes */
2016 (rect.x1 == 0) && (rect.y1 == 0) &&
2017 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2018 (This->currentDesc.Width == Src->currentDesc.Width) &&
2019 (This->currentDesc.Height == Src->currentDesc.Height)) {
2020 /* These flags are unimportant for the flag check, remove them */
2022 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2023 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2025 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2027 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2028 * take very long, while a flip is fast.
2029 * This applies to Half-Life, which does such Blts every time it finished
2030 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2031 * menu. This is also used by all apps when they do windowed rendering
2033 * The problem is that flipping is not really the same as copying. After a
2034 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2035 * untouched. Therefore it's necessary to override the swap effect
2036 * and to set it back after the flip.
2039 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2041 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2042 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2043 NULL, NULL, 0, NULL);
2045 swapchain->presentParms.SwapEffect = orig_swap;
2052 /* Blt from texture to rendertarget? */
2053 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2054 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2056 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2057 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2058 float glTexCoord[4];
2060 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2064 RECT SourceRectangle;
2067 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2070 SourceRectangle.left = SrcRect->left;
2071 SourceRectangle.right = SrcRect->right;
2072 SourceRectangle.top = SrcRect->top;
2073 SourceRectangle.bottom = SrcRect->bottom;
2075 SourceRectangle.left = 0;
2076 SourceRectangle.right = Src->currentDesc.Width;
2077 SourceRectangle.top = 0;
2078 SourceRectangle.bottom = Src->currentDesc.Height;
2081 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2082 /* Fall back to software */
2083 WARN("(%p) Source texture area (%ld,%ld)-(%ld,%ld) is too big\n", Src,
2084 SourceRectangle.left, SourceRectangle.top,
2085 SourceRectangle.right, SourceRectangle.bottom);
2086 return WINED3DERR_INVALIDCALL;
2089 /* Color keying: Check if we have to do a color keyed blt,
2090 * and if not check if a color key is activated.
2092 oldCKey = Src->CKeyFlags;
2093 if(!(Flags & DDBLT_KEYSRC) &&
2094 Src->CKeyFlags & DDSD_CKSRCBLT) {
2095 /* Ok, the surface has a color key, but we shall not use it -
2096 * Deactivate it for now and dirtify the surface to reload it
2098 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2099 Src->Flags |= SFLAG_DIRTY;
2102 /* Now load the surface */
2103 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2107 /* Save all the old stuff until we have a proper opengl state manager */
2108 oldLight = glIsEnabled(GL_LIGHTING);
2109 oldFog = glIsEnabled(GL_FOG);
2110 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2111 oldBlend = glIsEnabled(GL_BLEND);
2112 oldCull = glIsEnabled(GL_CULL_FACE);
2113 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2114 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2116 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2117 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2118 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2119 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2121 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2122 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2123 TRACE("Drawing to front buffer\n");
2124 glDrawBuffer(GL_FRONT);
2125 checkGLcall("glDrawBuffer GL_FRONT");
2128 /* Unbind the old texture */
2129 glBindTexture(GL_TEXTURE_2D, 0);
2131 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2132 /* We use texture unit 0 for blts */
2133 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2134 checkGLcall("glActiveTextureARB");
2136 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2139 /* Disable some fancy graphics effects */
2140 glDisable(GL_LIGHTING);
2141 checkGLcall("glDisable GL_LIGHTING");
2142 glDisable(GL_DEPTH_TEST);
2143 checkGLcall("glDisable GL_DEPTH_TEST");
2145 checkGLcall("glDisable GL_FOG");
2146 glDisable(GL_BLEND);
2147 checkGLcall("glDisable GL_BLEND");
2148 glDisable(GL_CULL_FACE);
2149 checkGLcall("glDisable GL_CULL_FACE");
2150 glDisable(GL_STENCIL_TEST);
2151 checkGLcall("glDisable GL_STENCIL_TEST");
2153 /* Ok, we need 2d textures, but not 1D or 3D */
2154 glDisable(GL_TEXTURE_1D);
2155 checkGLcall("glDisable GL_TEXTURE_1D");
2156 glEnable(GL_TEXTURE_2D);
2157 checkGLcall("glEnable GL_TEXTURE_2D");
2158 glDisable(GL_TEXTURE_3D);
2159 checkGLcall("glDisable GL_TEXTURE_3D");
2161 /* Bind the texture */
2162 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2163 checkGLcall("glBindTexture");
2165 glEnable(GL_SCISSOR_TEST);
2167 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2169 /* No filtering for blts */
2170 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2172 checkGLcall("glTexParameteri");
2173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2175 checkGLcall("glTexParameteri");
2176 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2177 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2178 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2179 checkGLcall("glTexEnvi");
2181 /* This is for color keying */
2182 if(Flags & DDBLT_KEYSRC) {
2183 glEnable(GL_ALPHA_TEST);
2184 checkGLcall("glEnable GL_ALPHA_TEST");
2185 glAlphaFunc(GL_NOTEQUAL, 0.0);
2186 checkGLcall("glAlphaFunc\n");
2188 glDisable(GL_ALPHA_TEST);
2189 checkGLcall("glDisable GL_ALPHA_TEST");
2192 /* Draw a textured quad
2194 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2198 glColor3d(1.0f, 1.0f, 1.0f);
2199 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2204 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2205 glVertex3f(rect.x1, rect.y2, 0.0);
2207 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2212 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2217 checkGLcall("glEnd");
2219 /* Unbind the texture */
2220 glBindTexture(GL_TEXTURE_2D, 0);
2221 checkGLcall("glEnable glBindTexture");
2223 /* Restore the old settings */
2225 glEnable(GL_LIGHTING);
2226 checkGLcall("glEnable GL_LIGHTING");
2230 checkGLcall("glEnable GL_FOG");
2233 glEnable(GL_DEPTH_TEST);
2234 checkGLcall("glEnable GL_DEPTH_TEST");
2238 checkGLcall("glEnable GL_BLEND");
2241 glEnable(GL_CULL_FACE);
2242 checkGLcall("glEnable GL_CULL_FACE");
2245 glEnable(GL_STENCIL_TEST);
2246 checkGLcall("glEnable GL_STENCIL_TEST");
2249 glDisable(GL_ALPHA_TEST);
2250 checkGLcall("glDisable GL_ALPHA_TEST");
2252 glEnable(GL_ALPHA_TEST);
2253 checkGLcall("glEnable GL_ALPHA_TEST");
2256 glAlphaFunc(alphafunc, alpharef);
2257 checkGLcall("glAlphaFunc\n");
2259 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2260 glDrawBuffer(oldDraw);
2263 /* Restore the color key */
2264 if(oldCKey != Src->CKeyFlags) {
2265 Src->CKeyFlags = oldCKey;
2266 Src->Flags |= SFLAG_DIRTY;
2271 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2272 This->Flags |= SFLAG_GLDIRTY;
2278 /* Blt from rendertarget to texture? */
2279 if( (SrcSurface == swapchain->frontBuffer) ||
2280 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2281 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2282 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2287 TRACE("Blt from rendertarget to texture\n");
2289 /* Call preload for the surface to make sure it isn't dirty */
2290 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2293 srect.x1 = SrcRect->left;
2294 srect.y1 = SrcRect->top;
2295 srect.x2 = SrcRect->right;
2296 srect.y2 = SrcRect->bottom;
2300 srect.x2 = Src->currentDesc.Width;
2301 srect.y2 = Src->currentDesc.Height;
2306 /* Bind the target texture */
2307 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2308 checkGLcall("glBindTexture");
2309 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2310 glReadBuffer(GL_BACK);
2312 glReadBuffer(GL_FRONT);
2314 checkGLcall("glReadBuffer");
2316 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2317 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2319 /* I have to process this row by row to swap the image,
2320 * otherwise it would be upside down, so streching in y direction
2321 * doesn't cost extra time
2323 * However, streching in x direction can be avoided if not necessary
2325 for(row = rect.y1; row < rect.y2; row++) {
2326 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2327 /* Well, that stuff works, but it's very slow.
2328 * find a better way instead
2331 for(col = rect.x1; col < rect.x2; col++) {
2332 glCopyTexSubImage2D(GL_TEXTURE_2D,
2334 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2335 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2339 glCopyTexSubImage2D(GL_TEXTURE_2D,
2341 rect.x1, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2342 srect.x1, Src->currentDesc.Height - srect.y2 + row * yrel,
2347 vcheckGLcall("glCopyTexSubImage2D");
2350 if(!(This->Flags & SFLAG_DONOTFREE)) {
2351 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2352 This->resource.allocatedMemory = NULL;
2354 This->Flags |= SFLAG_GLDIRTY;
2362 if (Flags & DDBLT_COLORFILL) {
2363 /* This is easy to handle for the D3D Device... */
2365 IWineD3DSwapChainImpl *implSwapChain;
2368 TRACE("Colorfill\n");
2370 /* The color as given in the Blt function is in the format of the frame-buffer...
2371 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2373 if (This->resource.format == WINED3DFMT_P8) {
2374 if (This->palette) {
2375 color = ((0xFF000000) |
2376 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2377 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2378 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2383 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2384 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2387 color = ((0xFF000000) |
2388 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2389 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2390 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2393 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2394 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2395 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2397 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2398 color = DDBltFx->u5.dwFillColor;
2401 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2402 return WINED3DERR_INVALIDCALL;
2405 /* Are we drawing to the Front buffer or the back buffer? */
2406 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
2407 vcheckGLcall("glIntegerv");
2409 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2410 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2411 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2412 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2413 glDrawBuffer(GL_BACK);
2414 checkGLcall("glDrawBuffer(GL_BACK)");
2416 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2417 glDrawBuffer(GL_FRONT);
2418 checkGLcall("glDrawBuffer(GL_FRONT)");
2421 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2422 return WINED3DERR_INVALIDCALL;
2425 TRACE("(%p) executing Render Target override, color = %lx\n", This, color);
2427 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2428 1 /* Number of rectangles */,
2435 /* Restore the original draw buffer */
2436 glDrawBuffer(prev_draw);
2437 vcheckGLcall("glDrawBuffer");
2442 /* Default: Fall back to the generic blt */
2443 return WINED3DERR_INVALIDCALL;
2446 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2447 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2448 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2449 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2450 TRACE("(%p): Usage is %08lx\n", This, This->resource.usage);
2452 /* Special cases for RenderTargets */
2453 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2454 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2455 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2458 /* For the rest call the X11 surface implementation.
2459 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2460 * other Blts are rather rare
2462 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2465 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2466 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2467 TRACE("(%p)->(%lx)\n", This, Flags);
2472 case DDGBS_ISBLTDONE:
2476 return DDERR_INVALIDPARAMS;
2480 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2481 /* XXX: DDERR_INVALIDSURFACETYPE */
2483 TRACE("(%p)->(%08lx)\n",iface,Flags);
2486 case DDGFS_ISFLIPDONE:
2490 return DDERR_INVALIDPARAMS;
2494 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2495 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2496 TRACE("(%p)\n", This);
2498 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2501 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2502 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2503 TRACE("(%p)\n", This);
2505 /* So far we don't lose anything :) */
2506 This->Flags &= ~SFLAG_LOST;
2510 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2511 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2512 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2513 TRACE("(%p)->(%ld, %ld, %p, %p, %08lx\n", iface, dstx, dsty, Source, rsrc, trans);
2515 /* Special cases for RenderTargets */
2516 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2517 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2519 RECT SrcRect, DstRect;
2522 SrcRect.left = rsrc->left;
2523 SrcRect.top= rsrc->top;
2524 SrcRect.bottom = rsrc->bottom;
2525 SrcRect.right = rsrc->right;
2529 SrcRect.right = srcImpl->currentDesc.Width;
2530 SrcRect.bottom = srcImpl->currentDesc.Height;
2533 DstRect.left = dstx;
2535 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2536 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2538 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, 0, NULL) == WINED3D_OK) return WINED3D_OK;
2542 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2545 HRESULT WINAPI IWineD3DSurfaceImpl_SetPixelFormat(IWineD3DSurface *iface, WINED3DFORMAT Format, BYTE *Surface, DWORD Size) {
2546 FIXME("This is unimplemented for now(d3d7 merge)\n");
2547 return WINED3DERR_INVALIDCALL;
2550 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2551 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2552 TRACE("(%p)->(%p)\n", This, Pal);
2554 *Pal = (IWineD3DPalette *) This->palette;
2558 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2559 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2561 IWineD3DPaletteImpl *pal = This->palette;
2563 TRACE("(%p)\n", This);
2565 if(This->resource.format == WINED3DFMT_P8 ||
2566 This->resource.format == WINED3DFMT_A8P8)
2568 TRACE("Dirtifying surface\n");
2569 This->Flags |= SFLAG_DIRTY;
2572 if(This->Flags & SFLAG_DIBSECTION) {
2573 TRACE("(%p): Updating the hdc's palette\n", This);
2574 for (n=0; n<256; n++) {
2576 col[n].rgbRed = pal->palents[n].peRed;
2577 col[n].rgbGreen = pal->palents[n].peGreen;
2578 col[n].rgbBlue = pal->palents[n].peBlue;
2580 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2581 /* Use the default device palette */
2582 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2583 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2584 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2586 col[n].rgbReserved = 0;
2588 SetDIBColorTable(This->hDC, 0, 256, col);
2594 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2595 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2596 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2597 TRACE("(%p)->(%p)\n", This, Pal);
2599 if(This->palette != NULL)
2600 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2601 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2603 if(PalImpl != NULL) {
2604 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2605 /* Set the device's main palette if the palette
2606 * wasn't a primary palette before
2608 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2609 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2612 for(i=0; i < 256; i++) {
2613 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2617 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2620 This->palette = PalImpl;
2622 return IWineD3DSurface_RealizePalette(iface);
2625 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2626 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2627 BOOL dirtify = FALSE;
2628 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
2630 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2631 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
2632 return DDERR_INVALIDPARAMS;
2635 /* Dirtify the surface, but only if a key was changed */
2637 switch (Flags & ~DDCKEY_COLORSPACE) {
2638 case DDCKEY_DESTBLT:
2639 if(!(This->CKeyFlags & DDSD_CKDESTBLT)) {
2642 dirtify = memcmp(&This->DestBltCKey, CKey, sizeof(*CKey) ) != 0;
2644 This->DestBltCKey = *CKey;
2645 This->CKeyFlags |= DDSD_CKDESTBLT;
2648 case DDCKEY_DESTOVERLAY:
2649 if(!(This->CKeyFlags & DDSD_CKDESTOVERLAY)) {
2652 dirtify = memcmp(&This->DestOverlayCKey, CKey, sizeof(*CKey)) != 0;
2654 This->DestOverlayCKey = *CKey;
2655 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2658 case DDCKEY_SRCOVERLAY:
2659 if(!(This->CKeyFlags & DDSD_CKSRCOVERLAY)) {
2662 dirtify = memcmp(&This->SrcOverlayCKey, CKey, sizeof(*CKey)) != 0;
2664 This->SrcOverlayCKey = *CKey;
2665 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2669 if(!(This->CKeyFlags & DDSD_CKSRCBLT)) {
2672 dirtify = memcmp(&This->SrcBltCKey, CKey, sizeof(*CKey)) != 0;
2674 This->SrcBltCKey = *CKey;
2675 This->CKeyFlags |= DDSD_CKSRCBLT;
2680 switch (Flags & ~DDCKEY_COLORSPACE) {
2681 case DDCKEY_DESTBLT:
2682 dirtify = This->CKeyFlags & DDSD_CKDESTBLT;
2683 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2686 case DDCKEY_DESTOVERLAY:
2687 dirtify = This->CKeyFlags & DDSD_CKDESTOVERLAY;
2688 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2691 case DDCKEY_SRCOVERLAY:
2692 dirtify = This->CKeyFlags & DDSD_CKSRCOVERLAY;
2693 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2697 dirtify = This->CKeyFlags & DDSD_CKSRCBLT;
2698 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2704 TRACE("Color key changed, dirtifying surface\n");
2705 This->Flags |= SFLAG_DIRTY;
2711 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2712 /** Check against the maximum texture sizes supported by the video card **/
2713 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2715 TRACE("%p\n", This);
2716 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2717 /* one of three options
2718 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)
2719 2: Set the texture to the maxium size (bad idea)
2720 3: WARN and return WINED3DERR_NOTAVAILABLE;
2721 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.
2723 WARN("(%p) Creating an oversized surface\n", This);
2724 This->Flags |= SFLAG_OVERSIZE;
2726 /* This will be initialized on the first blt */
2727 This->glRect.left = 0;
2728 This->glRect.top = 0;
2729 This->glRect.right = 0;
2730 This->glRect.bottom = 0;
2732 /* No oversize, gl rect is the full texture size */
2733 This->Flags &= ~SFLAG_OVERSIZE;
2734 This->glRect.left = 0;
2735 This->glRect.top = 0;
2736 This->glRect.right = This->pow2Width;
2737 This->glRect.bottom = This->pow2Height;
2743 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
2744 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2746 TRACE("(%p)\n", This);
2748 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
2749 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
2750 ie pitch = (width/4) * bytes per block */
2751 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
2752 ret = (This->currentDesc.Width >> 2) << 3;
2753 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
2754 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
2755 ret = (This->currentDesc.Width >> 2) << 4;
2757 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2758 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
2759 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
2761 ret = This->bytesPerPixel * This->pow2Width;
2764 TRACE("(%p) Returning %ld\n", This, ret);
2768 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
2771 IWineD3DSurfaceImpl_QueryInterface,
2772 IWineD3DSurfaceImpl_AddRef,
2773 IWineD3DSurfaceImpl_Release,
2774 /* IWineD3DResource */
2775 IWineD3DSurfaceImpl_GetParent,
2776 IWineD3DSurfaceImpl_GetDevice,
2777 IWineD3DSurfaceImpl_SetPrivateData,
2778 IWineD3DSurfaceImpl_GetPrivateData,
2779 IWineD3DSurfaceImpl_FreePrivateData,
2780 IWineD3DSurfaceImpl_SetPriority,
2781 IWineD3DSurfaceImpl_GetPriority,
2782 IWineD3DSurfaceImpl_PreLoad,
2783 IWineD3DSurfaceImpl_GetType,
2784 /* IWineD3DSurface */
2785 IWineD3DSurfaceImpl_GetContainerParent,
2786 IWineD3DSurfaceImpl_GetContainer,
2787 IWineD3DSurfaceImpl_GetDesc,
2788 IWineD3DSurfaceImpl_LockRect,
2789 IWineD3DSurfaceImpl_UnlockRect,
2790 IWineD3DSurfaceImpl_GetDC,
2791 IWineD3DSurfaceImpl_ReleaseDC,
2792 IWineD3DSurfaceImpl_Flip,
2793 IWineD3DSurfaceImpl_Blt,
2794 IWineD3DSurfaceImpl_GetBltStatus,
2795 IWineD3DSurfaceImpl_GetFlipStatus,
2796 IWineD3DSurfaceImpl_IsLost,
2797 IWineD3DSurfaceImpl_Restore,
2798 IWineD3DSurfaceImpl_BltFast,
2799 IWineD3DSurfaceImpl_SetPixelFormat,
2800 IWineD3DSurfaceImpl_GetPalette,
2801 IWineD3DSurfaceImpl_SetPalette,
2802 IWineD3DSurfaceImpl_RealizePalette,
2803 IWineD3DSurfaceImpl_SetColorKey,
2804 IWineD3DSurfaceImpl_GetPitch,
2806 IWineD3DSurfaceImpl_CleanDirtyRect,
2807 IWineD3DSurfaceImpl_AddDirtyRect,
2808 IWineD3DSurfaceImpl_LoadTexture,
2809 IWineD3DSurfaceImpl_SaveSnapshot,
2810 IWineD3DSurfaceImpl_SetContainer,
2811 IWineD3DSurfaceImpl_SetPBufferState,
2812 IWineD3DSurfaceImpl_SetGlTextureDesc,
2813 IWineD3DSurfaceImpl_GetGlDesc,
2814 IWineD3DSurfaceImpl_GetData,
2815 IWineD3DSurfaceImpl_SetFormat,
2816 IWineD3DSurfaceImpl_PrivateSetup