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_IWineD3DResource)
44 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
45 IUnknown_AddRef((IUnknown*)iface);
52 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
53 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
54 ULONG ref = InterlockedIncrement(&This->resource.ref);
55 TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
59 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
60 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
61 ULONG ref = InterlockedDecrement(&This->resource.ref);
62 TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
64 TRACE("(%p) : cleaning up\n", This);
65 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
67 TRACE("Deleting texture %d\n", This->glDescription.textureName);
68 glDeleteTextures(1, &This->glDescription.textureName);
71 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
73 TRACE("(%p) Released\n", This);
74 HeapFree(GetProcessHeap(), 0, This);
80 /* ****************************************************
81 IWineD3DSurface IWineD3DResource parts follow
82 **************************************************** */
83 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
84 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
87 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
88 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
91 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
92 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
95 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
96 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
99 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
100 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
103 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
104 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
107 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
108 /* TODO: re-write the way textures and managed,
109 * use a 'opengl context manager' to manage RenderTarget surfaces
110 ** *********************************************************/
112 /* TODO: check for locks */
113 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
114 IWineD3DBaseTexture *baseTexture = NULL;
115 TRACE("(%p)Checking to see if the container is a base texture\n", This);
116 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == D3D_OK) {
117 TRACE("Passing to conatiner\n");
118 IWineD3DBaseTexture_PreLoad(baseTexture);
119 IWineD3DBaseTexture_Release(baseTexture);
121 TRACE("(%p) : About to load surface\n", This);
123 #if 0 /* TODO: context manager support */
124 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
126 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
127 if (This->glDescription.level == 0 && This->glDescription.textureName == 0) {
128 glGenTextures(1, &This->glDescription.textureName);
129 checkGLcall("glGenTextures");
130 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
131 glBindTexture(This->glDescription.target, This->glDescription.textureName);
132 checkGLcall("glBindTexture");
133 IWineD3DSurface_LoadTexture(iface);
134 /* This is where we should be reducing the amount of GLMemoryUsed */
136 if (This->glDescription.level == 0) {
137 glBindTexture(This->glDescription.target, This->glDescription.textureName);
138 checkGLcall("glBindTexture");
139 IWineD3DSurface_LoadTexture(iface);
140 } else if (This->glDescription.textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
141 /* assume this is a coding error not a real error for now */
142 FIXME("Mipmap surface has a glTexture bound to it!\n");
145 if (This->resource.pool == D3DPOOL_DEFAULT) {
146 /* Tell opengl to try and keep this texture in video ram (well mostly) */
149 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
151 /* TODO: disable texture support, if it wastn't enabled when we entered. */
152 #if 0 /* TODO: context manager support */
153 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
154 /* we don't care when the state is disabled(if atall) */);
161 D3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
162 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
163 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
166 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
167 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
168 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
171 /* ******************************************************
172 IWineD3DSurface IWineD3DSurface parts follow
173 ****************************************************** */
175 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
176 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
178 if (ppContainer == NULL) {
179 ERR("Get container called witout a null ppContainer\n");
180 return E_NOINTERFACE;
182 TRACE("(%p) : Relaying to queryInterface %p %p\n", This, ppContainer, *ppContainer);
184 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
185 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
186 * GetContainer will return the Direct3D device used to create the surface.
188 hr = IUnknown_QueryInterface(This->container, riid, ppContainer);
192 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
193 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
195 TRACE("(%p) : copying into %p\n", This, pDesc);
196 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
197 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
198 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
199 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
200 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
201 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
202 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
203 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
204 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
208 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
209 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
210 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
211 if (This->glDescription.textureName == 0 && textureName != 0) {
213 IWineD3DSurface_AddDirtyRect(iface, NULL);
215 This->glDescription.textureName = textureName;
216 This->glDescription.target = target;
219 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
220 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
221 TRACE("(%p) : returning %p\n", This, &This->glDescription);
222 *glDescription = &This->glDescription;
225 /* TODO: think about moving this down to resource? */
226 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
227 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
228 /* 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 */
229 if (This->resource.pool != D3DPOOL_SYSTEMMEM) {
230 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
232 return (CONST void*)(This->resource.allocatedMemory);
235 HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
236 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
237 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
238 IWineD3DSwapChainImpl *swapchain = NULL;
239 static UINT messages = 0; /* holds flags to disable fixme messages */
241 /* fixme: should we really lock as such? */
242 if (This->inTexture && This->inPBuffer) {
243 FIXME("Warning: Surface is in texture memory or pbuffer\n");
248 if (FALSE == This->lockable) {
249 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
250 texture regions, and since the destination is an unlockable region we need
252 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
253 /*return D3DERR_INVALIDCALL; */
256 if (This->resource.usage & D3DUSAGE_RENDERTARGET) {
257 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
259 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
260 if (swapchain != NULL && iface == swapchain->backBuffer) {
261 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
262 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
263 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
264 } else if (iface == myDevice->renderTarget) {
265 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
266 } else if (iface == myDevice->depthStencilBuffer) {
267 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
270 if (NULL != swapchain) {
271 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
276 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
279 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
280 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
281 ie pitch = (width/4) * bytes per block */
282 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
283 pLockedRect->Pitch = (This->currentDesc.Width >> 2) << 3;
284 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
285 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
286 pLockedRect->Pitch = (This->currentDesc.Width >> 2) << 4;
288 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & D3DUSAGE_RENDERTARGET) {
289 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
290 pLockedRect->Pitch = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
292 pLockedRect->Pitch = This->bytesPerPixel * This->pow2Width;
297 pLockedRect->pBits = This->resource.allocatedMemory;
298 This->lockedRect.left = 0;
299 This->lockedRect.top = 0;
300 This->lockedRect.right = This->currentDesc.Width;
301 This->lockedRect.bottom = This->currentDesc.Height;
302 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);
304 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
306 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
307 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
309 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
311 This->lockedRect.left = pRect->left;
312 This->lockedRect.top = pRect->top;
313 This->lockedRect.right = pRect->right;
314 This->lockedRect.bottom = pRect->bottom;
318 TRACE("Locking non-power 2 texture\n");
321 if (0 == This->resource.usage || This->resource.usage & D3DUSAGE_DYNAMIC) {
322 /* classic surface TODO: non 2d surfaces?
323 Thease resources may be POOL_SYSTEMMEM, so they must not access the device */
324 TRACE("locking an ordinarary surface\n");
325 /* Check to see if memory has already been allocated fro the sufrace*/
326 if (NULL == This->resource.allocatedMemory) { /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
327 /* Non-systemmemory surfaces */
329 /*Surface has no memory currently allocate to it!*/
330 TRACE("(%p) Locking rect\n" , This);
331 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
332 if (0 != This->glDescription.textureName) {
333 /* Now I have to copy thing bits back */
334 This->activeLock = TRUE; /* When this flag is set to true, laoding the surface again won't free THis->resource.allocatedMemory */
335 /* TODO: make activeLock a bit more intelegent, maybe implement a method to purge the texture memory. */
338 /* Make sure that the texture is loaded */
339 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
341 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);
343 if (This->resource.format == WINED3DFMT_DXT1 ||
344 This->resource.format == WINED3DFMT_DXT2 ||
345 This->resource.format == WINED3DFMT_DXT3 ||
346 This->resource.format == WINED3DFMT_DXT4 ||
347 This->resource.format == WINED3DFMT_DXT5) {
348 TRACE("Locking a compressed texture\n");
349 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
350 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
351 This->glDescription.level,
352 This->resource.allocatedMemory);
355 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
358 glGetTexImage(This->glDescription.target,
359 This->glDescription.level,
360 This->glDescription.glFormat,
361 This->glDescription.glType,
362 This->resource.allocatedMemory);
363 vcheckGLcall("glGetTexImage");
364 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
365 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
366 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
367 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
371 instead of boxing the texture :
372 |<-texture width ->| -->pow2width| /\
373 |111111111111111111| | |
374 |222 Texture 222222| boxed empty | texture height
375 |3333 Data 33333333| | |
376 |444444444444444444| | \/
377 ----------------------------------- |
378 | boxed empty | boxed empty | pow2height
380 -----------------------------------
383 were repacking the data to the expected texture width
385 |<-texture width ->| -->pow2width| /\
386 |111111111111111111222222222222222| |
387 |222333333333333333333444444444444| texture height
393 -----------------------------------
397 |<-texture width ->| /\
399 |222222222222222222|texture height
401 |444444444444444444| \/
404 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.
406 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.
410 int pitcha = 0, pitchb = 0;
412 pitcha = This->bytesPerPixel * This->currentDesc.Width;
413 pitchb = This->bytesPerPixel * This->pow2Width;
414 datab = dataa = This->resource.allocatedMemory;
415 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
416 for (y = 1 ; y < This->currentDesc.Height; y++) {
417 dataa += pitcha; /* skip the first row */
419 memcpy(dataa, datab, pitcha);
426 } else { /* Nothing to do */
427 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
431 pLockedRect->pBits = This->resource.allocatedMemory;
433 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
434 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
436 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
440 } else if (D3DUSAGE_RENDERTARGET & This->resource.usage && !(Flags&D3DLOCK_DISCARD)) { /* render surfaces */
444 BOOL notInContext = FALSE;
445 IWineD3DSwapChainImpl *targetSwapChain = NULL;
451 * for render->surface copy begin to begin of allocatedMemory
452 * unlock can be more easy
455 TRACE("locking a render target\n");
457 if (This->resource.allocatedMemory == NULL)
458 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
460 This->activeLock = TRUE; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
461 pLockedRect->pBits = This->resource.allocatedMemory;
464 vcheckGLcall("glFlush");
465 glGetIntegerv(GL_READ_BUFFER, &prev_read);
466 vcheckGLcall("glIntegerv");
467 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
468 vcheckGLcall("glIntegerv");
470 /* Here's what we have to do:
471 See if the swapchain has the same context as the renderTarget or the surface is the render target.
472 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
473 and use the front back buffer as required.
474 if not, we need to switch contexts and then switchback at the end.
476 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
477 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
479 /* 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! */
480 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
481 if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) {
482 TRACE("locking back buffer\n");
483 glReadBuffer(GL_BACK);
484 } else if (iface == swapchain->frontBuffer) {
485 TRACE("locking front\n");
486 glReadBuffer(GL_FRONT);
487 } else if (iface == myDevice->depthStencilBuffer) {
488 FIXME("Stencil Buffer lock unsupported for now\n");
490 FIXME("(%p) Shouldn't have got here!\n", This);
491 glReadBuffer(GL_BACK);
493 } else if (swapchain != NULL) {
494 IWineD3DSwapChainImpl *implSwapChain;
495 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
496 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
497 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
498 if (iface == swapchain->backBuffer) {
499 glReadBuffer(GL_BACK);
500 } else if (iface == swapchain->frontBuffer) {
501 glReadBuffer(GL_FRONT);
502 } else if (iface == myDevice->depthStencilBuffer) {
503 FIXME("Stencil Buffer lock unsupported for now\n");
505 FIXME("Should have got here!\n");
506 glReadBuffer(GL_BACK);
509 /* We need to switch contexts to be able to read the buffer!!! */
510 FIXME("The buffer requested isn't in the current openGL context\n");
512 /* TODO: check the contexts, to see if were shared with the current context */
514 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
516 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
517 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
520 /** the depth stencil in openGL has a format of GL_FLOAT
521 * which should be good for WINED3DFMT_D16_LOCKABLE
523 * it is unclear what format the stencil buffer is in except.
524 * 'Each index is converted to fixed point...
525 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
526 * mappings in the table GL_PIXEL_MAP_S_TO_S.
527 * glReadPixels(This->lockedRect.left,
528 * This->lockedRect.bottom - j - 1,
529 * This->lockedRect.right - This->lockedRect.left,
531 * GL_DEPTH_COMPONENT,
533 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
534 *****************************************/
535 if (!notInContext) { /* Only read the buffer if it's in the current context */
538 /* 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,
539 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
540 * run ten times faster!
541 * ************************************/
542 BOOL ati_performance_hack = FALSE;
543 ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
545 if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
546 This->lockedRect.right == This->currentDesc.Width
547 && This->lockedRect.bottom == This->currentDesc.Height)) {
549 This->currentDesc.Width,
550 This->currentDesc.Height,
551 This->glDescription.glFormat,
552 This->glDescription.glType,
553 (char *)pLockedRect->pBits);
554 } else if (This->lockedRect.left == 0 && This->lockedRect.right == This->currentDesc.Width) {
556 This->lockedRect.top,
557 This->currentDesc.Width,
558 This->currentDesc.Height,
559 This->glDescription.glFormat,
560 This->glDescription.glType,
561 (char *)pLockedRect->pBits);
564 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
565 glReadPixels(This->lockedRect.left,
566 This->lockedRect.bottom - j - 1,
567 This->lockedRect.right - This->lockedRect.left,
569 This->glDescription.glFormat,
570 This->glDescription.glType,
571 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
575 vcheckGLcall("glReadPixels");
576 TRACE("Resetting buffer\n");
577 glReadBuffer(prev_read);
578 vcheckGLcall("glReadBuffer");
582 } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
585 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
588 glReadPixels(This->lockedRect.left,
589 This->lockedRect.bottom - j - 1,
590 This->lockedRect.right - This->lockedRect.left,
592 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
599 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
602 if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
605 IWineD3DBaseTexture *pBaseTexture;
608 * as seen in msdn docs
610 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
612 /** Dirtify Container if needed */
613 if (D3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
614 TRACE("Making container dirty\n");
615 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
616 IWineD3DBaseTexture_Release(pBaseTexture);
618 TRACE("Surface is standalone, no need to dirty the container\n");
622 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Dirty);
628 HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
630 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
631 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
632 const char *buffername = "";
633 IWineD3DSwapChainImpl *swapchain = NULL;
635 if (FALSE == This->locked) {
636 WARN("trying to Unlock an unlocked surf@%p\n", This);
637 return D3DERR_INVALIDCALL;
640 if (D3DUSAGE_RENDERTARGET & This->resource.usage) {
641 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
643 if ((swapchain != NULL) && iface == swapchain->backBuffer) {
644 buffername = "backBuffer";
645 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
646 buffername = "frontBuffer";
647 } else if (iface == myDevice->depthStencilBuffer) {
648 buffername = "depthStencilBuffer";
649 } else if (iface == myDevice->renderTarget) {
650 buffername = "renderTarget";
654 if (swapchain != NULL) {
655 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
658 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Dirty);
660 if (FALSE == This->Dirty) {
661 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
665 if (0 == This->resource.usage) { /* classic surface */
668 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
670 } else if (D3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
672 /****************************
673 * TODO: Render targets are 'special' and
674 * ?some? locking needs to be passed onto the context manager
675 * so that it becomes possible to use auxiliary buffers, pbuffers
676 * render-to-texture, shared, cached contexts etc...
677 * ****************************/
678 IWineD3DSwapChainImpl *implSwapChain;
679 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
681 if (iface == implSwapChain->backBuffer || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
684 GLint prev_rasterpos[4];
689 vcheckGLcall("glFlush");
690 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
691 vcheckGLcall("glIntegerv");
692 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
693 vcheckGLcall("glIntegerv");
694 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
695 vcheckGLcall("glIntegerv");
696 glPixelZoom(1.0, -1.0);
697 vcheckGLcall("glPixelZoom");
699 /* glDrawPixels transforms the raster position as though it was a vertex -
700 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
701 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
702 if (!myDevice->last_was_rhw) {
704 double X, Y, height, width, minZ, maxZ;
705 myDevice->last_was_rhw = TRUE;
707 /* Transformed already into viewport coordinates, so we do not need transform
708 matrices. Reset all matrices to identity and leave the default matrix in world
710 glMatrixMode(GL_MODELVIEW);
711 checkGLcall("glMatrixMode");
713 checkGLcall("glLoadIdentity");
715 glMatrixMode(GL_PROJECTION);
716 checkGLcall("glMatrixMode");
718 checkGLcall("glLoadIdentity");
720 /* Set up the viewport to be full viewport */
721 X = myDevice->stateBlock->viewport.X;
722 Y = myDevice->stateBlock->viewport.Y;
723 height = myDevice->stateBlock->viewport.Height;
724 width = myDevice->stateBlock->viewport.Width;
725 minZ = myDevice->stateBlock->viewport.MinZ;
726 maxZ = myDevice->stateBlock->viewport.MaxZ;
727 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
728 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
729 checkGLcall("glOrtho");
731 /* Window Coord 0 is the middle of the first pixel, so translate by half
732 a pixel (See comment above glTranslate below) */
733 glTranslatef(0.5, 0.5, 0);
734 checkGLcall("glTranslatef(0.5, 0.5, 0)");
737 if (iface == implSwapChain->backBuffer || iface == myDevice->renderTarget) {
738 glDrawBuffer(GL_BACK);
739 } else if (iface == implSwapChain->frontBuffer) {
740 glDrawBuffer(GL_FRONT);
743 vcheckGLcall("glDrawBuffer");
745 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
746 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
747 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
749 /* And back buffers are not blended */
752 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
753 vcheckGLcall("glRasterPos2f");
754 switch (This->resource.format) {
755 case WINED3DFMT_R5G6B5:
757 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
758 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
759 vcheckGLcall("glDrawPixels");
762 case WINED3DFMT_X1R5G5B5:
765 unsigned short *data;
766 data = (unsigned short *)This->resource.allocatedMemory;
767 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
774 case WINED3DFMT_A1R5G5B5:
776 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
777 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
778 vcheckGLcall("glDrawPixels");
781 case WINED3DFMT_R8G8B8:
783 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
784 GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
785 vcheckGLcall("glDrawPixels");
788 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
789 could be any random value this fixes the intro move in Pirates! */
793 data = (unsigned int *)This->resource.allocatedMemory;
794 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
801 case WINED3DFMT_A8R8G8B8:
803 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
804 vcheckGLcall("glPixelStorei");
805 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
806 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
807 vcheckGLcall("glDrawPixels");
808 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
809 vcheckGLcall("glPixelStorei");
812 case WINED3DFMT_A2R10G10B10:
814 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
815 vcheckGLcall("glPixelStorei");
816 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
817 GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
818 vcheckGLcall("glDrawPixels");
819 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
820 vcheckGLcall("glPixelStorei");
824 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
827 glPixelZoom(1.0,1.0);
828 vcheckGLcall("glPixelZoom");
829 glDrawBuffer(prev_draw);
830 vcheckGLcall("glDrawBuffer");
831 glRasterPos3iv(&prev_rasterpos[0]);
832 vcheckGLcall("glRasterPos3iv");
834 /* Reset to previous pack row length / blending state */
835 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
836 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
840 /** restore clean dirty state */
841 IWineD3DSurface_CleanDirtyRect(iface);
844 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->resource.usage);
846 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
848 } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
850 if (iface == myDevice->depthStencilBuffer) {
851 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
853 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
857 FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
861 This->locked = FALSE;
862 memset(&This->lockedRect, 0, sizeof(RECT));
866 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
867 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
868 FIXME("No support for GetDC yet for surface %p\n", This);
869 return D3DERR_INVALIDCALL;
872 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
873 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
874 FIXME("No support for ReleaseDC yet for surface %p\n", This);
875 return D3DERR_INVALIDCALL;
878 /* ******************************************************
879 IWineD3DSurface Internal (No mapping to directx api) parts follow
880 ****************************************************** */
881 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
882 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
884 if (This->inTexture) {
885 TRACE("Surface already in texture\n");
888 if (This->Dirty == FALSE) {
889 TRACE("surface isn't dirty\n");
895 /* Resources are placed in system RAM and do not need to be recreated when a device is lost. These resources are not bound by device size or format restrictions. Because of this, these resources cannot be accessed by the Direct3D device nor set as textures or render targets. However, these resources can always be created, locked, and copied. */
896 if (This->resource.pool == D3DPOOL_SCRATCH || This->resource.pool == D3DPOOL_SYSTEMMEM) /*never store scratch or system mem textures in the video ram*/
898 FIXME("(%p) Opperation not supported for scratch or SYSTEMMEM textures\n",This);
899 return D3DERR_INVALIDCALL;
902 if (This->inPBuffer) {
905 if (This->glDescription.level != 0)
906 FIXME("Surface in texture is only supported for level 0\n");
907 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
908 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
909 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
910 This->resource.format == WINED3DFMT_DXT5)
911 FIXME("Format %d not supported\n", This->resource.format);
914 glGetIntegerv(GL_READ_BUFFER, &prevRead);
915 vcheckGLcall("glGetIntegerv");
916 glReadBuffer(GL_BACK);
917 vcheckGLcall("glReadBuffer");
919 glCopyTexImage2D(This->glDescription.target,
920 This->glDescription.level,
921 This->glDescription.glFormatInternal,
924 This->currentDesc.Width,
925 This->currentDesc.Height,
928 checkGLcall("glCopyTexImage2D");
929 glReadBuffer(prevRead);
930 vcheckGLcall("glReadBuffer");
931 TRACE("Updating target %d\n", This->glDescription.target);
932 This->inTexture = TRUE;
938 if ((This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) &&
939 !GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
941 * wanted a paletted texture and not really support it in HW
942 * so software emulation code begin
945 PALETTEENTRY* pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
946 VOID* surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->currentDesc.Width * This->currentDesc.Height * sizeof(DWORD));
947 BYTE* dst = (BYTE*) surface;
948 BYTE* src = (BYTE*) This->resource.allocatedMemory;
950 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
952 *dst++ = pal[color].peRed;
953 *dst++ = pal[color].peGreen;
954 *dst++ = pal[color].peBlue;
955 if (This->resource.format == WINED3DFMT_A8P8)
956 *dst++ = pal[color].peFlags;
963 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
964 This->glDescription.target,
965 This->glDescription.level,
967 This->currentDesc.Width,
968 This->currentDesc.Height,
973 glTexImage2D(This->glDescription.target,
974 This->glDescription.level,
976 This->currentDesc.Width,
977 This->currentDesc.Height,
982 checkGLcall("glTexImage2D");
983 HeapFree(GetProcessHeap(), 0, surface);
990 /* TODO: Compressed non-power 2 support */
992 if (This->resource.format == WINED3DFMT_DXT1 ||
993 This->resource.format == WINED3DFMT_DXT2 ||
994 This->resource.format == WINED3DFMT_DXT3 ||
995 This->resource.format == WINED3DFMT_DXT4 ||
996 This->resource.format == WINED3DFMT_DXT5) {
997 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
998 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
999 This->glDescription.target,
1000 This->glDescription.level,
1001 This->glDescription.glFormatInternal,
1002 This->currentDesc.Width,
1003 This->currentDesc.Height,
1005 This->resource.size,
1006 This->resource.allocatedMemory);
1010 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1011 This->glDescription.level,
1012 This->glDescription.glFormatInternal,
1013 This->currentDesc.Width,
1014 This->currentDesc.Height,
1016 This->resource.size,
1017 This->resource.allocatedMemory);
1018 checkGLcall("glCommpressedTexTexImage2D");
1022 if(This->activeLock == FALSE){
1023 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1024 This->resource.allocatedMemory = NULL;
1028 FIXME("Using DXT1/3/5 without advertized support\n");
1032 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1033 if (NP2_REPACK == wined3d_settings.nonpower2_mode && This->nonpow2 == TRUE) {
1036 TRACE("non power of two support\n");
1038 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,
1039 This->glDescription.target,
1040 This->glDescription.level,
1041 debug_d3dformat(This->resource.format),
1042 This->glDescription.glFormatInternal,
1046 This->glDescription.glFormat,
1047 This->glDescription.glType,
1050 glTexImage2D(This->glDescription.target,
1051 This->glDescription.level,
1052 This->glDescription.glFormatInternal,
1056 This->glDescription.glFormat,
1057 This->glDescription.glType,
1060 checkGLcall("glTexImage2D");
1061 if (This->resource.allocatedMemory != NULL) {
1062 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1063 /* And map the non-power two data into the top left corner */
1065 This->glDescription.target,
1066 This->glDescription.level,
1069 This->currentDesc.Width,
1070 This->currentDesc.Height,
1071 This->glDescription.glFormat,
1072 This->glDescription.glType,
1073 This->resource.allocatedMemory
1075 checkGLcall("glTexSubImage2D");
1081 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1082 This->glDescription.target,
1083 This->glDescription.level,
1084 debug_d3dformat(This->resource.format),
1085 This->glDescription.glFormatInternal,
1089 This->glDescription.glFormat,
1090 This->glDescription.glType,
1091 This->resource.allocatedMemory);
1094 glTexImage2D(This->glDescription.target,
1095 This->glDescription.level,
1096 This->glDescription.glFormatInternal,
1100 This->glDescription.glFormat,
1101 This->glDescription.glType,
1102 This->resource.allocatedMemory);
1103 checkGLcall("glTexImage2D");
1109 static unsigned int gen = 0;
1112 if ((gen % 10) == 0) {
1113 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1114 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1117 * debugging crash code
1125 if(This->activeLock == FALSE){
1126 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1127 This->resource.allocatedMemory = NULL;
1137 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1140 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1141 char *allocatedMemory;
1143 IWineD3DSwapChain *swapChain = NULL;
1148 Textures my not be stored in ->allocatedgMemory and a GlTexture
1149 so we should lock the surface before saving a snapshot, or at least check that
1151 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1152 by calling GetTexImage and in compressed form by calling
1153 GetCompressedTexImageARB. Queried compressed images can be saved and
1154 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1155 texture images do not need to be processed by the GL and should
1156 significantly improve texture loading performance relative to uncompressed
1159 /* Setup the width and height to be the internal texture width and height. */
1160 width = This->pow2Width;
1161 height = This->pow2Height;
1162 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1163 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1165 if (swapChain || This->inPBuffer) { /* if were not a real texture then read the back buffer into a real texture*/
1166 /* 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 */
1169 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1170 glEnable(GL_TEXTURE_2D);
1172 glGenTextures(1, &tmpTexture);
1173 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1175 glTexImage2D(GL_TEXTURE_2D,
1182 GL_UNSIGNED_INT_8_8_8_8_REV,
1185 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1186 vcheckGLcall("glGetIntegerv");
1187 glReadBuffer(GL_BACK);
1188 vcheckGLcall("glReadBuffer");
1189 glCopyTexImage2D(GL_TEXTURE_2D,
1198 checkGLcall("glCopyTexImage2D");
1199 glReadBuffer(prevRead);
1202 } else { /* bind the real texture */
1203 IWineD3DSurface_PreLoad(iface);
1205 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1207 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1208 glGetTexImage(GL_TEXTURE_2D,
1209 This->glDescription.level,
1211 GL_UNSIGNED_INT_8_8_8_8_REV,
1213 checkGLcall("glTexImage2D");
1215 glBindTexture(GL_TEXTURE_2D, 0);
1216 glDeleteTextures(1, &tmpTexture);
1220 f = fopen(filename, "w+");
1222 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1223 return D3DERR_INVALIDCALL;
1225 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1226 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1241 fwrite(&width,2,1,f);
1243 fwrite(&height,2,1,f);
1248 /* 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*/
1250 textureRow = allocatedMemory + (width * (height - 1) *4);
1252 textureRow = allocatedMemory;
1253 for (y = 0 ; y < height; y++) {
1254 for (i = 0; i < width; i++) {
1255 color = *((DWORD*)textureRow);
1256 fputc((color >> 16) & 0xFF, f); /* B */
1257 fputc((color >> 8) & 0xFF, f); /* G */
1258 fputc((color >> 0) & 0xFF, f); /* R */
1259 fputc((color >> 24) & 0xFF, f); /* A */
1262 /* take two rows of the pointer to the texture memory */
1264 (textureRow-= width << 3);
1267 TRACE("Closing file\n");
1271 IWineD3DSwapChain_Release(swapChain);
1273 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1277 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1278 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1279 This->Dirty = FALSE;
1280 This->dirtyRect.left = This->currentDesc.Width;
1281 This->dirtyRect.top = This->currentDesc.Height;
1282 This->dirtyRect.right = 0;
1283 This->dirtyRect.bottom = 0;
1284 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1285 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1290 * Slightly inefficient way to handle multiple dirty rects but it works :)
1292 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1293 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1294 IWineD3DBaseTexture *baseTexture = NULL;
1296 if (NULL != pDirtyRect) {
1297 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1298 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1299 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1300 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1302 This->dirtyRect.left = 0;
1303 This->dirtyRect.top = 0;
1304 This->dirtyRect.right = This->currentDesc.Width;
1305 This->dirtyRect.bottom = This->currentDesc.Height;
1307 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1308 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1309 /* if the container is a basetexture then mark it dirty. */
1310 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == D3D_OK) {
1311 TRACE("Passing to conatiner\n");
1312 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1313 IWineD3DBaseTexture_Release(baseTexture);
1318 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IUnknown *container) {
1319 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1320 TRACE("Setting container to %p from %p\n", container, This->container);
1321 This->container = container;
1325 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1326 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1328 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1329 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1330 return D3DERR_INVALIDCALL;
1333 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1334 if (format == WINED3DFMT_UNKNOWN) {
1335 This->resource.size = 0;
1336 } else if (format == WINED3DFMT_DXT1) {
1337 /* DXT1 is half byte per pixel */
1338 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1340 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1341 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1342 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1344 This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1348 /* Setup some glformat defaults */
1349 if (format != WINED3DFMT_UNKNOWN) {
1350 This->glDescription.glFormat = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1351 This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1352 This->glDescription.glType = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1354 This->glDescription.glFormat = 0;
1355 This->glDescription.glFormatInternal = 0;
1356 This->glDescription.glType = 0;
1359 if (format != WINED3DFMT_UNKNOWN) {
1360 This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1361 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1363 This->bytesPerPixel = 0;
1367 This->lockable = (WINED3DFMT_D16_LOCKABLE == format) ? TRUE : This->lockable;
1369 This->resource.format = format;
1371 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);
1376 /* TODO: replace this function with context management routines */
1377 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1378 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1380 This->inPBuffer = inPBuffer;
1381 This->inTexture = inTexture;
1385 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
1388 IWineD3DSurfaceImpl_QueryInterface,
1389 IWineD3DSurfaceImpl_AddRef,
1390 IWineD3DSurfaceImpl_Release,
1391 /* IWineD3DResource */
1392 IWineD3DSurfaceImpl_GetParent,
1393 IWineD3DSurfaceImpl_GetDevice,
1394 IWineD3DSurfaceImpl_SetPrivateData,
1395 IWineD3DSurfaceImpl_GetPrivateData,
1396 IWineD3DSurfaceImpl_FreePrivateData,
1397 IWineD3DSurfaceImpl_SetPriority,
1398 IWineD3DSurfaceImpl_GetPriority,
1399 IWineD3DSurfaceImpl_PreLoad,
1400 IWineD3DSurfaceImpl_GetType,
1401 /* IWineD3DSurface */
1402 IWineD3DSurfaceImpl_GetContainer,
1403 IWineD3DSurfaceImpl_GetDesc,
1404 IWineD3DSurfaceImpl_LockRect,
1405 IWineD3DSurfaceImpl_UnlockRect,
1406 IWineD3DSurfaceImpl_GetDC,
1407 IWineD3DSurfaceImpl_ReleaseDC,
1409 IWineD3DSurfaceImpl_CleanDirtyRect,
1410 IWineD3DSurfaceImpl_AddDirtyRect,
1411 IWineD3DSurfaceImpl_LoadTexture,
1412 IWineD3DSurfaceImpl_SaveSnapshot,
1413 IWineD3DSurfaceImpl_SetContainer,
1414 IWineD3DSurfaceImpl_SetPBufferState,
1415 IWineD3DSurfaceImpl_SetGlTextureDesc,
1416 IWineD3DSurfaceImpl_GetGlDesc,
1417 IWineD3DSurfaceImpl_GetData,
1418 IWineD3DSurfaceImpl_SetFormat