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) {
771 GLint prev_depth_test;
772 GLint prev_rasterpos[4];
774 /* Some drivers(radeon dri, others?) don't like exceptions during
775 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
776 * after ReleaseDC. Reading it will cause an exception, which x11drv will
777 * catch to put the dib section in InSync mode, which leads to a crash
778 * and a blocked x server on my radeon card.
780 * The following lines read the dib section so it is put in inSync mode
781 * before glDrawPixels is called and the crash is prevented. There won't
782 * be any interfering gdi accesses, because UnlockRect is called from
783 * ReleaseDC, and the app won't use the dc any more afterwards.
785 if(This->Flags & SFLAG_DIBSECTION) {
787 read = This->resource.allocatedMemory[0];
793 vcheckGLcall("glFlush");
794 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
795 vcheckGLcall("glIntegerv");
796 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
797 vcheckGLcall("glIntegerv");
798 glPixelZoom(1.0, -1.0);
799 vcheckGLcall("glPixelZoom");
800 prev_depth_test = glIsEnabled(GL_DEPTH_TEST);
802 /* glDrawPixels transforms the raster position as though it was a vertex -
803 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
804 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
805 d3ddevice_set_ortho(This->resource.wineD3DDevice);
807 if (iface == implSwapChain->frontBuffer) {
808 glDrawBuffer(GL_FRONT);
809 checkGLcall("glDrawBuffer GL_FRONT");
810 } else if (backbuf || iface == myDevice->renderTarget) {
811 glDrawBuffer(GL_BACK);
812 checkGLcall("glDrawBuffer GL_BACK");
815 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
816 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
817 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
819 /* And back buffers are not blended */
821 glDisable(GL_DEPTH_TEST);
823 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
824 vcheckGLcall("glRasterPos2f");
826 switch (This->resource.format) {
827 case WINED3DFMT_X4R4G4B4:
830 unsigned short *data;
831 data = (unsigned short *)This->resource.allocatedMemory;
832 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
839 case WINED3DFMT_A4R4G4B4:
841 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
842 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
843 vcheckGLcall("glDrawPixels");
846 case WINED3DFMT_R5G6B5:
848 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
849 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
850 vcheckGLcall("glDrawPixels");
853 case WINED3DFMT_X1R5G5B5:
856 unsigned short *data;
857 data = (unsigned short *)This->resource.allocatedMemory;
858 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
865 case WINED3DFMT_A1R5G5B5:
867 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
868 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
869 vcheckGLcall("glDrawPixels");
872 case WINED3DFMT_R8G8B8:
874 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
875 GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
876 vcheckGLcall("glDrawPixels");
879 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
880 could be any random value this fixes the intro move in Pirates! */
884 data = (unsigned int *)This->resource.allocatedMemory;
885 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
892 case WINED3DFMT_A8R8G8B8:
894 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
895 vcheckGLcall("glPixelStorei");
896 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
897 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
898 vcheckGLcall("glDrawPixels");
899 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
900 vcheckGLcall("glPixelStorei");
903 case WINED3DFMT_A2R10G10B10:
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_INT_2_10_10_10_REV, This->resource.allocatedMemory);
909 vcheckGLcall("glDrawPixels");
910 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
911 vcheckGLcall("glPixelStorei");
915 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
918 glPixelZoom(1.0,1.0);
919 vcheckGLcall("glPixelZoom");
920 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
921 glDrawBuffer(GL_BACK);
922 vcheckGLcall("glDrawBuffer");
924 glRasterPos3iv(&prev_rasterpos[0]);
925 vcheckGLcall("glRasterPos3iv");
926 if(prev_depth_test) glEnable(GL_DEPTH_TEST);
928 /* Reset to previous pack row length / blending state */
929 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
930 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
934 /** restore clean dirty state */
935 IWineD3DSurface_CleanDirtyRect(iface);
938 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
940 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
942 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
944 if (iface == myDevice->depthStencilBuffer) {
945 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
947 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
951 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
955 This->Flags &= ~SFLAG_LOCKED;
956 memset(&This->lockedRect, 0, sizeof(RECT));
960 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
961 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
962 WINED3DLOCKED_RECT lock;
969 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
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] = formatEntry->redMask;
1053 masks[1] = formatEntry->greenMask;
1054 masks[2] = formatEntry->blueMask;
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);
1189 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1191 /* Default values: From the surface */
1192 *format = formatEntry->glFormat;
1193 *internal = formatEntry->glInternal;
1194 *type = formatEntry->glType;
1195 *convert = NO_CONVERSION;
1196 *target_bpp = This->bytesPerPixel;
1198 /* Ok, now look if we have to do any conversion */
1199 switch(This->resource.format) {
1204 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active) {
1206 *internal = GL_RGBA;
1207 *type = GL_UNSIGNED_BYTE;
1209 if(colorkey_active) {
1210 *convert = CONVERT_PALETTED;
1212 *convert = CONVERT_PALETTED_CK;
1218 case WINED3DFMT_R3G3B2:
1219 /* **********************
1220 GL_UNSIGNED_BYTE_3_3_2
1221 ********************** */
1222 if (colorkey_active) {
1223 /* This texture format will never be used.. So do not care about color keying
1224 up until the point in time it will be needed :-) */
1225 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1229 case WINED3DFMT_R5G6B5:
1230 if (colorkey_active) {
1231 *convert = CONVERT_CK_565;
1233 *internal = GL_RGBA;
1234 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1238 case WINED3DFMT_R8G8B8:
1239 if (colorkey_active) {
1240 *convert = CONVERT_CK_RGB24;
1242 *internal = GL_RGBA;
1243 *type = GL_UNSIGNED_INT_8_8_8_8;
1248 case WINED3DFMT_X8R8G8B8:
1249 if (colorkey_active) {
1250 *convert = CONVERT_RGB32_888;
1252 *internal = GL_RGBA;
1253 *type = GL_UNSIGNED_INT_8_8_8_8;
1257 /* Not sure if we should do color keying on Alpha-Enabled surfaces */
1258 case WINED3DFMT_A4R4G4B4:
1259 if (colorkey_active)
1261 *convert = CONVERT_CK_4444_ARGB;
1263 *internal = GL_RGBA;
1264 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1268 case WINED3DFMT_A1R5G5B5:
1269 if (colorkey_active)
1271 *convert = CONVERT_CK_1555;
1274 case WINED3DFMT_A8R8G8B8:
1275 if (colorkey_active)
1277 *convert = CONVERT_CK_8888_ARGB;
1279 *internal = GL_RGBA;
1280 *type = GL_UNSIGNED_INT_8_8_8_8;
1291 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1292 TRACE("(%p)->(%p),(%ld,%d,%p)\n", src, dst, len, convert, surf);
1297 memcpy(dst, src, len * surf->bytesPerPixel);
1300 case CONVERT_PALETTED:
1301 case CONVERT_PALETTED_CK:
1303 IWineD3DPaletteImpl* pal = surf->palette;
1309 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1313 /* Still no palette? Use the device's palette */
1314 /* Get the surface's palette */
1315 for (i = 0; i < 256; i++) {
1316 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1318 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1319 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1320 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1321 if ((convert == CONVERT_PALETTED_CK) &&
1322 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1323 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1324 /* We should maybe here put a more 'neutral' color than the standard bright purple
1325 one often used by application to prevent the nice purple borders when bi-linear
1333 TRACE("Using surface palette %p\n", pal);
1334 /* Get the surface's palette */
1335 for (i = 0; i < 256; i++) {
1336 table[i][0] = pal->palents[i].peRed;
1337 table[i][1] = pal->palents[i].peGreen;
1338 table[i][2] = pal->palents[i].peBlue;
1339 if ((convert == CONVERT_PALETTED_CK) &&
1340 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1341 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1342 /* We should maybe here put a more 'neutral' color than the standard bright purple
1343 one often used by application to prevent the nice purple borders when bi-linear
1352 for (x = 0; x < len; x++) {
1353 BYTE color = *src++;
1354 *dst++ = table[color][0];
1355 *dst++ = table[color][1];
1356 *dst++ = table[color][2];
1357 *dst++ = table[color][3];
1362 case CONVERT_CK_565:
1364 /* Converting the 565 format in 5551 packed to emulate color-keying.
1366 Note : in all these conversion, it would be best to average the averaging
1367 pixels to get the color of the pixel that will be color-keyed to
1368 prevent 'color bleeding'. This will be done later on if ever it is
1371 Note2: when using color-keying + alpha, are the alpha bits part of the
1372 color-space or not ?
1375 WORD *Source = (WORD *) src;
1376 WORD *Dest = (WORD *) dst;
1378 TRACE("Color keyed 565\n");
1380 for (x = 0; x < len; x++ ) {
1381 WORD color = *Source++;
1382 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1383 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1384 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1392 case CONVERT_CK_1555:
1395 WORD *Source = (WORD *) src;
1396 WORD *Dest = (WORD *) dst;
1398 for (x = 0; x < len * sizeof(WORD); x+=sizeof(WORD)) {
1399 WORD color = *Source++;
1400 *Dest = (color & 0x7FFF);
1401 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1402 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1403 *Dest |= (color & 0x8000);
1409 case CONVERT_CK_4444_ARGB:
1411 /* Move the four Alpha bits... */
1413 WORD *Source = (WORD *) src;
1414 WORD *Dest = (WORD *) dst;
1416 for (x = 0; x < len; x++) {
1417 WORD color = *Source++;
1418 *dst = (color & 0x0FFF) << 4;
1419 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1420 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1421 *Dest |= (color & 0xF000) >> 12;
1427 ERR("Unsupported conversation type %d\n", convert);
1433 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1434 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1436 if (This->Flags & SFLAG_INTEXTURE) {
1437 TRACE("Surface already in texture\n");
1440 if (!(This->Flags & SFLAG_DIRTY)) {
1441 TRACE("surface isn't dirty\n");
1445 This->Flags &= ~SFLAG_DIRTY;
1447 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1448 * These resources are not bound by device size or format restrictions. Because of this,
1449 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1450 * However, these resources can always be created, locked, and copied.
1452 if (This->resource.pool == WINED3DPOOL_SCRATCH)
1454 FIXME("(%p) Operation not supported for scratch textures\n",This);
1455 return WINED3DERR_INVALIDCALL;
1458 if (This->Flags & SFLAG_INPBUFFER) {
1461 if (This->glDescription.level != 0)
1462 FIXME("Surface in texture is only supported for level 0\n");
1463 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1464 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1465 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1466 This->resource.format == WINED3DFMT_DXT5)
1467 FIXME("Format %d not supported\n", This->resource.format);
1470 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1471 vcheckGLcall("glGetIntegerv");
1472 glReadBuffer(GL_BACK);
1473 vcheckGLcall("glReadBuffer");
1475 glCopyTexImage2D(This->glDescription.target,
1476 This->glDescription.level,
1477 This->glDescription.glFormatInternal,
1480 This->currentDesc.Width,
1481 This->currentDesc.Height,
1484 checkGLcall("glCopyTexImage2D");
1485 glReadBuffer(prevRead);
1486 vcheckGLcall("glReadBuffer");
1487 TRACE("Updating target %d\n", This->glDescription.target);
1488 This->Flags |= SFLAG_INTEXTURE;
1494 /* TODO: Compressed non-power 2 support */
1496 if (This->resource.format == WINED3DFMT_DXT1 ||
1497 This->resource.format == WINED3DFMT_DXT2 ||
1498 This->resource.format == WINED3DFMT_DXT3 ||
1499 This->resource.format == WINED3DFMT_DXT4 ||
1500 This->resource.format == WINED3DFMT_DXT5) {
1501 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1502 FIXME("Using DXT1/3/5 without advertized support\n");
1503 } else if (This->resource.allocatedMemory) {
1504 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1505 This->glDescription.target,
1506 This->glDescription.level,
1507 This->glDescription.glFormatInternal,
1508 This->currentDesc.Width,
1509 This->currentDesc.Height,
1511 This->resource.size,
1512 This->resource.allocatedMemory);
1516 GL_EXTCALL(glCompressedTexImage2DARB)(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);
1524 checkGLcall("glCommpressedTexImage2D");
1528 if(!(This->Flags & SFLAG_DONOTFREE)){
1529 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1530 This->resource.allocatedMemory = NULL;
1534 GLenum format, internal, type;
1535 CONVERT_TYPES convert;
1539 d3dfmt_get_conv(This, TRUE /* We need color keying */, &format, &internal, &type, &convert, &bpp);
1541 if((convert != NO_CONVERSION) &&
1542 This->resource.allocatedMemory) {
1543 int width = This->glRect.right - This->glRect.left;
1544 int height = This->glRect.bottom - This->glRect.top;
1547 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
1549 ERR("Out of memory %d, %d!\n", width, height);
1550 return WINED3DERR_OUTOFVIDEOMEMORY;
1553 for(row = This->glRect.top; row < This->glRect.bottom; row++) {
1554 BYTE *cur = This->resource.allocatedMemory + row * This->pow2Width * This->bytesPerPixel;
1555 d3dfmt_convert_surface(cur + This->glRect.left * This->bytesPerPixel,
1556 mem + row * width * bpp,
1561 This->Flags |= SFLAG_CONVERTED;
1563 This->Flags &= ~SFLAG_CONVERTED;
1564 mem = This->resource.allocatedMemory;
1567 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1568 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE) ) {
1571 TRACE("non power of two support\n");
1573 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,
1574 This->glDescription.target,
1575 This->glDescription.level,
1576 debug_d3dformat(This->resource.format),
1577 This->glDescription.glFormatInternal,
1581 This->glDescription.glFormat,
1582 This->glDescription.glType,
1585 glTexImage2D(This->glDescription.target,
1586 This->glDescription.level,
1587 This->glDescription.glFormatInternal,
1591 This->glDescription.glFormat,
1592 This->glDescription.glType,
1595 checkGLcall("glTexImage2D");
1596 if (This->resource.allocatedMemory != NULL) {
1597 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1598 /* And map the non-power two data into the top left corner */
1600 This->glDescription.target,
1601 This->glDescription.level,
1604 This->currentDesc.Width,
1605 This->currentDesc.Height,
1606 This->glDescription.glFormat,
1607 This->glDescription.glType,
1608 This->resource.allocatedMemory
1610 checkGLcall("glTexSubImage2D");
1616 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%ld, h=%ld,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1617 This->glDescription.target,
1618 This->glDescription.level,
1619 debug_d3dformat(This->resource.format),
1620 This->glDescription.glFormatInternal,
1621 This->glRect.right - This->glRect.left,
1622 This->glRect.bottom - This->glRect.top,
1624 This->glDescription.glFormat,
1625 This->glDescription.glType,
1630 /* OK, create the texture */
1631 glTexImage2D(This->glDescription.target,
1632 This->glDescription.level,
1634 This->glRect.right - This->glRect.left,
1635 This->glRect.bottom - This->glRect.top,
1641 checkGLcall("glTexImage2D");
1645 if(mem != This->resource.allocatedMemory)
1646 HeapFree(GetProcessHeap(), 0, mem);
1650 static unsigned int gen = 0;
1653 if ((gen % 10) == 0) {
1654 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1655 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1658 * debugging crash code
1666 if(!(This->Flags & SFLAG_DONOTFREE)){
1667 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1668 This->resource.allocatedMemory = NULL;
1678 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1681 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1682 char *allocatedMemory;
1684 IWineD3DSwapChain *swapChain = NULL;
1689 Textures my not be stored in ->allocatedgMemory and a GlTexture
1690 so we should lock the surface before saving a snapshot, or at least check that
1692 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1693 by calling GetTexImage and in compressed form by calling
1694 GetCompressedTexImageARB. Queried compressed images can be saved and
1695 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1696 texture images do not need to be processed by the GL and should
1697 significantly improve texture loading performance relative to uncompressed
1700 /* Setup the width and height to be the internal texture width and height. */
1701 width = This->pow2Width;
1702 height = This->pow2Height;
1703 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1704 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1706 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1707 /* 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 */
1710 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1711 glEnable(GL_TEXTURE_2D);
1713 glGenTextures(1, &tmpTexture);
1714 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1716 glTexImage2D(GL_TEXTURE_2D,
1723 GL_UNSIGNED_INT_8_8_8_8_REV,
1726 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1727 vcheckGLcall("glGetIntegerv");
1728 glReadBuffer(GL_BACK);
1729 vcheckGLcall("glReadBuffer");
1730 glCopyTexImage2D(GL_TEXTURE_2D,
1739 checkGLcall("glCopyTexImage2D");
1740 glReadBuffer(prevRead);
1743 } else { /* bind the real texture */
1744 IWineD3DSurface_PreLoad(iface);
1746 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1748 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1749 glGetTexImage(GL_TEXTURE_2D,
1750 This->glDescription.level,
1752 GL_UNSIGNED_INT_8_8_8_8_REV,
1754 checkGLcall("glTexImage2D");
1756 glBindTexture(GL_TEXTURE_2D, 0);
1757 glDeleteTextures(1, &tmpTexture);
1761 f = fopen(filename, "w+");
1763 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1764 return WINED3DERR_INVALIDCALL;
1766 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1767 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1782 fwrite(&width,2,1,f);
1784 fwrite(&height,2,1,f);
1789 /* 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*/
1791 textureRow = allocatedMemory + (width * (height - 1) *4);
1793 textureRow = allocatedMemory;
1794 for (y = 0 ; y < height; y++) {
1795 for (i = 0; i < width; i++) {
1796 color = *((DWORD*)textureRow);
1797 fputc((color >> 16) & 0xFF, f); /* B */
1798 fputc((color >> 8) & 0xFF, f); /* G */
1799 fputc((color >> 0) & 0xFF, f); /* R */
1800 fputc((color >> 24) & 0xFF, f); /* A */
1803 /* take two rows of the pointer to the texture memory */
1805 (textureRow-= width << 3);
1808 TRACE("Closing file\n");
1812 IWineD3DSwapChain_Release(swapChain);
1814 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1818 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1819 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1820 This->Flags &= ~SFLAG_DIRTY;
1821 This->dirtyRect.left = This->currentDesc.Width;
1822 This->dirtyRect.top = This->currentDesc.Height;
1823 This->dirtyRect.right = 0;
1824 This->dirtyRect.bottom = 0;
1825 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1826 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1831 * Slightly inefficient way to handle multiple dirty rects but it works :)
1833 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1834 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1835 IWineD3DBaseTexture *baseTexture = NULL;
1836 This->Flags |= SFLAG_DIRTY;
1837 if (NULL != pDirtyRect) {
1838 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1839 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1840 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1841 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1843 This->dirtyRect.left = 0;
1844 This->dirtyRect.top = 0;
1845 This->dirtyRect.right = This->currentDesc.Width;
1846 This->dirtyRect.bottom = This->currentDesc.Height;
1848 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
1849 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1850 /* if the container is a basetexture then mark it dirty. */
1851 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1852 TRACE("Passing to conatiner\n");
1853 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1854 IWineD3DBaseTexture_Release(baseTexture);
1859 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1860 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1862 TRACE("This %p, container %p\n", This, container);
1864 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1866 TRACE("Setting container to %p from %p\n", container, This->container);
1867 This->container = container;
1872 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1873 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1874 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
1876 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1877 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1878 return WINED3DERR_INVALIDCALL;
1881 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1882 if (format == WINED3DFMT_UNKNOWN) {
1883 This->resource.size = 0;
1884 } else if (format == WINED3DFMT_DXT1) {
1885 /* DXT1 is half byte per pixel */
1886 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
1888 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1889 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1890 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
1892 This->resource.size = (This->pow2Width * formatEntry->bpp) * This->pow2Height;
1896 /* Setup some glformat defaults */
1897 This->glDescription.glFormat = formatEntry->glFormat;
1898 This->glDescription.glFormatInternal = formatEntry->glInternal;
1899 This->glDescription.glType = formatEntry->glType;
1901 if (format != WINED3DFMT_UNKNOWN) {
1902 This->bytesPerPixel = formatEntry->bpp;
1903 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1905 This->bytesPerPixel = 0;
1909 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
1911 This->resource.format = format;
1913 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);
1918 /* TODO: replace this function with context management routines */
1919 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1920 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1923 This->Flags |= SFLAG_INPBUFFER;
1925 This->Flags &= ~SFLAG_INPBUFFER;
1929 This->Flags |= SFLAG_INTEXTURE;
1931 This->Flags &= ~SFLAG_INTEXTURE;
1937 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
1938 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1939 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
1940 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
1942 /* Flipping is only supported on RenderTargets */
1943 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
1946 /* DDraw sets this for the X11 surfaces, so don't confuse the user
1947 * FIXME("(%p) Target override is not supported by now\n", This);
1948 * Additionally, it isn't really possible to support triple-buffering
1949 * properly on opengl at all
1953 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
1954 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
1957 /* Not called from the VTable */
1958 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
1960 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1961 IWineD3DSwapChainImpl *swapchain = NULL;
1962 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
1965 TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
1967 /* Get the swapchain. One of the surfaces has to be a primary surface */
1968 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
1969 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1971 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
1972 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1973 else return WINED3DERR_INVALIDCALL;
1979 rect.x1 = DestRect->left;
1980 rect.y1 = DestRect->top;
1981 rect.x2 = DestRect->right;
1982 rect.y2 = DestRect->bottom;
1986 rect.x2 = This->currentDesc.Width;
1987 rect.y2 = This->currentDesc.Height;
1990 /* Half-life does a Blt from the back buffer to the front buffer,
1991 * Full surface size, no flags... Use present instead
1995 /* First, check if we can do a Flip */
1997 /* Check rects - IWineD3DDevice_Present doesn't handle them */
1999 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2000 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2007 /* Check the Destination rect and the surface sizes */
2009 (rect.x1 == 0) && (rect.y1 == 0) &&
2010 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2011 (This->currentDesc.Width == Src->currentDesc.Width) &&
2012 (This->currentDesc.Height == Src->currentDesc.Height)) {
2013 /* These flags are unimportant for the flag check, remove them */
2015 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2016 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2018 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2020 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2021 * take very long, while a flip is fast.
2022 * This applies to Half-Life, which does such Blts every time it finished
2023 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2024 * menu. This is also used by all apps when they do windowed rendering
2026 * The problem is that flipping is not really the same as copying. After a
2027 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2028 * untouched. Therefore it's necessary to override the swap effect
2029 * and to set it back after the flip.
2032 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2034 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2035 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2036 NULL, NULL, 0, NULL);
2038 swapchain->presentParms.SwapEffect = orig_swap;
2045 /* Blt from texture to rendertarget? */
2046 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2047 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2049 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2050 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2051 float glTexCoord[4];
2053 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2057 RECT SourceRectangle;
2060 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2063 SourceRectangle.left = SrcRect->left;
2064 SourceRectangle.right = SrcRect->right;
2065 SourceRectangle.top = SrcRect->top;
2066 SourceRectangle.bottom = SrcRect->bottom;
2068 SourceRectangle.left = 0;
2069 SourceRectangle.right = Src->currentDesc.Width;
2070 SourceRectangle.top = 0;
2071 SourceRectangle.bottom = Src->currentDesc.Height;
2074 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2075 /* Fall back to software */
2076 WARN("(%p) Source texture area (%ld,%ld)-(%ld,%ld) is too big\n", Src,
2077 SourceRectangle.left, SourceRectangle.top,
2078 SourceRectangle.right, SourceRectangle.bottom);
2079 return WINED3DERR_INVALIDCALL;
2082 /* Color keying: Check if we have to do a color keyed blt,
2083 * and if not check if a color key is activated.
2085 oldCKey = Src->CKeyFlags;
2086 if(!(Flags & DDBLT_KEYSRC) &&
2087 Src->CKeyFlags & DDSD_CKSRCBLT) {
2088 /* Ok, the surface has a color key, but we shall not use it -
2089 * Deactivate it for now and dirtify the surface to reload it
2091 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2092 Src->Flags |= SFLAG_DIRTY;
2095 /* Now load the surface */
2096 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2100 /* Save all the old stuff until we have a proper opengl state manager */
2101 oldLight = glIsEnabled(GL_LIGHTING);
2102 oldFog = glIsEnabled(GL_FOG);
2103 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2104 oldBlend = glIsEnabled(GL_BLEND);
2105 oldCull = glIsEnabled(GL_CULL_FACE);
2106 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2107 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2109 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2110 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2111 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2112 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2114 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2115 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2116 TRACE("Drawing to front buffer\n");
2117 glDrawBuffer(GL_FRONT);
2118 checkGLcall("glDrawBuffer GL_FRONT");
2121 /* Unbind the old texture */
2122 glBindTexture(GL_TEXTURE_2D, 0);
2124 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2125 /* We use texture unit 0 for blts */
2126 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2127 checkGLcall("glActiveTextureARB");
2129 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2132 /* Disable some fancy graphics effects */
2133 glDisable(GL_LIGHTING);
2134 checkGLcall("glDisable GL_LIGHTING");
2135 glDisable(GL_DEPTH_TEST);
2136 checkGLcall("glDisable GL_DEPTH_TEST");
2138 checkGLcall("glDisable GL_FOG");
2139 glDisable(GL_BLEND);
2140 checkGLcall("glDisable GL_BLEND");
2141 glDisable(GL_CULL_FACE);
2142 checkGLcall("glDisable GL_CULL_FACE");
2143 glDisable(GL_STENCIL_TEST);
2144 checkGLcall("glDisable GL_STENCIL_TEST");
2146 /* Ok, we need 2d textures, but not 1D or 3D */
2147 glDisable(GL_TEXTURE_1D);
2148 checkGLcall("glDisable GL_TEXTURE_1D");
2149 glEnable(GL_TEXTURE_2D);
2150 checkGLcall("glEnable GL_TEXTURE_2D");
2151 glDisable(GL_TEXTURE_3D);
2152 checkGLcall("glDisable GL_TEXTURE_3D");
2154 /* Bind the texture */
2155 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2156 checkGLcall("glBindTexture");
2158 glEnable(GL_SCISSOR_TEST);
2160 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2162 /* No filtering for blts */
2163 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2165 checkGLcall("glTexParameteri");
2166 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2168 checkGLcall("glTexParameteri");
2169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2170 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2171 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2172 checkGLcall("glTexEnvi");
2174 /* This is for color keying */
2175 if(Flags & DDBLT_KEYSRC) {
2176 glEnable(GL_ALPHA_TEST);
2177 checkGLcall("glEnable GL_ALPHA_TEST");
2178 glAlphaFunc(GL_NOTEQUAL, 0.0);
2179 checkGLcall("glAlphaFunc\n");
2181 glDisable(GL_ALPHA_TEST);
2182 checkGLcall("glDisable GL_ALPHA_TEST");
2185 /* Draw a textured quad
2187 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2191 glColor3d(1.0f, 1.0f, 1.0f);
2192 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2197 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2198 glVertex3f(rect.x1, rect.y2, 0.0);
2200 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2205 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2210 checkGLcall("glEnd");
2212 /* Unbind the texture */
2213 glBindTexture(GL_TEXTURE_2D, 0);
2214 checkGLcall("glEnable glBindTexture");
2216 /* Restore the old settings */
2218 glEnable(GL_LIGHTING);
2219 checkGLcall("glEnable GL_LIGHTING");
2223 checkGLcall("glEnable GL_FOG");
2226 glEnable(GL_DEPTH_TEST);
2227 checkGLcall("glEnable GL_DEPTH_TEST");
2231 checkGLcall("glEnable GL_BLEND");
2234 glEnable(GL_CULL_FACE);
2235 checkGLcall("glEnable GL_CULL_FACE");
2238 glEnable(GL_STENCIL_TEST);
2239 checkGLcall("glEnable GL_STENCIL_TEST");
2242 glDisable(GL_ALPHA_TEST);
2243 checkGLcall("glDisable GL_ALPHA_TEST");
2245 glEnable(GL_ALPHA_TEST);
2246 checkGLcall("glEnable GL_ALPHA_TEST");
2249 glAlphaFunc(alphafunc, alpharef);
2250 checkGLcall("glAlphaFunc\n");
2252 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2253 glDrawBuffer(oldDraw);
2256 /* Restore the color key */
2257 if(oldCKey != Src->CKeyFlags) {
2258 Src->CKeyFlags = oldCKey;
2259 Src->Flags |= SFLAG_DIRTY;
2264 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2265 This->Flags |= SFLAG_GLDIRTY;
2271 /* Blt from rendertarget to texture? */
2272 if( (SrcSurface == swapchain->frontBuffer) ||
2273 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2274 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2275 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2280 TRACE("Blt from rendertarget to texture\n");
2282 /* Call preload for the surface to make sure it isn't dirty */
2283 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2286 srect.x1 = SrcRect->left;
2287 srect.y1 = SrcRect->top;
2288 srect.x2 = SrcRect->right;
2289 srect.y2 = SrcRect->bottom;
2293 srect.x2 = Src->currentDesc.Width;
2294 srect.y2 = Src->currentDesc.Height;
2299 /* Bind the target texture */
2300 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2301 checkGLcall("glBindTexture");
2302 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2303 glReadBuffer(GL_BACK);
2305 glReadBuffer(GL_FRONT);
2307 checkGLcall("glReadBuffer");
2309 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2310 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2312 /* I have to process this row by row to swap the image,
2313 * otherwise it would be upside down, so streching in y direction
2314 * doesn't cost extra time
2316 * However, streching in x direction can be avoided if not necessary
2318 for(row = rect.y1; row < rect.y2; row++) {
2319 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2320 /* Well, that stuff works, but it's very slow.
2321 * find a better way instead
2324 for(col = rect.x1; col < rect.x2; col++) {
2325 glCopyTexSubImage2D(GL_TEXTURE_2D,
2327 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2328 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2332 glCopyTexSubImage2D(GL_TEXTURE_2D,
2334 rect.x1, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2335 srect.x1, Src->currentDesc.Height - srect.y2 + row * yrel,
2340 vcheckGLcall("glCopyTexSubImage2D");
2343 if(!(This->Flags & SFLAG_DONOTFREE)) {
2344 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2345 This->resource.allocatedMemory = NULL;
2347 This->Flags |= SFLAG_GLDIRTY;
2355 if (Flags & DDBLT_COLORFILL) {
2356 /* This is easy to handle for the D3D Device... */
2358 IWineD3DSwapChainImpl *implSwapChain;
2360 TRACE("Colorfill\n");
2362 /* The color as given in the Blt function is in the format of the frame-buffer...
2363 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2365 if (This->resource.format == WINED3DFMT_P8) {
2366 if (This->palette) {
2367 color = ((0xFF000000) |
2368 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2369 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2370 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2375 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2376 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2379 color = ((0xFF000000) |
2380 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2381 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2382 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2385 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2386 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2387 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2389 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2390 color = DDBltFx->u5.dwFillColor;
2393 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2394 return WINED3DERR_INVALIDCALL;
2397 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2398 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2399 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2400 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2401 glDrawBuffer(GL_BACK);
2402 checkGLcall("glDrawBuffer(GL_BACK)");
2404 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2405 glDrawBuffer(GL_FRONT);
2406 checkGLcall("glDrawBuffer(GL_FRONT)");
2409 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2410 return WINED3DERR_INVALIDCALL;
2413 TRACE("(%p) executing Render Target override, color = %lx\n", This, color);
2415 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2416 1 /* Number of rectangles */,
2423 /* Restore the original draw buffer */
2424 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2425 glDrawBuffer(GL_BACK);
2426 vcheckGLcall("glDrawBuffer");
2432 /* Default: Fall back to the generic blt */
2433 return WINED3DERR_INVALIDCALL;
2436 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2437 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2438 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2439 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2440 TRACE("(%p): Usage is %08lx\n", This, This->resource.usage);
2442 /* Special cases for RenderTargets */
2443 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2444 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2445 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2448 /* For the rest call the X11 surface implementation.
2449 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2450 * other Blts are rather rare
2452 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2455 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2456 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2457 TRACE("(%p)->(%lx)\n", This, Flags);
2462 case DDGBS_ISBLTDONE:
2466 return DDERR_INVALIDPARAMS;
2470 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2471 /* XXX: DDERR_INVALIDSURFACETYPE */
2473 TRACE("(%p)->(%08lx)\n",iface,Flags);
2476 case DDGFS_ISFLIPDONE:
2480 return DDERR_INVALIDPARAMS;
2484 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2485 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2486 TRACE("(%p)\n", This);
2488 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2491 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2492 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2493 TRACE("(%p)\n", This);
2495 /* So far we don't lose anything :) */
2496 This->Flags &= ~SFLAG_LOST;
2500 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2501 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2502 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2503 TRACE("(%p)->(%ld, %ld, %p, %p, %08lx\n", iface, dstx, dsty, Source, rsrc, trans);
2505 /* Special cases for RenderTargets */
2506 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2507 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2509 RECT SrcRect, DstRect;
2512 SrcRect.left = rsrc->left;
2513 SrcRect.top= rsrc->top;
2514 SrcRect.bottom = rsrc->bottom;
2515 SrcRect.right = rsrc->right;
2519 SrcRect.right = srcImpl->currentDesc.Width;
2520 SrcRect.bottom = srcImpl->currentDesc.Height;
2523 DstRect.left = dstx;
2525 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2526 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2528 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, 0, NULL) == WINED3D_OK) return WINED3D_OK;
2532 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2535 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2536 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2537 TRACE("(%p)->(%p)\n", This, Pal);
2539 *Pal = (IWineD3DPalette *) This->palette;
2543 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2544 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2546 IWineD3DPaletteImpl *pal = This->palette;
2548 TRACE("(%p)\n", This);
2550 if(This->resource.format == WINED3DFMT_P8 ||
2551 This->resource.format == WINED3DFMT_A8P8)
2553 TRACE("Dirtifying surface\n");
2554 This->Flags |= SFLAG_DIRTY;
2557 if(This->Flags & SFLAG_DIBSECTION) {
2558 TRACE("(%p): Updating the hdc's palette\n", This);
2559 for (n=0; n<256; n++) {
2561 col[n].rgbRed = pal->palents[n].peRed;
2562 col[n].rgbGreen = pal->palents[n].peGreen;
2563 col[n].rgbBlue = pal->palents[n].peBlue;
2565 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2566 /* Use the default device palette */
2567 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2568 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2569 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2571 col[n].rgbReserved = 0;
2573 SetDIBColorTable(This->hDC, 0, 256, col);
2579 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2580 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2581 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2582 TRACE("(%p)->(%p)\n", This, Pal);
2584 if(This->palette != NULL)
2585 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2586 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2588 if(PalImpl != NULL) {
2589 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2590 /* Set the device's main palette if the palette
2591 * wasn't a primary palette before
2593 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2594 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2597 for(i=0; i < 256; i++) {
2598 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2602 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2605 This->palette = PalImpl;
2607 return IWineD3DSurface_RealizePalette(iface);
2610 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2611 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2612 BOOL dirtify = FALSE;
2613 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
2615 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2616 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
2617 return DDERR_INVALIDPARAMS;
2620 /* Dirtify the surface, but only if a key was changed */
2622 switch (Flags & ~DDCKEY_COLORSPACE) {
2623 case DDCKEY_DESTBLT:
2624 if(!(This->CKeyFlags & DDSD_CKDESTBLT)) {
2627 dirtify = memcmp(&This->DestBltCKey, CKey, sizeof(*CKey) ) != 0;
2629 This->DestBltCKey = *CKey;
2630 This->CKeyFlags |= DDSD_CKDESTBLT;
2633 case DDCKEY_DESTOVERLAY:
2634 if(!(This->CKeyFlags & DDSD_CKDESTOVERLAY)) {
2637 dirtify = memcmp(&This->DestOverlayCKey, CKey, sizeof(*CKey)) != 0;
2639 This->DestOverlayCKey = *CKey;
2640 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2643 case DDCKEY_SRCOVERLAY:
2644 if(!(This->CKeyFlags & DDSD_CKSRCOVERLAY)) {
2647 dirtify = memcmp(&This->SrcOverlayCKey, CKey, sizeof(*CKey)) != 0;
2649 This->SrcOverlayCKey = *CKey;
2650 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2654 if(!(This->CKeyFlags & DDSD_CKSRCBLT)) {
2657 dirtify = memcmp(&This->SrcBltCKey, CKey, sizeof(*CKey)) != 0;
2659 This->SrcBltCKey = *CKey;
2660 This->CKeyFlags |= DDSD_CKSRCBLT;
2665 switch (Flags & ~DDCKEY_COLORSPACE) {
2666 case DDCKEY_DESTBLT:
2667 dirtify = This->CKeyFlags & DDSD_CKDESTBLT;
2668 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2671 case DDCKEY_DESTOVERLAY:
2672 dirtify = This->CKeyFlags & DDSD_CKDESTOVERLAY;
2673 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2676 case DDCKEY_SRCOVERLAY:
2677 dirtify = This->CKeyFlags & DDSD_CKSRCOVERLAY;
2678 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2682 dirtify = This->CKeyFlags & DDSD_CKSRCBLT;
2683 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2689 TRACE("Color key changed, dirtifying surface\n");
2690 This->Flags |= SFLAG_DIRTY;
2696 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2697 /** Check against the maximum texture sizes supported by the video card **/
2698 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2700 TRACE("%p\n", This);
2701 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2702 /* one of three options
2703 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)
2704 2: Set the texture to the maxium size (bad idea)
2705 3: WARN and return WINED3DERR_NOTAVAILABLE;
2706 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.
2708 WARN("(%p) Creating an oversized surface\n", This);
2709 This->Flags |= SFLAG_OVERSIZE;
2711 /* This will be initialized on the first blt */
2712 This->glRect.left = 0;
2713 This->glRect.top = 0;
2714 This->glRect.right = 0;
2715 This->glRect.bottom = 0;
2717 /* No oversize, gl rect is the full texture size */
2718 This->Flags &= ~SFLAG_OVERSIZE;
2719 This->glRect.left = 0;
2720 This->glRect.top = 0;
2721 This->glRect.right = This->pow2Width;
2722 This->glRect.bottom = This->pow2Height;
2728 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
2729 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2731 TRACE("(%p)\n", This);
2733 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
2734 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
2735 ie pitch = (width/4) * bytes per block */
2736 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
2737 ret = (This->currentDesc.Width >> 2) << 3;
2738 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
2739 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
2740 ret = (This->currentDesc.Width >> 2) << 4;
2742 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2743 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
2744 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
2746 ret = This->bytesPerPixel * This->pow2Width;
2749 TRACE("(%p) Returning %ld\n", This, ret);
2753 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
2756 IWineD3DSurfaceImpl_QueryInterface,
2757 IWineD3DSurfaceImpl_AddRef,
2758 IWineD3DSurfaceImpl_Release,
2759 /* IWineD3DResource */
2760 IWineD3DSurfaceImpl_GetParent,
2761 IWineD3DSurfaceImpl_GetDevice,
2762 IWineD3DSurfaceImpl_SetPrivateData,
2763 IWineD3DSurfaceImpl_GetPrivateData,
2764 IWineD3DSurfaceImpl_FreePrivateData,
2765 IWineD3DSurfaceImpl_SetPriority,
2766 IWineD3DSurfaceImpl_GetPriority,
2767 IWineD3DSurfaceImpl_PreLoad,
2768 IWineD3DSurfaceImpl_GetType,
2769 /* IWineD3DSurface */
2770 IWineD3DSurfaceImpl_GetContainerParent,
2771 IWineD3DSurfaceImpl_GetContainer,
2772 IWineD3DSurfaceImpl_GetDesc,
2773 IWineD3DSurfaceImpl_LockRect,
2774 IWineD3DSurfaceImpl_UnlockRect,
2775 IWineD3DSurfaceImpl_GetDC,
2776 IWineD3DSurfaceImpl_ReleaseDC,
2777 IWineD3DSurfaceImpl_Flip,
2778 IWineD3DSurfaceImpl_Blt,
2779 IWineD3DSurfaceImpl_GetBltStatus,
2780 IWineD3DSurfaceImpl_GetFlipStatus,
2781 IWineD3DSurfaceImpl_IsLost,
2782 IWineD3DSurfaceImpl_Restore,
2783 IWineD3DSurfaceImpl_BltFast,
2784 IWineD3DSurfaceImpl_GetPalette,
2785 IWineD3DSurfaceImpl_SetPalette,
2786 IWineD3DSurfaceImpl_RealizePalette,
2787 IWineD3DSurfaceImpl_SetColorKey,
2788 IWineD3DSurfaceImpl_GetPitch,
2790 IWineD3DSurfaceImpl_CleanDirtyRect,
2791 IWineD3DSurfaceImpl_AddDirtyRect,
2792 IWineD3DSurfaceImpl_LoadTexture,
2793 IWineD3DSurfaceImpl_SaveSnapshot,
2794 IWineD3DSurfaceImpl_SetContainer,
2795 IWineD3DSurfaceImpl_SetPBufferState,
2796 IWineD3DSurfaceImpl_SetGlTextureDesc,
2797 IWineD3DSurfaceImpl_GetGlDesc,
2798 IWineD3DSurfaceImpl_GetData,
2799 IWineD3DSurfaceImpl_SetFormat,
2800 IWineD3DSurfaceImpl_PrivateSetup