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
);
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
);
425 } else { /* Nothing to do */
426 TRACE("Memory %p already allocted for texture\n", This
->resource
.allocatedMemory
);
430 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
432 if (This
->resource
.format
== D3DFMT_DXT1
) { /* DXT1 is half byte per pixel */
433 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + ((pRect
->left
* This
->bytesPerPixel
/ 2));
435 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + (pRect
->left
* This
->bytesPerPixel
);
439 } else if (D3DUSAGE_RENDERTARGET
& This
->resource
.usage
&& !(Flags
&D3DLOCK_DISCARD
)) { /* render surfaces */
443 BOOL notInContext
= FALSE
;
444 IWineD3DSwapChainImpl
*targetSwapChain
= NULL
;
450 * for render->surface copy begin to begin of allocatedMemory
451 * unlock can be more easy
454 TRACE("locking a render target\n");
456 if (This
->resource
.allocatedMemory
== NULL
)
457 This
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap() ,0 ,This
->resource
.size
);
459 This
->activeLock
= TRUE
; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
460 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
463 vcheckGLcall("glFlush");
464 glGetIntegerv(GL_READ_BUFFER
, &prev_read
);
465 vcheckGLcall("glIntegerv");
466 glGetIntegerv(GL_PACK_SWAP_BYTES
, &prev_store
);
467 vcheckGLcall("glIntegerv");
469 /* Here's what we have to do:
470 See if the swapchain has the same context as the renderTarget or the surface is the render target.
471 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
472 and use the front back buffer as required.
473 if not, we need to switch contexts and then switchback at the end.
475 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
476 IWineD3DSurface_GetContainer(myDevice
->renderTarget
, &IID_IWineD3DSwapChain
, (void **)&targetSwapChain
);
478 /* 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! */
479 if ((swapchain
== targetSwapChain
&& targetSwapChain
!= NULL
) || iface
== myDevice
->renderTarget
) {
480 if (iface
== myDevice
->renderTarget
|| iface
== swapchain
->backBuffer
) {
481 TRACE("locking back buffer\n");
482 glReadBuffer(GL_BACK
);
483 } else if (iface
== swapchain
->frontBuffer
) {
484 TRACE("locking front\n");
485 glReadBuffer(GL_FRONT
);
486 } else if (iface
== myDevice
->depthStencilBuffer
) {
487 FIXME("Stencil Buffer lock unsupported for now\n");
489 FIXME("(%p) Shouldn't have got here!\n", This
);
490 glReadBuffer(GL_BACK
);
492 } else if (swapchain
!= NULL
) {
493 IWineD3DSwapChainImpl
*implSwapChain
;
494 IWineD3DDevice_GetSwapChain((IWineD3DDevice
*)myDevice
, 0, (IWineD3DSwapChain
**)&implSwapChain
);
495 if (swapchain
->glCtx
== implSwapChain
->render_ctx
&& swapchain
->drawable
== implSwapChain
->win
) {
496 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
497 if (iface
== swapchain
->backBuffer
) {
498 glReadBuffer(GL_BACK
);
499 } else if (iface
== swapchain
->frontBuffer
) {
500 glReadBuffer(GL_FRONT
);
501 } else if (iface
== myDevice
->depthStencilBuffer
) {
502 FIXME("Stencil Buffer lock unsupported for now\n");
504 FIXME("Should have got here!\n");
505 glReadBuffer(GL_BACK
);
508 /* We need to switch contexts to be able to read the buffer!!! */
509 FIXME("The buffer requested isn't in the current openGL context\n");
511 /* TODO: check the contexts, to see if were shared with the current context */
513 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)implSwapChain
);
515 if (swapchain
!= NULL
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
516 if (targetSwapChain
!= NULL
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*)targetSwapChain
);
519 /** the depth stencil in openGL has a format of GL_FLOAT
520 * which should be good for WINED3DFMT_D16_LOCKABLE
522 * it is unclear what format the stencil buffer is in except.
523 * 'Each index is converted to fixed point...
524 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
525 * mappings in the table GL_PIXEL_MAP_S_TO_S.
526 * glReadPixels(This->lockedRect.left,
527 * This->lockedRect.bottom - j - 1,
528 * This->lockedRect.right - This->lockedRect.left,
530 * GL_DEPTH_COMPONENT,
532 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
533 *****************************************/
534 if (!notInContext
) { /* Only read the buffer if it's in the current context */
537 /* 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,
538 * This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
539 * run ten times faster!
540 * ************************************/
541 BOOL ati_performance_hack
= FALSE
;
542 ati_performance_hack
= (This
->lockedRect
.bottom
- This
->lockedRect
.top
> 10) || (This
->lockedRect
.right
- This
->lockedRect
.left
> 10)? TRUE
: FALSE
;
544 if ((This
->lockedRect
.left
== 0 && This
->lockedRect
.top
== 0 &&
545 This
->lockedRect
.right
== This
->currentDesc
.Width
546 && This
->lockedRect
.bottom
== This
->currentDesc
.Height
)) {
548 This
->currentDesc
.Width
,
549 This
->currentDesc
.Height
,
550 This
->glDescription
.glFormat
,
551 This
->glDescription
.glType
,
552 (char *)pLockedRect
->pBits
);
553 } else if (This
->lockedRect
.left
== 0 && This
->lockedRect
.right
== This
->currentDesc
.Width
) {
555 This
->lockedRect
.top
,
556 This
->currentDesc
.Width
,
557 This
->currentDesc
.Height
,
558 This
->glDescription
.glFormat
,
559 This
->glDescription
.glType
,
560 (char *)pLockedRect
->pBits
);
563 for (j
= This
->lockedRect
.top
; j
< This
->lockedRect
.bottom
- This
->lockedRect
.top
; ++j
) {
564 glReadPixels(This
->lockedRect
.left
,
565 This
->lockedRect
.bottom
- j
- 1,
566 This
->lockedRect
.right
- This
->lockedRect
.left
,
568 This
->glDescription
.glFormat
,
569 This
->glDescription
.glType
,
570 (char *)pLockedRect
->pBits
+ (pLockedRect
->Pitch
* (j
-This
->lockedRect
.top
)));
574 vcheckGLcall("glReadPixels");
575 TRACE("Resetting buffer\n");
576 glReadBuffer(prev_read
);
577 vcheckGLcall("glReadBuffer");
581 } else if (D3DUSAGE_DEPTHSTENCIL
& This
->resource
.usage
) { /* stencil surfaces */
584 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This
, This
->resource
.usage
);
587 glReadPixels(This->lockedRect.left,
588 This->lockedRect.bottom - j - 1,
589 This->lockedRect.right - This->lockedRect.left,
591 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
598 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This
, This
->resource
.usage
);
601 if (Flags
& (D3DLOCK_NO_DIRTY_UPDATE
| D3DLOCK_READONLY
)) {
604 IWineD3DBaseTexture
*pBaseTexture
;
607 * as seen in msdn docs
609 IWineD3DSurface_AddDirtyRect(iface
, &This
->lockedRect
);
611 /** Dirtify Container if needed */
612 if (D3D_OK
== IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&pBaseTexture
) && pBaseTexture
!= NULL
) {
613 TRACE("Making container dirty\n");
614 IWineD3DBaseTexture_SetDirty(pBaseTexture
, TRUE
);
615 IWineD3DBaseTexture_Release(pBaseTexture
);
617 TRACE("Surface is standalone, no need to dirty the container\n");
621 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect
->pBits
, pLockedRect
->Pitch
, This
->Dirty
);
627 HRESULT WINAPI
IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface
*iface
) {
629 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
630 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
631 const char *buffername
= "";
632 IWineD3DSwapChainImpl
*swapchain
= NULL
;
634 if (FALSE
== This
->locked
) {
635 WARN("trying to Unlock an unlocked surf@%p\n", This
);
636 return D3DERR_INVALIDCALL
;
639 if (D3DUSAGE_RENDERTARGET
& This
->resource
.usage
) {
640 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
642 if ((swapchain
!= NULL
) && iface
== swapchain
->backBuffer
) {
643 buffername
= "backBuffer";
644 } else if ((swapchain
!= NULL
) && iface
== swapchain
->frontBuffer
) {
645 buffername
= "frontBuffer";
646 } else if (iface
== myDevice
->depthStencilBuffer
) {
647 buffername
= "depthStencilBuffer";
648 } else if (iface
== myDevice
->renderTarget
) {
649 buffername
= "renderTarget";
653 if (swapchain
!= NULL
) {
654 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
657 TRACE("(%p %s) : dirtyfied(%d)\n", This
, buffername
, This
->Dirty
);
659 if (FALSE
== This
->Dirty
) {
660 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This
);
664 if (0 == This
->resource
.usage
) { /* classic surface */
667 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
669 } else if (D3DUSAGE_RENDERTARGET
& This
->resource
.usage
) { /* render surfaces */
671 /****************************
672 * TODO: Render targets are 'special' and
673 * ?some? locking needs to be passed onto the context manager
674 * so that it becomes possible to use auxilary buffers, pbuffers
675 * render-to-texture, shared, cached contexts etc...
676 * ****************************/
677 IWineD3DSwapChainImpl
*implSwapChain
;
678 IWineD3DDevice_GetSwapChain((IWineD3DDevice
*)myDevice
, 0, (IWineD3DSwapChain
**)&implSwapChain
);
680 if (iface
== implSwapChain
->backBuffer
|| iface
== implSwapChain
->frontBuffer
|| iface
== myDevice
->renderTarget
) {
683 GLint prev_rasterpos
[4];
688 vcheckGLcall("glFlush");
689 glGetIntegerv(GL_DRAW_BUFFER
, &prev_draw
);
690 vcheckGLcall("glIntegerv");
691 glGetIntegerv(GL_PACK_SWAP_BYTES
, &prev_store
);
692 vcheckGLcall("glIntegerv");
693 glGetIntegerv(GL_CURRENT_RASTER_POSITION
, &prev_rasterpos
[0]);
694 vcheckGLcall("glIntegerv");
695 glPixelZoom(1.0, -1.0);
696 vcheckGLcall("glPixelZoom");
698 /* glDrawPixels transforms the raster position as though it was a vertex -
699 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
700 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
701 if (!myDevice
->last_was_rhw
) {
703 double X
, Y
, height
, width
, minZ
, maxZ
;
704 myDevice
->last_was_rhw
= TRUE
;
706 /* Transformed already into viewport coordinates, so we do not need transform
707 matrices. Reset all matrices to identity and leave the default matrix in world
709 glMatrixMode(GL_MODELVIEW
);
710 checkGLcall("glMatrixMode");
712 checkGLcall("glLoadIdentity");
714 glMatrixMode(GL_PROJECTION
);
715 checkGLcall("glMatrixMode");
717 checkGLcall("glLoadIdentity");
719 /* Set up the viewport to be full viewport */
720 X
= myDevice
->stateBlock
->viewport
.X
;
721 Y
= myDevice
->stateBlock
->viewport
.Y
;
722 height
= myDevice
->stateBlock
->viewport
.Height
;
723 width
= myDevice
->stateBlock
->viewport
.Width
;
724 minZ
= myDevice
->stateBlock
->viewport
.MinZ
;
725 maxZ
= myDevice
->stateBlock
->viewport
.MaxZ
;
726 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width
, height
, -minZ
, -maxZ
);
727 glOrtho(X
, X
+ width
, Y
+ height
, Y
, -minZ
, -maxZ
);
728 checkGLcall("glOrtho");
730 /* Window Coord 0 is the middle of the first pixel, so translate by half
731 a pixel (See comment above glTranslate below) */
732 glTranslatef(0.5, 0.5, 0);
733 checkGLcall("glTranslatef(0.5, 0.5, 0)");
736 if (iface
== implSwapChain
->backBuffer
|| iface
== myDevice
->renderTarget
) {
737 glDrawBuffer(GL_BACK
);
738 } else if (iface
== implSwapChain
->frontBuffer
) {
739 glDrawBuffer(GL_FRONT
);
742 vcheckGLcall("glDrawBuffer");
744 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
745 glGetIntegerv(GL_UNPACK_ROW_LENGTH
, &skipBytes
);
746 glPixelStorei(GL_UNPACK_ROW_LENGTH
, This
->currentDesc
.Width
);
748 /* And back buffers are not blended */
751 glRasterPos3i(This
->lockedRect
.left
, This
->lockedRect
.top
, 1);
752 vcheckGLcall("glRasterPos2f");
753 switch (This
->resource
.format
) {
754 case WINED3DFMT_R5G6B5
:
756 glDrawPixels(This
->lockedRect
.right
- This
->lockedRect
.left
, (This
->lockedRect
.bottom
- This
->lockedRect
.top
)-1,
757 GL_RGB
, GL_UNSIGNED_SHORT_5_6_5
, This
->resource
.allocatedMemory
);
758 vcheckGLcall("glDrawPixels");
761 case WINED3DFMT_X1R5G5B5
:
764 unsigned short *data
;
765 data
= (unsigned short *)This
->resource
.allocatedMemory
;
766 size
= (This
->lockedRect
.bottom
- This
->lockedRect
.top
) * (This
->lockedRect
.right
- This
->lockedRect
.left
);
773 case WINED3DFMT_A1R5G5B5
:
775 glDrawPixels(This
->lockedRect
.right
- This
->lockedRect
.left
, (This
->lockedRect
.bottom
- This
->lockedRect
.top
)-1,
776 GL_RGBA
, GL_UNSIGNED_SHORT_1_5_5_5_REV
, This
->resource
.allocatedMemory
);
777 vcheckGLcall("glDrawPixels");
780 case WINED3DFMT_R8G8B8
:
782 glDrawPixels(This
->lockedRect
.right
- This
->lockedRect
.left
, (This
->lockedRect
.bottom
- This
->lockedRect
.top
)-1,
783 GL_RGB
, GL_UNSIGNED_BYTE
, This
->resource
.allocatedMemory
);
784 vcheckGLcall("glDrawPixels");
787 case WINED3DFMT_X8R8G8B8
: /* make sure the X byte is set to alpha on, since it
788 could be any random value this fixes the intro move in Pirates! */
792 data
= (unsigned int *)This
->resource
.allocatedMemory
;
793 size
= (This
->lockedRect
.bottom
- This
->lockedRect
.top
) * (This
->lockedRect
.right
- This
->lockedRect
.left
);
800 case WINED3DFMT_A8R8G8B8
:
802 glPixelStorei(GL_PACK_SWAP_BYTES
, TRUE
);
803 vcheckGLcall("glPixelStorei");
804 glDrawPixels(This
->lockedRect
.right
- This
->lockedRect
.left
, (This
->lockedRect
.bottom
- This
->lockedRect
.top
)-1,
805 GL_BGRA
, GL_UNSIGNED_BYTE
, This
->resource
.allocatedMemory
);
806 vcheckGLcall("glDrawPixels");
807 glPixelStorei(GL_PACK_SWAP_BYTES
, prev_store
);
808 vcheckGLcall("glPixelStorei");
811 case WINED3DFMT_A2R10G10B10
:
813 glPixelStorei(GL_PACK_SWAP_BYTES
, TRUE
);
814 vcheckGLcall("glPixelStorei");
815 glDrawPixels(This
->lockedRect
.right
- This
->lockedRect
.left
, (This
->lockedRect
.bottom
- This
->lockedRect
.top
)-1,
816 GL_BGRA
, GL_UNSIGNED_INT_2_10_10_10_REV
, This
->resource
.allocatedMemory
);
817 vcheckGLcall("glDrawPixels");
818 glPixelStorei(GL_PACK_SWAP_BYTES
, prev_store
);
819 vcheckGLcall("glPixelStorei");
823 FIXME("Unsupported Format %u in locking func\n", This
->resource
.format
);
826 glPixelZoom(1.0,1.0);
827 vcheckGLcall("glPixelZoom");
828 glDrawBuffer(prev_draw
);
829 vcheckGLcall("glDrawBuffer");
830 glRasterPos3iv(&prev_rasterpos
[0]);
831 vcheckGLcall("glRasterPos3iv");
833 /* Reset to previous pack row length / blending state */
834 glPixelStorei(GL_UNPACK_ROW_LENGTH
, skipBytes
);
835 if (myDevice
->stateBlock
->renderState
[D3DRS_ALPHABLENDENABLE
]) glEnable(GL_BLEND
);
839 /** restore clean dirty state */
840 IWineD3DSurface_CleanDirtyRect(iface
);
843 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This
, This
->resource
.usage
);
845 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)implSwapChain
);
847 } else if (D3DUSAGE_DEPTHSTENCIL
& This
->resource
.usage
) { /* stencil surfaces */
849 if (iface
== myDevice
->depthStencilBuffer
) {
850 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This
, This
->resource
.usage
);
852 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This
, This
->resource
.usage
);
856 FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This
, This
->resource
.usage
);
860 This
->locked
= FALSE
;
861 memset(&This
->lockedRect
, 0, sizeof(RECT
));
865 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDC(IWineD3DSurface
*iface
, HDC
*pHDC
) {
866 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
867 FIXME("No support for GetDC yet for surface %p\n", This
);
868 return D3DERR_INVALIDCALL
;
871 HRESULT WINAPI
IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface
*iface
, HDC hDC
) {
872 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
873 FIXME("No support for ReleaseDC yet for surface %p\n", This
);
874 return D3DERR_INVALIDCALL
;
877 /* ******************************************************
878 IWineD3DSurface Internal (No mapping to directx api) parts follow
879 ****************************************************** */
880 HRESULT WINAPI
IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface
*iface
) {
881 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
883 if (This
->inTexture
) {
884 TRACE("Surface already in texture\n");
887 if (This
->Dirty
== FALSE
) {
888 TRACE("surface isn't dirty\n");
894 /* 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. */
895 if (This
->resource
.pool
== D3DPOOL_SCRATCH
|| This
->resource
.pool
== D3DPOOL_SYSTEMMEM
) /*never store scratch or system mem textures in the video ram*/
897 FIXME("(%p) Opperation not supported for scratch or SYSTEMMEM textures\n",This
);
898 return D3DERR_INVALIDCALL
;
901 if (This
->inPBuffer
) {
904 if (This
->glDescription
.level
!= 0)
905 FIXME("Surface in texture is only supported for level 0\n");
906 else if (This
->resource
.format
== WINED3DFMT_P8
|| This
->resource
.format
== WINED3DFMT_A8P8
||
907 This
->resource
.format
== WINED3DFMT_DXT1
|| This
->resource
.format
== WINED3DFMT_DXT2
||
908 This
->resource
.format
== WINED3DFMT_DXT3
|| This
->resource
.format
== WINED3DFMT_DXT4
||
909 This
->resource
.format
== WINED3DFMT_DXT5
)
910 FIXME("Format %d not supported\n", This
->resource
.format
);
913 glGetIntegerv(GL_READ_BUFFER
, &prevRead
);
914 vcheckGLcall("glGetIntegerv");
915 glReadBuffer(GL_BACK
);
916 vcheckGLcall("glReadBuffer");
918 glCopyTexImage2D(This
->glDescription
.target
,
919 This
->glDescription
.level
,
920 This
->glDescription
.glFormatInternal
,
923 This
->currentDesc
.Width
,
924 This
->currentDesc
.Height
,
927 checkGLcall("glCopyTexImage2D");
928 glReadBuffer(prevRead
);
929 vcheckGLcall("glReadBuffer");
930 TRACE("Updating target %d\n", This
->glDescription
.target
);
931 This
->inTexture
= TRUE
;
937 if ((This
->resource
.format
== WINED3DFMT_P8
|| This
->resource
.format
== WINED3DFMT_A8P8
) &&
938 !GL_SUPPORT(EXT_PALETTED_TEXTURE
)) {
940 * wanted a paletted texture and not really support it in HW
941 * so software emulation code begin
944 PALETTEENTRY
* pal
= This
->resource
.wineD3DDevice
->palettes
[This
->resource
.wineD3DDevice
->currentPalette
];
945 VOID
* surface
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->currentDesc
.Width
* This
->currentDesc
.Height
* sizeof(DWORD
));
946 BYTE
* dst
= (BYTE
*) surface
;
947 BYTE
* src
= (BYTE
*) This
->resource
.allocatedMemory
;
949 for (i
= 0; i
< This
->currentDesc
.Width
* This
->currentDesc
.Height
; i
++) {
951 *dst
++ = pal
[color
].peRed
;
952 *dst
++ = pal
[color
].peGreen
;
953 *dst
++ = pal
[color
].peBlue
;
954 if (This
->resource
.format
== WINED3DFMT_A8P8
)
955 *dst
++ = pal
[color
].peFlags
;
962 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
963 This
->glDescription
.target
,
964 This
->glDescription
.level
,
966 This
->currentDesc
.Width
,
967 This
->currentDesc
.Height
,
972 glTexImage2D(This
->glDescription
.target
,
973 This
->glDescription
.level
,
975 This
->currentDesc
.Width
,
976 This
->currentDesc
.Height
,
981 checkGLcall("glTexImage2D");
982 HeapFree(GetProcessHeap(), 0, surface
);
989 /* TODO: Compressed non-power 2 support */
991 if (This
->resource
.format
== WINED3DFMT_DXT1
||
992 This
->resource
.format
== WINED3DFMT_DXT2
||
993 This
->resource
.format
== WINED3DFMT_DXT3
||
994 This
->resource
.format
== WINED3DFMT_DXT4
||
995 This
->resource
.format
== WINED3DFMT_DXT5
) {
996 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
997 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
998 This
->glDescription
.target
,
999 This
->glDescription
.level
,
1000 This
->glDescription
.glFormatInternal
,
1001 This
->currentDesc
.Width
,
1002 This
->currentDesc
.Height
,
1004 This
->resource
.size
,
1005 This
->resource
.allocatedMemory
);
1009 GL_EXTCALL(glCompressedTexImage2DARB
)(This
->glDescription
.target
,
1010 This
->glDescription
.level
,
1011 This
->glDescription
.glFormatInternal
,
1012 This
->currentDesc
.Width
,
1013 This
->currentDesc
.Height
,
1015 This
->resource
.size
,
1016 This
->resource
.allocatedMemory
);
1017 checkGLcall("glCommpressedTexTexImage2D");
1021 if(This
->activeLock
== FALSE
){
1022 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
1023 This
->resource
.allocatedMemory
= NULL
;
1027 FIXME("Using DXT1/3/5 without advertized support\n");
1031 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1032 if (NP2_REPACK
== wined3d_settings
.nonpower2_mode
&& This
->nonpow2
== TRUE
) {
1035 TRACE("non power of two support\n");
1037 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
,
1038 This
->glDescription
.target
,
1039 This
->glDescription
.level
,
1040 debug_d3dformat(This
->resource
.format
),
1041 This
->glDescription
.glFormatInternal
,
1045 This
->glDescription
.glFormat
,
1046 This
->glDescription
.glType
,
1049 glTexImage2D(This
->glDescription
.target
,
1050 This
->glDescription
.level
,
1051 This
->glDescription
.glFormatInternal
,
1055 This
->glDescription
.glFormat
,
1056 This
->glDescription
.glType
,
1059 checkGLcall("glTexImage2D");
1060 if (This
->resource
.allocatedMemory
!= NULL
) {
1061 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This
, This
->currentDesc
.Width
, This
->currentDesc
.Height
, This
->resource
.allocatedMemory
);
1062 /* And map the non-power two data into the top left corner */
1064 This
->glDescription
.target
,
1065 This
->glDescription
.level
,
1068 This
->currentDesc
.Width
,
1069 This
->currentDesc
.Height
,
1070 This
->glDescription
.glFormat
,
1071 This
->glDescription
.glType
,
1072 This
->resource
.allocatedMemory
1074 checkGLcall("glTexSubImage2D");
1080 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1081 This
->glDescription
.target
,
1082 This
->glDescription
.level
,
1083 debug_d3dformat(This
->resource
.format
),
1084 This
->glDescription
.glFormatInternal
,
1088 This
->glDescription
.glFormat
,
1089 This
->glDescription
.glType
,
1090 This
->resource
.allocatedMemory
);
1093 glTexImage2D(This
->glDescription
.target
,
1094 This
->glDescription
.level
,
1095 This
->glDescription
.glFormatInternal
,
1099 This
->glDescription
.glFormat
,
1100 This
->glDescription
.glType
,
1101 This
->resource
.allocatedMemory
);
1102 checkGLcall("glTexImage2D");
1108 static unsigned int gen
= 0;
1111 if ((gen
% 10) == 0) {
1112 snprintf(buffer
, sizeof(buffer
), "/tmp/surface%p_type%u_level%u_%u.ppm", This
, This
->glDescription
.target
, This
->glDescription
.level
, gen
);
1113 IWineD3DSurfaceImpl_SaveSnapshot(iface
, buffer
);
1116 * debugging crash code
1124 if(This
->activeLock
== FALSE
){
1125 HeapFree(GetProcessHeap(),0,This
->resource
.allocatedMemory
);
1126 This
->resource
.allocatedMemory
= NULL
;
1136 HRESULT WINAPI
IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface
*iface
, const char* filename
) {
1139 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1140 char *allocatedMemory
;
1142 IWineD3DSwapChain
*swapChain
= NULL
;
1147 Textures my not be stored in ->allocatedgMemory and a GlTexture
1148 so we should lock the surface before saving a snapshot, or atleast check that
1150 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1151 by calling GetTexImage and in compressed form by calling
1152 GetCompressedTexImageARB. Queried compressed images can be saved and
1153 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1154 texture images do not need to be processed by the GL and should
1155 significantly improve texture loading performance relative to uncompressed
1158 /* Setup the width and height to be the internal texture width and height. */
1159 width
= This
->pow2Width
;
1160 height
= This
->pow2Height
;
1161 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1162 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapChain
);
1164 if (swapChain
|| This
->inPBuffer
) { /* if were not a real texture then read the back buffer into a real texture*/
1165 /* we don't want to interfere with the back buffer so read the data into a tempory texture and then save the data out of the tempory texture */
1168 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This
);
1169 glEnable(GL_TEXTURE_2D
);
1171 glGenTextures(1, &tmpTexture
);
1172 glBindTexture(GL_TEXTURE_2D
, tmpTexture
);
1174 glTexImage2D(GL_TEXTURE_2D
,
1181 GL_UNSIGNED_INT_8_8_8_8_REV
,
1184 glGetIntegerv(GL_READ_BUFFER
, &prevRead
);
1185 vcheckGLcall("glGetIntegerv");
1186 glReadBuffer(GL_BACK
);
1187 vcheckGLcall("glReadBuffer");
1188 glCopyTexImage2D(GL_TEXTURE_2D
,
1197 checkGLcall("glCopyTexImage2D");
1198 glReadBuffer(prevRead
);
1201 } else { /* bind the real texture */
1202 IWineD3DSurface_PreLoad(iface
);
1204 allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, width
* height
* 4);
1206 FIXME("Saving texture level %d width %d height %d\n", This
->glDescription
.level
, width
, height
);
1207 glGetTexImage(GL_TEXTURE_2D
,
1208 This
->glDescription
.level
,
1210 GL_UNSIGNED_INT_8_8_8_8_REV
,
1212 checkGLcall("glTexImage2D");
1214 glBindTexture(GL_TEXTURE_2D
, 0);
1215 glDeleteTextures(1, &tmpTexture
);
1219 f
= fopen(filename
, "w+");
1221 ERR("opening of %s failed with: %s\n", filename
, strerror(errno
));
1222 return D3DERR_INVALIDCALL
;
1224 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1225 TRACE("(%p) opened %s with format %s\n", This
, filename
, debug_d3dformat(This
->resource
.format
));
1240 fwrite(&width
,2,1,f
);
1242 fwrite(&height
,2,1,f
);
1247 /* 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*/
1249 textureRow
= allocatedMemory
+ (width
* (height
- 1) *4);
1251 textureRow
= allocatedMemory
;
1252 for (y
= 0 ; y
< height
; y
++) {
1253 for (i
= 0; i
< width
; i
++) {
1254 color
= *((DWORD
*)textureRow
);
1255 fputc((color
>> 16) & 0xFF, f
); /* B */
1256 fputc((color
>> 8) & 0xFF, f
); /* G */
1257 fputc((color
>> 0) & 0xFF, f
); /* R */
1258 fputc((color
>> 24) & 0xFF, f
); /* A */
1261 /* take two rows of the pointer to the texture memory */
1263 (textureRow
-= width
<< 3);
1266 TRACE("Closing file\n");
1270 IWineD3DSwapChain_Release(swapChain
);
1272 HeapFree(GetProcessHeap(), 0, allocatedMemory
);
1276 HRESULT WINAPI
IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface
*iface
) {
1277 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1278 This
->Dirty
= FALSE
;
1279 This
->dirtyRect
.left
= This
->currentDesc
.Width
;
1280 This
->dirtyRect
.top
= This
->currentDesc
.Height
;
1281 This
->dirtyRect
.right
= 0;
1282 This
->dirtyRect
.bottom
= 0;
1283 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This
, This
->Dirty
, This
->dirtyRect
.left
,
1284 This
->dirtyRect
.top
, This
->dirtyRect
.right
, This
->dirtyRect
.bottom
);
1289 * Slightly inefficient way to handle multiple dirty rects but it works :)
1291 extern HRESULT WINAPI
IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface
*iface
, CONST RECT
* pDirtyRect
) {
1292 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1293 IWineD3DBaseTexture
*baseTexture
= NULL
;
1295 if (NULL
!= pDirtyRect
) {
1296 This
->dirtyRect
.left
= min(This
->dirtyRect
.left
, pDirtyRect
->left
);
1297 This
->dirtyRect
.top
= min(This
->dirtyRect
.top
, pDirtyRect
->top
);
1298 This
->dirtyRect
.right
= max(This
->dirtyRect
.right
, pDirtyRect
->right
);
1299 This
->dirtyRect
.bottom
= max(This
->dirtyRect
.bottom
, pDirtyRect
->bottom
);
1301 This
->dirtyRect
.left
= 0;
1302 This
->dirtyRect
.top
= 0;
1303 This
->dirtyRect
.right
= This
->currentDesc
.Width
;
1304 This
->dirtyRect
.bottom
= This
->currentDesc
.Height
;
1306 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This
, This
->Dirty
, This
->dirtyRect
.left
,
1307 This
->dirtyRect
.top
, This
->dirtyRect
.right
, This
->dirtyRect
.bottom
);
1308 /* if the container is a basetexture then mark it dirty. */
1309 if (IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
) == D3D_OK
) {
1310 TRACE("Passing to conatiner\n");
1311 IWineD3DBaseTexture_SetDirty(baseTexture
, TRUE
);
1312 IWineD3DBaseTexture_Release(baseTexture
);
1317 HRESULT WINAPI
IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface
*iface
, IUnknown
*container
) {
1318 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1319 TRACE("Setting container to %p from %p\n", container
, This
->container
);
1320 This
->container
= container
;
1324 /* TODO: replace this function with context management routines */
1325 HRESULT WINAPI
IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface
*iface
, BOOL inPBuffer
, BOOL inTexture
) {
1326 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1328 This
->inPBuffer
= inPBuffer
;
1329 This
->inTexture
= inTexture
;
1333 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl
=
1336 IWineD3DSurfaceImpl_QueryInterface
,
1337 IWineD3DSurfaceImpl_AddRef
,
1338 IWineD3DSurfaceImpl_Release
,
1339 /* IWineD3DResource */
1340 IWineD3DSurfaceImpl_GetParent
,
1341 IWineD3DSurfaceImpl_GetDevice
,
1342 IWineD3DSurfaceImpl_SetPrivateData
,
1343 IWineD3DSurfaceImpl_GetPrivateData
,
1344 IWineD3DSurfaceImpl_FreePrivateData
,
1345 IWineD3DSurfaceImpl_SetPriority
,
1346 IWineD3DSurfaceImpl_GetPriority
,
1347 IWineD3DSurfaceImpl_PreLoad
,
1348 IWineD3DSurfaceImpl_GetType
,
1349 /* IWineD3DSurface */
1350 IWineD3DSurfaceImpl_GetContainer
,
1351 IWineD3DSurfaceImpl_GetDesc
,
1352 IWineD3DSurfaceImpl_LockRect
,
1353 IWineD3DSurfaceImpl_UnlockRect
,
1354 IWineD3DSurfaceImpl_GetDC
,
1355 IWineD3DSurfaceImpl_ReleaseDC
,
1357 IWineD3DSurfaceImpl_CleanDirtyRect
,
1358 IWineD3DSurfaceImpl_AddDirtyRect
,
1359 IWineD3DSurfaceImpl_LoadTexture
,
1360 IWineD3DSurfaceImpl_SaveSnapshot
,
1361 IWineD3DSurfaceImpl_SetContainer
,
1362 IWineD3DSurfaceImpl_SetPBufferState
,
1363 IWineD3DSurfaceImpl_SetGlTextureDesc
,
1364 IWineD3DSurfaceImpl_GetGlDesc
,
1365 IWineD3DSurfaceImpl_GetData