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 "wined3d_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface
);
28 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
30 /* *******************************************
31 IWineD3DSurface IUnknown parts follow
32 ******************************************* */
33 HRESULT WINAPI
IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface
*iface
, REFIID riid
, LPVOID
*ppobj
)
35 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
36 /* Warn ,but be nice about things */
37 TRACE("(%p)->(%s,%p) \n", This
,debugstr_guid(riid
),ppobj
);
39 ERR("Probably FIXME: Calling query interface with NULL riid\n");
41 if (IsEqualGUID(riid
, &IID_IUnknown
)
42 || IsEqualGUID(riid
, &IID_IWineD3DResource
)
43 || IsEqualGUID(riid
, &IID_IWineD3DSurface
)) {
44 IUnknown_AddRef((IUnknown
*)iface
);
51 ULONG WINAPI
IWineD3DSurfaceImpl_AddRef(IWineD3DSurface
*iface
) {
52 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
53 ULONG ref
= InterlockedIncrement(&This
->resource
.ref
);
54 TRACE("(%p) : AddRef increasing from %ld\n", This
,ref
- 1);
58 ULONG WINAPI
IWineD3DSurfaceImpl_Release(IWineD3DSurface
*iface
) {
59 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
60 ULONG ref
= InterlockedDecrement(&This
->resource
.ref
);
61 TRACE("(%p) : Releasing from %ld\n", This
, ref
+ 1);
63 if (This
->textureName
!= 0) { /* release the openGL texture.. */
65 TRACE("Deleting texture %d\n", This
->textureName
);
66 glDeleteTextures(1, &This
->textureName
);
69 IWineD3DResourceImpl_CleanUp((IWineD3DResource
*)iface
);
70 HeapFree(GetProcessHeap(), 0, This
);
76 /* ****************************************************
77 IWineD3DSurface IWineD3DResource parts follow
78 **************************************************** */
79 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface
*iface
, IWineD3DDevice
** ppDevice
) {
80 return IWineD3DResourceImpl_GetDevice((IWineD3DResource
*)iface
, ppDevice
);
83 HRESULT WINAPI
IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface
*iface
, REFGUID refguid
, CONST
void* pData
, DWORD SizeOfData
, DWORD Flags
) {
84 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource
*)iface
, refguid
, pData
, SizeOfData
, Flags
);
87 HRESULT WINAPI
IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface
*iface
, REFGUID refguid
, void* pData
, DWORD
* pSizeOfData
) {
88 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource
*)iface
, refguid
, pData
, pSizeOfData
);
91 HRESULT WINAPI
IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface
*iface
, REFGUID refguid
) {
92 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource
*)iface
, refguid
);
95 DWORD WINAPI
IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface
*iface
, DWORD PriorityNew
) {
96 return IWineD3DResourceImpl_SetPriority((IWineD3DResource
*)iface
, PriorityNew
);
99 DWORD WINAPI
IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface
*iface
) {
100 return IWineD3DResourceImpl_GetPriority((IWineD3DResource
*)iface
);
103 void WINAPI
IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface
*iface
) {
104 /* TODO: re-write the way textures and managed,
105 * use a 'opengl context manager' to manage RenderTarget surfaces
106 ** *********************************************************/
108 /* TODO: check for locks */
109 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
110 IWineD3DBaseTexture
*baseTexture
= NULL
;
111 TRACE("(%p)Checking to see if the container is a base textuer\n", This
);
112 if (IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
) == D3D_OK
) {
113 TRACE("Passing to conatiner\n");
114 IWineD3DBaseTexture_PreLoad(baseTexture
);
115 IWineD3DBaseTexture_Release(baseTexture
);
117 TRACE("(%p) : About to load surface\n", This
);
119 #if 0 /* TODO: context manager support */
120 IWineD3DContextManager_PushState(This
->contextManager
, GL_TEXTURE_2D
, ENABLED
, NOW
/* make sure the state is applied now */);
122 glEnable(GL_TEXTURE_2D
); /* make sure texture support is enabled in this context */
123 if (This
->currentDesc
.Level
== 0 && This
->textureName
== 0) {
124 glGenTextures(1, &This
->textureName
);
125 checkGLcall("glGenTextures");
126 TRACE("Surface %p given name %d\n", This
, This
->textureName
);
127 glBindTexture(GL_TEXTURE_2D
, This
->textureName
);
128 checkGLcall("glBindTexture");
129 IWineD3DSurface_LoadTexture((IWineD3DSurface
*) This
, GL_TEXTURE_2D
, This
->currentDesc
.Level
);
130 /* This is where we should be reducing the amount of GLMemoryUsed */
132 if (This
->currentDesc
.Level
== 0) {
133 glBindTexture(GL_TEXTURE_2D
, This
->textureName
);
134 checkGLcall("glBindTexture");
135 IWineD3DSurface_LoadTexture((IWineD3DSurface
*) This
, GL_TEXTURE_2D
, This
->currentDesc
.Level
);
136 } else if (This
->textureName
!= 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
137 /* assume this is a coding error not a real error for now */
138 FIXME("Mipmap surface has a glTexture bound to it!\n");
141 if (This
->resource
.pool
== D3DPOOL_DEFAULT
) {
142 /* Tell opengl to try and keep this texture in video ram (well mostly) */
145 glPrioritizeTextures(1, &This
->textureName
, &tmp
);
147 /* TODO: disable texture support, if it wastn't enabled when we entered. */
148 #if 0 /* TODO: context manager support */
149 IWineD3DContextManager_PopState(This
->contextManager
, GL_TEXTURE_2D
, DISABLED
,DELAYED
150 /* we don't care when the state is disabled(if atall) */);
157 D3DRESOURCETYPE WINAPI
IWineD3DSurfaceImpl_GetType(IWineD3DSurface
*iface
) {
158 return IWineD3DResourceImpl_GetType((IWineD3DResource
*)iface
);
161 HRESULT WINAPI
IWineD3DSurfaceImpl_GetParent(IWineD3DSurface
*iface
, IUnknown
**pParent
) {
162 return IWineD3DResourceImpl_GetParent((IWineD3DResource
*)iface
, pParent
);
165 /* ******************************************************
166 IWineD3DSurface IWineD3DSurface parts follow
167 ****************************************************** */
169 HRESULT WINAPI
IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface
* iface
, REFIID riid
, void** ppContainer
) {
170 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
172 if (ppContainer
== NULL
) {
173 ERR("Get container called witout a null ppContainer\n");
174 return E_NOINTERFACE
;
176 TRACE("(%p) : Relaying to queryInterface %p %p\n", This
, ppContainer
, *ppContainer
);
178 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
179 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
180 * GetContainer will return the Direct3D device used to create the surface.
182 hr
= IUnknown_QueryInterface(This
->container
, riid
, ppContainer
);
186 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface
*iface
, WINED3DSURFACE_DESC
*pDesc
) {
187 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
189 TRACE("(%p) : copying into %p\n", This
, pDesc
);
190 *(pDesc
->Format
) = This
->resource
.format
;
191 *(pDesc
->Type
) = This
->resource
.resourceType
;
192 *(pDesc
->Usage
) = This
->resource
.usage
;
193 *(pDesc
->Pool
) = This
->resource
.pool
;
194 *(pDesc
->Size
) = This
->resource
.size
; /* dx8 only */
195 *(pDesc
->MultiSampleType
) = This
->currentDesc
.MultiSampleType
;
196 *(pDesc
->MultiSampleQuality
) = This
->currentDesc
.MultiSampleQuality
;
197 *(pDesc
->Width
) = This
->currentDesc
.Width
;
198 *(pDesc
->Height
) = This
->currentDesc
.Height
;
202 HRESULT WINAPI
IWineD3DSurfaceImpl_LockRect(IWineD3DSurface
*iface
, D3DLOCKED_RECT
* pLockedRect
, CONST RECT
* pRect
, DWORD Flags
) {
203 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
205 /* fixme: should we really lock as such? */
206 if (This
->inTexture
&& This
->inPBuffer
) {
207 FIXME("Warning: Surface is in texture memory or pbuffer\n");
212 if (FALSE
== This
->lockable
) {
213 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
214 texture regions, and since the destination is an unlockable region we need
216 TRACE("Warning: trying to lock unlockable surf@%p\n", This
);
217 /*return D3DERR_INVALIDCALL; */
220 if (iface
== This
->resource
.wineD3DDevice
->backBuffer
|| iface
== This
->resource
.wineD3DDevice
->renderTarget
||
221 iface
== This
->resource
.wineD3DDevice
->frontBuffer
|| iface
== This
->resource
.wineD3DDevice
->depthStencilBuffer
) {
222 if (iface
== This
->resource
.wineD3DDevice
->backBuffer
) {
223 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
224 } else if (iface
== This
->resource
.wineD3DDevice
->frontBuffer
) {
225 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
226 } else if (iface
== This
->resource
.wineD3DDevice
->renderTarget
) {
227 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
228 } else if (iface
== This
->resource
.wineD3DDevice
->depthStencilBuffer
) {
229 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
232 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
235 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
236 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt3/5)
237 ie pitch = (width/4) * bytes per block */
238 if (This
->resource
.format
== WINED3DFMT_DXT1
) /* DXT1 is 8 bytes per block */
239 pLockedRect
->Pitch
= (This
->currentDesc
.Width
>> 2) << 3;
240 else if (This
->resource
.format
== WINED3DFMT_DXT3
|| This
->resource
.format
== WINED3DFMT_DXT5
) /* DXT3/5 is 16 bytes per block */
241 pLockedRect
->Pitch
= (This
->currentDesc
.Width
>> 2) << 4;
243 pLockedRect
->Pitch
= This
->bytesPerPixel
* This
->currentDesc
.Width
; /* Bytes / row */
246 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
247 This
->lockedRect
.left
= 0;
248 This
->lockedRect
.top
= 0;
249 This
->lockedRect
.right
= This
->currentDesc
.Width
;
250 This
->lockedRect
.bottom
= This
->currentDesc
.Height
;
251 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
);
253 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
255 if (This
->resource
.format
== WINED3DFMT_DXT1
) { /* DXT1 is half byte per pixel */
256 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + ((pRect
->left
* This
->bytesPerPixel
/2));
258 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + (pRect
->left
* This
->bytesPerPixel
);
260 This
->lockedRect
.left
= pRect
->left
;
261 This
->lockedRect
.top
= pRect
->top
;
262 This
->lockedRect
.right
= pRect
->right
;
263 This
->lockedRect
.bottom
= pRect
->bottom
;
267 if (0 == This
->resource
.usage
) { /* classic surface */
269 /* Nothing to do ;) */
271 } else if (D3DUSAGE_RENDERTARGET
& This
->resource
.usage
&& !(Flags
&D3DLOCK_DISCARD
)) { /* render surfaces */
273 if (iface
== This
->resource
.wineD3DDevice
->backBuffer
|| iface
== This
->resource
.wineD3DDevice
->renderTarget
|| iface
== This
->resource
.wineD3DDevice
->frontBuffer
) {
280 * for render->surface copy begin to begin of allocatedMemory
281 * unlock can be more easy
283 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
286 vcheckGLcall("glFlush");
287 glGetIntegerv(GL_READ_BUFFER
, &prev_read
);
288 vcheckGLcall("glIntegerv");
289 glGetIntegerv(GL_PACK_SWAP_BYTES
, &prev_store
);
290 vcheckGLcall("glIntegerv");
292 if (iface
== This
->resource
.wineD3DDevice
->backBuffer
) {
293 glReadBuffer(GL_BACK
);
294 } else if (iface
== This
->resource
.wineD3DDevice
->frontBuffer
|| iface
== This
->resource
.wineD3DDevice
->renderTarget
) {
295 glReadBuffer(GL_FRONT
);
296 } else if (iface
== This
->resource
.wineD3DDevice
->depthStencilBuffer
) {
297 ERR("Stencil Buffer lock unsupported for now\n");
299 vcheckGLcall("glReadBuffer");
303 GLenum format
= D3DFmt2GLFmt(This
->resource
.wineD3DDevice
, This
->resource
.format
);
304 GLenum type
= D3DFmt2GLType(This
->resource
.wineD3DDevice
, This
->resource
.format
);
305 for (j
= This
->lockedRect
.top
; j
< This
->lockedRect
.bottom
- This
->lockedRect
.top
; ++j
) {
306 glReadPixels(This
->lockedRect
.left
,
307 This
->lockedRect
.bottom
- j
- 1,
308 This
->lockedRect
.right
- This
->lockedRect
.left
,
312 (char *)pLockedRect
->pBits
+ (pLockedRect
->Pitch
* (j
-This
->lockedRect
.top
)));
313 vcheckGLcall("glReadPixels");
317 glReadBuffer(prev_read
);
318 vcheckGLcall("glReadBuffer");
323 FIXME("unsupported locking to Rendering surface surf@%p usage(%lu)\n", This
, This
->resource
.usage
);
326 } else if (D3DUSAGE_DEPTHSTENCIL
& This
->resource
.usage
) { /* stencil surfaces */
328 FIXME("TODO stencil depth surface locking surf@%p usage(%lu)\n", This
, This
->resource
.usage
);
331 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This
, This
->resource
.usage
);
334 if (Flags
& (D3DLOCK_NO_DIRTY_UPDATE
| D3DLOCK_READONLY
)) {
337 IWineD3DBaseTexture
*pBaseTexture
;
340 * as seen in msdn docs
342 IWineD3DSurface_AddDirtyRect(iface
, &This
->lockedRect
);
344 /** Dirtify Container if needed */
345 if (D3D_OK
== IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&pBaseTexture
) && pBaseTexture
!= NULL
) {
346 TRACE("Making container dirty\n");
347 IWineD3DBaseTexture_SetDirty(pBaseTexture
, TRUE
);
348 IWineD3DBaseTexture_Release(pBaseTexture
);
350 TRACE("Surface is standalone, no need to dirty the container\n");
354 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect
->pBits
, pLockedRect
->Pitch
, This
->Dirty
);
360 HRESULT WINAPI
IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface
*iface
) {
362 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
364 if (FALSE
== This
->locked
) {
365 ERR("trying to Unlock an unlocked surf@%p\n", This
);
366 return D3DERR_INVALIDCALL
;
369 if (iface
== This
->resource
.wineD3DDevice
->backBuffer
|| iface
== This
->resource
.wineD3DDevice
->frontBuffer
||
370 iface
== This
->resource
.wineD3DDevice
->depthStencilBuffer
|| iface
== This
->resource
.wineD3DDevice
->renderTarget
) {
371 if (iface
== This
->resource
.wineD3DDevice
->backBuffer
) {
372 TRACE("(%p, backBuffer) : dirtyfied(%d)\n", This
, This
->Dirty
);
373 } else if (iface
== This
->resource
.wineD3DDevice
->frontBuffer
) {
374 TRACE("(%p, frontBuffer) : dirtyfied(%d)\n", This
, This
->Dirty
);
375 } else if (iface
== This
->resource
.wineD3DDevice
->depthStencilBuffer
) {
376 TRACE("(%p, stencilBuffer) : dirtyfied(%d)\n", This
, This
->Dirty
);
377 } else if (iface
== This
->resource
.wineD3DDevice
->renderTarget
) {
378 TRACE("(%p, renderTarget) : dirtyfied(%d)\n", This
, This
->Dirty
);
381 TRACE("(%p) : dirtyfied(%d)\n", This
, This
->Dirty
);
384 if (FALSE
== This
->Dirty
) {
385 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This
);
389 if (0 == This
->resource
.usage
) { /* classic surface */
392 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
394 } else if (D3DUSAGE_RENDERTARGET
& This
->resource
.usage
) { /* render surfaces */
396 if (iface
== This
->resource
.wineD3DDevice
->backBuffer
|| iface
== This
->resource
.wineD3DDevice
->frontBuffer
|| iface
== This
->resource
.wineD3DDevice
->renderTarget
) {
399 GLint prev_rasterpos
[4];
404 vcheckGLcall("glFlush");
405 glGetIntegerv(GL_DRAW_BUFFER
, &prev_draw
);
406 vcheckGLcall("glIntegerv");
407 glGetIntegerv(GL_PACK_SWAP_BYTES
, &prev_store
);
408 vcheckGLcall("glIntegerv");
409 glGetIntegerv(GL_CURRENT_RASTER_POSITION
, &prev_rasterpos
[0]);
410 vcheckGLcall("glIntegerv");
411 glPixelZoom(1.0, -1.0);
412 vcheckGLcall("glPixelZoom");
414 /* glDrawPixels transforms the raster position as though it was a vertex -
415 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
416 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
417 if (!This
->resource
.wineD3DDevice
->last_was_rhw
) {
419 double X
, Y
, height
, width
, minZ
, maxZ
;
420 This
->resource
.wineD3DDevice
->last_was_rhw
= TRUE
;
422 /* Transformed already into viewport coordinates, so we do not need transform
423 matrices. Reset all matrices to identity and leave the default matrix in world
425 glMatrixMode(GL_MODELVIEW
);
426 checkGLcall("glMatrixMode");
428 checkGLcall("glLoadIdentity");
430 glMatrixMode(GL_PROJECTION
);
431 checkGLcall("glMatrixMode");
433 checkGLcall("glLoadIdentity");
435 /* Set up the viewport to be full viewport */
436 X
= This
->resource
.wineD3DDevice
->stateBlock
->viewport
.X
;
437 Y
= This
->resource
.wineD3DDevice
->stateBlock
->viewport
.Y
;
438 height
= This
->resource
.wineD3DDevice
->stateBlock
->viewport
.Height
;
439 width
= This
->resource
.wineD3DDevice
->stateBlock
->viewport
.Width
;
440 minZ
= This
->resource
.wineD3DDevice
->stateBlock
->viewport
.MinZ
;
441 maxZ
= This
->resource
.wineD3DDevice
->stateBlock
->viewport
.MaxZ
;
442 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width
, height
, -minZ
, -maxZ
);
443 glOrtho(X
, X
+ width
, Y
+ height
, Y
, -minZ
, -maxZ
);
444 checkGLcall("glOrtho");
446 /* Window Coord 0 is the middle of the first pixel, so translate by half
447 a pixel (See comment above glTranslate below) */
448 glTranslatef(0.5, 0.5, 0);
449 checkGLcall("glTranslatef(0.5, 0.5, 0)");
452 if (iface
== This
->resource
.wineD3DDevice
->backBuffer
) {
453 glDrawBuffer(GL_BACK
);
454 } else if (iface
== This
->resource
.wineD3DDevice
->frontBuffer
|| iface
== This
->resource
.wineD3DDevice
->renderTarget
) {
455 glDrawBuffer(GL_FRONT
);
457 vcheckGLcall("glDrawBuffer");
459 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
460 glGetIntegerv(GL_UNPACK_ROW_LENGTH
, &skipBytes
);
461 glPixelStorei(GL_UNPACK_ROW_LENGTH
, This
->currentDesc
.Width
);
463 /* And back buffers are not blended */
466 glRasterPos3i(This
->lockedRect
.left
, This
->lockedRect
.top
, 1);
467 vcheckGLcall("glRasterPos2f");
468 switch (This
->resource
.format
) {
469 case WINED3DFMT_R5G6B5
:
471 glDrawPixels(This
->lockedRect
.right
- This
->lockedRect
.left
, (This
->lockedRect
.bottom
- This
->lockedRect
.top
)-1,
472 GL_RGB
, GL_UNSIGNED_SHORT_5_6_5
, This
->resource
.allocatedMemory
);
473 vcheckGLcall("glDrawPixels");
476 case WINED3DFMT_R8G8B8
:
478 glDrawPixels(This
->lockedRect
.right
- This
->lockedRect
.left
, (This
->lockedRect
.bottom
- This
->lockedRect
.top
)-1,
479 GL_RGB
, GL_UNSIGNED_BYTE
, This
->resource
.allocatedMemory
);
480 vcheckGLcall("glDrawPixels");
483 case WINED3DFMT_X8R8G8B8
: /* FIXME: there's no alpha change with D3DFMT_X8R8G8B8 but were using GL_BGRA */
484 case WINED3DFMT_A8R8G8B8
:
486 glPixelStorei(GL_PACK_SWAP_BYTES
, TRUE
);
487 vcheckGLcall("glPixelStorei");
488 glDrawPixels(This
->lockedRect
.right
- This
->lockedRect
.left
, (This
->lockedRect
.bottom
- This
->lockedRect
.top
)-1,
489 GL_BGRA
, GL_UNSIGNED_BYTE
, This
->resource
.allocatedMemory
);
490 vcheckGLcall("glDrawPixels");
491 glPixelStorei(GL_PACK_SWAP_BYTES
, prev_store
);
492 vcheckGLcall("glPixelStorei");
496 FIXME("Unsupported Format %u in locking func\n", This
->resource
.format
);
499 glPixelZoom(1.0,1.0);
500 vcheckGLcall("glPixelZoom");
501 glDrawBuffer(prev_draw
);
502 vcheckGLcall("glDrawBuffer");
503 glRasterPos3iv(&prev_rasterpos
[0]);
504 vcheckGLcall("glRasterPos3iv");
506 /* Reset to previous pack row length / blending state */
507 glPixelStorei(GL_UNPACK_ROW_LENGTH
, skipBytes
);
508 if (This
->resource
.wineD3DDevice
->stateBlock
->renderState
[D3DRS_ALPHABLENDENABLE
]) glEnable(GL_BLEND
);
512 /** restore clean dirty state */
513 IWineD3DSurface_CleanDirtyRect(iface
);
516 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This
, This
->resource
.usage
);
519 } else if (D3DUSAGE_DEPTHSTENCIL
& This
->resource
.usage
) { /* stencil surfaces */
521 if (iface
== This
->resource
.wineD3DDevice
->depthStencilBuffer
) {
522 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This
, This
->resource
.usage
);
524 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This
, This
->resource
.usage
);
528 FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This
, This
->resource
.usage
);
532 This
->locked
= FALSE
;
533 memset(&This
->lockedRect
, 0, sizeof(RECT
));
537 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDC(IWineD3DSurface
*iface
, HDC
*pHDC
) {
538 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
539 FIXME("No support for GetDC yet for surface %p\n", This
);
540 return D3DERR_INVALIDCALL
;
543 HRESULT WINAPI
IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface
*iface
, HDC hDC
) {
544 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
545 FIXME("No support for ReleaseDC yet for surface %p\n", This
);
546 return D3DERR_INVALIDCALL
;
549 /* ******************************************************
550 IWineD3DSurface Internal (No mapping to directx api) parts follow
551 ****************************************************** */
552 HRESULT WINAPI
IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface
*iface
, GLenum gl_target
, GLenum gl_level
) {
553 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
558 if (This
->inPBuffer
) {
562 FIXME("Surface in texture is only supported for level 0\n");
563 else if (This
->resource
.format
== WINED3DFMT_P8
|| This
->resource
.format
== WINED3DFMT_A8P8
||
564 This
->resource
.format
== WINED3DFMT_DXT1
|| This
->resource
.format
== WINED3DFMT_DXT3
||
565 This
->resource
.format
== WINED3DFMT_DXT5
)
566 FIXME("Format %d not supported\n", This
->resource
.format
);
568 glCopyTexImage2D(gl_target
,
570 D3DFmt2GLIntFmt(This
->resource
.wineD3DDevice
,
571 This
->resource
.format
),
574 This
->currentDesc
.Width
,
575 This
->currentDesc
.Height
,
577 TRACE("Updating target %d\n", gl_target
);
578 This
->inTexture
= TRUE
;
584 if ((This
->resource
.format
== WINED3DFMT_P8
|| This
->resource
.format
== WINED3DFMT_A8P8
) &&
585 !GL_SUPPORT(EXT_PALETTED_TEXTURE
)) {
587 * wanted a paletted texture and not really support it in HW
588 * so software emulation code begin
591 PALETTEENTRY
* pal
= This
->resource
.wineD3DDevice
->palettes
[This
->resource
.wineD3DDevice
->currentPalette
];
592 VOID
* surface
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->currentDesc
.Width
* This
->currentDesc
.Height
* sizeof(DWORD
));
593 BYTE
* dst
= (BYTE
*) surface
;
594 BYTE
* src
= (BYTE
*) This
->resource
.allocatedMemory
;
596 for (i
= 0; i
< This
->currentDesc
.Width
* This
->currentDesc
.Height
; i
++) {
598 *dst
++ = pal
[color
].peRed
;
599 *dst
++ = pal
[color
].peGreen
;
600 *dst
++ = pal
[color
].peBlue
;
601 if (This
->resource
.format
== WINED3DFMT_A8P8
)
602 *dst
++ = pal
[color
].peFlags
;
609 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
613 This
->currentDesc
.Width
,
614 This
->currentDesc
.Height
,
619 glTexImage2D(gl_target
,
622 This
->currentDesc
.Width
,
623 This
->currentDesc
.Height
,
628 checkGLcall("glTexImage2D");
629 HeapFree(GetProcessHeap(), 0, surface
);
636 if (This
->resource
.format
== WINED3DFMT_DXT1
||
637 This
->resource
.format
== WINED3DFMT_DXT3
||
638 This
->resource
.format
== WINED3DFMT_DXT5
) {
639 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
640 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
643 D3DFmt2GLIntFmt(This
->resource
.wineD3DDevice
, This
->resource
.format
),
644 This
->currentDesc
.Width
,
645 This
->currentDesc
.Height
,
648 This
->resource
.allocatedMemory
);
652 GL_EXTCALL(glCompressedTexImage2DARB
)(gl_target
,
654 D3DFmt2GLIntFmt(This
->resource
.wineD3DDevice
, This
->resource
.format
),
655 This
->currentDesc
.Width
,
656 This
->currentDesc
.Height
,
659 This
->resource
.allocatedMemory
);
660 checkGLcall("glCommpressedTexTexImage2D");
664 FIXME("Using DXT1/3/5 without advertized support\n");
668 TRACE("Calling glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
671 debug_d3dformat(This
->resource
.format
),
672 D3DFmt2GLIntFmt(This
->resource
.wineD3DDevice
, This
->resource
.format
),
673 This
->currentDesc
.Width
,
674 This
->currentDesc
.Height
,
676 D3DFmt2GLFmt(This
->resource
.wineD3DDevice
, This
->resource
.format
),
677 D3DFmt2GLType(This
->resource
.wineD3DDevice
, This
->resource
.format
),
678 This
->resource
.allocatedMemory
);
682 glTexImage2D(gl_target
,
684 D3DFmt2GLIntFmt(This
->resource
.wineD3DDevice
, This
->resource
.format
),
685 This
->currentDesc
.Width
,
686 This
->currentDesc
.Height
,
688 D3DFmt2GLFmt(This
->resource
.wineD3DDevice
, This
->resource
.format
),
689 D3DFmt2GLType(This
->resource
.wineD3DDevice
, This
->resource
.format
),
690 This
->resource
.allocatedMemory
);
691 checkGLcall("glTexImage2D");
697 static unsigned int gen
= 0;
700 if ((gen
% 10) == 0) {
701 snprintf(buffer
, sizeof(buffer
), "/tmp/surface%p_type%u_level%u_%u.ppm", This
, gl_target
, gl_level
, gen
);
702 IWineD3DSurfaceImpl_SaveSnapshot((LPDIRECT3DSURFACE8
) This
, buffer
);
705 * debugging crash code
720 HRESULT WINAPI
IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface
*iface
, const char* filename
) {
723 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
725 f
= fopen(filename
, "w+");
727 ERR("opening of %s failed with: %s\n", filename
, strerror(errno
));
728 return D3DERR_INVALIDCALL
;
731 TRACE("opened %s with format %s\n", filename
, debug_d3dformat(This
->resource
.format
));
733 fprintf(f
, "P6\n%u %u\n255\n", This
->currentDesc
.Width
, This
->currentDesc
.Height
);
734 switch (This
->resource
.format
) {
735 case WINED3DFMT_X8R8G8B8
:
736 case WINED3DFMT_A8R8G8B8
:
739 for (i
= 0; i
< This
->currentDesc
.Width
* This
->currentDesc
.Height
; i
++) {
740 color
= ((DWORD
*) This
->resource
.allocatedMemory
)[i
];
741 fputc((color
>> 16) & 0xFF, f
);
742 fputc((color
>> 8) & 0xFF, f
);
743 fputc((color
>> 0) & 0xFF, f
);
747 case WINED3DFMT_R8G8B8
:
750 for (i
= 0; i
< This
->currentDesc
.Width
* This
->currentDesc
.Height
; i
++) {
751 color
= ((BYTE
*) This
->resource
.allocatedMemory
) + (3 * i
);
752 fputc((color
[0]) & 0xFF, f
);
753 fputc((color
[1]) & 0xFF, f
);
754 fputc((color
[2]) & 0xFF, f
);
758 case WINED3DFMT_A1R5G5B5
:
761 for (i
= 0; i
< This
->currentDesc
.Width
* This
->currentDesc
.Height
; i
++) {
762 color
= ((WORD
*) This
->resource
.allocatedMemory
)[i
];
763 fputc(((color
>> 10) & 0x1F) * 255 / 31, f
);
764 fputc(((color
>> 5) & 0x1F) * 255 / 31, f
);
765 fputc(((color
>> 0) & 0x1F) * 255 / 31, f
);
769 case WINED3DFMT_A4R4G4B4
:
772 for (i
= 0; i
< This
->currentDesc
.Width
* This
->currentDesc
.Height
; i
++) {
773 color
= ((WORD
*) This
->resource
.allocatedMemory
)[i
];
774 fputc(((color
>> 8) & 0x0F) * 255 / 15, f
);
775 fputc(((color
>> 4) & 0x0F) * 255 / 15, f
);
776 fputc(((color
>> 0) & 0x0F) * 255 / 15, f
);
781 case WINED3DFMT_R5G6B5
:
784 for (i
= 0; i
< This
->currentDesc
.Width
* This
->currentDesc
.Height
; i
++) {
785 color
= ((WORD
*) This
->resource
.allocatedMemory
)[i
];
786 fputc(((color
>> 11) & 0x1F) * 255 / 31, f
);
787 fputc(((color
>> 5) & 0x3F) * 255 / 63, f
);
788 fputc(((color
>> 0) & 0x1F) * 255 / 31, f
);
793 FIXME("Unimplemented dump mode format(%u,%s)\n", This
->resource
.format
, debug_d3dformat(This
->resource
.format
));
799 HRESULT WINAPI
IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface
*iface
) {
800 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
802 This
->dirtyRect
.left
= This
->currentDesc
.Width
;
803 This
->dirtyRect
.top
= This
->currentDesc
.Height
;
804 This
->dirtyRect
.right
= 0;
805 This
->dirtyRect
.bottom
= 0;
806 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This
, This
->Dirty
, This
->dirtyRect
.left
,
807 This
->dirtyRect
.top
, This
->dirtyRect
.right
, This
->dirtyRect
.bottom
);
812 * Slightly inefficient way to handle multiple dirty rects but it works :)
814 extern HRESULT WINAPI
IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface
*iface
, CONST RECT
* pDirtyRect
) {
815 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
817 if (NULL
!= pDirtyRect
) {
818 This
->dirtyRect
.left
= min(This
->dirtyRect
.left
, pDirtyRect
->left
);
819 This
->dirtyRect
.top
= min(This
->dirtyRect
.top
, pDirtyRect
->top
);
820 This
->dirtyRect
.right
= max(This
->dirtyRect
.right
, pDirtyRect
->right
);
821 This
->dirtyRect
.bottom
= max(This
->dirtyRect
.bottom
, pDirtyRect
->bottom
);
823 This
->dirtyRect
.left
= 0;
824 This
->dirtyRect
.top
= 0;
825 This
->dirtyRect
.right
= This
->currentDesc
.Width
;
826 This
->dirtyRect
.bottom
= This
->currentDesc
.Height
;
828 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This
, This
->Dirty
, This
->dirtyRect
.left
,
829 This
->dirtyRect
.top
, This
->dirtyRect
.right
, This
->dirtyRect
.bottom
);
833 HRESULT WINAPI
IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface
*iface
, IUnknown
*container
) {
834 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
835 TRACE("Setting container to %p from %p\n", container
, This
->container
);
836 This
->container
= container
;
840 /* TODO: replace this function with context management routines */
841 HRESULT WINAPI
IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface
*iface
, BOOL inPBuffer
, BOOL inTexture
) {
842 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
844 This
->inPBuffer
= inPBuffer
;
845 This
->inTexture
= inTexture
;
849 IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl
=
852 IWineD3DSurfaceImpl_QueryInterface
,
853 IWineD3DSurfaceImpl_AddRef
,
854 IWineD3DSurfaceImpl_Release
,
855 /* IWineD3DResource */
856 IWineD3DSurfaceImpl_GetParent
,
857 IWineD3DSurfaceImpl_GetDevice
,
858 IWineD3DSurfaceImpl_SetPrivateData
,
859 IWineD3DSurfaceImpl_GetPrivateData
,
860 IWineD3DSurfaceImpl_FreePrivateData
,
861 IWineD3DSurfaceImpl_SetPriority
,
862 IWineD3DSurfaceImpl_GetPriority
,
863 IWineD3DSurfaceImpl_PreLoad
,
864 IWineD3DSurfaceImpl_GetType
,
865 /* IWineD3DSurface */
866 IWineD3DSurfaceImpl_GetContainer
,
867 IWineD3DSurfaceImpl_GetDesc
,
868 IWineD3DSurfaceImpl_LockRect
,
869 IWineD3DSurfaceImpl_UnlockRect
,
870 IWineD3DSurfaceImpl_GetDC
,
871 IWineD3DSurfaceImpl_ReleaseDC
,
873 IWineD3DSurfaceImpl_CleanDirtyRect
,
874 IWineD3DSurfaceImpl_AddDirtyRect
,
875 IWineD3DSurfaceImpl_LoadTexture
,
876 IWineD3DSurfaceImpl_SaveSnapshot
,
877 IWineD3DSurfaceImpl_SetContainer
,
878 IWineD3DSurfaceImpl_SetPBufferState