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 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
69 TRACE("(%p) : cleaning up\n", This);
70 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
72 TRACE("Deleting texture %d\n", This->glDescription.textureName);
73 glDeleteTextures(1, &This->glDescription.textureName);
77 if(This->Flags & SFLAG_DIBSECTION) {
79 SelectObject(This->hDC, This->dib.holdbitmap);
81 /* Release the DIB section */
82 DeleteObject(This->dib.DIBsection);
83 This->dib.bitmap_data = NULL;
84 This->resource.allocatedMemory = NULL;
87 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
88 if(iface == device->ddraw_primary)
89 device->ddraw_primary = NULL;
91 TRACE("(%p) Released\n", This);
92 HeapFree(GetProcessHeap(), 0, This);
98 /* ****************************************************
99 IWineD3DSurface IWineD3DResource parts follow
100 **************************************************** */
101 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
102 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
105 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
106 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
109 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
110 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
113 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
114 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
117 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
118 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
121 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
122 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
125 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
126 /* TODO: re-write the way textures and managed,
127 * use a 'opengl context manager' to manage RenderTarget surfaces
128 ** *********************************************************/
130 /* TODO: check for locks */
131 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
132 IWineD3DBaseTexture *baseTexture = NULL;
133 TRACE("(%p)Checking to see if the container is a base texture\n", This);
134 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
135 TRACE("Passing to conatiner\n");
136 IWineD3DBaseTexture_PreLoad(baseTexture);
137 IWineD3DBaseTexture_Release(baseTexture);
139 TRACE("(%p) : About to load surface\n", This);
141 #if 0 /* TODO: context manager support */
142 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
144 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
145 if (This->glDescription.level == 0 && This->glDescription.textureName == 0) {
146 glGenTextures(1, &This->glDescription.textureName);
147 checkGLcall("glGenTextures");
148 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
149 glBindTexture(This->glDescription.target, This->glDescription.textureName);
150 checkGLcall("glBindTexture");
151 IWineD3DSurface_LoadTexture(iface);
152 /* This is where we should be reducing the amount of GLMemoryUsed */
154 if (This->glDescription.level == 0) {
155 glBindTexture(This->glDescription.target, This->glDescription.textureName);
156 checkGLcall("glBindTexture");
157 IWineD3DSurface_LoadTexture(iface);
158 } else if (This->glDescription.textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
159 /* assume this is a coding error not a real error for now */
160 FIXME("Mipmap surface has a glTexture bound to it!\n");
163 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
164 /* Tell opengl to try and keep this texture in video ram (well mostly) */
167 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
169 /* TODO: disable texture support, if it wastn't enabled when we entered. */
170 #if 0 /* TODO: context manager support */
171 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
172 /* we don't care when the state is disabled(if atall) */);
179 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
180 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
181 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
184 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
185 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
186 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
189 /* ******************************************************
190 IWineD3DSurface IWineD3DSurface parts follow
191 ****************************************************** */
193 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainerParent(IWineD3DSurface* iface, IUnknown **ppContainerParent) {
194 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
196 TRACE("(%p) : ppContainerParent %p)\n", This, ppContainerParent);
198 if (!ppContainerParent) {
199 ERR("(%p) : Called without a valid ppContainerParent.\n", This);
202 if (This->container) {
203 IWineD3DBase_GetParent(This->container, ppContainerParent);
204 if (!ppContainerParent) {
205 /* WineD3D objects should always have a parent */
206 ERR("(%p) : GetParent returned NULL\n", This);
208 IUnknown_Release(*ppContainerParent); /* GetParent adds a reference; we want just the pointer */
210 *ppContainerParent = NULL;
216 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
217 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
218 IWineD3DBase *container = 0;
220 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
223 ERR("Called without a valid ppContainer.\n");
227 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
228 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
229 * GetContainer will return the Direct3D device used to create the surface.
231 if (This->container) {
232 container = This->container;
234 container = (IWineD3DBase *)This->resource.wineD3DDevice;
237 TRACE("Relaying to QueryInterface\n");
238 if (IUnknown_QueryInterface(container, riid, ppContainer) != S_OK)
239 return WINED3DERR_INVALIDCALL;
244 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
245 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
247 TRACE("(%p) : copying into %p\n", This, pDesc);
248 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
249 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
250 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
251 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
252 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
253 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
254 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
255 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
256 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
260 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
261 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
262 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
263 if (This->glDescription.textureName == 0 && textureName != 0) {
264 This->Flags |= SFLAG_DIRTY;
265 IWineD3DSurface_AddDirtyRect(iface, NULL);
267 This->glDescription.textureName = textureName;
268 This->glDescription.target = target;
271 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
272 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
273 TRACE("(%p) : returning %p\n", This, &This->glDescription);
274 *glDescription = &This->glDescription;
277 /* TODO: think about moving this down to resource? */
278 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
279 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
280 /* 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 */
281 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
282 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
284 return (CONST void*)(This->resource.allocatedMemory);
287 HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
288 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
289 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
290 IWineD3DSwapChainImpl *swapchain = NULL;
291 static UINT messages = 0; /* holds flags to disable fixme messages */
293 /* fixme: should we really lock as such? */
294 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
295 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
296 FIXME("Warning: Surface is in texture memory or pbuffer\n");
297 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
300 if (!(This->Flags & SFLAG_LOCKABLE)) {
301 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
302 texture regions, and since the destination is an unlockable region we need
304 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
305 /*return WINED3DERR_INVALIDCALL; */
308 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
309 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
311 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
312 if (swapchain != NULL && iface == swapchain->backBuffer) {
313 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
314 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
315 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
316 } else if (iface == myDevice->renderTarget) {
317 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
318 } else if (iface == myDevice->depthStencilBuffer) {
319 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
322 if (NULL != swapchain) {
323 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
328 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
331 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
334 pLockedRect->pBits = This->resource.allocatedMemory;
335 This->lockedRect.left = 0;
336 This->lockedRect.top = 0;
337 This->lockedRect.right = This->currentDesc.Width;
338 This->lockedRect.bottom = This->currentDesc.Height;
339 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);
341 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
343 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
344 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
346 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
348 This->lockedRect.left = pRect->left;
349 This->lockedRect.top = pRect->top;
350 This->lockedRect.right = pRect->right;
351 This->lockedRect.bottom = pRect->bottom;
354 if (This->Flags & SFLAG_NONPOW2) {
355 TRACE("Locking non-power 2 texture\n");
358 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
359 /* classic surface TODO: non 2d surfaces?
360 These resources may be POOL_SYSTEMMEM, so they must not access the device */
361 TRACE("locking an ordinarary surface\n");
362 /* Check to see if memory has already been allocated from the surface*/
363 if ((NULL == This->resource.allocatedMemory) ||
364 (This->Flags & SFLAG_NEWDC) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
365 /* Non-system memory surfaces */
367 /*Surface has no memory currently allocated to it!*/
368 TRACE("(%p) Locking rect\n" , This);
369 if(!This->resource.allocatedMemory) {
370 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
372 if (0 != This->glDescription.textureName) {
373 /* Now I have to copy thing bits back */
374 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
375 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
378 /* Make sure that the texture is loaded */
379 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
381 TRACE("(%p) glGetTexImage level(%d), fmt(%d), typ(%d), mem(%p)\n" , This, This->glDescription.level, This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
383 if (This->resource.format == WINED3DFMT_DXT1 ||
384 This->resource.format == WINED3DFMT_DXT2 ||
385 This->resource.format == WINED3DFMT_DXT3 ||
386 This->resource.format == WINED3DFMT_DXT4 ||
387 This->resource.format == WINED3DFMT_DXT5) {
388 TRACE("Locking a compressed texture\n");
389 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
390 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
391 This->glDescription.level,
392 This->resource.allocatedMemory);
395 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
398 glGetTexImage(This->glDescription.target,
399 This->glDescription.level,
400 This->glDescription.glFormat,
401 This->glDescription.glType,
402 This->resource.allocatedMemory);
403 vcheckGLcall("glGetTexImage");
404 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
405 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
406 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
407 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
411 instead of boxing the texture :
412 |<-texture width ->| -->pow2width| /\
413 |111111111111111111| | |
414 |222 Texture 222222| boxed empty | texture height
415 |3333 Data 33333333| | |
416 |444444444444444444| | \/
417 ----------------------------------- |
418 | boxed empty | boxed empty | pow2height
420 -----------------------------------
423 were repacking the data to the expected texture width
425 |<-texture width ->| -->pow2width| /\
426 |111111111111111111222222222222222| |
427 |222333333333333333333444444444444| texture height
433 -----------------------------------
437 |<-texture width ->| /\
439 |222222222222222222|texture height
441 |444444444444444444| \/
444 this also means that any references to allocatedMemory should work with the data as if were a standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
446 internally the texture is still stored in a boxed format so any references to textureName will get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
448 if (This->Flags & SFLAG_NONPOW2) {
450 int pitcha = 0, pitchb = 0;
452 pitcha = This->bytesPerPixel * This->currentDesc.Width;
453 pitchb = This->bytesPerPixel * This->pow2Width;
454 datab = dataa = This->resource.allocatedMemory;
455 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
456 for (y = 1 ; y < This->currentDesc.Height; y++) {
457 dataa += pitcha; /* skip the first row */
459 memcpy(dataa, datab, pitcha);
466 } else { /* Nothing to do */
467 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
471 pLockedRect->pBits = This->resource.allocatedMemory;
473 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
474 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
476 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
480 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage && !(Flags&WINED3DLOCK_DISCARD)) { /* render surfaces */
484 BOOL notInContext = FALSE;
485 IWineD3DSwapChainImpl *targetSwapChain = NULL;
491 * for render->surface copy begin to begin of allocatedMemory
492 * unlock can be more easy
495 TRACE("locking a render target\n");
497 if (This->resource.allocatedMemory == NULL)
498 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
500 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
501 pLockedRect->pBits = This->resource.allocatedMemory;
504 vcheckGLcall("glFlush");
505 glGetIntegerv(GL_READ_BUFFER, &prev_read);
506 vcheckGLcall("glIntegerv");
507 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
508 vcheckGLcall("glIntegerv");
510 /* Here's what we have to do:
511 See if the swapchain has the same context as the renderTarget or the surface is the render target.
512 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
513 and use the front back buffer as required.
514 if not, we need to switch contexts and then switchback at the end.
516 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
517 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
519 /* NOTE: In a shared context environment the renderTarget will use the same context as the implicit swapchain (we're not in a shared environment yet! */
520 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
521 if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) {
522 TRACE("locking back buffer\n");
523 glReadBuffer(GL_BACK);
524 } else if (iface == swapchain->frontBuffer) {
525 TRACE("locking front\n");
526 glReadBuffer(GL_FRONT);
527 } else if (iface == myDevice->depthStencilBuffer) {
528 FIXME("Stencil Buffer lock unsupported for now\n");
530 FIXME("(%p) Shouldn't have got here!\n", This);
531 glReadBuffer(GL_BACK);
533 } else if (swapchain != NULL) {
534 IWineD3DSwapChainImpl *implSwapChain;
535 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
536 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
537 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
538 if (iface == swapchain->backBuffer) {
539 glReadBuffer(GL_BACK);
540 } else if (iface == swapchain->frontBuffer) {
541 glReadBuffer(GL_FRONT);
542 } else if (iface == myDevice->depthStencilBuffer) {
543 FIXME("Stencil Buffer lock unsupported for now\n");
545 FIXME("Should have got here!\n");
546 glReadBuffer(GL_BACK);
549 /* We need to switch contexts to be able to read the buffer!!! */
550 FIXME("The buffer requested isn't in the current openGL context\n");
552 /* TODO: check the contexts, to see if were shared with the current context */
554 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
556 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
557 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
560 /** the depth stencil in openGL has a format of GL_FLOAT
561 * which should be good for WINED3DFMT_D16_LOCKABLE
563 * it is unclear what format the stencil buffer is in except.
564 * 'Each index is converted to fixed point...
565 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
566 * mappings in the table GL_PIXEL_MAP_S_TO_S.
567 * glReadPixels(This->lockedRect.left,
568 * This->lockedRect.bottom - j - 1,
569 * This->lockedRect.right - This->lockedRect.left,
571 * GL_DEPTH_COMPONENT,
573 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
574 *****************************************/
575 if (!notInContext) { /* Only read the buffer if it's in the current context */
578 /* Bizarly it takes 120 millseconds to get an 800x600 region a line at a time, but only 10 to get the whole lot every time,
579 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
580 * run ten times faster!
581 * ************************************/
582 BOOL ati_performance_hack = FALSE;
583 ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
585 if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
586 This->lockedRect.right == This->currentDesc.Width
587 && This->lockedRect.bottom == This->currentDesc.Height)) {
589 This->currentDesc.Width,
590 This->currentDesc.Height,
591 This->glDescription.glFormat,
592 This->glDescription.glType,
593 (char *)pLockedRect->pBits);
594 } else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
596 This->lockedRect.top,
597 This->currentDesc.Width,
598 This->currentDesc.Height,
599 This->glDescription.glFormat,
600 This->glDescription.glType,
601 (char *)pLockedRect->pBits);
604 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
605 glReadPixels(This->lockedRect.left,
606 This->lockedRect.bottom - j - 1,
607 This->lockedRect.right - This->lockedRect.left,
609 This->glDescription.glFormat,
610 This->glDescription.glType,
611 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
615 vcheckGLcall("glReadPixels");
616 TRACE("Resetting buffer\n");
617 glReadBuffer(prev_read);
618 vcheckGLcall("glReadBuffer");
622 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
625 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
628 glReadPixels(This->lockedRect.left,
629 This->lockedRect.bottom - j - 1,
630 This->lockedRect.right - This->lockedRect.left,
632 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
639 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
642 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
645 IWineD3DBaseTexture *pBaseTexture;
648 * as seen in msdn docs
650 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
652 /** Dirtify Container if needed */
653 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
654 TRACE("Making container dirty\n");
655 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
656 IWineD3DBaseTexture_Release(pBaseTexture);
658 TRACE("Surface is standalone, no need to dirty the container\n");
662 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
664 This->Flags |= SFLAG_LOCKED;
668 HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
670 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
671 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
672 const char *buffername = "";
673 IWineD3DSwapChainImpl *swapchain = NULL;
675 if (!(This->Flags & SFLAG_LOCKED)) {
676 WARN("trying to Unlock an unlocked surf@%p\n", This);
677 return WINED3DERR_INVALIDCALL;
680 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
681 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
683 if ((swapchain != NULL) && iface == swapchain->backBuffer) {
684 buffername = "backBuffer";
685 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
686 buffername = "frontBuffer";
687 } else if (iface == myDevice->depthStencilBuffer) {
688 buffername = "depthStencilBuffer";
689 } else if (iface == myDevice->renderTarget) {
690 buffername = "renderTarget";
694 if (swapchain != NULL) {
695 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
698 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
700 if (!(This->Flags & SFLAG_DIRTY)) {
701 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
705 if (0 == This->resource.usage) { /* classic surface */
708 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
710 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
712 /****************************
713 * TODO: Render targets are 'special' and
714 * ?some? locking needs to be passed onto the context manager
715 * so that it becomes possible to use auxiliary buffers, pbuffers
716 * render-to-texture, shared, cached contexts etc...
717 * ****************************/
718 IWineD3DSwapChainImpl *implSwapChain;
719 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
721 if (iface == implSwapChain->backBuffer || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
724 GLint prev_rasterpos[4];
726 /* Some drivers(radeon dri, others?) don't like exceptions during
727 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
728 * after ReleaseDC. Reading it will cause an exception, which x11drv will
729 * catch to put the dib section in InSync mode, which leads to a crash
730 * and a blocked x server on my radeon card.
732 * The following lines read the dib section so it is put in inSync mode
733 * before glDrawPixels is called and the crash is prevented. There won't
734 * be any interfering gdi accesses, because UnlockRect is called from
735 * ReleaseDC, and the app won't use the dc any more afterwards.
737 if(This->Flags & SFLAG_DIBSECTION) {
739 read = This->resource.allocatedMemory[0];
745 vcheckGLcall("glFlush");
746 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
747 vcheckGLcall("glIntegerv");
748 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
749 vcheckGLcall("glIntegerv");
750 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
751 vcheckGLcall("glIntegerv");
752 glPixelZoom(1.0, -1.0);
753 vcheckGLcall("glPixelZoom");
755 /* glDrawPixels transforms the raster position as though it was a vertex -
756 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
757 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
758 if ( (!myDevice->last_was_rhw) || (myDevice->viewport_changed) ) {
760 double X, Y, height, width, minZ, maxZ;
761 myDevice->last_was_rhw = TRUE;
762 myDevice->viewport_changed = FALSE;
764 /* Transformed already into viewport coordinates, so we do not need transform
765 matrices. Reset all matrices to identity and leave the default matrix in world
767 glMatrixMode(GL_MODELVIEW);
768 checkGLcall("glMatrixMode");
770 checkGLcall("glLoadIdentity");
772 glMatrixMode(GL_PROJECTION);
773 checkGLcall("glMatrixMode");
775 checkGLcall("glLoadIdentity");
777 /* Set up the viewport to be full viewport */
778 X = myDevice->stateBlock->viewport.X;
779 Y = myDevice->stateBlock->viewport.Y;
780 height = myDevice->stateBlock->viewport.Height;
781 width = myDevice->stateBlock->viewport.Width;
782 minZ = myDevice->stateBlock->viewport.MinZ;
783 maxZ = myDevice->stateBlock->viewport.MaxZ;
784 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
785 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
786 checkGLcall("glOrtho");
788 /* Window Coord 0 is the middle of the first pixel, so translate by half
789 a pixel (See comment above glTranslate below) */
790 glTranslatef(0.5, 0.5, 0);
791 checkGLcall("glTranslatef(0.5, 0.5, 0)");
794 if (iface == implSwapChain->backBuffer || iface == myDevice->renderTarget) {
795 glDrawBuffer(GL_BACK);
796 } else if (iface == implSwapChain->frontBuffer) {
797 glDrawBuffer(GL_FRONT);
800 vcheckGLcall("glDrawBuffer");
802 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
803 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
804 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
806 /* And back buffers are not blended */
809 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
810 vcheckGLcall("glRasterPos2f");
811 switch (This->resource.format) {
812 case WINED3DFMT_X4R4G4B4:
815 unsigned short *data;
816 data = (unsigned short *)This->resource.allocatedMemory;
817 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
824 case WINED3DFMT_A4R4G4B4:
826 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
827 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
828 vcheckGLcall("glDrawPixels");
831 case WINED3DFMT_R5G6B5:
833 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
834 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
835 vcheckGLcall("glDrawPixels");
838 case WINED3DFMT_X1R5G5B5:
841 unsigned short *data;
842 data = (unsigned short *)This->resource.allocatedMemory;
843 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
850 case WINED3DFMT_A1R5G5B5:
852 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
853 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
854 vcheckGLcall("glDrawPixels");
857 case WINED3DFMT_R8G8B8:
859 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
860 GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
861 vcheckGLcall("glDrawPixels");
864 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
865 could be any random value this fixes the intro move in Pirates! */
869 data = (unsigned int *)This->resource.allocatedMemory;
870 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
877 case WINED3DFMT_A8R8G8B8:
879 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
880 vcheckGLcall("glPixelStorei");
881 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
882 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
883 vcheckGLcall("glDrawPixels");
884 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
885 vcheckGLcall("glPixelStorei");
888 case WINED3DFMT_A2R10G10B10:
890 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
891 vcheckGLcall("glPixelStorei");
892 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
893 GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
894 vcheckGLcall("glDrawPixels");
895 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
896 vcheckGLcall("glPixelStorei");
900 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
903 glPixelZoom(1.0,1.0);
904 vcheckGLcall("glPixelZoom");
905 glDrawBuffer(prev_draw);
906 vcheckGLcall("glDrawBuffer");
907 glRasterPos3iv(&prev_rasterpos[0]);
908 vcheckGLcall("glRasterPos3iv");
910 /* Reset to previous pack row length / blending state */
911 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
912 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
916 /** restore clean dirty state */
917 IWineD3DSurface_CleanDirtyRect(iface);
920 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
922 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
924 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
926 if (iface == myDevice->depthStencilBuffer) {
927 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
929 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
933 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
937 This->Flags &= ~SFLAG_LOCKED;
938 memset(&This->lockedRect, 0, sizeof(RECT));
942 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
943 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
944 WINED3DLOCKED_RECT lock;
952 TRACE("(%p)->(%p)\n",This,pHDC);
954 /* Give more detailed info for ddraw */
955 if (This->Flags & SFLAG_DCINUSE)
956 return DDERR_DCALREADYCREATED;
958 /* Can't GetDC if the surface is locked */
959 if (This->Flags & SFLAG_LOCKED)
960 return WINED3DERR_INVALIDCALL;
962 memset(&lock, 0, sizeof(lock)); /* To be sure */
964 /* Create a DIB section if there isn't a hdc yet */
966 if(This->Flags & SFLAG_ACTIVELOCK) {
967 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
970 switch (This->bytesPerPixel) {
973 /* Allocate extra space to store the RGB bit masks. */
974 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
978 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
982 /* Allocate extra space for a palette. */
983 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
984 sizeof(BITMAPINFOHEADER)
986 * (1 << (This->bytesPerPixel * 8)));
990 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
991 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
992 b_info->bmiHeader.biWidth = This->currentDesc.Width;
993 b_info->bmiHeader.biHeight = -This->currentDesc.Height;
994 /* Use the full pow2 image size(assigned below) because LockRect
995 * will need it for a full glGetTexImage call
998 b_info->bmiHeader.biWidth = This->pow2Width;
999 b_info->bmiHeader.biHeight = -This->pow2Height;
1001 b_info->bmiHeader.biPlanes = 1;
1002 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1004 b_info->bmiHeader.biSizeImage = This->resource.size;
1006 b_info->bmiHeader.biXPelsPerMeter = 0;
1007 b_info->bmiHeader.biYPelsPerMeter = 0;
1008 b_info->bmiHeader.biClrUsed = 0;
1009 b_info->bmiHeader.biClrImportant = 0;
1011 /* Get the bit masks */
1012 masks = (DWORD *) &(b_info->bmiColors);
1013 switch (This->resource.format) {
1014 case WINED3DFMT_R8G8B8:
1015 usage = DIB_RGB_COLORS;
1016 b_info->bmiHeader.biCompression = BI_RGB;
1019 case WINED3DFMT_X1R5G5B5:
1020 case WINED3DFMT_A1R5G5B5:
1021 case WINED3DFMT_A4R4G4B4:
1022 case WINED3DFMT_X4R4G4B4:
1023 case WINED3DFMT_R3G3B2:
1024 case WINED3DFMT_A8R3G3B2:
1025 case WINED3DFMT_A2B10G10R10:
1026 case WINED3DFMT_A8B8G8R8:
1027 case WINED3DFMT_X8B8G8R8:
1028 case WINED3DFMT_A2R10G10B10:
1029 case WINED3DFMT_R5G6B5:
1030 case WINED3DFMT_A16B16G16R16:
1032 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1033 masks[0] = get_bitmask_red(This->resource.format);
1034 masks[1] = get_bitmask_green(This->resource.format);
1035 masks[2] = get_bitmask_blue(This->resource.format);
1039 /* Don't know palette */
1040 b_info->bmiHeader.biCompression = BI_RGB;
1045 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1047 HeapFree(GetProcessHeap(), 0, b_info);
1048 return HRESULT_FROM_WIN32(GetLastError());
1051 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);
1052 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1055 if (!This->dib.DIBsection) {
1056 ERR("CreateDIBSection failed!\n");
1057 return HRESULT_FROM_WIN32(GetLastError());
1059 HeapFree(GetProcessHeap(), 0, b_info);
1061 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1063 /* copy the existing surface to the dib section */
1064 if(This->resource.allocatedMemory) {
1065 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->resource.size);
1066 /* We won't need that any more */
1067 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1070 /* Use the dib section from now on */
1071 This->resource.allocatedMemory = This->dib.bitmap_data;
1073 /* Now allocate a HDC */
1074 This->hDC = CreateCompatibleDC(0);
1075 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1076 TRACE("using wined3d palette %p\n", This->palette);
1077 SelectPalette(This->hDC,
1078 This->palette ? This->palette->hpal : 0,
1081 /* This is to make LockRect read the gl Texture although memory is allocated */
1082 This->Flags |= SFLAG_NEWDC;
1084 This->Flags |= SFLAG_DIBSECTION;
1087 /* Lock the surface */
1088 hr = IWineD3DSurface_LockRect(iface,
1092 This->Flags &= ~SFLAG_NEWDC;
1094 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1095 /* keep the dib section */
1099 if(This->resource.format == WINED3DFMT_P8 ||
1100 This->resource.format == WINED3DFMT_A8P8) {
1103 PALETTEENTRY ent[256];
1105 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1106 for (n=0; n<256; n++) {
1107 col[n].rgbRed = ent[n].peRed;
1108 col[n].rgbGreen = ent[n].peGreen;
1109 col[n].rgbBlue = ent[n].peBlue;
1110 col[n].rgbReserved = 0;
1113 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1115 for (n=0; n<256; n++) {
1116 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1117 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1118 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1119 col[n].rgbReserved = 0;
1123 SetDIBColorTable(This->hDC, 0, 256, col);
1127 TRACE("returning %p\n",*pHDC);
1128 This->Flags |= SFLAG_DCINUSE;
1133 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1134 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1136 TRACE("(%p)->(%p)\n",This,hDC);
1138 if (!(This->Flags & SFLAG_DCINUSE))
1139 return D3DERR_INVALIDCALL;
1141 /* we locked first, so unlock now */
1142 IWineD3DSurface_UnlockRect(iface);
1144 This->Flags &= ~SFLAG_DCINUSE;
1149 /* ******************************************************
1150 IWineD3DSurface Internal (No mapping to directx api) parts follow
1151 ****************************************************** */
1152 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1153 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1155 if (This->Flags & SFLAG_INTEXTURE) {
1156 TRACE("Surface already in texture\n");
1159 if (!(This->Flags & SFLAG_DIRTY)) {
1160 TRACE("surface isn't dirty\n");
1164 This->Flags &= ~SFLAG_DIRTY;
1166 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1167 * These resources are not bound by device size or format restrictions. Because of this,
1168 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1169 * However, these resources can always be created, locked, and copied.
1170 * In general never store scratch or system mem textures in the video ram. However it is allowed
1171 * for system memory textures when WINED3DDEVCAPS_TEXTURESYSTEMMEMORY is set but it isn't right now.
1173 if (This->resource.pool == WINED3DPOOL_SCRATCH || This->resource.pool == WINED3DPOOL_SYSTEMMEM)
1175 FIXME("(%p) Operation not supported for scratch or SYSTEMMEM textures\n",This);
1176 return WINED3DERR_INVALIDCALL;
1179 if (This->Flags & SFLAG_INPBUFFER) {
1182 if (This->glDescription.level != 0)
1183 FIXME("Surface in texture is only supported for level 0\n");
1184 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1185 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1186 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1187 This->resource.format == WINED3DFMT_DXT5)
1188 FIXME("Format %d not supported\n", This->resource.format);
1191 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1192 vcheckGLcall("glGetIntegerv");
1193 glReadBuffer(GL_BACK);
1194 vcheckGLcall("glReadBuffer");
1196 glCopyTexImage2D(This->glDescription.target,
1197 This->glDescription.level,
1198 This->glDescription.glFormatInternal,
1201 This->currentDesc.Width,
1202 This->currentDesc.Height,
1205 checkGLcall("glCopyTexImage2D");
1206 glReadBuffer(prevRead);
1207 vcheckGLcall("glReadBuffer");
1208 TRACE("Updating target %d\n", This->glDescription.target);
1209 This->Flags |= SFLAG_INTEXTURE;
1215 if ((This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) &&
1216 !GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1218 * wanted a paletted texture and not really support it in HW
1219 * so software emulation code begin
1222 PALETTEENTRY* pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
1223 VOID* surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->currentDesc.Width * This->currentDesc.Height * sizeof(DWORD));
1224 BYTE* dst = (BYTE*) surface;
1225 BYTE* src = (BYTE*) This->resource.allocatedMemory;
1227 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
1228 BYTE color = *src++;
1229 *dst++ = pal[color].peRed;
1230 *dst++ = pal[color].peGreen;
1231 *dst++ = pal[color].peBlue;
1232 if (This->resource.format == WINED3DFMT_A8P8)
1233 *dst++ = pal[color].peFlags;
1240 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1241 This->glDescription.target,
1242 This->glDescription.level,
1244 This->currentDesc.Width,
1245 This->currentDesc.Height,
1250 glTexImage2D(This->glDescription.target,
1251 This->glDescription.level,
1253 This->currentDesc.Width,
1254 This->currentDesc.Height,
1259 checkGLcall("glTexImage2D");
1260 HeapFree(GetProcessHeap(), 0, surface);
1267 /* TODO: Compressed non-power 2 support */
1269 if (This->resource.format == WINED3DFMT_DXT1 ||
1270 This->resource.format == WINED3DFMT_DXT2 ||
1271 This->resource.format == WINED3DFMT_DXT3 ||
1272 This->resource.format == WINED3DFMT_DXT4 ||
1273 This->resource.format == WINED3DFMT_DXT5) {
1274 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1275 FIXME("Using DXT1/3/5 without advertized support\n");
1276 } else if (This->resource.allocatedMemory) {
1277 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1278 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);
1289 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1290 This->glDescription.level,
1291 This->glDescription.glFormatInternal,
1292 This->currentDesc.Width,
1293 This->currentDesc.Height,
1295 This->resource.size,
1296 This->resource.allocatedMemory);
1297 checkGLcall("glCommpressedTexImage2D");
1301 if(!(This->Flags & SFLAG_DONOTFREE)){
1302 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1303 This->resource.allocatedMemory = NULL;
1308 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1309 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2)) {
1312 TRACE("non power of two support\n");
1314 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,
1315 This->glDescription.target,
1316 This->glDescription.level,
1317 debug_d3dformat(This->resource.format),
1318 This->glDescription.glFormatInternal,
1322 This->glDescription.glFormat,
1323 This->glDescription.glType,
1326 glTexImage2D(This->glDescription.target,
1327 This->glDescription.level,
1328 This->glDescription.glFormatInternal,
1332 This->glDescription.glFormat,
1333 This->glDescription.glType,
1336 checkGLcall("glTexImage2D");
1337 if (This->resource.allocatedMemory != NULL) {
1338 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1339 /* And map the non-power two data into the top left corner */
1341 This->glDescription.target,
1342 This->glDescription.level,
1345 This->currentDesc.Width,
1346 This->currentDesc.Height,
1347 This->glDescription.glFormat,
1348 This->glDescription.glType,
1349 This->resource.allocatedMemory
1351 checkGLcall("glTexSubImage2D");
1357 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1358 This->glDescription.target,
1359 This->glDescription.level,
1360 debug_d3dformat(This->resource.format),
1361 This->glDescription.glFormatInternal,
1365 This->glDescription.glFormat,
1366 This->glDescription.glType,
1367 This->resource.allocatedMemory);
1370 glTexImage2D(This->glDescription.target,
1371 This->glDescription.level,
1372 This->glDescription.glFormatInternal,
1376 This->glDescription.glFormat,
1377 This->glDescription.glType,
1378 This->resource.allocatedMemory);
1379 checkGLcall("glTexImage2D");
1385 static unsigned int gen = 0;
1388 if ((gen % 10) == 0) {
1389 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1390 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1393 * debugging crash code
1401 if(!(This->Flags & SFLAG_DONOTFREE)){
1402 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1403 This->resource.allocatedMemory = NULL;
1413 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1416 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1417 char *allocatedMemory;
1419 IWineD3DSwapChain *swapChain = NULL;
1424 Textures my not be stored in ->allocatedgMemory and a GlTexture
1425 so we should lock the surface before saving a snapshot, or at least check that
1427 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1428 by calling GetTexImage and in compressed form by calling
1429 GetCompressedTexImageARB. Queried compressed images can be saved and
1430 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1431 texture images do not need to be processed by the GL and should
1432 significantly improve texture loading performance relative to uncompressed
1435 /* Setup the width and height to be the internal texture width and height. */
1436 width = This->pow2Width;
1437 height = This->pow2Height;
1438 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1439 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1441 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1442 /* 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 */
1445 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1446 glEnable(GL_TEXTURE_2D);
1448 glGenTextures(1, &tmpTexture);
1449 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1451 glTexImage2D(GL_TEXTURE_2D,
1458 GL_UNSIGNED_INT_8_8_8_8_REV,
1461 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1462 vcheckGLcall("glGetIntegerv");
1463 glReadBuffer(GL_BACK);
1464 vcheckGLcall("glReadBuffer");
1465 glCopyTexImage2D(GL_TEXTURE_2D,
1474 checkGLcall("glCopyTexImage2D");
1475 glReadBuffer(prevRead);
1478 } else { /* bind the real texture */
1479 IWineD3DSurface_PreLoad(iface);
1481 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1483 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1484 glGetTexImage(GL_TEXTURE_2D,
1485 This->glDescription.level,
1487 GL_UNSIGNED_INT_8_8_8_8_REV,
1489 checkGLcall("glTexImage2D");
1491 glBindTexture(GL_TEXTURE_2D, 0);
1492 glDeleteTextures(1, &tmpTexture);
1496 f = fopen(filename, "w+");
1498 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1499 return WINED3DERR_INVALIDCALL;
1501 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1502 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1517 fwrite(&width,2,1,f);
1519 fwrite(&height,2,1,f);
1524 /* 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*/
1526 textureRow = allocatedMemory + (width * (height - 1) *4);
1528 textureRow = allocatedMemory;
1529 for (y = 0 ; y < height; y++) {
1530 for (i = 0; i < width; i++) {
1531 color = *((DWORD*)textureRow);
1532 fputc((color >> 16) & 0xFF, f); /* B */
1533 fputc((color >> 8) & 0xFF, f); /* G */
1534 fputc((color >> 0) & 0xFF, f); /* R */
1535 fputc((color >> 24) & 0xFF, f); /* A */
1538 /* take two rows of the pointer to the texture memory */
1540 (textureRow-= width << 3);
1543 TRACE("Closing file\n");
1547 IWineD3DSwapChain_Release(swapChain);
1549 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1553 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1554 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1555 This->Flags &= ~SFLAG_DIRTY;
1556 This->dirtyRect.left = This->currentDesc.Width;
1557 This->dirtyRect.top = This->currentDesc.Height;
1558 This->dirtyRect.right = 0;
1559 This->dirtyRect.bottom = 0;
1560 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1561 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1566 * Slightly inefficient way to handle multiple dirty rects but it works :)
1568 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1569 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1570 IWineD3DBaseTexture *baseTexture = NULL;
1571 This->Flags |= SFLAG_DIRTY;
1572 if (NULL != pDirtyRect) {
1573 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1574 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1575 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1576 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1578 This->dirtyRect.left = 0;
1579 This->dirtyRect.top = 0;
1580 This->dirtyRect.right = This->currentDesc.Width;
1581 This->dirtyRect.bottom = This->currentDesc.Height;
1583 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
1584 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1585 /* if the container is a basetexture then mark it dirty. */
1586 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1587 TRACE("Passing to conatiner\n");
1588 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1589 IWineD3DBaseTexture_Release(baseTexture);
1594 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1595 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1597 TRACE("This %p, container %p\n", This, container);
1599 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1601 TRACE("Setting container to %p from %p\n", container, This->container);
1602 This->container = container;
1607 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1608 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1610 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1611 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1612 return WINED3DERR_INVALIDCALL;
1615 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1616 if (format == WINED3DFMT_UNKNOWN) {
1617 This->resource.size = 0;
1618 } else if (format == WINED3DFMT_DXT1) {
1619 /* DXT1 is half byte per pixel */
1620 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1622 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1623 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1624 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1626 This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1630 /* Setup some glformat defaults */
1631 if (format != WINED3DFMT_UNKNOWN) {
1632 This->glDescription.glFormat = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1633 This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1634 This->glDescription.glType = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1636 This->glDescription.glFormat = 0;
1637 This->glDescription.glFormatInternal = 0;
1638 This->glDescription.glType = 0;
1641 if (format != WINED3DFMT_UNKNOWN) {
1642 This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1643 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1645 This->bytesPerPixel = 0;
1649 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
1651 This->resource.format = format;
1653 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);
1658 /* TODO: replace this function with context management routines */
1659 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1660 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1663 This->Flags |= SFLAG_INPBUFFER;
1665 This->Flags &= ~SFLAG_INPBUFFER;
1669 This->Flags |= SFLAG_INTEXTURE;
1671 This->Flags &= ~SFLAG_INTEXTURE;
1677 HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
1678 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1679 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
1680 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
1682 /* Flipping is only supported on RenderTargets */
1683 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
1686 /* DDraw sets this for the X11 surfaces, so don't confuse the user
1687 * FIXME("(%p) Target override is not supported by now\n", This);
1688 * Additionally, it isn't really possible to support triple-buffering
1689 * properly on opengl at all
1693 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
1694 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
1697 HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
1698 FIXME("This is unimplemented for now(d3d7 merge)\n");
1699 return WINED3DERR_INVALIDCALL;
1702 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
1703 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1704 TRACE("(%p)->(%lx)\n", This, Flags);
1709 case DDGBS_ISBLTDONE:
1713 return DDERR_INVALIDPARAMS;
1717 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
1718 /* XXX: DDERR_INVALIDSURFACETYPE */
1720 TRACE("(%p)->(%08lx)\n",iface,Flags);
1723 case DDGFS_ISFLIPDONE:
1727 return DDERR_INVALIDPARAMS;
1731 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
1732 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1733 TRACE("(%p)\n", This);
1735 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
1738 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
1739 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1740 TRACE("(%p)\n", This);
1742 /* So far we don't lose anything :) */
1743 This->Flags &= ~SFLAG_LOST;
1747 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
1748 FIXME("This is unimplemented for now(d3d7 merge)\n");
1749 return WINED3DERR_INVALIDCALL;
1752 HRESULT WINAPI IWineD3DSurfaceImpl_SetPixelFormat(IWineD3DSurface *iface, WINED3DFORMAT Format, BYTE *Surface, DWORD Size) {
1753 FIXME("This is unimplemented for now(d3d7 merge)\n");
1754 return WINED3DERR_INVALIDCALL;
1757 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
1758 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1759 TRACE("(%p)->(%p)\n", This, Pal);
1761 *Pal = (IWineD3DPalette *) This->palette;
1765 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
1766 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1768 IWineD3DPaletteImpl *pal = This->palette;
1770 TRACE("(%p)\n", This);
1772 if(This->resource.format == WINED3DFMT_P8 ||
1773 This->resource.format == WINED3DFMT_A8P8)
1775 TRACE("Dirtifying surface\n");
1776 This->Flags |= SFLAG_DIRTY;
1779 if(This->Flags & SFLAG_DIBSECTION) {
1780 TRACE("(%p): Updating the hdc's palette\n", This);
1781 for (n=0; n<256; n++) {
1783 col[n].rgbRed = pal->palents[n].peRed;
1784 col[n].rgbGreen = pal->palents[n].peGreen;
1785 col[n].rgbBlue = pal->palents[n].peBlue;
1787 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1788 /* Use the default device palette */
1789 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1790 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1791 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1793 col[n].rgbReserved = 0;
1795 SetDIBColorTable(This->hDC, 0, 256, col);
1801 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
1802 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1803 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
1804 TRACE("(%p)->(%p)\n", This, Pal);
1806 if(This->palette != NULL)
1807 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
1808 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
1810 if(PalImpl != NULL) {
1811 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
1812 /* Set the device's main palette if the palette
1813 * wasn't a primary palette before
1815 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
1816 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1819 for(i=0; i < 256; i++) {
1820 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
1824 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
1827 This->palette = PalImpl;
1829 return IWineD3DSurface_RealizePalette(iface);
1832 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
1833 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1834 BOOL dirtify = FALSE;
1835 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
1837 if ((Flags & DDCKEY_COLORSPACE) != 0) {
1838 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
1839 return DDERR_INVALIDPARAMS;
1842 /* Dirtify the surface, but only if a key was changed */
1844 switch (Flags & ~DDCKEY_COLORSPACE) {
1845 case DDCKEY_DESTBLT:
1846 if(!(This->CKeyFlags & DDSD_CKDESTBLT)) {
1849 dirtify = memcmp(&This->DestBltCKey, CKey, sizeof(*CKey) ) != 0;
1851 This->DestBltCKey = *CKey;
1852 This->CKeyFlags |= DDSD_CKDESTBLT;
1855 case DDCKEY_DESTOVERLAY:
1856 if(!(This->CKeyFlags & DDSD_CKDESTOVERLAY)) {
1859 dirtify = memcmp(&This->DestOverlayCKey, CKey, sizeof(*CKey)) != 0;
1861 This->DestOverlayCKey = *CKey;
1862 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
1865 case DDCKEY_SRCOVERLAY:
1866 if(!(This->CKeyFlags & DDSD_CKSRCOVERLAY)) {
1869 dirtify = memcmp(&This->SrcOverlayCKey, CKey, sizeof(*CKey)) != 0;
1871 This->SrcOverlayCKey = *CKey;
1872 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
1876 if(!(This->CKeyFlags & DDSD_CKSRCBLT)) {
1879 dirtify = memcmp(&This->SrcBltCKey, CKey, sizeof(*CKey)) != 0;
1881 This->SrcBltCKey = *CKey;
1882 This->CKeyFlags |= DDSD_CKSRCBLT;
1887 switch (Flags & ~DDCKEY_COLORSPACE) {
1888 case DDCKEY_DESTBLT:
1889 dirtify = This->CKeyFlags & DDSD_CKDESTBLT;
1890 This->CKeyFlags &= ~DDSD_CKDESTBLT;
1893 case DDCKEY_DESTOVERLAY:
1894 dirtify = This->CKeyFlags & DDSD_CKDESTOVERLAY;
1895 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
1898 case DDCKEY_SRCOVERLAY:
1899 dirtify = This->CKeyFlags & DDSD_CKSRCOVERLAY;
1900 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
1904 dirtify = This->CKeyFlags & DDSD_CKSRCBLT;
1905 This->CKeyFlags &= ~DDSD_CKSRCBLT;
1911 TRACE("Color key changed, dirtifying surface\n");
1912 This->Flags |= SFLAG_DIRTY;
1918 HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
1919 /* Nothing to do for now */
1923 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
1924 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1926 TRACE("(%p)\n", This);
1928 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
1929 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
1930 ie pitch = (width/4) * bytes per block */
1931 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
1932 ret = (This->currentDesc.Width >> 2) << 3;
1933 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
1934 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
1935 ret = (This->currentDesc.Width >> 2) << 4;
1937 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
1938 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
1939 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
1941 ret = This->bytesPerPixel * This->pow2Width;
1944 TRACE("(%p) Returning %ld\n", This, ret);
1948 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
1951 IWineD3DSurfaceImpl_QueryInterface,
1952 IWineD3DSurfaceImpl_AddRef,
1953 IWineD3DSurfaceImpl_Release,
1954 /* IWineD3DResource */
1955 IWineD3DSurfaceImpl_GetParent,
1956 IWineD3DSurfaceImpl_GetDevice,
1957 IWineD3DSurfaceImpl_SetPrivateData,
1958 IWineD3DSurfaceImpl_GetPrivateData,
1959 IWineD3DSurfaceImpl_FreePrivateData,
1960 IWineD3DSurfaceImpl_SetPriority,
1961 IWineD3DSurfaceImpl_GetPriority,
1962 IWineD3DSurfaceImpl_PreLoad,
1963 IWineD3DSurfaceImpl_GetType,
1964 /* IWineD3DSurface */
1965 IWineD3DSurfaceImpl_GetContainerParent,
1966 IWineD3DSurfaceImpl_GetContainer,
1967 IWineD3DSurfaceImpl_GetDesc,
1968 IWineD3DSurfaceImpl_LockRect,
1969 IWineD3DSurfaceImpl_UnlockRect,
1970 IWineD3DSurfaceImpl_GetDC,
1971 IWineD3DSurfaceImpl_ReleaseDC,
1972 IWineD3DSurfaceImpl_Flip,
1973 IWineD3DSurfaceImpl_Blt,
1974 IWineD3DSurfaceImpl_GetBltStatus,
1975 IWineD3DSurfaceImpl_GetFlipStatus,
1976 IWineD3DSurfaceImpl_IsLost,
1977 IWineD3DSurfaceImpl_Restore,
1978 IWineD3DSurfaceImpl_BltFast,
1979 IWineD3DSurfaceImpl_SetPixelFormat,
1980 IWineD3DSurfaceImpl_GetPalette,
1981 IWineD3DSurfaceImpl_SetPalette,
1982 IWineD3DSurfaceImpl_RealizePalette,
1983 IWineD3DSurfaceImpl_SetColorKey,
1984 IWineD3DSurfaceImpl_GetPitch,
1986 IWineD3DSurfaceImpl_CleanDirtyRect,
1987 IWineD3DSurfaceImpl_AddDirtyRect,
1988 IWineD3DSurfaceImpl_LoadTexture,
1989 IWineD3DSurfaceImpl_SaveSnapshot,
1990 IWineD3DSurfaceImpl_SetContainer,
1991 IWineD3DSurfaceImpl_SetPBufferState,
1992 IWineD3DSurfaceImpl_SetGlTextureDesc,
1993 IWineD3DSurfaceImpl_GetGlDesc,
1994 IWineD3DSurfaceImpl_GetData,
1995 IWineD3DSurfaceImpl_SetFormat,
1996 IWineD3DSurfaceImpl_PrivateSetup