2 * IWineD3DSurface Implementation
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "wine/port.h"
28 #include "wined3d_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
31 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
33 /* *******************************************
34 IWineD3DSurface IUnknown parts follow
35 ******************************************* */
36 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
38 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
39 /* Warn ,but be nice about things */
40 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
42 ERR("Probably FIXME: Calling query interface with NULL riid\n");
44 if (IsEqualGUID(riid, &IID_IUnknown)
45 || IsEqualGUID(riid, &IID_IWineD3DBase)
46 || IsEqualGUID(riid, &IID_IWineD3DResource)
47 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
48 IUnknown_AddRef((IUnknown*)iface);
56 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
57 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
58 ULONG ref = InterlockedIncrement(&This->resource.ref);
59 TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
63 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
64 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
65 ULONG ref = InterlockedDecrement(&This->resource.ref);
66 TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
68 TRACE("(%p) : cleaning up\n", This);
69 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
71 TRACE("Deleting texture %d\n", This->glDescription.textureName);
72 glDeleteTextures(1, &This->glDescription.textureName);
76 if(This->Flags & SFLAG_DIBSECTION) {
78 SelectObject(This->hDC, This->dib.holdbitmap);
80 /* Release the DIB section */
81 DeleteObject(This->dib.DIBsection);
82 This->dib.bitmap_data = NULL;
83 This->resource.allocatedMemory = NULL;
86 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
88 TRACE("(%p) Released\n", This);
89 HeapFree(GetProcessHeap(), 0, This);
95 /* ****************************************************
96 IWineD3DSurface IWineD3DResource parts follow
97 **************************************************** */
98 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
99 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
102 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
103 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
106 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
107 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
110 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
111 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
114 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
115 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
118 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
119 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
122 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
123 /* TODO: re-write the way textures and managed,
124 * use a 'opengl context manager' to manage RenderTarget surfaces
125 ** *********************************************************/
127 /* TODO: check for locks */
128 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
129 IWineD3DBaseTexture *baseTexture = NULL;
130 TRACE("(%p)Checking to see if the container is a base texture\n", This);
131 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
132 TRACE("Passing to conatiner\n");
133 IWineD3DBaseTexture_PreLoad(baseTexture);
134 IWineD3DBaseTexture_Release(baseTexture);
136 TRACE("(%p) : About to load surface\n", This);
138 #if 0 /* TODO: context manager support */
139 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
141 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
142 if (This->glDescription.level == 0 && This->glDescription.textureName == 0) {
143 glGenTextures(1, &This->glDescription.textureName);
144 checkGLcall("glGenTextures");
145 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
146 glBindTexture(This->glDescription.target, This->glDescription.textureName);
147 checkGLcall("glBindTexture");
148 IWineD3DSurface_LoadTexture(iface);
149 /* This is where we should be reducing the amount of GLMemoryUsed */
151 if (This->glDescription.level == 0) {
152 glBindTexture(This->glDescription.target, This->glDescription.textureName);
153 checkGLcall("glBindTexture");
154 IWineD3DSurface_LoadTexture(iface);
155 } else if (This->glDescription.textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
156 /* assume this is a coding error not a real error for now */
157 FIXME("Mipmap surface has a glTexture bound to it!\n");
160 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
161 /* Tell opengl to try and keep this texture in video ram (well mostly) */
164 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
166 /* TODO: disable texture support, if it wastn't enabled when we entered. */
167 #if 0 /* TODO: context manager support */
168 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
169 /* we don't care when the state is disabled(if atall) */);
176 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
177 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
178 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
181 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
182 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
183 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
186 /* ******************************************************
187 IWineD3DSurface IWineD3DSurface parts follow
188 ****************************************************** */
190 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainerParent(IWineD3DSurface* iface, IUnknown **ppContainerParent) {
191 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
193 TRACE("(%p) : ppContainerParent %p)\n", This, ppContainerParent);
195 if (!ppContainerParent) {
196 ERR("(%p) : Called without a valid ppContainerParent.\n", This);
199 if (This->container) {
200 IWineD3DBase_GetParent(This->container, ppContainerParent);
201 if (!ppContainerParent) {
202 /* WineD3D objects should always have a parent */
203 ERR("(%p) : GetParent returned NULL\n", This);
205 IUnknown_Release(*ppContainerParent); /* GetParent adds a reference; we want just the pointer */
207 *ppContainerParent = NULL;
213 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
214 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
215 IWineD3DBase *container = 0;
217 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
220 ERR("Called without a valid ppContainer.\n");
224 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
225 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
226 * GetContainer will return the Direct3D device used to create the surface.
228 if (This->container) {
229 container = This->container;
231 container = (IWineD3DBase *)This->resource.wineD3DDevice;
234 TRACE("Relaying to QueryInterface\n");
235 if (IUnknown_QueryInterface(container, riid, ppContainer) != S_OK)
236 return WINED3DERR_INVALIDCALL;
241 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
242 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
244 TRACE("(%p) : copying into %p\n", This, pDesc);
245 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
246 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
247 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
248 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
249 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
250 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
251 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
252 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
253 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
257 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
258 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
259 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
260 if (This->glDescription.textureName == 0 && textureName != 0) {
261 This->Flags |= SFLAG_DIRTY;
262 IWineD3DSurface_AddDirtyRect(iface, NULL);
264 This->glDescription.textureName = textureName;
265 This->glDescription.target = target;
268 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
269 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
270 TRACE("(%p) : returning %p\n", This, &This->glDescription);
271 *glDescription = &This->glDescription;
274 /* TODO: think about moving this down to resource? */
275 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
276 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
277 /* 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 */
278 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
279 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
281 return (CONST void*)(This->resource.allocatedMemory);
284 HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
285 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
286 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
287 IWineD3DSwapChainImpl *swapchain = NULL;
288 static UINT messages = 0; /* holds flags to disable fixme messages */
290 /* fixme: should we really lock as such? */
291 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
292 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
293 FIXME("Warning: Surface is in texture memory or pbuffer\n");
294 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
297 if (!(This->Flags & SFLAG_LOCKABLE)) {
298 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
299 texture regions, and since the destination is an unlockable region we need
301 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
302 /*return WINED3DERR_INVALIDCALL; */
305 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
306 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
308 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
309 if (swapchain != NULL && iface == swapchain->backBuffer) {
310 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
311 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
312 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
313 } else if (iface == myDevice->renderTarget) {
314 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
315 } else if (iface == myDevice->depthStencilBuffer) {
316 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
319 if (NULL != swapchain) {
320 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
325 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
328 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
331 pLockedRect->pBits = This->resource.allocatedMemory;
332 This->lockedRect.left = 0;
333 This->lockedRect.top = 0;
334 This->lockedRect.right = This->currentDesc.Width;
335 This->lockedRect.bottom = This->currentDesc.Height;
336 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);
338 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
340 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
341 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
343 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
345 This->lockedRect.left = pRect->left;
346 This->lockedRect.top = pRect->top;
347 This->lockedRect.right = pRect->right;
348 This->lockedRect.bottom = pRect->bottom;
351 if (This->Flags & SFLAG_NONPOW2) {
352 TRACE("Locking non-power 2 texture\n");
355 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
356 /* classic surface TODO: non 2d surfaces?
357 These resources may be POOL_SYSTEMMEM, so they must not access the device */
358 TRACE("locking an ordinarary surface\n");
359 /* Check to see if memory has already been allocated from the surface*/
360 if ((NULL == This->resource.allocatedMemory) ||
361 (This->Flags & SFLAG_NEWDC) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
362 /* Non-system memory surfaces */
364 /*Surface has no memory currently allocated to it!*/
365 TRACE("(%p) Locking rect\n" , This);
366 if(!This->resource.allocatedMemory) {
367 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
369 if (0 != This->glDescription.textureName) {
370 /* Now I have to copy thing bits back */
371 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
372 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
375 /* Make sure that the texture is loaded */
376 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
378 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);
380 if (This->resource.format == WINED3DFMT_DXT1 ||
381 This->resource.format == WINED3DFMT_DXT2 ||
382 This->resource.format == WINED3DFMT_DXT3 ||
383 This->resource.format == WINED3DFMT_DXT4 ||
384 This->resource.format == WINED3DFMT_DXT5) {
385 TRACE("Locking a compressed texture\n");
386 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
387 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
388 This->glDescription.level,
389 This->resource.allocatedMemory);
392 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
395 glGetTexImage(This->glDescription.target,
396 This->glDescription.level,
397 This->glDescription.glFormat,
398 This->glDescription.glType,
399 This->resource.allocatedMemory);
400 vcheckGLcall("glGetTexImage");
401 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
402 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
403 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
404 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
408 instead of boxing the texture :
409 |<-texture width ->| -->pow2width| /\
410 |111111111111111111| | |
411 |222 Texture 222222| boxed empty | texture height
412 |3333 Data 33333333| | |
413 |444444444444444444| | \/
414 ----------------------------------- |
415 | boxed empty | boxed empty | pow2height
417 -----------------------------------
420 were repacking the data to the expected texture width
422 |<-texture width ->| -->pow2width| /\
423 |111111111111111111222222222222222| |
424 |222333333333333333333444444444444| texture height
430 -----------------------------------
434 |<-texture width ->| /\
436 |222222222222222222|texture height
438 |444444444444444444| \/
441 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.
443 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.
445 if (This->Flags & SFLAG_NONPOW2) {
447 int pitcha = 0, pitchb = 0;
449 pitcha = This->bytesPerPixel * This->currentDesc.Width;
450 pitchb = This->bytesPerPixel * This->pow2Width;
451 datab = dataa = This->resource.allocatedMemory;
452 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
453 for (y = 1 ; y < This->currentDesc.Height; y++) {
454 dataa += pitcha; /* skip the first row */
456 memcpy(dataa, datab, pitcha);
463 } else { /* Nothing to do */
464 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
468 pLockedRect->pBits = This->resource.allocatedMemory;
470 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
471 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
473 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
477 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage && !(Flags&WINED3DLOCK_DISCARD)) { /* render surfaces */
481 BOOL notInContext = FALSE;
482 IWineD3DSwapChainImpl *targetSwapChain = NULL;
488 * for render->surface copy begin to begin of allocatedMemory
489 * unlock can be more easy
492 TRACE("locking a render target\n");
494 if (This->resource.allocatedMemory == NULL)
495 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
497 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
498 pLockedRect->pBits = This->resource.allocatedMemory;
501 vcheckGLcall("glFlush");
502 glGetIntegerv(GL_READ_BUFFER, &prev_read);
503 vcheckGLcall("glIntegerv");
504 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
505 vcheckGLcall("glIntegerv");
507 /* Here's what we have to do:
508 See if the swapchain has the same context as the renderTarget or the surface is the render target.
509 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
510 and use the front back buffer as required.
511 if not, we need to switch contexts and then switchback at the end.
513 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
514 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
516 /* 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! */
517 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
518 if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) {
519 TRACE("locking back buffer\n");
520 glReadBuffer(GL_BACK);
521 } else if (iface == swapchain->frontBuffer) {
522 TRACE("locking front\n");
523 glReadBuffer(GL_FRONT);
524 } else if (iface == myDevice->depthStencilBuffer) {
525 FIXME("Stencil Buffer lock unsupported for now\n");
527 FIXME("(%p) Shouldn't have got here!\n", This);
528 glReadBuffer(GL_BACK);
530 } else if (swapchain != NULL) {
531 IWineD3DSwapChainImpl *implSwapChain;
532 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
533 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
534 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
535 if (iface == swapchain->backBuffer) {
536 glReadBuffer(GL_BACK);
537 } else if (iface == swapchain->frontBuffer) {
538 glReadBuffer(GL_FRONT);
539 } else if (iface == myDevice->depthStencilBuffer) {
540 FIXME("Stencil Buffer lock unsupported for now\n");
542 FIXME("Should have got here!\n");
543 glReadBuffer(GL_BACK);
546 /* We need to switch contexts to be able to read the buffer!!! */
547 FIXME("The buffer requested isn't in the current openGL context\n");
549 /* TODO: check the contexts, to see if were shared with the current context */
551 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
553 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
554 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
557 /** the depth stencil in openGL has a format of GL_FLOAT
558 * which should be good for WINED3DFMT_D16_LOCKABLE
560 * it is unclear what format the stencil buffer is in except.
561 * 'Each index is converted to fixed point...
562 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
563 * mappings in the table GL_PIXEL_MAP_S_TO_S.
564 * glReadPixels(This->lockedRect.left,
565 * This->lockedRect.bottom - j - 1,
566 * This->lockedRect.right - This->lockedRect.left,
568 * GL_DEPTH_COMPONENT,
570 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
571 *****************************************/
572 if (!notInContext) { /* Only read the buffer if it's in the current context */
575 /* 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,
576 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
577 * run ten times faster!
578 * ************************************/
579 BOOL ati_performance_hack = FALSE;
580 ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
582 if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
583 This->lockedRect.right == This->currentDesc.Width
584 && This->lockedRect.bottom == This->currentDesc.Height)) {
586 This->currentDesc.Width,
587 This->currentDesc.Height,
588 This->glDescription.glFormat,
589 This->glDescription.glType,
590 (char *)pLockedRect->pBits);
591 } else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
593 This->lockedRect.top,
594 This->currentDesc.Width,
595 This->currentDesc.Height,
596 This->glDescription.glFormat,
597 This->glDescription.glType,
598 (char *)pLockedRect->pBits);
601 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
602 glReadPixels(This->lockedRect.left,
603 This->lockedRect.bottom - j - 1,
604 This->lockedRect.right - This->lockedRect.left,
606 This->glDescription.glFormat,
607 This->glDescription.glType,
608 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
612 vcheckGLcall("glReadPixels");
613 TRACE("Resetting buffer\n");
614 glReadBuffer(prev_read);
615 vcheckGLcall("glReadBuffer");
619 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
622 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
625 glReadPixels(This->lockedRect.left,
626 This->lockedRect.bottom - j - 1,
627 This->lockedRect.right - This->lockedRect.left,
629 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
636 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
639 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
642 IWineD3DBaseTexture *pBaseTexture;
645 * as seen in msdn docs
647 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
649 /** Dirtify Container if needed */
650 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
651 TRACE("Making container dirty\n");
652 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
653 IWineD3DBaseTexture_Release(pBaseTexture);
655 TRACE("Surface is standalone, no need to dirty the container\n");
659 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
661 This->Flags |= SFLAG_LOCKED;
665 HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
667 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
668 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
669 const char *buffername = "";
670 IWineD3DSwapChainImpl *swapchain = NULL;
672 if (!(This->Flags & SFLAG_LOCKED)) {
673 WARN("trying to Unlock an unlocked surf@%p\n", This);
674 return WINED3DERR_INVALIDCALL;
677 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
678 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
680 if ((swapchain != NULL) && iface == swapchain->backBuffer) {
681 buffername = "backBuffer";
682 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
683 buffername = "frontBuffer";
684 } else if (iface == myDevice->depthStencilBuffer) {
685 buffername = "depthStencilBuffer";
686 } else if (iface == myDevice->renderTarget) {
687 buffername = "renderTarget";
691 if (swapchain != NULL) {
692 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
695 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
697 if (!(This->Flags & SFLAG_DIRTY)) {
698 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
702 if (0 == This->resource.usage) { /* classic surface */
705 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
707 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
709 /****************************
710 * TODO: Render targets are 'special' and
711 * ?some? locking needs to be passed onto the context manager
712 * so that it becomes possible to use auxiliary buffers, pbuffers
713 * render-to-texture, shared, cached contexts etc...
714 * ****************************/
715 IWineD3DSwapChainImpl *implSwapChain;
716 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
718 if (iface == implSwapChain->backBuffer || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
721 GLint prev_rasterpos[4];
723 /* Some drivers(radeon dri, others?) don't like exceptions during
724 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
725 * after ReleaseDC. Reading it will cause an exception, which x11drv will
726 * catch to put the dib section in InSync mode, which leads to a crash
727 * and a blocked x server on my radeon card.
729 * The following lines read the dib section so it is put in inSync mode
730 * before glDrawPixels is called and the crash is prevented. There won't
731 * be any interfering gdi accesses, because UnlockRect is called from
732 * ReleaseDC, and the app won't use the dc any more afterwards.
734 if(This->Flags & SFLAG_DIBSECTION) {
736 read = This->resource.allocatedMemory[0];
742 vcheckGLcall("glFlush");
743 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
744 vcheckGLcall("glIntegerv");
745 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
746 vcheckGLcall("glIntegerv");
747 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
748 vcheckGLcall("glIntegerv");
749 glPixelZoom(1.0, -1.0);
750 vcheckGLcall("glPixelZoom");
752 /* glDrawPixels transforms the raster position as though it was a vertex -
753 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
754 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
755 if ( (!myDevice->last_was_rhw) || (myDevice->viewport_changed) ) {
757 double X, Y, height, width, minZ, maxZ;
758 myDevice->last_was_rhw = TRUE;
759 myDevice->viewport_changed = FALSE;
761 /* Transformed already into viewport coordinates, so we do not need transform
762 matrices. Reset all matrices to identity and leave the default matrix in world
764 glMatrixMode(GL_MODELVIEW);
765 checkGLcall("glMatrixMode");
767 checkGLcall("glLoadIdentity");
769 glMatrixMode(GL_PROJECTION);
770 checkGLcall("glMatrixMode");
772 checkGLcall("glLoadIdentity");
774 /* Set up the viewport to be full viewport */
775 X = myDevice->stateBlock->viewport.X;
776 Y = myDevice->stateBlock->viewport.Y;
777 height = myDevice->stateBlock->viewport.Height;
778 width = myDevice->stateBlock->viewport.Width;
779 minZ = myDevice->stateBlock->viewport.MinZ;
780 maxZ = myDevice->stateBlock->viewport.MaxZ;
781 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
782 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
783 checkGLcall("glOrtho");
785 /* Window Coord 0 is the middle of the first pixel, so translate by half
786 a pixel (See comment above glTranslate below) */
787 glTranslatef(0.5, 0.5, 0);
788 checkGLcall("glTranslatef(0.5, 0.5, 0)");
791 if (iface == implSwapChain->backBuffer || iface == myDevice->renderTarget) {
792 glDrawBuffer(GL_BACK);
793 } else if (iface == implSwapChain->frontBuffer) {
794 glDrawBuffer(GL_FRONT);
797 vcheckGLcall("glDrawBuffer");
799 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
800 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
801 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
803 /* And back buffers are not blended */
806 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
807 vcheckGLcall("glRasterPos2f");
808 switch (This->resource.format) {
809 case WINED3DFMT_X4R4G4B4:
812 unsigned short *data;
813 data = (unsigned short *)This->resource.allocatedMemory;
814 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
821 case WINED3DFMT_A4R4G4B4:
823 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
824 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
825 vcheckGLcall("glDrawPixels");
828 case WINED3DFMT_R5G6B5:
830 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
831 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
832 vcheckGLcall("glDrawPixels");
835 case WINED3DFMT_X1R5G5B5:
838 unsigned short *data;
839 data = (unsigned short *)This->resource.allocatedMemory;
840 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
847 case WINED3DFMT_A1R5G5B5:
849 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
850 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
851 vcheckGLcall("glDrawPixels");
854 case WINED3DFMT_R8G8B8:
856 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
857 GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
858 vcheckGLcall("glDrawPixels");
861 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
862 could be any random value this fixes the intro move in Pirates! */
866 data = (unsigned int *)This->resource.allocatedMemory;
867 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
874 case WINED3DFMT_A8R8G8B8:
876 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
877 vcheckGLcall("glPixelStorei");
878 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
879 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
880 vcheckGLcall("glDrawPixels");
881 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
882 vcheckGLcall("glPixelStorei");
885 case WINED3DFMT_A2R10G10B10:
887 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
888 vcheckGLcall("glPixelStorei");
889 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
890 GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
891 vcheckGLcall("glDrawPixels");
892 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
893 vcheckGLcall("glPixelStorei");
897 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
900 glPixelZoom(1.0,1.0);
901 vcheckGLcall("glPixelZoom");
902 glDrawBuffer(prev_draw);
903 vcheckGLcall("glDrawBuffer");
904 glRasterPos3iv(&prev_rasterpos[0]);
905 vcheckGLcall("glRasterPos3iv");
907 /* Reset to previous pack row length / blending state */
908 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
909 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
913 /** restore clean dirty state */
914 IWineD3DSurface_CleanDirtyRect(iface);
917 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
919 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
921 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
923 if (iface == myDevice->depthStencilBuffer) {
924 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
926 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
930 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
934 This->Flags &= ~SFLAG_LOCKED;
935 memset(&This->lockedRect, 0, sizeof(RECT));
939 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
940 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
941 WINED3DLOCKED_RECT lock;
949 TRACE("(%p)->(%p)\n",This,pHDC);
951 /* Give more detailed info for ddraw */
952 if (This->Flags & SFLAG_DCINUSE)
953 return DDERR_DCALREADYCREATED;
955 /* Can't GetDC if the surface is locked */
956 if (This->Flags & SFLAG_LOCKED)
957 return WINED3DERR_INVALIDCALL;
959 memset(&lock, 0, sizeof(lock)); /* To be sure */
961 /* Create a DIB section if there isn't a hdc yet */
963 if(This->Flags & SFLAG_ACTIVELOCK) {
964 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
967 switch (This->bytesPerPixel) {
970 /* Allocate extra space to store the RGB bit masks. */
971 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
975 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
979 /* Allocate extra space for a palette. */
980 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
981 sizeof(BITMAPINFOHEADER)
983 * (1 << (This->bytesPerPixel * 8)));
987 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
988 b_info->bmiHeader.biWidth = This->pow2Width;
989 b_info->bmiHeader.biHeight = -This->pow2Height;
990 b_info->bmiHeader.biPlanes = 1;
991 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
993 b_info->bmiHeader.biSizeImage = This->resource.size;
995 b_info->bmiHeader.biXPelsPerMeter = 0;
996 b_info->bmiHeader.biYPelsPerMeter = 0;
997 b_info->bmiHeader.biClrUsed = 0;
998 b_info->bmiHeader.biClrImportant = 0;
1000 /* Get the bit masks */
1001 masks = (DWORD *) &(b_info->bmiColors);
1002 switch (This->resource.format) {
1003 case WINED3DFMT_R8G8B8:
1004 usage = DIB_RGB_COLORS;
1005 b_info->bmiHeader.biCompression = BI_RGB;
1008 case WINED3DFMT_X1R5G5B5:
1009 case WINED3DFMT_A1R5G5B5:
1010 case WINED3DFMT_A4R4G4B4:
1011 case WINED3DFMT_X4R4G4B4:
1012 case WINED3DFMT_R3G3B2:
1013 case WINED3DFMT_A8R3G3B2:
1014 case WINED3DFMT_A2B10G10R10:
1015 case WINED3DFMT_A8B8G8R8:
1016 case WINED3DFMT_X8B8G8R8:
1017 case WINED3DFMT_A2R10G10B10:
1018 case WINED3DFMT_R5G6B5:
1019 case WINED3DFMT_A16B16G16R16:
1021 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1022 masks[0] = get_bitmask_red(This->resource.format);
1023 masks[1] = get_bitmask_green(This->resource.format);
1024 masks[2] = get_bitmask_blue(This->resource.format);
1028 /* Don't know palette */
1029 b_info->bmiHeader.biCompression = BI_RGB;
1034 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1036 HeapFree(GetProcessHeap(), 0, b_info);
1037 return HRESULT_FROM_WIN32(GetLastError());
1040 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);
1041 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1044 if (!This->dib.DIBsection) {
1045 ERR("CreateDIBSection failed!\n");
1046 return HRESULT_FROM_WIN32(GetLastError());
1048 HeapFree(GetProcessHeap(), 0, b_info);
1050 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1052 /* copy the existing surface to the dib section */
1053 if(This->resource.allocatedMemory) {
1054 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->resource.size);
1055 /* We won't need that any more */
1056 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1059 /* Use the dib section from now on */
1060 This->resource.allocatedMemory = This->dib.bitmap_data;
1062 /* Now allocate a HDC */
1063 This->hDC = CreateCompatibleDC(0);
1064 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1065 TRACE("using wined3d palette %p\n", This->palette);
1066 SelectPalette(This->hDC,
1067 This->palette ? This->palette->hpal : 0,
1070 /* This is to make LockRect read the gl Texture although memory is allocated */
1071 This->Flags |= SFLAG_NEWDC;
1073 This->Flags |= SFLAG_DIBSECTION;
1076 /* Lock the surface */
1077 hr = IWineD3DSurface_LockRect(iface,
1081 This->Flags &= ~SFLAG_NEWDC;
1083 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1084 /* keep the dib section */
1088 if(This->resource.format == WINED3DFMT_P8 ||
1089 This->resource.format == WINED3DFMT_A8P8) {
1092 PALETTEENTRY ent[256];
1094 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1095 for (n=0; n<256; n++) {
1096 col[n].rgbRed = ent[n].peRed;
1097 col[n].rgbGreen = ent[n].peGreen;
1098 col[n].rgbBlue = ent[n].peBlue;
1099 col[n].rgbReserved = 0;
1102 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1104 for (n=0; n<256; n++) {
1105 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1106 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1107 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1108 col[n].rgbReserved = 0;
1112 SetDIBColorTable(This->hDC, 0, 256, col);
1116 TRACE("returning %p\n",*pHDC);
1117 This->Flags |= SFLAG_DCINUSE;
1122 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1123 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1125 TRACE("(%p)->(%p)\n",This,hDC);
1127 if (!(This->Flags & SFLAG_DCINUSE))
1128 return D3DERR_INVALIDCALL;
1130 /* we locked first, so unlock now */
1131 IWineD3DSurface_UnlockRect(iface);
1133 This->Flags &= ~SFLAG_DCINUSE;
1138 /* ******************************************************
1139 IWineD3DSurface Internal (No mapping to directx api) parts follow
1140 ****************************************************** */
1141 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1142 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1144 if (This->Flags & SFLAG_INTEXTURE) {
1145 TRACE("Surface already in texture\n");
1148 if (!(This->Flags & SFLAG_DIRTY)) {
1149 TRACE("surface isn't dirty\n");
1153 This->Flags &= ~SFLAG_DIRTY;
1155 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1156 * These resources are not bound by device size or format restrictions. Because of this,
1157 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1158 * However, these resources can always be created, locked, and copied.
1159 * In general never store scratch or system mem textures in the video ram. However it is allowed
1160 * for system memory textures when WINED3DDEVCAPS_TEXTURESYSTEMMEMORY is set but it isn't right now.
1162 if (This->resource.pool == WINED3DPOOL_SCRATCH || This->resource.pool == WINED3DPOOL_SYSTEMMEM)
1164 FIXME("(%p) Operation not supported for scratch or SYSTEMMEM textures\n",This);
1165 return WINED3DERR_INVALIDCALL;
1168 if (This->Flags & SFLAG_INPBUFFER) {
1171 if (This->glDescription.level != 0)
1172 FIXME("Surface in texture is only supported for level 0\n");
1173 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1174 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1175 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1176 This->resource.format == WINED3DFMT_DXT5)
1177 FIXME("Format %d not supported\n", This->resource.format);
1180 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1181 vcheckGLcall("glGetIntegerv");
1182 glReadBuffer(GL_BACK);
1183 vcheckGLcall("glReadBuffer");
1185 glCopyTexImage2D(This->glDescription.target,
1186 This->glDescription.level,
1187 This->glDescription.glFormatInternal,
1190 This->currentDesc.Width,
1191 This->currentDesc.Height,
1194 checkGLcall("glCopyTexImage2D");
1195 glReadBuffer(prevRead);
1196 vcheckGLcall("glReadBuffer");
1197 TRACE("Updating target %d\n", This->glDescription.target);
1198 This->Flags |= SFLAG_INTEXTURE;
1204 if ((This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) &&
1205 !GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1207 * wanted a paletted texture and not really support it in HW
1208 * so software emulation code begin
1211 PALETTEENTRY* pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
1212 VOID* surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->currentDesc.Width * This->currentDesc.Height * sizeof(DWORD));
1213 BYTE* dst = (BYTE*) surface;
1214 BYTE* src = (BYTE*) This->resource.allocatedMemory;
1216 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
1217 BYTE color = *src++;
1218 *dst++ = pal[color].peRed;
1219 *dst++ = pal[color].peGreen;
1220 *dst++ = pal[color].peBlue;
1221 if (This->resource.format == WINED3DFMT_A8P8)
1222 *dst++ = pal[color].peFlags;
1229 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1230 This->glDescription.target,
1231 This->glDescription.level,
1233 This->currentDesc.Width,
1234 This->currentDesc.Height,
1239 glTexImage2D(This->glDescription.target,
1240 This->glDescription.level,
1242 This->currentDesc.Width,
1243 This->currentDesc.Height,
1248 checkGLcall("glTexImage2D");
1249 HeapFree(GetProcessHeap(), 0, surface);
1256 /* TODO: Compressed non-power 2 support */
1258 if (This->resource.format == WINED3DFMT_DXT1 ||
1259 This->resource.format == WINED3DFMT_DXT2 ||
1260 This->resource.format == WINED3DFMT_DXT3 ||
1261 This->resource.format == WINED3DFMT_DXT4 ||
1262 This->resource.format == WINED3DFMT_DXT5) {
1263 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1264 FIXME("Using DXT1/3/5 without advertized support\n");
1265 } else if (This->resource.allocatedMemory) {
1266 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1267 This->glDescription.target,
1268 This->glDescription.level,
1269 This->glDescription.glFormatInternal,
1270 This->currentDesc.Width,
1271 This->currentDesc.Height,
1273 This->resource.size,
1274 This->resource.allocatedMemory);
1278 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1279 This->glDescription.level,
1280 This->glDescription.glFormatInternal,
1281 This->currentDesc.Width,
1282 This->currentDesc.Height,
1284 This->resource.size,
1285 This->resource.allocatedMemory);
1286 checkGLcall("glCommpressedTexImage2D");
1290 if(!(This->Flags & SFLAG_DONOTFREE)){
1291 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1292 This->resource.allocatedMemory = NULL;
1297 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1298 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2)) {
1301 TRACE("non power of two support\n");
1303 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,
1304 This->glDescription.target,
1305 This->glDescription.level,
1306 debug_d3dformat(This->resource.format),
1307 This->glDescription.glFormatInternal,
1311 This->glDescription.glFormat,
1312 This->glDescription.glType,
1315 glTexImage2D(This->glDescription.target,
1316 This->glDescription.level,
1317 This->glDescription.glFormatInternal,
1321 This->glDescription.glFormat,
1322 This->glDescription.glType,
1325 checkGLcall("glTexImage2D");
1326 if (This->resource.allocatedMemory != NULL) {
1327 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1328 /* And map the non-power two data into the top left corner */
1330 This->glDescription.target,
1331 This->glDescription.level,
1334 This->currentDesc.Width,
1335 This->currentDesc.Height,
1336 This->glDescription.glFormat,
1337 This->glDescription.glType,
1338 This->resource.allocatedMemory
1340 checkGLcall("glTexSubImage2D");
1346 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1347 This->glDescription.target,
1348 This->glDescription.level,
1349 debug_d3dformat(This->resource.format),
1350 This->glDescription.glFormatInternal,
1354 This->glDescription.glFormat,
1355 This->glDescription.glType,
1356 This->resource.allocatedMemory);
1359 glTexImage2D(This->glDescription.target,
1360 This->glDescription.level,
1361 This->glDescription.glFormatInternal,
1365 This->glDescription.glFormat,
1366 This->glDescription.glType,
1367 This->resource.allocatedMemory);
1368 checkGLcall("glTexImage2D");
1374 static unsigned int gen = 0;
1377 if ((gen % 10) == 0) {
1378 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1379 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1382 * debugging crash code
1390 if(!(This->Flags & SFLAG_DONOTFREE)){
1391 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1392 This->resource.allocatedMemory = NULL;
1402 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1405 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1406 char *allocatedMemory;
1408 IWineD3DSwapChain *swapChain = NULL;
1413 Textures my not be stored in ->allocatedgMemory and a GlTexture
1414 so we should lock the surface before saving a snapshot, or at least check that
1416 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1417 by calling GetTexImage and in compressed form by calling
1418 GetCompressedTexImageARB. Queried compressed images can be saved and
1419 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1420 texture images do not need to be processed by the GL and should
1421 significantly improve texture loading performance relative to uncompressed
1424 /* Setup the width and height to be the internal texture width and height. */
1425 width = This->pow2Width;
1426 height = This->pow2Height;
1427 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1428 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1430 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1431 /* 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 */
1434 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1435 glEnable(GL_TEXTURE_2D);
1437 glGenTextures(1, &tmpTexture);
1438 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1440 glTexImage2D(GL_TEXTURE_2D,
1447 GL_UNSIGNED_INT_8_8_8_8_REV,
1450 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1451 vcheckGLcall("glGetIntegerv");
1452 glReadBuffer(GL_BACK);
1453 vcheckGLcall("glReadBuffer");
1454 glCopyTexImage2D(GL_TEXTURE_2D,
1463 checkGLcall("glCopyTexImage2D");
1464 glReadBuffer(prevRead);
1467 } else { /* bind the real texture */
1468 IWineD3DSurface_PreLoad(iface);
1470 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1472 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1473 glGetTexImage(GL_TEXTURE_2D,
1474 This->glDescription.level,
1476 GL_UNSIGNED_INT_8_8_8_8_REV,
1478 checkGLcall("glTexImage2D");
1480 glBindTexture(GL_TEXTURE_2D, 0);
1481 glDeleteTextures(1, &tmpTexture);
1485 f = fopen(filename, "w+");
1487 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1488 return WINED3DERR_INVALIDCALL;
1490 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1491 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1506 fwrite(&width,2,1,f);
1508 fwrite(&height,2,1,f);
1513 /* 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*/
1515 textureRow = allocatedMemory + (width * (height - 1) *4);
1517 textureRow = allocatedMemory;
1518 for (y = 0 ; y < height; y++) {
1519 for (i = 0; i < width; i++) {
1520 color = *((DWORD*)textureRow);
1521 fputc((color >> 16) & 0xFF, f); /* B */
1522 fputc((color >> 8) & 0xFF, f); /* G */
1523 fputc((color >> 0) & 0xFF, f); /* R */
1524 fputc((color >> 24) & 0xFF, f); /* A */
1527 /* take two rows of the pointer to the texture memory */
1529 (textureRow-= width << 3);
1532 TRACE("Closing file\n");
1536 IWineD3DSwapChain_Release(swapChain);
1538 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1542 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1543 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1544 This->Flags &= ~SFLAG_DIRTY;
1545 This->dirtyRect.left = This->currentDesc.Width;
1546 This->dirtyRect.top = This->currentDesc.Height;
1547 This->dirtyRect.right = 0;
1548 This->dirtyRect.bottom = 0;
1549 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1550 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1555 * Slightly inefficient way to handle multiple dirty rects but it works :)
1557 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1558 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1559 IWineD3DBaseTexture *baseTexture = NULL;
1560 This->Flags |= SFLAG_DIRTY;
1561 if (NULL != pDirtyRect) {
1562 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1563 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1564 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1565 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1567 This->dirtyRect.left = 0;
1568 This->dirtyRect.top = 0;
1569 This->dirtyRect.right = This->currentDesc.Width;
1570 This->dirtyRect.bottom = This->currentDesc.Height;
1572 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
1573 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1574 /* if the container is a basetexture then mark it dirty. */
1575 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1576 TRACE("Passing to conatiner\n");
1577 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1578 IWineD3DBaseTexture_Release(baseTexture);
1583 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1584 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1586 TRACE("This %p, container %p\n", This, container);
1588 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1590 TRACE("Setting container to %p from %p\n", container, This->container);
1591 This->container = container;
1596 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1597 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1599 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1600 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1601 return WINED3DERR_INVALIDCALL;
1604 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1605 if (format == WINED3DFMT_UNKNOWN) {
1606 This->resource.size = 0;
1607 } else if (format == WINED3DFMT_DXT1) {
1608 /* DXT1 is half byte per pixel */
1609 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1611 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1612 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1613 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1615 This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1619 /* Setup some glformat defaults */
1620 if (format != WINED3DFMT_UNKNOWN) {
1621 This->glDescription.glFormat = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1622 This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1623 This->glDescription.glType = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1625 This->glDescription.glFormat = 0;
1626 This->glDescription.glFormatInternal = 0;
1627 This->glDescription.glType = 0;
1630 if (format != WINED3DFMT_UNKNOWN) {
1631 This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1632 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1634 This->bytesPerPixel = 0;
1638 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
1640 This->resource.format = format;
1642 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);
1647 /* TODO: replace this function with context management routines */
1648 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1649 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1652 This->Flags |= SFLAG_INPBUFFER;
1654 This->Flags &= ~SFLAG_INPBUFFER;
1658 This->Flags |= SFLAG_INTEXTURE;
1660 This->Flags &= ~SFLAG_INTEXTURE;
1666 HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
1667 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1668 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
1669 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
1671 /* Flipping is only supported on RenderTargets */
1672 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
1675 /* DDraw sets this for the X11 surfaces, so don't confuse the user
1676 * FIXME("(%p) Target override is not supported by now\n", This);
1677 * Additionally, it isn't really possible to support triple-buffering
1678 * properly on opengl at all
1682 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
1683 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
1686 HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
1687 FIXME("This is unimplemented for now(d3d7 merge)\n");
1688 return WINED3DERR_INVALIDCALL;
1691 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
1692 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1693 TRACE("(%p)->(%lx)\n", This, Flags);
1698 case DDGBS_ISBLTDONE:
1702 return DDERR_INVALIDPARAMS;
1706 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
1707 /* XXX: DDERR_INVALIDSURFACETYPE */
1709 TRACE("(%p)->(%08lx)\n",iface,Flags);
1712 case DDGFS_ISFLIPDONE:
1716 return DDERR_INVALIDPARAMS;
1720 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
1721 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1722 TRACE("(%p)\n", This);
1724 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
1727 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
1728 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1729 TRACE("(%p)\n", This);
1731 /* So far we don't lose anything :) */
1732 This->Flags &= ~SFLAG_LOST;
1736 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
1737 FIXME("This is unimplemented for now(d3d7 merge)\n");
1738 return WINED3DERR_INVALIDCALL;
1741 HRESULT WINAPI IWineD3DSurfaceImpl_SetPixelFormat(IWineD3DSurface *iface, WINED3DFORMAT Format, BYTE *Surface, DWORD Size) {
1742 FIXME("This is unimplemented for now(d3d7 merge)\n");
1743 return WINED3DERR_INVALIDCALL;
1746 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
1747 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1748 TRACE("(%p)->(%p)\n", This, Pal);
1750 *Pal = (IWineD3DPalette *) This->palette;
1754 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
1755 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1757 IWineD3DPaletteImpl *pal = This->palette;
1759 TRACE("(%p)\n", This);
1761 if(This->resource.format == WINED3DFMT_P8 ||
1762 This->resource.format == WINED3DFMT_A8P8)
1764 TRACE("Dirtifying surface\n");
1765 This->Flags |= SFLAG_DIRTY;
1768 TRACE("(%p): Updating the palette\n", This);
1769 for (n=0; n<256; n++) {
1770 col[n].rgbRed = pal->palents[n].peRed;
1771 col[n].rgbGreen = pal->palents[n].peGreen;
1772 col[n].rgbBlue = pal->palents[n].peBlue;
1773 col[n].rgbReserved = 0;
1775 SetDIBColorTable(This->hDC, 0, 256, col);
1780 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
1781 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1782 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
1783 TRACE("(%p)->(%p)\n", This, Pal);
1785 if(This->palette != NULL)
1786 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
1787 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
1789 if(PalImpl != NULL) {
1790 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
1791 /* Set the device's main palette if the palette
1792 * wasn't a primary palette before
1794 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
1795 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1798 for(i=0; i < 256; i++) {
1799 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
1803 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
1806 This->palette = PalImpl;
1808 return IWineD3DSurface_RealizePalette(iface);
1811 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
1812 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1813 BOOL dirtify = FALSE;
1814 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
1816 if ((Flags & DDCKEY_COLORSPACE) != 0) {
1817 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
1818 return DDERR_INVALIDPARAMS;
1821 /* Dirtify the surface, but only if a key was changed */
1823 switch (Flags & ~DDCKEY_COLORSPACE) {
1824 case DDCKEY_DESTBLT:
1825 if(!(This->CKeyFlags & DDSD_CKDESTBLT)) {
1828 dirtify = memcmp(&This->DestBltCKey, CKey, sizeof(*CKey) ) != 0;
1830 This->DestBltCKey = *CKey;
1831 This->CKeyFlags |= DDSD_CKDESTBLT;
1834 case DDCKEY_DESTOVERLAY:
1835 if(!(This->CKeyFlags & DDSD_CKDESTOVERLAY)) {
1838 dirtify = memcmp(&This->DestOverlayCKey, CKey, sizeof(*CKey)) != 0;
1840 This->DestOverlayCKey = *CKey;
1841 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
1844 case DDCKEY_SRCOVERLAY:
1845 if(!(This->CKeyFlags & DDSD_CKSRCOVERLAY)) {
1848 dirtify = memcmp(&This->SrcOverlayCKey, CKey, sizeof(*CKey)) != 0;
1850 This->SrcOverlayCKey = *CKey;
1851 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
1855 if(!(This->CKeyFlags & DDSD_CKSRCBLT)) {
1858 dirtify = memcmp(&This->SrcBltCKey, CKey, sizeof(*CKey)) != 0;
1860 This->SrcBltCKey = *CKey;
1861 This->CKeyFlags |= DDSD_CKSRCBLT;
1866 switch (Flags & ~DDCKEY_COLORSPACE) {
1867 case DDCKEY_DESTBLT:
1868 dirtify = This->CKeyFlags & DDSD_CKDESTBLT;
1869 This->CKeyFlags &= ~DDSD_CKDESTBLT;
1872 case DDCKEY_DESTOVERLAY:
1873 dirtify = This->CKeyFlags & DDSD_CKDESTOVERLAY;
1874 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
1877 case DDCKEY_SRCOVERLAY:
1878 dirtify = This->CKeyFlags & DDSD_CKSRCOVERLAY;
1879 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
1883 dirtify = This->CKeyFlags & DDSD_CKSRCBLT;
1884 This->CKeyFlags &= ~DDSD_CKSRCBLT;
1890 TRACE("Color key changed, dirtifing surface\n");
1891 This->Flags |= SFLAG_DIRTY;
1897 HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
1898 /* Nothing to do for now */
1902 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
1903 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1905 TRACE("(%p)\n", This);
1907 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
1908 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
1909 ie pitch = (width/4) * bytes per block */
1910 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
1911 ret = (This->currentDesc.Width >> 2) << 3;
1912 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
1913 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
1914 ret = (This->currentDesc.Width >> 2) << 4;
1916 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
1917 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
1918 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
1920 ret = This->bytesPerPixel * This->pow2Width;
1923 TRACE("(%p) Returning %ld\n", This, ret);
1927 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
1930 IWineD3DSurfaceImpl_QueryInterface,
1931 IWineD3DSurfaceImpl_AddRef,
1932 IWineD3DSurfaceImpl_Release,
1933 /* IWineD3DResource */
1934 IWineD3DSurfaceImpl_GetParent,
1935 IWineD3DSurfaceImpl_GetDevice,
1936 IWineD3DSurfaceImpl_SetPrivateData,
1937 IWineD3DSurfaceImpl_GetPrivateData,
1938 IWineD3DSurfaceImpl_FreePrivateData,
1939 IWineD3DSurfaceImpl_SetPriority,
1940 IWineD3DSurfaceImpl_GetPriority,
1941 IWineD3DSurfaceImpl_PreLoad,
1942 IWineD3DSurfaceImpl_GetType,
1943 /* IWineD3DSurface */
1944 IWineD3DSurfaceImpl_GetContainerParent,
1945 IWineD3DSurfaceImpl_GetContainer,
1946 IWineD3DSurfaceImpl_GetDesc,
1947 IWineD3DSurfaceImpl_LockRect,
1948 IWineD3DSurfaceImpl_UnlockRect,
1949 IWineD3DSurfaceImpl_GetDC,
1950 IWineD3DSurfaceImpl_ReleaseDC,
1951 IWineD3DSurfaceImpl_Flip,
1952 IWineD3DSurfaceImpl_Blt,
1953 IWineD3DSurfaceImpl_GetBltStatus,
1954 IWineD3DSurfaceImpl_GetFlipStatus,
1955 IWineD3DSurfaceImpl_IsLost,
1956 IWineD3DSurfaceImpl_Restore,
1957 IWineD3DSurfaceImpl_BltFast,
1958 IWineD3DSurfaceImpl_SetPixelFormat,
1959 IWineD3DSurfaceImpl_GetPalette,
1960 IWineD3DSurfaceImpl_SetPalette,
1961 IWineD3DSurfaceImpl_RealizePalette,
1962 IWineD3DSurfaceImpl_SetColorKey,
1963 IWineD3DSurfaceImpl_GetPitch,
1965 IWineD3DSurfaceImpl_CleanDirtyRect,
1966 IWineD3DSurfaceImpl_AddDirtyRect,
1967 IWineD3DSurfaceImpl_LoadTexture,
1968 IWineD3DSurfaceImpl_SaveSnapshot,
1969 IWineD3DSurfaceImpl_SetContainer,
1970 IWineD3DSurfaceImpl_SetPBufferState,
1971 IWineD3DSurfaceImpl_SetGlTextureDesc,
1972 IWineD3DSurfaceImpl_GetGlDesc,
1973 IWineD3DSurfaceImpl_GetData,
1974 IWineD3DSurfaceImpl_SetFormat,
1975 IWineD3DSurfaceImpl_PrivateSetup