Release 20050930.
[wine/gsoc-2012-control.git] / dlls / wined3d / surface.c
blob83936f35e995a957bff2ee1cc72c195c01d16745
1 /*
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
24 #include "config.h"
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);
39 if (riid == NULL) {
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);
46 *ppobj = This;
47 return D3D_OK;
49 return E_NOINTERFACE;
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);
56 return ref;
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);
63 if (ref == 0) {
64 TRACE("(%p) : cleaning up\n", This);
65 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
66 ENTER_GL();
67 TRACE("Deleting texture %d\n", This->glDescription.textureName);
68 glDeleteTextures(1, &This->glDescription.textureName);
69 LEAVE_GL();
71 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
73 TRACE("(%p) Released\n", This);
74 HeapFree(GetProcessHeap(), 0, This);
77 return ref;
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);
120 } else {
121 TRACE("(%p) : About to load surface\n", This);
122 ENTER_GL();
123 #if 0 /* TODO: context manager support */
124 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
125 #endif
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 */
135 } else {
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) */
147 GLclampf tmp;
148 tmp = 0.9f;
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) */);
155 #endif
156 LEAVE_GL();
158 return;
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;
177 HRESULT hr;
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);
183 /** From MSDN:
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);
189 return hr;
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;
205 return D3D_OK;
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) {
212 This->Dirty = TRUE;
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");
244 This->inTexture = 0;
245 This->inPBuffer = 0;
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
251 to tolerate this */
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);
273 swapchain = NULL;
275 } else {
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;
287 else {
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 */
291 } else {
292 pLockedRect->Pitch = This->bytesPerPixel * This->pow2Width;
296 if (NULL == pRect) {
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);
303 } else {
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));
308 } else {
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;
317 if (This->nonpow2) {
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. */
336 ENTER_GL();
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);
354 } else {
355 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
357 } else {
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.
369 Were doing this...
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
379 | | | \/
380 -----------------------------------
383 were repacking the data to the expected texture width
385 |<-texture width ->| -->pow2width| /\
386 |111111111111111111222222222222222| |
387 |222333333333333333333444444444444| texture height
388 |444444 | |
389 | | \/
390 | | |
391 | empty | pow2height
392 | | \/
393 -----------------------------------
395 == is the same as
397 |<-texture width ->| /\
398 |111111111111111111|
399 |222222222222222222|texture height
400 |333333333333333333|
401 |444444444444444444| \/
402 --------------------
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.
408 if (This->nonpow2) {
409 BYTE* dataa, *datab;
410 int pitcha = 0, pitchb = 0;
411 int y;
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 */
418 datab += pitchb;
419 memcpy(dataa, datab, pitcha);
424 LEAVE_GL();
425 } else { /* Nothing to do */
426 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
429 if (NULL == pRect) {
430 pLockedRect->pBits = This->resource.allocatedMemory;
431 } else{
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));
434 } else {
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 */
441 GLint prev_store;
442 GLint prev_read;
443 BOOL notInContext = FALSE;
444 IWineD3DSwapChainImpl *targetSwapChain = NULL;
447 ENTER_GL();
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;
462 glFlush();
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");
488 } else {
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");
503 } else {
504 FIXME("Should have got here!\n");
505 glReadBuffer(GL_BACK);
507 } else {
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");
510 notInContext = TRUE;
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
521 * and WINED3DFMT_D16
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,
529 * 1,
530 * GL_DEPTH_COMPONENT,
531 * type,
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 */
535 long j;
536 #if 0
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;
543 #endif
544 if ((This->lockedRect.left == 0 && This->lockedRect.top == 0 &&
545 This->lockedRect.right == This->currentDesc.Width
546 && This->lockedRect.bottom == This->currentDesc.Height)) {
547 glReadPixels(0, 0,
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) {
554 glReadPixels(0,
555 This->lockedRect.top,
556 This->currentDesc.Width,
557 This->currentDesc.Height,
558 This->glDescription.glFormat,
559 This->glDescription.glType,
560 (char *)pLockedRect->pBits);
561 } else{
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");
579 LEAVE_GL();
581 } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
583 if (!messages & 1) {
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
595 messages |= 1;
597 } else {
598 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
601 if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
602 /* Don't dirtify */
603 } else {
604 IWineD3DBaseTexture *pBaseTexture;
606 * Dirtify on lock
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);
616 } else {
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);
623 This->locked = TRUE;
624 return D3D_OK;
627 HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
628 GLint skipBytes = 0;
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);
661 goto unlock_end;
664 if (0 == This->resource.usage) { /* classic surface */
666 * nothing to do
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) {
681 GLint prev_store;
682 GLint prev_draw;
683 GLint prev_rasterpos[4];
685 ENTER_GL();
687 glFlush();
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
708 mode. */
709 glMatrixMode(GL_MODELVIEW);
710 checkGLcall("glMatrixMode");
711 glLoadIdentity();
712 checkGLcall("glLoadIdentity");
714 glMatrixMode(GL_PROJECTION);
715 checkGLcall("glMatrixMode");
716 glLoadIdentity();
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 */
749 glDisable(GL_BLEND);
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");
760 break;
761 case WINED3DFMT_X1R5G5B5:
763 int size;
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);
767 while(size > 0) {
768 *data |= 0x8000;
769 data++;
770 size--;
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");
779 break;
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");
786 break;
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! */
790 int size;
791 unsigned int *data;
792 data = (unsigned int *)This->resource.allocatedMemory;
793 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
794 while(size > 0) {
795 *data |= 0xFF000000;
796 data++;
797 size--;
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");
810 break;
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");
821 break;
822 default:
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);
837 LEAVE_GL();
839 /** restore clean dirty state */
840 IWineD3DSurface_CleanDirtyRect(iface);
842 } else {
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);
851 } else {
852 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
855 } else {
856 FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
859 unlock_end:
860 This->locked = FALSE;
861 memset(&This->lockedRect, 0, sizeof(RECT));
862 return D3D_OK;
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");
885 return D3D_OK;
887 if (This->Dirty == FALSE) {
888 TRACE("surface isn't dirty\n");
889 return D3D_OK;
892 This->Dirty = FALSE;
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) {
902 ENTER_GL();
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);
911 else {
912 GLint prevRead;
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;
933 LEAVE_GL();
934 return D3D_OK;
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
943 UINT i;
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++) {
950 BYTE color = *src++;
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;
956 else
957 *dst++ = 0xFF;
960 ENTER_GL();
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,
965 GL_RGBA,
966 This->currentDesc.Width,
967 This->currentDesc.Height,
969 GL_RGBA,
970 GL_UNSIGNED_BYTE,
971 surface);
972 glTexImage2D(This->glDescription.target,
973 This->glDescription.level,
974 GL_RGBA,
975 This->currentDesc.Width,
976 This->currentDesc.Height,
978 GL_RGBA,
979 GL_UNSIGNED_BYTE,
980 surface);
981 checkGLcall("glTexImage2D");
982 HeapFree(GetProcessHeap(), 0, surface);
984 LEAVE_GL();
986 return D3D_OK;
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);
1007 ENTER_GL();
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");
1019 LEAVE_GL();
1021 if(This->activeLock == FALSE){
1022 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1023 This->resource.allocatedMemory = NULL;
1026 } else {
1027 FIXME("Using DXT1/3/5 without advertized support\n");
1029 } else {
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");
1036 ENTER_GL();
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,
1042 This->pow2Width,
1043 This->pow2Height,
1045 This->glDescription.glFormat,
1046 This->glDescription.glType,
1047 NULL);
1049 glTexImage2D(This->glDescription.target,
1050 This->glDescription.level,
1051 This->glDescription.glFormatInternal,
1052 This->pow2Width,
1053 This->pow2Height,
1054 0/*border*/,
1055 This->glDescription.glFormat,
1056 This->glDescription.glType,
1057 NULL);
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 */
1063 glTexSubImage2D(
1064 This->glDescription.target,
1065 This->glDescription.level,
1066 0 /* xoffset */,
1067 0 /* ysoffset */ ,
1068 This->currentDesc.Width,
1069 This->currentDesc.Height,
1070 This->glDescription.glFormat,
1071 This->glDescription.glType,
1072 This->resource.allocatedMemory
1074 checkGLcall("glTexSubImage2D");
1076 LEAVE_GL();
1078 } else {
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,
1085 This->pow2Width,
1086 This->pow2Height,
1088 This->glDescription.glFormat,
1089 This->glDescription.glType,
1090 This->resource.allocatedMemory);
1092 ENTER_GL();
1093 glTexImage2D(This->glDescription.target,
1094 This->glDescription.level,
1095 This->glDescription.glFormatInternal,
1096 This->pow2Width,
1097 This->pow2Height,
1098 0 /* border */,
1099 This->glDescription.glFormat,
1100 This->glDescription.glType,
1101 This->resource.allocatedMemory);
1102 checkGLcall("glTexImage2D");
1103 LEAVE_GL();
1106 #if 0
1108 static unsigned int gen = 0;
1109 char buffer[4096];
1110 ++gen;
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
1117 if (gen == 250) {
1118 void** test = NULL;
1119 *test = 0;
1123 #endif
1124 if(This->activeLock == FALSE){
1125 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1126 This->resource.allocatedMemory = NULL;
1131 return D3D_OK;
1134 #include <errno.h>
1135 #include <stdio.h>
1136 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1137 FILE* f = NULL;
1138 UINT i, y;
1139 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1140 char *allocatedMemory;
1141 char *textureRow;
1142 IWineD3DSwapChain *swapChain = NULL;
1143 int width, height;
1144 GLuint tmpTexture;
1145 DWORD color;
1146 /*FIXME:
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
1156 images. */
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 */
1166 GLint prevRead;
1167 ENTER_GL();
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,
1176 GL_RGBA,
1177 width,
1178 height,
1179 0/*border*/,
1180 GL_RGBA,
1181 GL_UNSIGNED_INT_8_8_8_8_REV,
1182 NULL);
1184 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1185 vcheckGLcall("glGetIntegerv");
1186 glReadBuffer(GL_BACK);
1187 vcheckGLcall("glReadBuffer");
1188 glCopyTexImage2D(GL_TEXTURE_2D,
1190 GL_RGBA,
1193 width,
1194 height,
1197 checkGLcall("glCopyTexImage2D");
1198 glReadBuffer(prevRead);
1199 LEAVE_GL();
1201 } else { /* bind the real texture */
1202 IWineD3DSurface_PreLoad(iface);
1204 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1205 ENTER_GL();
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,
1209 GL_RGBA,
1210 GL_UNSIGNED_INT_8_8_8_8_REV,
1211 allocatedMemory);
1212 checkGLcall("glTexImage2D");
1213 if (tmpTexture) {
1214 glBindTexture(GL_TEXTURE_2D, 0);
1215 glDeleteTextures(1, &tmpTexture);
1217 LEAVE_GL();
1219 f = fopen(filename, "w+");
1220 if (NULL == f) {
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));
1226 /* TGA header */
1227 fputc(0,f);
1228 fputc(0,f);
1229 fputc(2,f);
1230 fputc(0,f);
1231 fputc(0,f);
1232 fputc(0,f);
1233 fputc(0,f);
1234 fputc(0,f);
1235 fputc(0,f);
1236 fputc(0,f);
1237 fputc(0,f);
1238 fputc(0,f);
1239 /* short width*/
1240 fwrite(&width,2,1,f);
1241 /* short height */
1242 fwrite(&height,2,1,f);
1243 /* format rgba */
1244 fputc(0x20,f);
1245 fputc(0x28,f);
1246 /* raw data */
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*/
1248 if(swapChain)
1249 textureRow = allocatedMemory + (width * (height - 1) *4);
1250 else
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 */
1259 textureRow += 4;
1261 /* take two rows of the pointer to the texture memory */
1262 if(swapChain)
1263 (textureRow-= width << 3);
1266 TRACE("Closing file\n");
1267 fclose(f);
1269 if(swapChain) {
1270 IWineD3DSwapChain_Release(swapChain);
1272 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1273 return D3D_OK;
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);
1285 return D3D_OK;
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;
1294 This->Dirty = TRUE;
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);
1300 } else {
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);
1314 return D3D_OK;
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;
1321 return D3D_OK;
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;
1330 return D3D_OK;
1333 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
1335 /* IUnknown */
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,
1356 /* Internal use: */
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