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 ((pRect->top < 0) ||
353 (pRect->left >= pRect->right) ||
354 (pRect->top >= pRect->bottom) ||
355 (pRect->right > This->currentDesc.Width) ||
356 (pRect->bottom > This->currentDesc.Height))
358 WARN(" Invalid values in pRect !!!\n");
359 return D3DERR_INVALIDCALL;
362 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
363 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
365 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
367 This->lockedRect.left = pRect->left;
368 This->lockedRect.top = pRect->top;
369 This->lockedRect.right = pRect->right;
370 This->lockedRect.bottom = pRect->bottom;
373 if (This->Flags & SFLAG_NONPOW2) {
374 TRACE("Locking non-power 2 texture\n");
377 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
378 /* classic surface TODO: non 2d surfaces?
379 These resources may be POOL_SYSTEMMEM, so they must not access the device */
380 TRACE("locking an ordinarary surface\n");
381 /* Check to see if memory has already been allocated from the surface*/
382 if ((NULL == This->resource.allocatedMemory) ||
383 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
384 /* Non-system memory surfaces */
386 This->Flags &= ~SFLAG_GLDIRTY;
388 /*Surface has no memory currently allocated to it!*/
389 TRACE("(%p) Locking rect\n" , This);
390 if(!This->resource.allocatedMemory) {
391 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
393 if (0 != This->glDescription.textureName) {
394 /* Now I have to copy thing bits back */
395 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
396 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
399 /* Make sure that the texture is loaded */
400 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
402 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);
404 if (This->resource.format == WINED3DFMT_DXT1 ||
405 This->resource.format == WINED3DFMT_DXT2 ||
406 This->resource.format == WINED3DFMT_DXT3 ||
407 This->resource.format == WINED3DFMT_DXT4 ||
408 This->resource.format == WINED3DFMT_DXT5) {
409 TRACE("Locking a compressed texture\n");
410 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
411 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
412 This->glDescription.level,
413 This->resource.allocatedMemory);
416 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
419 glGetTexImage(This->glDescription.target,
420 This->glDescription.level,
421 This->glDescription.glFormat,
422 This->glDescription.glType,
423 This->resource.allocatedMemory);
424 vcheckGLcall("glGetTexImage");
425 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
426 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
427 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
428 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
432 instead of boxing the texture :
433 |<-texture width ->| -->pow2width| /\
434 |111111111111111111| | |
435 |222 Texture 222222| boxed empty | texture height
436 |3333 Data 33333333| | |
437 |444444444444444444| | \/
438 ----------------------------------- |
439 | boxed empty | boxed empty | pow2height
441 -----------------------------------
444 were repacking the data to the expected texture width
446 |<-texture width ->| -->pow2width| /\
447 |111111111111111111222222222222222| |
448 |222333333333333333333444444444444| texture height
454 -----------------------------------
458 |<-texture width ->| /\
460 |222222222222222222|texture height
462 |444444444444444444| \/
465 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.
467 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.
469 if (This->Flags & SFLAG_NONPOW2) {
471 int pitcha = 0, pitchb = 0;
473 pitcha = This->bytesPerPixel * This->currentDesc.Width;
474 pitchb = This->bytesPerPixel * This->pow2Width;
475 datab = dataa = This->resource.allocatedMemory;
476 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
477 for (y = 1 ; y < This->currentDesc.Height; y++) {
478 dataa += pitcha; /* skip the first row */
480 memcpy(dataa, datab, pitcha);
487 } else { /* Nothing to do */
488 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
492 pLockedRect->pBits = This->resource.allocatedMemory;
494 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
495 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
497 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
501 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
502 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
505 BOOL notInContext = FALSE;
506 IWineD3DSwapChainImpl *targetSwapChain = NULL;
512 * for render->surface copy begin to begin of allocatedMemory
513 * unlock can be more easy
516 TRACE("locking a render target\n");
518 if (This->resource.allocatedMemory == NULL)
519 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
521 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
522 pLockedRect->pBits = This->resource.allocatedMemory;
525 vcheckGLcall("glFlush");
526 glGetIntegerv(GL_READ_BUFFER, &prev_read);
527 vcheckGLcall("glIntegerv");
528 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
529 vcheckGLcall("glIntegerv");
531 /* Here's what we have to do:
532 See if the swapchain has the same context as the renderTarget or the surface is the render target.
533 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
534 and use the front back buffer as required.
535 if not, we need to switch contexts and then switchback at the end.
537 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
538 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
540 /* 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! */
541 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
542 if (iface == swapchain->frontBuffer) {
543 TRACE("locking front\n");
544 glReadBuffer(GL_FRONT);
546 else if (iface == myDevice->renderTarget || backbuf) {
547 TRACE("locking back buffer\n");
548 glReadBuffer(GL_BACK);
549 } else if (iface == myDevice->depthStencilBuffer) {
550 FIXME("Stencil Buffer lock unsupported for now\n");
552 FIXME("(%p) Shouldn't have got here!\n", This);
553 glReadBuffer(GL_BACK);
555 } else if (swapchain != NULL) {
556 IWineD3DSwapChainImpl *implSwapChain;
557 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
558 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
559 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
561 glReadBuffer(GL_BACK);
562 } else if (iface == swapchain->frontBuffer) {
563 glReadBuffer(GL_FRONT);
564 } else if (iface == myDevice->depthStencilBuffer) {
565 FIXME("Stencil Buffer lock unsupported for now\n");
567 FIXME("Should have got here!\n");
568 glReadBuffer(GL_BACK);
571 /* We need to switch contexts to be able to read the buffer!!! */
572 FIXME("The buffer requested isn't in the current openGL context\n");
574 /* TODO: check the contexts, to see if were shared with the current context */
576 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
578 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
579 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
581 /** the depth stencil in openGL has a format of GL_FLOAT
582 * which should be good for WINED3DFMT_D16_LOCKABLE
584 * it is unclear what format the stencil buffer is in except.
585 * 'Each index is converted to fixed point...
586 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
587 * mappings in the table GL_PIXEL_MAP_S_TO_S.
588 * glReadPixels(This->lockedRect.left,
589 * This->lockedRect.bottom - j - 1,
590 * This->lockedRect.right - This->lockedRect.left,
592 * GL_DEPTH_COMPONENT,
594 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
595 *****************************************/
596 if (!notInContext) { /* Only read the buffer if it's in the current context */
600 /* 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,
601 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
602 * run ten times faster!
603 * ************************************/
604 BOOL ati_performance_hack = FALSE;
605 ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
607 if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
608 This->lockedRect.right == This->currentDesc.Width
609 && This->lockedRect.bottom == This->currentDesc.Height)) {
610 BYTE *row, *top, *bottom;
614 This->currentDesc.Width,
615 This->currentDesc.Height,
616 This->glDescription.glFormat,
617 This->glDescription.glType,
618 (char *)pLockedRect->pBits);
620 /* glReadPixels returns the image upside down, and there is no way to prevent this.
621 Flip the lines in software*/
622 row = HeapAlloc(GetProcessHeap(), 0, pLockedRect->Pitch);
624 ERR("Out of memory\n");
625 return E_OUTOFMEMORY;
627 top = This->resource.allocatedMemory;
628 bottom = ( (BYTE *) This->resource.allocatedMemory) + pLockedRect->Pitch * ( This->currentDesc.Height - 1);
629 for(i = 0; i < This->currentDesc.Height / 2; i++) {
630 memcpy(row, top, pLockedRect->Pitch);
631 memcpy(top, bottom, pLockedRect->Pitch);
632 memcpy(bottom, row, pLockedRect->Pitch);
633 top += pLockedRect->Pitch;
634 bottom -= pLockedRect->Pitch;
636 HeapFree(GetProcessHeap(), 0, row);
638 This->Flags &= ~SFLAG_GLDIRTY;
640 } else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
642 This->lockedRect.top,
643 This->currentDesc.Width,
644 This->currentDesc.Height,
645 This->glDescription.glFormat,
646 This->glDescription.glType,
647 (char *)pLockedRect->pBits);
650 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
651 glReadPixels(This->lockedRect.left,
652 This->lockedRect.bottom - j - 1,
653 This->lockedRect.right - This->lockedRect.left,
655 This->glDescription.glFormat,
656 This->glDescription.glType,
657 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
662 vcheckGLcall("glReadPixels");
663 TRACE("Resetting buffer\n");
665 glReadBuffer(prev_read);
666 vcheckGLcall("glReadBuffer");
670 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
673 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
676 glReadPixels(This->lockedRect.left,
677 This->lockedRect.bottom - j - 1,
678 This->lockedRect.right - This->lockedRect.left,
680 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
687 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
690 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
693 IWineD3DBaseTexture *pBaseTexture;
696 * as seen in msdn docs
698 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
700 /** Dirtify Container if needed */
701 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
702 TRACE("Making container dirty\n");
703 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
704 IWineD3DBaseTexture_Release(pBaseTexture);
706 TRACE("Surface is standalone, no need to dirty the container\n");
710 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
712 This->Flags |= SFLAG_LOCKED;
716 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
718 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
719 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
720 const char *buffername = "";
721 IWineD3DSwapChainImpl *swapchain = NULL;
722 BOOL backbuf = FALSE;
724 if (!(This->Flags & SFLAG_LOCKED)) {
725 WARN("trying to Unlock an unlocked surf@%p\n", This);
726 return WINED3DERR_INVALIDCALL;
729 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
730 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
734 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
735 if(iface == swapchain->backBuffer[i]) {
743 buffername = "backBuffer";
744 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
745 buffername = "frontBuffer";
746 } else if (iface == myDevice->depthStencilBuffer) {
747 buffername = "depthStencilBuffer";
748 } else if (iface == myDevice->renderTarget) {
749 buffername = "renderTarget";
753 if (swapchain != NULL) {
754 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
757 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
759 if (!(This->Flags & SFLAG_DIRTY)) {
760 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
764 if (0 == This->resource.usage) { /* classic surface */
767 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
769 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
771 /****************************
772 * TODO: Render targets are 'special' and
773 * ?some? locking needs to be passed onto the context manager
774 * so that it becomes possible to use auxiliary buffers, pbuffers
775 * render-to-texture, shared, cached contexts etc...
776 * ****************************/
777 IWineD3DSwapChainImpl *implSwapChain;
778 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
780 if (backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
782 GLint prev_depth_test;
783 GLint prev_rasterpos[4];
785 /* Some drivers(radeon dri, others?) don't like exceptions during
786 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
787 * after ReleaseDC. Reading it will cause an exception, which x11drv will
788 * catch to put the dib section in InSync mode, which leads to a crash
789 * and a blocked x server on my radeon card.
791 * The following lines read the dib section so it is put in inSync mode
792 * before glDrawPixels is called and the crash is prevented. There won't
793 * be any interfering gdi accesses, because UnlockRect is called from
794 * ReleaseDC, and the app won't use the dc any more afterwards.
796 if(This->Flags & SFLAG_DIBSECTION) {
798 read = This->resource.allocatedMemory[0];
804 vcheckGLcall("glFlush");
805 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
806 vcheckGLcall("glIntegerv");
807 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
808 vcheckGLcall("glIntegerv");
809 glPixelZoom(1.0, -1.0);
810 vcheckGLcall("glPixelZoom");
811 prev_depth_test = glIsEnabled(GL_DEPTH_TEST);
813 /* glDrawPixels transforms the raster position as though it was a vertex -
814 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
815 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
816 d3ddevice_set_ortho(This->resource.wineD3DDevice);
818 if (iface == implSwapChain->frontBuffer) {
819 glDrawBuffer(GL_FRONT);
820 checkGLcall("glDrawBuffer GL_FRONT");
821 } else if (backbuf || iface == myDevice->renderTarget) {
822 glDrawBuffer(GL_BACK);
823 checkGLcall("glDrawBuffer GL_BACK");
826 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
827 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
828 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
830 /* And back buffers are not blended */
832 glDisable(GL_DEPTH_TEST);
834 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
835 vcheckGLcall("glRasterPos2f");
837 switch (This->resource.format) {
838 case WINED3DFMT_X4R4G4B4:
841 unsigned short *data;
842 data = (unsigned short *)This->resource.allocatedMemory;
843 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
850 case WINED3DFMT_A4R4G4B4:
852 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
853 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
854 vcheckGLcall("glDrawPixels");
857 case WINED3DFMT_R5G6B5:
859 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
860 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
861 vcheckGLcall("glDrawPixels");
864 case WINED3DFMT_X1R5G5B5:
867 unsigned short *data;
868 data = (unsigned short *)This->resource.allocatedMemory;
869 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
876 case WINED3DFMT_A1R5G5B5:
878 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
879 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
880 vcheckGLcall("glDrawPixels");
883 case WINED3DFMT_R8G8B8:
885 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
886 GL_BGR, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
887 vcheckGLcall("glDrawPixels");
890 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
891 could be any random value this fixes the intro move in Pirates! */
895 data = (unsigned int *)This->resource.allocatedMemory;
896 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
903 case WINED3DFMT_A8R8G8B8:
905 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
906 vcheckGLcall("glPixelStorei");
907 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
908 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
909 vcheckGLcall("glDrawPixels");
910 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
911 vcheckGLcall("glPixelStorei");
914 case WINED3DFMT_A2R10G10B10:
916 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
917 vcheckGLcall("glPixelStorei");
918 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
919 GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
920 vcheckGLcall("glDrawPixels");
921 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
922 vcheckGLcall("glPixelStorei");
926 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
929 glPixelZoom(1.0,1.0);
930 vcheckGLcall("glPixelZoom");
931 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
932 glDrawBuffer(GL_BACK);
933 vcheckGLcall("glDrawBuffer");
935 glRasterPos3iv(&prev_rasterpos[0]);
936 vcheckGLcall("glRasterPos3iv");
937 if(prev_depth_test) glEnable(GL_DEPTH_TEST);
939 /* Reset to previous pack row length / blending state */
940 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
941 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
945 /** restore clean dirty state */
946 IWineD3DSurface_CleanDirtyRect(iface);
949 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
951 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
953 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
955 if (iface == myDevice->depthStencilBuffer) {
956 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
958 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
962 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
966 This->Flags &= ~SFLAG_LOCKED;
967 memset(&This->lockedRect, 0, sizeof(RECT));
971 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
972 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
973 WINED3DLOCKED_RECT lock;
980 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
982 TRACE("(%p)->(%p)\n",This,pHDC);
984 /* Give more detailed info for ddraw */
985 if (This->Flags & SFLAG_DCINUSE)
986 return DDERR_DCALREADYCREATED;
988 /* Can't GetDC if the surface is locked */
989 if (This->Flags & SFLAG_LOCKED)
990 return WINED3DERR_INVALIDCALL;
992 memset(&lock, 0, sizeof(lock)); /* To be sure */
994 /* Create a DIB section if there isn't a hdc yet */
996 if(This->Flags & SFLAG_ACTIVELOCK) {
997 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1000 switch (This->bytesPerPixel) {
1003 /* Allocate extra space to store the RGB bit masks. */
1004 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1008 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1012 /* Allocate extra space for a palette. */
1013 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1014 sizeof(BITMAPINFOHEADER)
1016 * (1 << (This->bytesPerPixel * 8)));
1020 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1021 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1022 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1023 b_info->bmiHeader.biHeight = -This->currentDesc.Height;
1024 /* Use the full pow2 image size(assigned below) because LockRect
1025 * will need it for a full glGetTexImage call
1028 b_info->bmiHeader.biWidth = This->pow2Width;
1029 b_info->bmiHeader.biHeight = -This->pow2Height;
1031 b_info->bmiHeader.biPlanes = 1;
1032 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1034 b_info->bmiHeader.biSizeImage = This->resource.size;
1036 b_info->bmiHeader.biXPelsPerMeter = 0;
1037 b_info->bmiHeader.biYPelsPerMeter = 0;
1038 b_info->bmiHeader.biClrUsed = 0;
1039 b_info->bmiHeader.biClrImportant = 0;
1041 /* Get the bit masks */
1042 masks = (DWORD *) &(b_info->bmiColors);
1043 switch (This->resource.format) {
1044 case WINED3DFMT_R8G8B8:
1045 usage = DIB_RGB_COLORS;
1046 b_info->bmiHeader.biCompression = BI_RGB;
1049 case WINED3DFMT_X1R5G5B5:
1050 case WINED3DFMT_A1R5G5B5:
1051 case WINED3DFMT_A4R4G4B4:
1052 case WINED3DFMT_X4R4G4B4:
1053 case WINED3DFMT_R3G3B2:
1054 case WINED3DFMT_A8R3G3B2:
1055 case WINED3DFMT_A2B10G10R10:
1056 case WINED3DFMT_A8B8G8R8:
1057 case WINED3DFMT_X8B8G8R8:
1058 case WINED3DFMT_A2R10G10B10:
1059 case WINED3DFMT_R5G6B5:
1060 case WINED3DFMT_A16B16G16R16:
1062 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1063 masks[0] = formatEntry->redMask;
1064 masks[1] = formatEntry->greenMask;
1065 masks[2] = formatEntry->blueMask;
1069 /* Don't know palette */
1070 b_info->bmiHeader.biCompression = BI_RGB;
1075 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1077 HeapFree(GetProcessHeap(), 0, b_info);
1078 return HRESULT_FROM_WIN32(GetLastError());
1081 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);
1082 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1085 if (!This->dib.DIBsection) {
1086 ERR("CreateDIBSection failed!\n");
1087 return HRESULT_FROM_WIN32(GetLastError());
1089 HeapFree(GetProcessHeap(), 0, b_info);
1091 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1093 /* copy the existing surface to the dib section */
1094 if(This->resource.allocatedMemory) {
1095 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->resource.size);
1096 /* We won't need that any more */
1097 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1099 /* This is to make LockRect read the gl Texture although memory is allocated */
1100 This->Flags |= SFLAG_GLDIRTY;
1103 /* Use the dib section from now on */
1104 This->resource.allocatedMemory = This->dib.bitmap_data;
1106 /* Now allocate a HDC */
1107 This->hDC = CreateCompatibleDC(0);
1108 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1109 TRACE("using wined3d palette %p\n", This->palette);
1110 SelectPalette(This->hDC,
1111 This->palette ? This->palette->hpal : 0,
1114 This->Flags |= SFLAG_DIBSECTION;
1117 /* Lock the surface */
1118 hr = IWineD3DSurface_LockRect(iface,
1123 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1124 /* keep the dib section */
1128 if(This->resource.format == WINED3DFMT_P8 ||
1129 This->resource.format == WINED3DFMT_A8P8) {
1132 PALETTEENTRY ent[256];
1134 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1135 for (n=0; n<256; n++) {
1136 col[n].rgbRed = ent[n].peRed;
1137 col[n].rgbGreen = ent[n].peGreen;
1138 col[n].rgbBlue = ent[n].peBlue;
1139 col[n].rgbReserved = 0;
1142 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1144 for (n=0; n<256; n++) {
1145 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1146 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1147 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1148 col[n].rgbReserved = 0;
1152 SetDIBColorTable(This->hDC, 0, 256, col);
1156 TRACE("returning %p\n",*pHDC);
1157 This->Flags |= SFLAG_DCINUSE;
1162 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1163 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1165 TRACE("(%p)->(%p)\n",This,hDC);
1167 if (!(This->Flags & SFLAG_DCINUSE))
1168 return D3DERR_INVALIDCALL;
1170 /* we locked first, so unlock now */
1171 IWineD3DSurface_UnlockRect(iface);
1173 This->Flags &= ~SFLAG_DCINUSE;
1178 /* ******************************************************
1179 IWineD3DSurface Internal (No mapping to directx api) parts follow
1180 ****************************************************** */
1185 CONVERT_PALETTED_CK,
1189 CONVERT_CK_4444_ARGB,
1194 CONVERT_CK_8888_ARGB,
1198 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp) {
1199 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1200 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1202 /* Default values: From the surface */
1203 *format = formatEntry->glFormat;
1204 *internal = formatEntry->glInternal;
1205 *type = formatEntry->glType;
1206 *convert = NO_CONVERSION;
1207 *target_bpp = This->bytesPerPixel;
1209 /* Ok, now look if we have to do any conversion */
1210 switch(This->resource.format) {
1215 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active) {
1217 *internal = GL_RGBA;
1218 *type = GL_UNSIGNED_BYTE;
1220 if(colorkey_active) {
1221 *convert = CONVERT_PALETTED;
1223 *convert = CONVERT_PALETTED_CK;
1229 case WINED3DFMT_R3G3B2:
1230 /* **********************
1231 GL_UNSIGNED_BYTE_3_3_2
1232 ********************** */
1233 if (colorkey_active) {
1234 /* This texture format will never be used.. So do not care about color keying
1235 up until the point in time it will be needed :-) */
1236 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1240 case WINED3DFMT_R5G6B5:
1241 if (colorkey_active) {
1242 *convert = CONVERT_CK_565;
1244 *internal = GL_RGBA;
1245 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1249 case WINED3DFMT_R8G8B8:
1250 if (colorkey_active) {
1251 *convert = CONVERT_CK_RGB24;
1253 *internal = GL_RGBA;
1254 *type = GL_UNSIGNED_INT_8_8_8_8;
1259 case WINED3DFMT_X8R8G8B8:
1260 if (colorkey_active) {
1261 *convert = CONVERT_RGB32_888;
1263 *internal = GL_RGBA;
1264 *type = GL_UNSIGNED_INT_8_8_8_8;
1268 /* Not sure if we should do color keying on Alpha-Enabled surfaces */
1269 case WINED3DFMT_A4R4G4B4:
1270 if (colorkey_active)
1272 *convert = CONVERT_CK_4444_ARGB;
1274 *internal = GL_RGBA;
1275 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1279 case WINED3DFMT_A1R5G5B5:
1280 if (colorkey_active)
1282 *convert = CONVERT_CK_1555;
1285 case WINED3DFMT_A8R8G8B8:
1286 if (colorkey_active)
1288 *convert = CONVERT_CK_8888_ARGB;
1290 *internal = GL_RGBA;
1291 *type = GL_UNSIGNED_INT_8_8_8_8;
1302 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1303 TRACE("(%p)->(%p),(%ld,%d,%p)\n", src, dst, len, convert, surf);
1308 memcpy(dst, src, len * surf->bytesPerPixel);
1311 case CONVERT_PALETTED:
1312 case CONVERT_PALETTED_CK:
1314 IWineD3DPaletteImpl* pal = surf->palette;
1320 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1324 /* Still no palette? Use the device's palette */
1325 /* Get the surface's palette */
1326 for (i = 0; i < 256; i++) {
1327 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1329 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1330 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1331 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1332 if ((convert == CONVERT_PALETTED_CK) &&
1333 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1334 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1335 /* We should maybe here put a more 'neutral' color than the standard bright purple
1336 one often used by application to prevent the nice purple borders when bi-linear
1344 TRACE("Using surface palette %p\n", pal);
1345 /* Get the surface's palette */
1346 for (i = 0; i < 256; i++) {
1347 table[i][0] = pal->palents[i].peRed;
1348 table[i][1] = pal->palents[i].peGreen;
1349 table[i][2] = pal->palents[i].peBlue;
1350 if ((convert == CONVERT_PALETTED_CK) &&
1351 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1352 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1353 /* We should maybe here put a more 'neutral' color than the standard bright purple
1354 one often used by application to prevent the nice purple borders when bi-linear
1363 for (x = 0; x < len; x++) {
1364 BYTE color = *src++;
1365 *dst++ = table[color][0];
1366 *dst++ = table[color][1];
1367 *dst++ = table[color][2];
1368 *dst++ = table[color][3];
1373 case CONVERT_CK_565:
1375 /* Converting the 565 format in 5551 packed to emulate color-keying.
1377 Note : in all these conversion, it would be best to average the averaging
1378 pixels to get the color of the pixel that will be color-keyed to
1379 prevent 'color bleeding'. This will be done later on if ever it is
1382 Note2: when using color-keying + alpha, are the alpha bits part of the
1383 color-space or not ?
1386 WORD *Source = (WORD *) src;
1387 WORD *Dest = (WORD *) dst;
1389 TRACE("Color keyed 565\n");
1391 for (x = 0; x < len; x++ ) {
1392 WORD color = *Source++;
1393 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1394 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1395 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1403 case CONVERT_CK_1555:
1406 WORD *Source = (WORD *) src;
1407 WORD *Dest = (WORD *) dst;
1409 for (x = 0; x < len * sizeof(WORD); x+=sizeof(WORD)) {
1410 WORD color = *Source++;
1411 *Dest = (color & 0x7FFF);
1412 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1413 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1414 *Dest |= (color & 0x8000);
1420 case CONVERT_CK_4444_ARGB:
1422 /* Move the four Alpha bits... */
1424 WORD *Source = (WORD *) src;
1425 WORD *Dest = (WORD *) dst;
1427 for (x = 0; x < len; x++) {
1428 WORD color = *Source++;
1429 *dst = (color & 0x0FFF) << 4;
1430 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1431 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1432 *Dest |= (color & 0xF000) >> 12;
1438 ERR("Unsupported conversation type %d\n", convert);
1444 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1445 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1447 if (This->Flags & SFLAG_INTEXTURE) {
1448 TRACE("Surface already in texture\n");
1451 if (!(This->Flags & SFLAG_DIRTY)) {
1452 TRACE("surface isn't dirty\n");
1456 This->Flags &= ~SFLAG_DIRTY;
1458 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1459 * These resources are not bound by device size or format restrictions. Because of this,
1460 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1461 * However, these resources can always be created, locked, and copied.
1463 if (This->resource.pool == WINED3DPOOL_SCRATCH)
1465 FIXME("(%p) Operation not supported for scratch textures\n",This);
1466 return WINED3DERR_INVALIDCALL;
1469 if (This->Flags & SFLAG_INPBUFFER) {
1472 if (This->glDescription.level != 0)
1473 FIXME("Surface in texture is only supported for level 0\n");
1474 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1475 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1476 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1477 This->resource.format == WINED3DFMT_DXT5)
1478 FIXME("Format %d not supported\n", This->resource.format);
1481 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1482 vcheckGLcall("glGetIntegerv");
1483 glReadBuffer(GL_BACK);
1484 vcheckGLcall("glReadBuffer");
1486 glCopyTexImage2D(This->glDescription.target,
1487 This->glDescription.level,
1488 This->glDescription.glFormatInternal,
1491 This->currentDesc.Width,
1492 This->currentDesc.Height,
1495 checkGLcall("glCopyTexImage2D");
1496 glReadBuffer(prevRead);
1497 vcheckGLcall("glReadBuffer");
1498 TRACE("Updating target %d\n", This->glDescription.target);
1499 This->Flags |= SFLAG_INTEXTURE;
1505 /* TODO: Compressed non-power 2 support */
1507 if (This->resource.format == WINED3DFMT_DXT1 ||
1508 This->resource.format == WINED3DFMT_DXT2 ||
1509 This->resource.format == WINED3DFMT_DXT3 ||
1510 This->resource.format == WINED3DFMT_DXT4 ||
1511 This->resource.format == WINED3DFMT_DXT5) {
1512 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1513 FIXME("Using DXT1/3/5 without advertized support\n");
1514 } else if (This->resource.allocatedMemory) {
1515 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1516 This->glDescription.target,
1517 This->glDescription.level,
1518 This->glDescription.glFormatInternal,
1519 This->currentDesc.Width,
1520 This->currentDesc.Height,
1522 This->resource.size,
1523 This->resource.allocatedMemory);
1527 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1528 This->glDescription.level,
1529 This->glDescription.glFormatInternal,
1530 This->currentDesc.Width,
1531 This->currentDesc.Height,
1533 This->resource.size,
1534 This->resource.allocatedMemory);
1535 checkGLcall("glCommpressedTexImage2D");
1539 if(!(This->Flags & SFLAG_DONOTFREE)){
1540 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1541 This->resource.allocatedMemory = NULL;
1545 GLenum format, internal, type;
1546 CONVERT_TYPES convert;
1550 d3dfmt_get_conv(This, TRUE /* We need color keying */, &format, &internal, &type, &convert, &bpp);
1552 if((convert != NO_CONVERSION) &&
1553 This->resource.allocatedMemory) {
1554 int width = This->glRect.right - This->glRect.left;
1555 int height = This->glRect.bottom - This->glRect.top;
1558 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
1560 ERR("Out of memory %d, %d!\n", width, height);
1561 return WINED3DERR_OUTOFVIDEOMEMORY;
1564 for(row = This->glRect.top; row < This->glRect.bottom; row++) {
1565 BYTE *cur = This->resource.allocatedMemory + row * This->pow2Width * This->bytesPerPixel;
1566 d3dfmt_convert_surface(cur + This->glRect.left * This->bytesPerPixel,
1567 mem + row * width * bpp,
1572 This->Flags |= SFLAG_CONVERTED;
1574 This->Flags &= ~SFLAG_CONVERTED;
1575 mem = This->resource.allocatedMemory;
1578 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1579 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE) ) {
1582 TRACE("non power of two support\n");
1584 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,
1585 This->glDescription.target,
1586 This->glDescription.level,
1587 debug_d3dformat(This->resource.format),
1588 This->glDescription.glFormatInternal,
1592 This->glDescription.glFormat,
1593 This->glDescription.glType,
1596 glTexImage2D(This->glDescription.target,
1597 This->glDescription.level,
1598 This->glDescription.glFormatInternal,
1602 This->glDescription.glFormat,
1603 This->glDescription.glType,
1606 checkGLcall("glTexImage2D");
1607 if (This->resource.allocatedMemory != NULL) {
1608 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1609 /* And map the non-power two data into the top left corner */
1611 This->glDescription.target,
1612 This->glDescription.level,
1615 This->currentDesc.Width,
1616 This->currentDesc.Height,
1617 This->glDescription.glFormat,
1618 This->glDescription.glType,
1619 This->resource.allocatedMemory
1621 checkGLcall("glTexSubImage2D");
1627 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%ld, h=%ld,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1628 This->glDescription.target,
1629 This->glDescription.level,
1630 debug_d3dformat(This->resource.format),
1631 This->glDescription.glFormatInternal,
1632 This->glRect.right - This->glRect.left,
1633 This->glRect.bottom - This->glRect.top,
1635 This->glDescription.glFormat,
1636 This->glDescription.glType,
1641 /* OK, create the texture */
1642 glTexImage2D(This->glDescription.target,
1643 This->glDescription.level,
1645 This->glRect.right - This->glRect.left,
1646 This->glRect.bottom - This->glRect.top,
1652 checkGLcall("glTexImage2D");
1656 if(mem != This->resource.allocatedMemory)
1657 HeapFree(GetProcessHeap(), 0, mem);
1661 static unsigned int gen = 0;
1664 if ((gen % 10) == 0) {
1665 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1666 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1669 * debugging crash code
1677 if(!(This->Flags & SFLAG_DONOTFREE)){
1678 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1679 This->resource.allocatedMemory = NULL;
1689 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1692 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1693 char *allocatedMemory;
1695 IWineD3DSwapChain *swapChain = NULL;
1700 Textures my not be stored in ->allocatedgMemory and a GlTexture
1701 so we should lock the surface before saving a snapshot, or at least check that
1703 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1704 by calling GetTexImage and in compressed form by calling
1705 GetCompressedTexImageARB. Queried compressed images can be saved and
1706 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1707 texture images do not need to be processed by the GL and should
1708 significantly improve texture loading performance relative to uncompressed
1711 /* Setup the width and height to be the internal texture width and height. */
1712 width = This->pow2Width;
1713 height = This->pow2Height;
1714 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1715 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1717 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1718 /* 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 */
1721 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1722 glEnable(GL_TEXTURE_2D);
1724 glGenTextures(1, &tmpTexture);
1725 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1727 glTexImage2D(GL_TEXTURE_2D,
1734 GL_UNSIGNED_INT_8_8_8_8_REV,
1737 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1738 vcheckGLcall("glGetIntegerv");
1739 glReadBuffer(GL_BACK);
1740 vcheckGLcall("glReadBuffer");
1741 glCopyTexImage2D(GL_TEXTURE_2D,
1750 checkGLcall("glCopyTexImage2D");
1751 glReadBuffer(prevRead);
1754 } else { /* bind the real texture */
1755 IWineD3DSurface_PreLoad(iface);
1757 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1759 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1760 glGetTexImage(GL_TEXTURE_2D,
1761 This->glDescription.level,
1763 GL_UNSIGNED_INT_8_8_8_8_REV,
1765 checkGLcall("glTexImage2D");
1767 glBindTexture(GL_TEXTURE_2D, 0);
1768 glDeleteTextures(1, &tmpTexture);
1772 f = fopen(filename, "w+");
1774 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1775 return WINED3DERR_INVALIDCALL;
1777 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1778 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1793 fwrite(&width,2,1,f);
1795 fwrite(&height,2,1,f);
1800 /* 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*/
1802 textureRow = allocatedMemory + (width * (height - 1) *4);
1804 textureRow = allocatedMemory;
1805 for (y = 0 ; y < height; y++) {
1806 for (i = 0; i < width; i++) {
1807 color = *((DWORD*)textureRow);
1808 fputc((color >> 16) & 0xFF, f); /* B */
1809 fputc((color >> 8) & 0xFF, f); /* G */
1810 fputc((color >> 0) & 0xFF, f); /* R */
1811 fputc((color >> 24) & 0xFF, f); /* A */
1814 /* take two rows of the pointer to the texture memory */
1816 (textureRow-= width << 3);
1819 TRACE("Closing file\n");
1823 IWineD3DSwapChain_Release(swapChain);
1825 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1829 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1830 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1831 This->Flags &= ~SFLAG_DIRTY;
1832 This->dirtyRect.left = This->currentDesc.Width;
1833 This->dirtyRect.top = This->currentDesc.Height;
1834 This->dirtyRect.right = 0;
1835 This->dirtyRect.bottom = 0;
1836 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1837 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1842 * Slightly inefficient way to handle multiple dirty rects but it works :)
1844 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1845 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1846 IWineD3DBaseTexture *baseTexture = NULL;
1847 This->Flags |= SFLAG_DIRTY;
1848 if (NULL != pDirtyRect) {
1849 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1850 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1851 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1852 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1854 This->dirtyRect.left = 0;
1855 This->dirtyRect.top = 0;
1856 This->dirtyRect.right = This->currentDesc.Width;
1857 This->dirtyRect.bottom = This->currentDesc.Height;
1859 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
1860 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1861 /* if the container is a basetexture then mark it dirty. */
1862 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1863 TRACE("Passing to conatiner\n");
1864 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1865 IWineD3DBaseTexture_Release(baseTexture);
1870 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1871 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1873 TRACE("This %p, container %p\n", This, container);
1875 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1877 TRACE("Setting container to %p from %p\n", container, This->container);
1878 This->container = container;
1883 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1884 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1885 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
1887 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1888 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1889 return WINED3DERR_INVALIDCALL;
1892 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1893 if (format == WINED3DFMT_UNKNOWN) {
1894 This->resource.size = 0;
1895 } else if (format == WINED3DFMT_DXT1) {
1896 /* DXT1 is half byte per pixel */
1897 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
1899 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1900 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1901 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
1903 This->resource.size = (This->pow2Width * formatEntry->bpp) * This->pow2Height;
1907 /* Setup some glformat defaults */
1908 This->glDescription.glFormat = formatEntry->glFormat;
1909 This->glDescription.glFormatInternal = formatEntry->glInternal;
1910 This->glDescription.glType = formatEntry->glType;
1912 if (format != WINED3DFMT_UNKNOWN) {
1913 This->bytesPerPixel = formatEntry->bpp;
1914 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1916 This->bytesPerPixel = 0;
1920 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
1922 This->resource.format = format;
1924 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);
1929 /* TODO: replace this function with context management routines */
1930 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1931 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1934 This->Flags |= SFLAG_INPBUFFER;
1936 This->Flags &= ~SFLAG_INPBUFFER;
1940 This->Flags |= SFLAG_INTEXTURE;
1942 This->Flags &= ~SFLAG_INTEXTURE;
1948 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
1949 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1950 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
1951 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
1953 /* Flipping is only supported on RenderTargets */
1954 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
1957 /* DDraw sets this for the X11 surfaces, so don't confuse the user
1958 * FIXME("(%p) Target override is not supported by now\n", This);
1959 * Additionally, it isn't really possible to support triple-buffering
1960 * properly on opengl at all
1964 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
1965 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
1968 /* Not called from the VTable */
1969 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
1971 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1972 IWineD3DSwapChainImpl *swapchain = NULL;
1973 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
1976 TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
1978 /* Get the swapchain. One of the surfaces has to be a primary surface */
1979 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
1980 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1982 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
1983 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1984 else return WINED3DERR_INVALIDCALL;
1990 rect.x1 = DestRect->left;
1991 rect.y1 = DestRect->top;
1992 rect.x2 = DestRect->right;
1993 rect.y2 = DestRect->bottom;
1997 rect.x2 = This->currentDesc.Width;
1998 rect.y2 = This->currentDesc.Height;
2001 /* Half-life does a Blt from the back buffer to the front buffer,
2002 * Full surface size, no flags... Use present instead
2006 /* First, check if we can do a Flip */
2008 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2010 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2011 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2018 /* Check the Destination rect and the surface sizes */
2020 (rect.x1 == 0) && (rect.y1 == 0) &&
2021 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2022 (This->currentDesc.Width == Src->currentDesc.Width) &&
2023 (This->currentDesc.Height == Src->currentDesc.Height)) {
2024 /* These flags are unimportant for the flag check, remove them */
2026 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2027 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2029 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2031 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2032 * take very long, while a flip is fast.
2033 * This applies to Half-Life, which does such Blts every time it finished
2034 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2035 * menu. This is also used by all apps when they do windowed rendering
2037 * The problem is that flipping is not really the same as copying. After a
2038 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2039 * untouched. Therefore it's necessary to override the swap effect
2040 * and to set it back after the flip.
2043 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2045 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2046 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2047 NULL, NULL, 0, NULL);
2049 swapchain->presentParms.SwapEffect = orig_swap;
2056 /* Blt from texture to rendertarget? */
2057 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2058 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2060 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2061 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2062 float glTexCoord[4];
2064 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2068 RECT SourceRectangle;
2071 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2074 SourceRectangle.left = SrcRect->left;
2075 SourceRectangle.right = SrcRect->right;
2076 SourceRectangle.top = SrcRect->top;
2077 SourceRectangle.bottom = SrcRect->bottom;
2079 SourceRectangle.left = 0;
2080 SourceRectangle.right = Src->currentDesc.Width;
2081 SourceRectangle.top = 0;
2082 SourceRectangle.bottom = Src->currentDesc.Height;
2085 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2086 /* Fall back to software */
2087 WARN("(%p) Source texture area (%ld,%ld)-(%ld,%ld) is too big\n", Src,
2088 SourceRectangle.left, SourceRectangle.top,
2089 SourceRectangle.right, SourceRectangle.bottom);
2090 return WINED3DERR_INVALIDCALL;
2093 /* Color keying: Check if we have to do a color keyed blt,
2094 * and if not check if a color key is activated.
2096 oldCKey = Src->CKeyFlags;
2097 if(!(Flags & DDBLT_KEYSRC) &&
2098 Src->CKeyFlags & DDSD_CKSRCBLT) {
2099 /* Ok, the surface has a color key, but we shall not use it -
2100 * Deactivate it for now and dirtify the surface to reload it
2102 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2103 Src->Flags |= SFLAG_DIRTY;
2106 /* Now load the surface */
2107 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2111 /* Save all the old stuff until we have a proper opengl state manager */
2112 oldLight = glIsEnabled(GL_LIGHTING);
2113 oldFog = glIsEnabled(GL_FOG);
2114 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2115 oldBlend = glIsEnabled(GL_BLEND);
2116 oldCull = glIsEnabled(GL_CULL_FACE);
2117 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2118 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2120 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2121 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2122 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2123 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2125 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2126 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2127 TRACE("Drawing to front buffer\n");
2128 glDrawBuffer(GL_FRONT);
2129 checkGLcall("glDrawBuffer GL_FRONT");
2132 /* Unbind the old texture */
2133 glBindTexture(GL_TEXTURE_2D, 0);
2135 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2136 /* We use texture unit 0 for blts */
2137 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2138 checkGLcall("glActiveTextureARB");
2140 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2143 /* Disable some fancy graphics effects */
2144 glDisable(GL_LIGHTING);
2145 checkGLcall("glDisable GL_LIGHTING");
2146 glDisable(GL_DEPTH_TEST);
2147 checkGLcall("glDisable GL_DEPTH_TEST");
2149 checkGLcall("glDisable GL_FOG");
2150 glDisable(GL_BLEND);
2151 checkGLcall("glDisable GL_BLEND");
2152 glDisable(GL_CULL_FACE);
2153 checkGLcall("glDisable GL_CULL_FACE");
2154 glDisable(GL_STENCIL_TEST);
2155 checkGLcall("glDisable GL_STENCIL_TEST");
2157 /* Ok, we need 2d textures, but not 1D or 3D */
2158 glDisable(GL_TEXTURE_1D);
2159 checkGLcall("glDisable GL_TEXTURE_1D");
2160 glEnable(GL_TEXTURE_2D);
2161 checkGLcall("glEnable GL_TEXTURE_2D");
2162 glDisable(GL_TEXTURE_3D);
2163 checkGLcall("glDisable GL_TEXTURE_3D");
2165 /* Bind the texture */
2166 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2167 checkGLcall("glBindTexture");
2169 glEnable(GL_SCISSOR_TEST);
2171 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2173 /* No filtering for blts */
2174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2176 checkGLcall("glTexParameteri");
2177 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2179 checkGLcall("glTexParameteri");
2180 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2181 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2182 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2183 checkGLcall("glTexEnvi");
2185 /* This is for color keying */
2186 if(Flags & DDBLT_KEYSRC) {
2187 glEnable(GL_ALPHA_TEST);
2188 checkGLcall("glEnable GL_ALPHA_TEST");
2189 glAlphaFunc(GL_NOTEQUAL, 0.0);
2190 checkGLcall("glAlphaFunc\n");
2192 glDisable(GL_ALPHA_TEST);
2193 checkGLcall("glDisable GL_ALPHA_TEST");
2196 /* Draw a textured quad
2198 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2202 glColor3d(1.0f, 1.0f, 1.0f);
2203 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2208 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2209 glVertex3f(rect.x1, rect.y2, 0.0);
2211 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2216 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2221 checkGLcall("glEnd");
2223 /* Unbind the texture */
2224 glBindTexture(GL_TEXTURE_2D, 0);
2225 checkGLcall("glEnable glBindTexture");
2227 /* Restore the old settings */
2229 glEnable(GL_LIGHTING);
2230 checkGLcall("glEnable GL_LIGHTING");
2234 checkGLcall("glEnable GL_FOG");
2237 glEnable(GL_DEPTH_TEST);
2238 checkGLcall("glEnable GL_DEPTH_TEST");
2242 checkGLcall("glEnable GL_BLEND");
2245 glEnable(GL_CULL_FACE);
2246 checkGLcall("glEnable GL_CULL_FACE");
2249 glEnable(GL_STENCIL_TEST);
2250 checkGLcall("glEnable GL_STENCIL_TEST");
2253 glDisable(GL_ALPHA_TEST);
2254 checkGLcall("glDisable GL_ALPHA_TEST");
2256 glEnable(GL_ALPHA_TEST);
2257 checkGLcall("glEnable GL_ALPHA_TEST");
2260 glAlphaFunc(alphafunc, alpharef);
2261 checkGLcall("glAlphaFunc\n");
2263 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2264 glDrawBuffer(oldDraw);
2267 /* Restore the color key */
2268 if(oldCKey != Src->CKeyFlags) {
2269 Src->CKeyFlags = oldCKey;
2270 Src->Flags |= SFLAG_DIRTY;
2275 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2276 This->Flags |= SFLAG_GLDIRTY;
2282 /* Blt from rendertarget to texture? */
2283 if( (SrcSurface == swapchain->frontBuffer) ||
2284 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2285 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2286 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2291 TRACE("Blt from rendertarget to texture\n");
2293 /* Call preload for the surface to make sure it isn't dirty */
2294 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2297 srect.x1 = SrcRect->left;
2298 srect.y1 = SrcRect->top;
2299 srect.x2 = SrcRect->right;
2300 srect.y2 = SrcRect->bottom;
2304 srect.x2 = Src->currentDesc.Width;
2305 srect.y2 = Src->currentDesc.Height;
2310 /* Bind the target texture */
2311 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2312 checkGLcall("glBindTexture");
2313 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2314 glReadBuffer(GL_BACK);
2316 glReadBuffer(GL_FRONT);
2318 checkGLcall("glReadBuffer");
2320 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2321 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2323 /* I have to process this row by row to swap the image,
2324 * otherwise it would be upside down, so streching in y direction
2325 * doesn't cost extra time
2327 * However, streching in x direction can be avoided if not necessary
2329 for(row = rect.y1; row < rect.y2; row++) {
2330 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2331 /* Well, that stuff works, but it's very slow.
2332 * find a better way instead
2335 for(col = rect.x1; col < rect.x2; col++) {
2336 glCopyTexSubImage2D(GL_TEXTURE_2D,
2338 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2339 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2343 glCopyTexSubImage2D(GL_TEXTURE_2D,
2345 rect.x1, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2346 srect.x1, Src->currentDesc.Height - srect.y2 + row * yrel,
2351 vcheckGLcall("glCopyTexSubImage2D");
2354 if(!(This->Flags & SFLAG_DONOTFREE)) {
2355 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2356 This->resource.allocatedMemory = NULL;
2358 This->Flags |= SFLAG_GLDIRTY;
2366 if (Flags & DDBLT_COLORFILL) {
2367 /* This is easy to handle for the D3D Device... */
2369 IWineD3DSwapChainImpl *implSwapChain;
2371 TRACE("Colorfill\n");
2373 /* The color as given in the Blt function is in the format of the frame-buffer...
2374 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2376 if (This->resource.format == WINED3DFMT_P8) {
2377 if (This->palette) {
2378 color = ((0xFF000000) |
2379 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2380 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2381 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2386 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2387 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2390 color = ((0xFF000000) |
2391 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2392 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2393 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2396 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2397 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2398 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2400 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2401 color = DDBltFx->u5.dwFillColor;
2404 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2405 return WINED3DERR_INVALIDCALL;
2408 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2409 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2410 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2411 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2412 glDrawBuffer(GL_BACK);
2413 checkGLcall("glDrawBuffer(GL_BACK)");
2415 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2416 glDrawBuffer(GL_FRONT);
2417 checkGLcall("glDrawBuffer(GL_FRONT)");
2420 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2421 return WINED3DERR_INVALIDCALL;
2424 TRACE("(%p) executing Render Target override, color = %lx\n", This, color);
2426 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2427 1 /* Number of rectangles */,
2434 /* Restore the original draw buffer */
2435 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2436 glDrawBuffer(GL_BACK);
2437 vcheckGLcall("glDrawBuffer");
2443 /* Default: Fall back to the generic blt */
2444 return WINED3DERR_INVALIDCALL;
2447 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2448 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2449 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2450 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2451 TRACE("(%p): Usage is %08lx\n", This, This->resource.usage);
2453 /* Special cases for RenderTargets */
2454 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2455 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2456 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2459 /* For the rest call the X11 surface implementation.
2460 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2461 * other Blts are rather rare
2463 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2466 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2467 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2468 TRACE("(%p)->(%lx)\n", This, Flags);
2473 case DDGBS_ISBLTDONE:
2477 return DDERR_INVALIDPARAMS;
2481 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2482 /* XXX: DDERR_INVALIDSURFACETYPE */
2484 TRACE("(%p)->(%08lx)\n",iface,Flags);
2487 case DDGFS_ISFLIPDONE:
2491 return DDERR_INVALIDPARAMS;
2495 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2496 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2497 TRACE("(%p)\n", This);
2499 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2502 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2503 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2504 TRACE("(%p)\n", This);
2506 /* So far we don't lose anything :) */
2507 This->Flags &= ~SFLAG_LOST;
2511 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2512 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2513 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2514 TRACE("(%p)->(%ld, %ld, %p, %p, %08lx\n", iface, dstx, dsty, Source, rsrc, trans);
2516 /* Special cases for RenderTargets */
2517 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2518 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2520 RECT SrcRect, DstRect;
2523 SrcRect.left = rsrc->left;
2524 SrcRect.top= rsrc->top;
2525 SrcRect.bottom = rsrc->bottom;
2526 SrcRect.right = rsrc->right;
2530 SrcRect.right = srcImpl->currentDesc.Width;
2531 SrcRect.bottom = srcImpl->currentDesc.Height;
2534 DstRect.left = dstx;
2536 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2537 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2539 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, 0, NULL) == WINED3D_OK) return WINED3D_OK;
2543 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2546 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2547 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2548 TRACE("(%p)->(%p)\n", This, Pal);
2550 *Pal = (IWineD3DPalette *) This->palette;
2554 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2555 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2557 IWineD3DPaletteImpl *pal = This->palette;
2559 TRACE("(%p)\n", This);
2561 if(This->resource.format == WINED3DFMT_P8 ||
2562 This->resource.format == WINED3DFMT_A8P8)
2564 TRACE("Dirtifying surface\n");
2565 This->Flags |= SFLAG_DIRTY;
2568 if(This->Flags & SFLAG_DIBSECTION) {
2569 TRACE("(%p): Updating the hdc's palette\n", This);
2570 for (n=0; n<256; n++) {
2572 col[n].rgbRed = pal->palents[n].peRed;
2573 col[n].rgbGreen = pal->palents[n].peGreen;
2574 col[n].rgbBlue = pal->palents[n].peBlue;
2576 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2577 /* Use the default device palette */
2578 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2579 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2580 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2582 col[n].rgbReserved = 0;
2584 SetDIBColorTable(This->hDC, 0, 256, col);
2590 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2591 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2592 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2593 TRACE("(%p)->(%p)\n", This, Pal);
2595 if(This->palette != NULL)
2596 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2597 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2599 if(PalImpl != NULL) {
2600 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2601 /* Set the device's main palette if the palette
2602 * wasn't a primary palette before
2604 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2605 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2608 for(i=0; i < 256; i++) {
2609 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2613 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2616 This->palette = PalImpl;
2618 return IWineD3DSurface_RealizePalette(iface);
2621 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2622 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2623 BOOL dirtify = FALSE;
2624 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
2626 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2627 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
2628 return DDERR_INVALIDPARAMS;
2631 /* Dirtify the surface, but only if a key was changed */
2633 switch (Flags & ~DDCKEY_COLORSPACE) {
2634 case DDCKEY_DESTBLT:
2635 if(!(This->CKeyFlags & DDSD_CKDESTBLT)) {
2638 dirtify = memcmp(&This->DestBltCKey, CKey, sizeof(*CKey) ) != 0;
2640 This->DestBltCKey = *CKey;
2641 This->CKeyFlags |= DDSD_CKDESTBLT;
2644 case DDCKEY_DESTOVERLAY:
2645 if(!(This->CKeyFlags & DDSD_CKDESTOVERLAY)) {
2648 dirtify = memcmp(&This->DestOverlayCKey, CKey, sizeof(*CKey)) != 0;
2650 This->DestOverlayCKey = *CKey;
2651 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2654 case DDCKEY_SRCOVERLAY:
2655 if(!(This->CKeyFlags & DDSD_CKSRCOVERLAY)) {
2658 dirtify = memcmp(&This->SrcOverlayCKey, CKey, sizeof(*CKey)) != 0;
2660 This->SrcOverlayCKey = *CKey;
2661 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2665 if(!(This->CKeyFlags & DDSD_CKSRCBLT)) {
2668 dirtify = memcmp(&This->SrcBltCKey, CKey, sizeof(*CKey)) != 0;
2670 This->SrcBltCKey = *CKey;
2671 This->CKeyFlags |= DDSD_CKSRCBLT;
2676 switch (Flags & ~DDCKEY_COLORSPACE) {
2677 case DDCKEY_DESTBLT:
2678 dirtify = This->CKeyFlags & DDSD_CKDESTBLT;
2679 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2682 case DDCKEY_DESTOVERLAY:
2683 dirtify = This->CKeyFlags & DDSD_CKDESTOVERLAY;
2684 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2687 case DDCKEY_SRCOVERLAY:
2688 dirtify = This->CKeyFlags & DDSD_CKSRCOVERLAY;
2689 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2693 dirtify = This->CKeyFlags & DDSD_CKSRCBLT;
2694 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2700 TRACE("Color key changed, dirtifying surface\n");
2701 This->Flags |= SFLAG_DIRTY;
2707 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2708 /** Check against the maximum texture sizes supported by the video card **/
2709 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2711 TRACE("%p\n", This);
2712 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2713 /* one of three options
2714 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)
2715 2: Set the texture to the maxium size (bad idea)
2716 3: WARN and return WINED3DERR_NOTAVAILABLE;
2717 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.
2719 WARN("(%p) Creating an oversized surface\n", This);
2720 This->Flags |= SFLAG_OVERSIZE;
2722 /* This will be initialized on the first blt */
2723 This->glRect.left = 0;
2724 This->glRect.top = 0;
2725 This->glRect.right = 0;
2726 This->glRect.bottom = 0;
2728 /* No oversize, gl rect is the full texture size */
2729 This->Flags &= ~SFLAG_OVERSIZE;
2730 This->glRect.left = 0;
2731 This->glRect.top = 0;
2732 This->glRect.right = This->pow2Width;
2733 This->glRect.bottom = This->pow2Height;
2739 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
2740 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2742 TRACE("(%p)\n", This);
2744 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
2745 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
2746 ie pitch = (width/4) * bytes per block */
2747 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
2748 ret = (This->currentDesc.Width >> 2) << 3;
2749 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
2750 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
2751 ret = (This->currentDesc.Width >> 2) << 4;
2753 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2754 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
2755 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
2757 ret = This->bytesPerPixel * This->pow2Width;
2760 TRACE("(%p) Returning %ld\n", This, ret);
2764 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
2767 IWineD3DSurfaceImpl_QueryInterface,
2768 IWineD3DSurfaceImpl_AddRef,
2769 IWineD3DSurfaceImpl_Release,
2770 /* IWineD3DResource */
2771 IWineD3DSurfaceImpl_GetParent,
2772 IWineD3DSurfaceImpl_GetDevice,
2773 IWineD3DSurfaceImpl_SetPrivateData,
2774 IWineD3DSurfaceImpl_GetPrivateData,
2775 IWineD3DSurfaceImpl_FreePrivateData,
2776 IWineD3DSurfaceImpl_SetPriority,
2777 IWineD3DSurfaceImpl_GetPriority,
2778 IWineD3DSurfaceImpl_PreLoad,
2779 IWineD3DSurfaceImpl_GetType,
2780 /* IWineD3DSurface */
2781 IWineD3DSurfaceImpl_GetContainerParent,
2782 IWineD3DSurfaceImpl_GetContainer,
2783 IWineD3DSurfaceImpl_GetDesc,
2784 IWineD3DSurfaceImpl_LockRect,
2785 IWineD3DSurfaceImpl_UnlockRect,
2786 IWineD3DSurfaceImpl_GetDC,
2787 IWineD3DSurfaceImpl_ReleaseDC,
2788 IWineD3DSurfaceImpl_Flip,
2789 IWineD3DSurfaceImpl_Blt,
2790 IWineD3DSurfaceImpl_GetBltStatus,
2791 IWineD3DSurfaceImpl_GetFlipStatus,
2792 IWineD3DSurfaceImpl_IsLost,
2793 IWineD3DSurfaceImpl_Restore,
2794 IWineD3DSurfaceImpl_BltFast,
2795 IWineD3DSurfaceImpl_GetPalette,
2796 IWineD3DSurfaceImpl_SetPalette,
2797 IWineD3DSurfaceImpl_RealizePalette,
2798 IWineD3DSurfaceImpl_SetColorKey,
2799 IWineD3DSurfaceImpl_GetPitch,
2801 IWineD3DSurfaceImpl_CleanDirtyRect,
2802 IWineD3DSurfaceImpl_AddDirtyRect,
2803 IWineD3DSurfaceImpl_LoadTexture,
2804 IWineD3DSurfaceImpl_SaveSnapshot,
2805 IWineD3DSurfaceImpl_SetContainer,
2806 IWineD3DSurfaceImpl_SetPBufferState,
2807 IWineD3DSurfaceImpl_SetGlTextureDesc,
2808 IWineD3DSurfaceImpl_GetGlDesc,
2809 IWineD3DSurfaceImpl_GetData,
2810 IWineD3DSurfaceImpl_SetFormat,
2811 IWineD3DSurfaceImpl_PrivateSetup