2 * IWineD3DSurface Implementation
4 * Copyright 2002-2005 Jason Edmeades
5 * Copyright 2002-2003 Raphael Junqueira
6 * Copyright 2004 Christian Costa
7 * Copyright 2005 Oliver Stieber
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "wine/port.h"
26 #include "wined3d_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
29 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
31 /* *******************************************
32 IWineD3DSurface IUnknown parts follow
33 ******************************************* */
34 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
36 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
37 /* Warn ,but be nice about things */
38 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
40 ERR("Probably FIXME: Calling query interface with NULL riid\n");
42 if (IsEqualGUID(riid, &IID_IUnknown)
43 || IsEqualGUID(riid, &IID_IWineD3DBase)
44 || IsEqualGUID(riid, &IID_IWineD3DResource)
45 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
46 IUnknown_AddRef((IUnknown*)iface);
53 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
54 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
55 ULONG ref = InterlockedIncrement(&This->resource.ref);
56 TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
60 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
61 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
62 ULONG ref = InterlockedDecrement(&This->resource.ref);
63 TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
65 TRACE("(%p) : cleaning up\n", This);
66 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
68 TRACE("Deleting texture %d\n", This->glDescription.textureName);
69 glDeleteTextures(1, &This->glDescription.textureName);
72 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
74 TRACE("(%p) Released\n", This);
75 HeapFree(GetProcessHeap(), 0, This);
81 /* ****************************************************
82 IWineD3DSurface IWineD3DResource parts follow
83 **************************************************** */
84 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
85 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
88 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
89 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
92 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
93 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
96 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
97 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
100 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
101 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
104 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
105 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
108 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
109 /* TODO: re-write the way textures and managed,
110 * use a 'opengl context manager' to manage RenderTarget surfaces
111 ** *********************************************************/
113 /* TODO: check for locks */
114 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
115 IWineD3DBaseTexture *baseTexture = NULL;
116 TRACE("(%p)Checking to see if the container is a base texture\n", This);
117 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == D3D_OK) {
118 TRACE("Passing to conatiner\n");
119 IWineD3DBaseTexture_PreLoad(baseTexture);
120 IWineD3DBaseTexture_Release(baseTexture);
122 TRACE("(%p) : About to load surface\n", This);
124 #if 0 /* TODO: context manager support */
125 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
127 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
128 if (This->glDescription.level == 0 && This->glDescription.textureName == 0) {
129 glGenTextures(1, &This->glDescription.textureName);
130 checkGLcall("glGenTextures");
131 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
132 glBindTexture(This->glDescription.target, This->glDescription.textureName);
133 checkGLcall("glBindTexture");
134 IWineD3DSurface_LoadTexture(iface);
135 /* This is where we should be reducing the amount of GLMemoryUsed */
137 if (This->glDescription.level == 0) {
138 glBindTexture(This->glDescription.target, This->glDescription.textureName);
139 checkGLcall("glBindTexture");
140 IWineD3DSurface_LoadTexture(iface);
141 } else if (This->glDescription.textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
142 /* assume this is a coding error not a real error for now */
143 FIXME("Mipmap surface has a glTexture bound to it!\n");
146 if (This->resource.pool == D3DPOOL_DEFAULT) {
147 /* Tell opengl to try and keep this texture in video ram (well mostly) */
150 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
152 /* TODO: disable texture support, if it wastn't enabled when we entered. */
153 #if 0 /* TODO: context manager support */
154 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
155 /* we don't care when the state is disabled(if atall) */);
162 D3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
163 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
164 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
167 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
168 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
169 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
172 /* ******************************************************
173 IWineD3DSurface IWineD3DSurface parts follow
174 ****************************************************** */
176 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
177 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
178 IWineD3DBase *container = 0;
180 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
183 ERR("Called without a valid ppContainer.\n");
187 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
188 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
189 * GetContainer will return the Direct3D device used to create the surface.
191 if (This->container) {
192 container = This->container;
194 IWineD3DSurface_GetDevice(iface, (IWineD3DDevice **)&container);
197 TRACE("Relaying to QueryInterface\n");
198 return IUnknown_QueryInterface(container, riid, ppContainer);
201 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
202 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
204 TRACE("(%p) : copying into %p\n", This, pDesc);
205 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
206 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
207 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
208 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
209 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
210 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
211 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
212 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
213 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
217 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
218 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
219 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
220 if (This->glDescription.textureName == 0 && textureName != 0) {
222 IWineD3DSurface_AddDirtyRect(iface, NULL);
224 This->glDescription.textureName = textureName;
225 This->glDescription.target = target;
228 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
229 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
230 TRACE("(%p) : returning %p\n", This, &This->glDescription);
231 *glDescription = &This->glDescription;
234 /* TODO: think about moving this down to resource? */
235 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
236 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
237 /* 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 */
238 if (This->resource.pool != D3DPOOL_SYSTEMMEM) {
239 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
241 return (CONST void*)(This->resource.allocatedMemory);
244 HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
245 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
246 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
247 IWineD3DSwapChainImpl *swapchain = NULL;
248 static UINT messages = 0; /* holds flags to disable fixme messages */
250 /* fixme: should we really lock as such? */
251 if (This->inTexture && This->inPBuffer) {
252 FIXME("Warning: Surface is in texture memory or pbuffer\n");
257 if (FALSE == This->lockable) {
258 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
259 texture regions, and since the destination is an unlockable region we need
261 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
262 /*return D3DERR_INVALIDCALL; */
265 if (This->resource.usage & D3DUSAGE_RENDERTARGET) {
266 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
268 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
269 if (swapchain != NULL && iface == swapchain->backBuffer) {
270 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
271 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
272 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
273 } else if (iface == myDevice->renderTarget) {
274 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
275 } else if (iface == myDevice->depthStencilBuffer) {
276 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
279 if (NULL != swapchain) {
280 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
285 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
288 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
289 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
290 ie pitch = (width/4) * bytes per block */
291 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
292 pLockedRect->Pitch = (This->currentDesc.Width >> 2) << 3;
293 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
294 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
295 pLockedRect->Pitch = (This->currentDesc.Width >> 2) << 4;
297 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & D3DUSAGE_RENDERTARGET) {
298 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
299 pLockedRect->Pitch = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
301 pLockedRect->Pitch = This->bytesPerPixel * This->pow2Width;
306 pLockedRect->pBits = This->resource.allocatedMemory;
307 This->lockedRect.left = 0;
308 This->lockedRect.top = 0;
309 This->lockedRect.right = This->currentDesc.Width;
310 This->lockedRect.bottom = This->currentDesc.Height;
311 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);
313 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
315 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
316 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
318 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
320 This->lockedRect.left = pRect->left;
321 This->lockedRect.top = pRect->top;
322 This->lockedRect.right = pRect->right;
323 This->lockedRect.bottom = pRect->bottom;
327 TRACE("Locking non-power 2 texture\n");
330 if (0 == This->resource.usage || This->resource.usage & D3DUSAGE_DYNAMIC) {
331 /* classic surface TODO: non 2d surfaces?
332 These resources may be POOL_SYSTEMMEM, so they must not access the device */
333 TRACE("locking an ordinarary surface\n");
334 /* Check to see if memory has already been allocated from the surface*/
335 if (NULL == This->resource.allocatedMemory) { /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
336 /* Non-system memory surfaces */
338 /*Surface has no memory currently allocated to it!*/
339 TRACE("(%p) Locking rect\n" , This);
340 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
341 if (0 != This->glDescription.textureName) {
342 /* Now I have to copy thing bits back */
343 This->activeLock = TRUE; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
344 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
347 /* Make sure that the texture is loaded */
348 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
350 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);
352 if (This->resource.format == WINED3DFMT_DXT1 ||
353 This->resource.format == WINED3DFMT_DXT2 ||
354 This->resource.format == WINED3DFMT_DXT3 ||
355 This->resource.format == WINED3DFMT_DXT4 ||
356 This->resource.format == WINED3DFMT_DXT5) {
357 TRACE("Locking a compressed texture\n");
358 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
359 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
360 This->glDescription.level,
361 This->resource.allocatedMemory);
364 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
367 glGetTexImage(This->glDescription.target,
368 This->glDescription.level,
369 This->glDescription.glFormat,
370 This->glDescription.glType,
371 This->resource.allocatedMemory);
372 vcheckGLcall("glGetTexImage");
373 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
374 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
375 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
376 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
380 instead of boxing the texture :
381 |<-texture width ->| -->pow2width| /\
382 |111111111111111111| | |
383 |222 Texture 222222| boxed empty | texture height
384 |3333 Data 33333333| | |
385 |444444444444444444| | \/
386 ----------------------------------- |
387 | boxed empty | boxed empty | pow2height
389 -----------------------------------
392 were repacking the data to the expected texture width
394 |<-texture width ->| -->pow2width| /\
395 |111111111111111111222222222222222| |
396 |222333333333333333333444444444444| texture height
402 -----------------------------------
406 |<-texture width ->| /\
408 |222222222222222222|texture height
410 |444444444444444444| \/
413 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.
415 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.
419 int pitcha = 0, pitchb = 0;
421 pitcha = This->bytesPerPixel * This->currentDesc.Width;
422 pitchb = This->bytesPerPixel * This->pow2Width;
423 datab = dataa = This->resource.allocatedMemory;
424 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
425 for (y = 1 ; y < This->currentDesc.Height; y++) {
426 dataa += pitcha; /* skip the first row */
428 memcpy(dataa, datab, pitcha);
435 } else { /* Nothing to do */
436 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
440 pLockedRect->pBits = This->resource.allocatedMemory;
442 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
443 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
445 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
449 } else if (D3DUSAGE_RENDERTARGET & This->resource.usage && !(Flags&D3DLOCK_DISCARD)) { /* render surfaces */
453 BOOL notInContext = FALSE;
454 IWineD3DSwapChainImpl *targetSwapChain = NULL;
460 * for render->surface copy begin to begin of allocatedMemory
461 * unlock can be more easy
464 TRACE("locking a render target\n");
466 if (This->resource.allocatedMemory == NULL)
467 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
469 This->activeLock = TRUE; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
470 pLockedRect->pBits = This->resource.allocatedMemory;
473 vcheckGLcall("glFlush");
474 glGetIntegerv(GL_READ_BUFFER, &prev_read);
475 vcheckGLcall("glIntegerv");
476 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
477 vcheckGLcall("glIntegerv");
479 /* Here's what we have to do:
480 See if the swapchain has the same context as the renderTarget or the surface is the render target.
481 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
482 and use the front back buffer as required.
483 if not, we need to switch contexts and then switchback at the end.
485 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
486 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
488 /* 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! */
489 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
490 if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) {
491 TRACE("locking back buffer\n");
492 glReadBuffer(GL_BACK);
493 } else if (iface == swapchain->frontBuffer) {
494 TRACE("locking front\n");
495 glReadBuffer(GL_FRONT);
496 } else if (iface == myDevice->depthStencilBuffer) {
497 FIXME("Stencil Buffer lock unsupported for now\n");
499 FIXME("(%p) Shouldn't have got here!\n", This);
500 glReadBuffer(GL_BACK);
502 } else if (swapchain != NULL) {
503 IWineD3DSwapChainImpl *implSwapChain;
504 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
505 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
506 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
507 if (iface == swapchain->backBuffer) {
508 glReadBuffer(GL_BACK);
509 } else if (iface == swapchain->frontBuffer) {
510 glReadBuffer(GL_FRONT);
511 } else if (iface == myDevice->depthStencilBuffer) {
512 FIXME("Stencil Buffer lock unsupported for now\n");
514 FIXME("Should have got here!\n");
515 glReadBuffer(GL_BACK);
518 /* We need to switch contexts to be able to read the buffer!!! */
519 FIXME("The buffer requested isn't in the current openGL context\n");
521 /* TODO: check the contexts, to see if were shared with the current context */
523 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
525 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
526 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
529 /** the depth stencil in openGL has a format of GL_FLOAT
530 * which should be good for WINED3DFMT_D16_LOCKABLE
532 * it is unclear what format the stencil buffer is in except.
533 * 'Each index is converted to fixed point...
534 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
535 * mappings in the table GL_PIXEL_MAP_S_TO_S.
536 * glReadPixels(This->lockedRect.left,
537 * This->lockedRect.bottom - j - 1,
538 * This->lockedRect.right - This->lockedRect.left,
540 * GL_DEPTH_COMPONENT,
542 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
543 *****************************************/
544 if (!notInContext) { /* Only read the buffer if it's in the current context */
547 /* 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,
548 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
549 * run ten times faster!
550 * ************************************/
551 BOOL ati_performance_hack = FALSE;
552 ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
554 if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
555 This->lockedRect.right == This->currentDesc.Width
556 && This->lockedRect.bottom == This->currentDesc.Height)) {
558 This->currentDesc.Width,
559 This->currentDesc.Height,
560 This->glDescription.glFormat,
561 This->glDescription.glType,
562 (char *)pLockedRect->pBits);
563 } else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
565 This->lockedRect.top,
566 This->currentDesc.Width,
567 This->currentDesc.Height,
568 This->glDescription.glFormat,
569 This->glDescription.glType,
570 (char *)pLockedRect->pBits);
573 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
574 glReadPixels(This->lockedRect.left,
575 This->lockedRect.bottom - j - 1,
576 This->lockedRect.right - This->lockedRect.left,
578 This->glDescription.glFormat,
579 This->glDescription.glType,
580 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
584 vcheckGLcall("glReadPixels");
585 TRACE("Resetting buffer\n");
586 glReadBuffer(prev_read);
587 vcheckGLcall("glReadBuffer");
591 } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
594 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
597 glReadPixels(This->lockedRect.left,
598 This->lockedRect.bottom - j - 1,
599 This->lockedRect.right - This->lockedRect.left,
601 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
608 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
611 if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
614 IWineD3DBaseTexture *pBaseTexture;
617 * as seen in msdn docs
619 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
621 /** Dirtify Container if needed */
622 if (D3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
623 TRACE("Making container dirty\n");
624 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
625 IWineD3DBaseTexture_Release(pBaseTexture);
627 TRACE("Surface is standalone, no need to dirty the container\n");
631 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Dirty);
637 HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
639 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
640 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
641 const char *buffername = "";
642 IWineD3DSwapChainImpl *swapchain = NULL;
644 if (FALSE == This->locked) {
645 WARN("trying to Unlock an unlocked surf@%p\n", This);
646 return D3DERR_INVALIDCALL;
649 if (D3DUSAGE_RENDERTARGET & This->resource.usage) {
650 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
652 if ((swapchain != NULL) && iface == swapchain->backBuffer) {
653 buffername = "backBuffer";
654 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
655 buffername = "frontBuffer";
656 } else if (iface == myDevice->depthStencilBuffer) {
657 buffername = "depthStencilBuffer";
658 } else if (iface == myDevice->renderTarget) {
659 buffername = "renderTarget";
663 if (swapchain != NULL) {
664 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
667 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Dirty);
669 if (FALSE == This->Dirty) {
670 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
674 if (0 == This->resource.usage) { /* classic surface */
677 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
679 } else if (D3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
681 /****************************
682 * TODO: Render targets are 'special' and
683 * ?some? locking needs to be passed onto the context manager
684 * so that it becomes possible to use auxiliary buffers, pbuffers
685 * render-to-texture, shared, cached contexts etc...
686 * ****************************/
687 IWineD3DSwapChainImpl *implSwapChain;
688 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
690 if (iface == implSwapChain->backBuffer || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
693 GLint prev_rasterpos[4];
698 vcheckGLcall("glFlush");
699 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
700 vcheckGLcall("glIntegerv");
701 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
702 vcheckGLcall("glIntegerv");
703 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
704 vcheckGLcall("glIntegerv");
705 glPixelZoom(1.0, -1.0);
706 vcheckGLcall("glPixelZoom");
708 /* glDrawPixels transforms the raster position as though it was a vertex -
709 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
710 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
711 if ( (!myDevice->last_was_rhw) || (myDevice->viewport_changed) ) {
713 double X, Y, height, width, minZ, maxZ;
714 myDevice->last_was_rhw = TRUE;
715 myDevice->viewport_changed = FALSE;
717 /* Transformed already into viewport coordinates, so we do not need transform
718 matrices. Reset all matrices to identity and leave the default matrix in world
720 glMatrixMode(GL_MODELVIEW);
721 checkGLcall("glMatrixMode");
723 checkGLcall("glLoadIdentity");
725 glMatrixMode(GL_PROJECTION);
726 checkGLcall("glMatrixMode");
728 checkGLcall("glLoadIdentity");
730 /* Set up the viewport to be full viewport */
731 X = myDevice->stateBlock->viewport.X;
732 Y = myDevice->stateBlock->viewport.Y;
733 height = myDevice->stateBlock->viewport.Height;
734 width = myDevice->stateBlock->viewport.Width;
735 minZ = myDevice->stateBlock->viewport.MinZ;
736 maxZ = myDevice->stateBlock->viewport.MaxZ;
737 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
738 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
739 checkGLcall("glOrtho");
741 /* Window Coord 0 is the middle of the first pixel, so translate by half
742 a pixel (See comment above glTranslate below) */
743 glTranslatef(0.5, 0.5, 0);
744 checkGLcall("glTranslatef(0.5, 0.5, 0)");
747 if (iface == implSwapChain->backBuffer || iface == myDevice->renderTarget) {
748 glDrawBuffer(GL_BACK);
749 } else if (iface == implSwapChain->frontBuffer) {
750 glDrawBuffer(GL_FRONT);
753 vcheckGLcall("glDrawBuffer");
755 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
756 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
757 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
759 /* And back buffers are not blended */
762 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
763 vcheckGLcall("glRasterPos2f");
764 switch (This->resource.format) {
765 case WINED3DFMT_X4R4G4B4:
768 unsigned short *data;
769 data = (unsigned short *)This->resource.allocatedMemory;
770 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
777 case WINED3DFMT_A4R4G4B4:
779 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
780 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
781 vcheckGLcall("glDrawPixels");
784 case WINED3DFMT_R5G6B5:
786 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
787 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
788 vcheckGLcall("glDrawPixels");
791 case WINED3DFMT_X1R5G5B5:
794 unsigned short *data;
795 data = (unsigned short *)This->resource.allocatedMemory;
796 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
803 case WINED3DFMT_A1R5G5B5:
805 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
806 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
807 vcheckGLcall("glDrawPixels");
810 case WINED3DFMT_R8G8B8:
812 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
813 GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
814 vcheckGLcall("glDrawPixels");
817 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
818 could be any random value this fixes the intro move in Pirates! */
822 data = (unsigned int *)This->resource.allocatedMemory;
823 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
830 case WINED3DFMT_A8R8G8B8:
832 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
833 vcheckGLcall("glPixelStorei");
834 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
835 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
836 vcheckGLcall("glDrawPixels");
837 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
838 vcheckGLcall("glPixelStorei");
841 case WINED3DFMT_A2R10G10B10:
843 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
844 vcheckGLcall("glPixelStorei");
845 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
846 GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
847 vcheckGLcall("glDrawPixels");
848 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
849 vcheckGLcall("glPixelStorei");
853 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
856 glPixelZoom(1.0,1.0);
857 vcheckGLcall("glPixelZoom");
858 glDrawBuffer(prev_draw);
859 vcheckGLcall("glDrawBuffer");
860 glRasterPos3iv(&prev_rasterpos[0]);
861 vcheckGLcall("glRasterPos3iv");
863 /* Reset to previous pack row length / blending state */
864 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
865 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
869 /** restore clean dirty state */
870 IWineD3DSurface_CleanDirtyRect(iface);
873 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->resource.usage);
875 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
877 } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
879 if (iface == myDevice->depthStencilBuffer) {
880 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
882 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
886 FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
890 This->locked = FALSE;
891 memset(&This->lockedRect, 0, sizeof(RECT));
895 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
896 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
897 FIXME("No support for GetDC yet for surface %p\n", This);
898 return D3DERR_INVALIDCALL;
901 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
902 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
903 FIXME("No support for ReleaseDC yet for surface %p\n", This);
904 return D3DERR_INVALIDCALL;
907 /* ******************************************************
908 IWineD3DSurface Internal (No mapping to directx api) parts follow
909 ****************************************************** */
910 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
911 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
913 if (This->inTexture) {
914 TRACE("Surface already in texture\n");
917 if (This->Dirty == FALSE) {
918 TRACE("surface isn't dirty\n");
924 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
925 * These resources are not bound by device size or format restrictions. Because of this,
926 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
927 * However, these resources can always be created, locked, and copied.
928 * In general never store scratch or system mem textures in the video ram. However it is allowed
929 * for system memory textures when D3DDEVCAPS_TEXTURESYSTEMMEMORY is set but it isn't right now.
931 if (This->resource.pool == D3DPOOL_SCRATCH || This->resource.pool == D3DPOOL_SYSTEMMEM)
933 FIXME("(%p) Operation not supported for scratch or SYSTEMMEM textures\n",This);
934 return D3DERR_INVALIDCALL;
937 if (This->inPBuffer) {
940 if (This->glDescription.level != 0)
941 FIXME("Surface in texture is only supported for level 0\n");
942 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
943 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
944 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
945 This->resource.format == WINED3DFMT_DXT5)
946 FIXME("Format %d not supported\n", This->resource.format);
949 glGetIntegerv(GL_READ_BUFFER, &prevRead);
950 vcheckGLcall("glGetIntegerv");
951 glReadBuffer(GL_BACK);
952 vcheckGLcall("glReadBuffer");
954 glCopyTexImage2D(This->glDescription.target,
955 This->glDescription.level,
956 This->glDescription.glFormatInternal,
959 This->currentDesc.Width,
960 This->currentDesc.Height,
963 checkGLcall("glCopyTexImage2D");
964 glReadBuffer(prevRead);
965 vcheckGLcall("glReadBuffer");
966 TRACE("Updating target %d\n", This->glDescription.target);
967 This->inTexture = TRUE;
973 if ((This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) &&
974 !GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
976 * wanted a paletted texture and not really support it in HW
977 * so software emulation code begin
980 PALETTEENTRY* pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
981 VOID* surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->currentDesc.Width * This->currentDesc.Height * sizeof(DWORD));
982 BYTE* dst = (BYTE*) surface;
983 BYTE* src = (BYTE*) This->resource.allocatedMemory;
985 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
987 *dst++ = pal[color].peRed;
988 *dst++ = pal[color].peGreen;
989 *dst++ = pal[color].peBlue;
990 if (This->resource.format == WINED3DFMT_A8P8)
991 *dst++ = pal[color].peFlags;
998 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
999 This->glDescription.target,
1000 This->glDescription.level,
1002 This->currentDesc.Width,
1003 This->currentDesc.Height,
1008 glTexImage2D(This->glDescription.target,
1009 This->glDescription.level,
1011 This->currentDesc.Width,
1012 This->currentDesc.Height,
1017 checkGLcall("glTexImage2D");
1018 HeapFree(GetProcessHeap(), 0, surface);
1025 /* TODO: Compressed non-power 2 support */
1027 if (This->resource.format == WINED3DFMT_DXT1 ||
1028 This->resource.format == WINED3DFMT_DXT2 ||
1029 This->resource.format == WINED3DFMT_DXT3 ||
1030 This->resource.format == WINED3DFMT_DXT4 ||
1031 This->resource.format == WINED3DFMT_DXT5) {
1032 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1033 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1034 This->glDescription.target,
1035 This->glDescription.level,
1036 This->glDescription.glFormatInternal,
1037 This->currentDesc.Width,
1038 This->currentDesc.Height,
1040 This->resource.size,
1041 This->resource.allocatedMemory);
1045 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1046 This->glDescription.level,
1047 This->glDescription.glFormatInternal,
1048 This->currentDesc.Width,
1049 This->currentDesc.Height,
1051 This->resource.size,
1052 This->resource.allocatedMemory);
1053 checkGLcall("glCommpressedTexTexImage2D");
1057 if(This->activeLock == FALSE){
1058 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1059 This->resource.allocatedMemory = NULL;
1063 FIXME("Using DXT1/3/5 without advertized support\n");
1067 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1068 if (NP2_REPACK == wined3d_settings.nonpower2_mode && This->nonpow2 == TRUE) {
1071 TRACE("non power of two support\n");
1073 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,
1074 This->glDescription.target,
1075 This->glDescription.level,
1076 debug_d3dformat(This->resource.format),
1077 This->glDescription.glFormatInternal,
1081 This->glDescription.glFormat,
1082 This->glDescription.glType,
1085 glTexImage2D(This->glDescription.target,
1086 This->glDescription.level,
1087 This->glDescription.glFormatInternal,
1091 This->glDescription.glFormat,
1092 This->glDescription.glType,
1095 checkGLcall("glTexImage2D");
1096 if (This->resource.allocatedMemory != NULL) {
1097 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1098 /* And map the non-power two data into the top left corner */
1100 This->glDescription.target,
1101 This->glDescription.level,
1104 This->currentDesc.Width,
1105 This->currentDesc.Height,
1106 This->glDescription.glFormat,
1107 This->glDescription.glType,
1108 This->resource.allocatedMemory
1110 checkGLcall("glTexSubImage2D");
1116 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1117 This->glDescription.target,
1118 This->glDescription.level,
1119 debug_d3dformat(This->resource.format),
1120 This->glDescription.glFormatInternal,
1124 This->glDescription.glFormat,
1125 This->glDescription.glType,
1126 This->resource.allocatedMemory);
1129 glTexImage2D(This->glDescription.target,
1130 This->glDescription.level,
1131 This->glDescription.glFormatInternal,
1135 This->glDescription.glFormat,
1136 This->glDescription.glType,
1137 This->resource.allocatedMemory);
1138 checkGLcall("glTexImage2D");
1144 static unsigned int gen = 0;
1147 if ((gen % 10) == 0) {
1148 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1149 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1152 * debugging crash code
1160 if(This->activeLock == FALSE){
1161 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1162 This->resource.allocatedMemory = NULL;
1172 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1175 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1176 char *allocatedMemory;
1178 IWineD3DSwapChain *swapChain = NULL;
1183 Textures my not be stored in ->allocatedgMemory and a GlTexture
1184 so we should lock the surface before saving a snapshot, or at least check that
1186 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1187 by calling GetTexImage and in compressed form by calling
1188 GetCompressedTexImageARB. Queried compressed images can be saved and
1189 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1190 texture images do not need to be processed by the GL and should
1191 significantly improve texture loading performance relative to uncompressed
1194 /* Setup the width and height to be the internal texture width and height. */
1195 width = This->pow2Width;
1196 height = This->pow2Height;
1197 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1198 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1200 if (swapChain || This->inPBuffer) { /* if were not a real texture then read the back buffer into a real texture*/
1201 /* 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 */
1204 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1205 glEnable(GL_TEXTURE_2D);
1207 glGenTextures(1, &tmpTexture);
1208 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1210 glTexImage2D(GL_TEXTURE_2D,
1217 GL_UNSIGNED_INT_8_8_8_8_REV,
1220 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1221 vcheckGLcall("glGetIntegerv");
1222 glReadBuffer(GL_BACK);
1223 vcheckGLcall("glReadBuffer");
1224 glCopyTexImage2D(GL_TEXTURE_2D,
1233 checkGLcall("glCopyTexImage2D");
1234 glReadBuffer(prevRead);
1237 } else { /* bind the real texture */
1238 IWineD3DSurface_PreLoad(iface);
1240 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1242 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1243 glGetTexImage(GL_TEXTURE_2D,
1244 This->glDescription.level,
1246 GL_UNSIGNED_INT_8_8_8_8_REV,
1248 checkGLcall("glTexImage2D");
1250 glBindTexture(GL_TEXTURE_2D, 0);
1251 glDeleteTextures(1, &tmpTexture);
1255 f = fopen(filename, "w+");
1257 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1258 return D3DERR_INVALIDCALL;
1260 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1261 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1276 fwrite(&width,2,1,f);
1278 fwrite(&height,2,1,f);
1283 /* 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*/
1285 textureRow = allocatedMemory + (width * (height - 1) *4);
1287 textureRow = allocatedMemory;
1288 for (y = 0 ; y < height; y++) {
1289 for (i = 0; i < width; i++) {
1290 color = *((DWORD*)textureRow);
1291 fputc((color >> 16) & 0xFF, f); /* B */
1292 fputc((color >> 8) & 0xFF, f); /* G */
1293 fputc((color >> 0) & 0xFF, f); /* R */
1294 fputc((color >> 24) & 0xFF, f); /* A */
1297 /* take two rows of the pointer to the texture memory */
1299 (textureRow-= width << 3);
1302 TRACE("Closing file\n");
1306 IWineD3DSwapChain_Release(swapChain);
1308 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1312 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1313 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1314 This->Dirty = FALSE;
1315 This->dirtyRect.left = This->currentDesc.Width;
1316 This->dirtyRect.top = This->currentDesc.Height;
1317 This->dirtyRect.right = 0;
1318 This->dirtyRect.bottom = 0;
1319 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1320 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1325 * Slightly inefficient way to handle multiple dirty rects but it works :)
1327 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1328 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1329 IWineD3DBaseTexture *baseTexture = NULL;
1331 if (NULL != pDirtyRect) {
1332 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1333 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1334 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1335 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1337 This->dirtyRect.left = 0;
1338 This->dirtyRect.top = 0;
1339 This->dirtyRect.right = This->currentDesc.Width;
1340 This->dirtyRect.bottom = This->currentDesc.Height;
1342 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1343 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1344 /* if the container is a basetexture then mark it dirty. */
1345 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == D3D_OK) {
1346 TRACE("Passing to conatiner\n");
1347 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1348 IWineD3DBaseTexture_Release(baseTexture);
1353 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1354 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1356 TRACE("This %p, container %p\n", This, container);
1358 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1360 TRACE("Setting container to %p from %p\n", container, This->container);
1361 This->container = container;
1366 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1367 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1369 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1370 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1371 return D3DERR_INVALIDCALL;
1374 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1375 if (format == WINED3DFMT_UNKNOWN) {
1376 This->resource.size = 0;
1377 } else if (format == WINED3DFMT_DXT1) {
1378 /* DXT1 is half byte per pixel */
1379 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1381 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1382 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1383 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1385 This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1389 /* Setup some glformat defaults */
1390 if (format != WINED3DFMT_UNKNOWN) {
1391 This->glDescription.glFormat = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1392 This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1393 This->glDescription.glType = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1395 This->glDescription.glFormat = 0;
1396 This->glDescription.glFormatInternal = 0;
1397 This->glDescription.glType = 0;
1400 if (format != WINED3DFMT_UNKNOWN) {
1401 This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1402 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1404 This->bytesPerPixel = 0;
1408 This->lockable = (WINED3DFMT_D16_LOCKABLE == format) ? TRUE : This->lockable;
1410 This->resource.format = format;
1412 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);
1417 /* TODO: replace this function with context management routines */
1418 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1419 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1421 This->inPBuffer = inPBuffer;
1422 This->inTexture = inTexture;
1426 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
1429 IWineD3DSurfaceImpl_QueryInterface,
1430 IWineD3DSurfaceImpl_AddRef,
1431 IWineD3DSurfaceImpl_Release,
1432 /* IWineD3DResource */
1433 IWineD3DSurfaceImpl_GetParent,
1434 IWineD3DSurfaceImpl_GetDevice,
1435 IWineD3DSurfaceImpl_SetPrivateData,
1436 IWineD3DSurfaceImpl_GetPrivateData,
1437 IWineD3DSurfaceImpl_FreePrivateData,
1438 IWineD3DSurfaceImpl_SetPriority,
1439 IWineD3DSurfaceImpl_GetPriority,
1440 IWineD3DSurfaceImpl_PreLoad,
1441 IWineD3DSurfaceImpl_GetType,
1442 /* IWineD3DSurface */
1443 IWineD3DSurfaceImpl_GetContainer,
1444 IWineD3DSurfaceImpl_GetDesc,
1445 IWineD3DSurfaceImpl_LockRect,
1446 IWineD3DSurfaceImpl_UnlockRect,
1447 IWineD3DSurfaceImpl_GetDC,
1448 IWineD3DSurfaceImpl_ReleaseDC,
1450 IWineD3DSurfaceImpl_CleanDirtyRect,
1451 IWineD3DSurfaceImpl_AddDirtyRect,
1452 IWineD3DSurfaceImpl_LoadTexture,
1453 IWineD3DSurfaceImpl_SaveSnapshot,
1454 IWineD3DSurfaceImpl_SetContainer,
1455 IWineD3DSurfaceImpl_SetPBufferState,
1456 IWineD3DSurfaceImpl_SetGlTextureDesc,
1457 IWineD3DSurfaceImpl_GetGlDesc,
1458 IWineD3DSurfaceImpl_GetData,
1459 IWineD3DSurfaceImpl_SetFormat