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 These 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 from the surface*/
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-system memory surfaces */
329 /*Surface has no memory currently allocated 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, loading the surface again won't free THis->resource.allocatedMemory */
335 /* TODO: make activeLock a bit more intelligent, 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_X4R4G4B4:
758 unsigned short *data;
759 data = (unsigned short *)This->resource.allocatedMemory;
760 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
767 case WINED3DFMT_A4R4G4B4:
769 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
770 GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
771 vcheckGLcall("glDrawPixels");
774 case WINED3DFMT_R5G6B5:
776 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
777 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
778 vcheckGLcall("glDrawPixels");
781 case WINED3DFMT_X1R5G5B5:
784 unsigned short *data;
785 data = (unsigned short *)This->resource.allocatedMemory;
786 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
793 case WINED3DFMT_A1R5G5B5:
795 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
796 GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
797 vcheckGLcall("glDrawPixels");
800 case WINED3DFMT_R8G8B8:
802 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
803 GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
804 vcheckGLcall("glDrawPixels");
807 case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it
808 could be any random value this fixes the intro move in Pirates! */
812 data = (unsigned int *)This->resource.allocatedMemory;
813 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
820 case WINED3DFMT_A8R8G8B8:
822 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
823 vcheckGLcall("glPixelStorei");
824 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
825 GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
826 vcheckGLcall("glDrawPixels");
827 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
828 vcheckGLcall("glPixelStorei");
831 case WINED3DFMT_A2R10G10B10:
833 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
834 vcheckGLcall("glPixelStorei");
835 glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
836 GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
837 vcheckGLcall("glDrawPixels");
838 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
839 vcheckGLcall("glPixelStorei");
843 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
846 glPixelZoom(1.0,1.0);
847 vcheckGLcall("glPixelZoom");
848 glDrawBuffer(prev_draw);
849 vcheckGLcall("glDrawBuffer");
850 glRasterPos3iv(&prev_rasterpos[0]);
851 vcheckGLcall("glRasterPos3iv");
853 /* Reset to previous pack row length / blending state */
854 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
855 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
859 /** restore clean dirty state */
860 IWineD3DSurface_CleanDirtyRect(iface);
863 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->resource.usage);
865 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
867 } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
869 if (iface == myDevice->depthStencilBuffer) {
870 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
872 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
876 FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
880 This->locked = FALSE;
881 memset(&This->lockedRect, 0, sizeof(RECT));
885 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
886 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
887 FIXME("No support for GetDC yet for surface %p\n", This);
888 return D3DERR_INVALIDCALL;
891 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
892 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
893 FIXME("No support for ReleaseDC yet for surface %p\n", This);
894 return D3DERR_INVALIDCALL;
897 /* ******************************************************
898 IWineD3DSurface Internal (No mapping to directx api) parts follow
899 ****************************************************** */
900 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
901 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
903 if (This->inTexture) {
904 TRACE("Surface already in texture\n");
907 if (This->Dirty == FALSE) {
908 TRACE("surface isn't dirty\n");
914 /* 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. */
915 if (This->resource.pool == D3DPOOL_SCRATCH || This->resource.pool == D3DPOOL_SYSTEMMEM) /*never store scratch or system mem textures in the video ram*/
917 FIXME("(%p) Operation not supported for scratch or SYSTEMMEM textures\n",This);
918 return D3DERR_INVALIDCALL;
921 if (This->inPBuffer) {
924 if (This->glDescription.level != 0)
925 FIXME("Surface in texture is only supported for level 0\n");
926 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
927 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
928 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
929 This->resource.format == WINED3DFMT_DXT5)
930 FIXME("Format %d not supported\n", This->resource.format);
933 glGetIntegerv(GL_READ_BUFFER, &prevRead);
934 vcheckGLcall("glGetIntegerv");
935 glReadBuffer(GL_BACK);
936 vcheckGLcall("glReadBuffer");
938 glCopyTexImage2D(This->glDescription.target,
939 This->glDescription.level,
940 This->glDescription.glFormatInternal,
943 This->currentDesc.Width,
944 This->currentDesc.Height,
947 checkGLcall("glCopyTexImage2D");
948 glReadBuffer(prevRead);
949 vcheckGLcall("glReadBuffer");
950 TRACE("Updating target %d\n", This->glDescription.target);
951 This->inTexture = TRUE;
957 if ((This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) &&
958 !GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
960 * wanted a paletted texture and not really support it in HW
961 * so software emulation code begin
964 PALETTEENTRY* pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
965 VOID* surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->currentDesc.Width * This->currentDesc.Height * sizeof(DWORD));
966 BYTE* dst = (BYTE*) surface;
967 BYTE* src = (BYTE*) This->resource.allocatedMemory;
969 for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
971 *dst++ = pal[color].peRed;
972 *dst++ = pal[color].peGreen;
973 *dst++ = pal[color].peBlue;
974 if (This->resource.format == WINED3DFMT_A8P8)
975 *dst++ = pal[color].peFlags;
982 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
983 This->glDescription.target,
984 This->glDescription.level,
986 This->currentDesc.Width,
987 This->currentDesc.Height,
992 glTexImage2D(This->glDescription.target,
993 This->glDescription.level,
995 This->currentDesc.Width,
996 This->currentDesc.Height,
1001 checkGLcall("glTexImage2D");
1002 HeapFree(GetProcessHeap(), 0, surface);
1009 /* TODO: Compressed non-power 2 support */
1011 if (This->resource.format == WINED3DFMT_DXT1 ||
1012 This->resource.format == WINED3DFMT_DXT2 ||
1013 This->resource.format == WINED3DFMT_DXT3 ||
1014 This->resource.format == WINED3DFMT_DXT4 ||
1015 This->resource.format == WINED3DFMT_DXT5) {
1016 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1017 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1018 This->glDescription.target,
1019 This->glDescription.level,
1020 This->glDescription.glFormatInternal,
1021 This->currentDesc.Width,
1022 This->currentDesc.Height,
1024 This->resource.size,
1025 This->resource.allocatedMemory);
1029 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1030 This->glDescription.level,
1031 This->glDescription.glFormatInternal,
1032 This->currentDesc.Width,
1033 This->currentDesc.Height,
1035 This->resource.size,
1036 This->resource.allocatedMemory);
1037 checkGLcall("glCommpressedTexTexImage2D");
1041 if(This->activeLock == FALSE){
1042 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1043 This->resource.allocatedMemory = NULL;
1047 FIXME("Using DXT1/3/5 without advertized support\n");
1051 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1052 if (NP2_REPACK == wined3d_settings.nonpower2_mode && This->nonpow2 == TRUE) {
1055 TRACE("non power of two support\n");
1057 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,
1058 This->glDescription.target,
1059 This->glDescription.level,
1060 debug_d3dformat(This->resource.format),
1061 This->glDescription.glFormatInternal,
1065 This->glDescription.glFormat,
1066 This->glDescription.glType,
1069 glTexImage2D(This->glDescription.target,
1070 This->glDescription.level,
1071 This->glDescription.glFormatInternal,
1075 This->glDescription.glFormat,
1076 This->glDescription.glType,
1079 checkGLcall("glTexImage2D");
1080 if (This->resource.allocatedMemory != NULL) {
1081 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1082 /* And map the non-power two data into the top left corner */
1084 This->glDescription.target,
1085 This->glDescription.level,
1088 This->currentDesc.Width,
1089 This->currentDesc.Height,
1090 This->glDescription.glFormat,
1091 This->glDescription.glType,
1092 This->resource.allocatedMemory
1094 checkGLcall("glTexSubImage2D");
1100 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1101 This->glDescription.target,
1102 This->glDescription.level,
1103 debug_d3dformat(This->resource.format),
1104 This->glDescription.glFormatInternal,
1108 This->glDescription.glFormat,
1109 This->glDescription.glType,
1110 This->resource.allocatedMemory);
1113 glTexImage2D(This->glDescription.target,
1114 This->glDescription.level,
1115 This->glDescription.glFormatInternal,
1119 This->glDescription.glFormat,
1120 This->glDescription.glType,
1121 This->resource.allocatedMemory);
1122 checkGLcall("glTexImage2D");
1128 static unsigned int gen = 0;
1131 if ((gen % 10) == 0) {
1132 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1133 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1136 * debugging crash code
1144 if(This->activeLock == FALSE){
1145 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1146 This->resource.allocatedMemory = NULL;
1156 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1159 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1160 char *allocatedMemory;
1162 IWineD3DSwapChain *swapChain = NULL;
1167 Textures my not be stored in ->allocatedgMemory and a GlTexture
1168 so we should lock the surface before saving a snapshot, or at least check that
1170 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1171 by calling GetTexImage and in compressed form by calling
1172 GetCompressedTexImageARB. Queried compressed images can be saved and
1173 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1174 texture images do not need to be processed by the GL and should
1175 significantly improve texture loading performance relative to uncompressed
1178 /* Setup the width and height to be the internal texture width and height. */
1179 width = This->pow2Width;
1180 height = This->pow2Height;
1181 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1182 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1184 if (swapChain || This->inPBuffer) { /* if were not a real texture then read the back buffer into a real texture*/
1185 /* 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 */
1188 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1189 glEnable(GL_TEXTURE_2D);
1191 glGenTextures(1, &tmpTexture);
1192 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1194 glTexImage2D(GL_TEXTURE_2D,
1201 GL_UNSIGNED_INT_8_8_8_8_REV,
1204 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1205 vcheckGLcall("glGetIntegerv");
1206 glReadBuffer(GL_BACK);
1207 vcheckGLcall("glReadBuffer");
1208 glCopyTexImage2D(GL_TEXTURE_2D,
1217 checkGLcall("glCopyTexImage2D");
1218 glReadBuffer(prevRead);
1221 } else { /* bind the real texture */
1222 IWineD3DSurface_PreLoad(iface);
1224 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1226 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1227 glGetTexImage(GL_TEXTURE_2D,
1228 This->glDescription.level,
1230 GL_UNSIGNED_INT_8_8_8_8_REV,
1232 checkGLcall("glTexImage2D");
1234 glBindTexture(GL_TEXTURE_2D, 0);
1235 glDeleteTextures(1, &tmpTexture);
1239 f = fopen(filename, "w+");
1241 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1242 return D3DERR_INVALIDCALL;
1244 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1245 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1260 fwrite(&width,2,1,f);
1262 fwrite(&height,2,1,f);
1267 /* 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*/
1269 textureRow = allocatedMemory + (width * (height - 1) *4);
1271 textureRow = allocatedMemory;
1272 for (y = 0 ; y < height; y++) {
1273 for (i = 0; i < width; i++) {
1274 color = *((DWORD*)textureRow);
1275 fputc((color >> 16) & 0xFF, f); /* B */
1276 fputc((color >> 8) & 0xFF, f); /* G */
1277 fputc((color >> 0) & 0xFF, f); /* R */
1278 fputc((color >> 24) & 0xFF, f); /* A */
1281 /* take two rows of the pointer to the texture memory */
1283 (textureRow-= width << 3);
1286 TRACE("Closing file\n");
1290 IWineD3DSwapChain_Release(swapChain);
1292 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1296 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1297 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1298 This->Dirty = FALSE;
1299 This->dirtyRect.left = This->currentDesc.Width;
1300 This->dirtyRect.top = This->currentDesc.Height;
1301 This->dirtyRect.right = 0;
1302 This->dirtyRect.bottom = 0;
1303 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1304 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1309 * Slightly inefficient way to handle multiple dirty rects but it works :)
1311 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1312 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1313 IWineD3DBaseTexture *baseTexture = NULL;
1315 if (NULL != pDirtyRect) {
1316 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1317 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1318 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1319 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1321 This->dirtyRect.left = 0;
1322 This->dirtyRect.top = 0;
1323 This->dirtyRect.right = This->currentDesc.Width;
1324 This->dirtyRect.bottom = This->currentDesc.Height;
1326 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1327 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1328 /* if the container is a basetexture then mark it dirty. */
1329 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == D3D_OK) {
1330 TRACE("Passing to conatiner\n");
1331 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1332 IWineD3DBaseTexture_Release(baseTexture);
1337 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IUnknown *container) {
1338 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1339 TRACE("Setting container to %p from %p\n", container, This->container);
1340 This->container = container;
1344 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1345 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1347 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1348 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1349 return D3DERR_INVALIDCALL;
1352 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1353 if (format == WINED3DFMT_UNKNOWN) {
1354 This->resource.size = 0;
1355 } else if (format == WINED3DFMT_DXT1) {
1356 /* DXT1 is half byte per pixel */
1357 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1359 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1360 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1361 This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1363 This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1367 /* Setup some glformat defaults */
1368 if (format != WINED3DFMT_UNKNOWN) {
1369 This->glDescription.glFormat = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1370 This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1371 This->glDescription.glType = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1373 This->glDescription.glFormat = 0;
1374 This->glDescription.glFormatInternal = 0;
1375 This->glDescription.glType = 0;
1378 if (format != WINED3DFMT_UNKNOWN) {
1379 This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1380 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1382 This->bytesPerPixel = 0;
1386 This->lockable = (WINED3DFMT_D16_LOCKABLE == format) ? TRUE : This->lockable;
1388 This->resource.format = format;
1390 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);
1395 /* TODO: replace this function with context management routines */
1396 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
1397 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1399 This->inPBuffer = inPBuffer;
1400 This->inTexture = inTexture;
1404 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
1407 IWineD3DSurfaceImpl_QueryInterface,
1408 IWineD3DSurfaceImpl_AddRef,
1409 IWineD3DSurfaceImpl_Release,
1410 /* IWineD3DResource */
1411 IWineD3DSurfaceImpl_GetParent,
1412 IWineD3DSurfaceImpl_GetDevice,
1413 IWineD3DSurfaceImpl_SetPrivateData,
1414 IWineD3DSurfaceImpl_GetPrivateData,
1415 IWineD3DSurfaceImpl_FreePrivateData,
1416 IWineD3DSurfaceImpl_SetPriority,
1417 IWineD3DSurfaceImpl_GetPriority,
1418 IWineD3DSurfaceImpl_PreLoad,
1419 IWineD3DSurfaceImpl_GetType,
1420 /* IWineD3DSurface */
1421 IWineD3DSurfaceImpl_GetContainer,
1422 IWineD3DSurfaceImpl_GetDesc,
1423 IWineD3DSurfaceImpl_LockRect,
1424 IWineD3DSurfaceImpl_UnlockRect,
1425 IWineD3DSurfaceImpl_GetDC,
1426 IWineD3DSurfaceImpl_ReleaseDC,
1428 IWineD3DSurfaceImpl_CleanDirtyRect,
1429 IWineD3DSurfaceImpl_AddDirtyRect,
1430 IWineD3DSurfaceImpl_LoadTexture,
1431 IWineD3DSurfaceImpl_SaveSnapshot,
1432 IWineD3DSurfaceImpl_SetContainer,
1433 IWineD3DSurfaceImpl_SetPBufferState,
1434 IWineD3DSurfaceImpl_SetGlTextureDesc,
1435 IWineD3DSurfaceImpl_GetGlDesc,
1436 IWineD3DSurfaceImpl_GetData,
1437 IWineD3DSurfaceImpl_SetFormat