2 * IWineD3DSurface Implementation
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006 Stefan Dösinger for CodeWeavers
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
29 #include "wined3d_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface
);
32 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
50 HRESULT
d3dfmt_convert_surface(BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
, UINT height
, UINT outpitch
, CONVERT_TYPES convert
, IWineD3DSurfaceImpl
*surf
);
52 static void surface_download_data(IWineD3DSurfaceImpl
*This
) {
53 if (This
->resource
.format
== WINED3DFMT_DXT1
||
54 This
->resource
.format
== WINED3DFMT_DXT2
|| This
->resource
.format
== WINED3DFMT_DXT3
||
55 This
->resource
.format
== WINED3DFMT_DXT4
|| This
->resource
.format
== WINED3DFMT_DXT5
) {
56 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) { /* We can assume this as the texture would not have been created otherwise */
57 FIXME("(%p) : Attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This
);
59 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This
, This
->glDescription
.level
,
60 This
->glDescription
.glFormat
, This
->glDescription
.glType
, This
->resource
.allocatedMemory
);
64 GL_EXTCALL(glGetCompressedTexImageARB(This
->glDescription
.target
, This
->glDescription
.level
, This
->resource
.allocatedMemory
));
65 checkGLcall("glGetCompressedTexImageARB()");
70 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This
, This
->glDescription
.level
,
71 This
->glDescription
.glFormat
, This
->glDescription
.glType
, This
->resource
.allocatedMemory
);
75 glGetTexImage(This
->glDescription
.target
, This
->glDescription
.level
, This
->glDescription
.glFormat
,
76 This
->glDescription
.glType
, This
->resource
.allocatedMemory
);
77 checkGLcall("glGetTexImage()");
81 if (wined3d_settings
.nonpower2_mode
== NP2_REPACK
) {
83 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
84 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
85 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
89 * instead of boxing the texture :
90 * |<-texture width ->| -->pow2width| /\
91 * |111111111111111111| | |
92 * |222 Texture 222222| boxed empty | texture height
93 * |3333 Data 33333333| | |
94 * |444444444444444444| | \/
95 * ----------------------------------- |
96 * | boxed empty | boxed empty | pow2height
98 * -----------------------------------
101 * we're repacking the data to the expected texture width
103 * |<-texture width ->| -->pow2width| /\
104 * |111111111111111111222222222222222| |
105 * |222333333333333333333444444444444| texture height
109 * | empty | pow2height
111 * -----------------------------------
115 * |<-texture width ->| /\
116 * |111111111111111111|
117 * |222222222222222222|texture height
118 * |333333333333333333|
119 * |444444444444444444| \/
120 * --------------------
122 * this also means that any references to allocatedMemory should work with the data as if were a
123 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
125 * internally the texture is still stored in a boxed format so any references to textureName will
126 * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
129 if (This
->Flags
& SFLAG_NONPOW2
) {
130 LPBYTE src_data
, dst_data
;
131 int src_pitch
= This
->bytesPerPixel
* This
->pow2Width
;
132 int dst_pitch
= This
->bytesPerPixel
* This
->currentDesc
.Width
;
135 src_data
= dst_data
= This
->resource
.allocatedMemory
;
136 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This
, src_pitch
, dst_pitch
);
137 for (y
= 1 ; y
< This
->currentDesc
.Height
; y
++) {
138 /* skip the first row */
139 src_data
+= src_pitch
;
140 dst_data
+= dst_pitch
;
141 memcpy(dst_data
, src_data
, dst_pitch
);
148 static void surface_upload_data(IWineD3DSurfaceImpl
*This
, GLsizei width
, GLsizei height
, GLenum format
, GLenum type
, const GLvoid
*data
) {
149 if (This
->resource
.format
== WINED3DFMT_DXT1
||
150 This
->resource
.format
== WINED3DFMT_DXT2
|| This
->resource
.format
== WINED3DFMT_DXT3
||
151 This
->resource
.format
== WINED3DFMT_DXT4
|| This
->resource
.format
== WINED3DFMT_DXT5
) {
152 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
153 FIXME("Using DXT1/3/5 without advertized support\n");
155 TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This
, width
, height
, data
);
157 GL_EXTCALL(glCompressedTexSubImage2DARB(This
->glDescription
.target
, This
->glDescription
.level
, 0, 0, width
, height
,
158 This
->glDescription
.glFormatInternal
, This
->resource
.size
, data
));
159 checkGLcall("glCompressedTexSubImage2D");
163 TRACE("(%p) : Calling glTexSubImage2D w %d, h %d, data, %p\n", This
, width
, height
, data
);
165 glTexSubImage2D(This
->glDescription
.target
, This
->glDescription
.level
, 0, 0, width
, height
, format
, type
, data
);
166 checkGLcall("glTexSubImage2D");
171 static void surface_allocate_surface(IWineD3DSurfaceImpl
*This
, GLenum internal
, GLsizei width
, GLsizei height
, GLenum format
, GLenum type
) {
172 TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n", This
,
173 This
->glDescription
.target
, This
->glDescription
.level
, debug_d3dformat(This
->resource
.format
), internal
, width
, height
, format
, type
);
177 glTexImage2D(This
->glDescription
.target
, This
->glDescription
.level
, internal
, width
, height
, 0, format
, type
, NULL
);
178 checkGLcall("glTexImage2D");
183 /* *******************************************
184 IWineD3DSurface IUnknown parts follow
185 ******************************************* */
186 HRESULT WINAPI
IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface
*iface
, REFIID riid
, LPVOID
*ppobj
)
188 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
189 /* Warn ,but be nice about things */
190 TRACE("(%p)->(%s,%p)\n", This
,debugstr_guid(riid
),ppobj
);
192 if (IsEqualGUID(riid
, &IID_IUnknown
)
193 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
194 || IsEqualGUID(riid
, &IID_IWineD3DResource
)
195 || IsEqualGUID(riid
, &IID_IWineD3DSurface
)) {
196 IUnknown_AddRef((IUnknown
*)iface
);
201 return E_NOINTERFACE
;
204 ULONG WINAPI
IWineD3DSurfaceImpl_AddRef(IWineD3DSurface
*iface
) {
205 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
206 ULONG ref
= InterlockedIncrement(&This
->resource
.ref
);
207 TRACE("(%p) : AddRef increasing from %d\n", This
,ref
- 1);
211 ULONG WINAPI
IWineD3DSurfaceImpl_Release(IWineD3DSurface
*iface
) {
212 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
213 ULONG ref
= InterlockedDecrement(&This
->resource
.ref
);
214 TRACE("(%p) : Releasing from %d\n", This
, ref
+ 1);
216 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*) This
->resource
.wineD3DDevice
;
217 TRACE("(%p) : cleaning up\n", This
);
218 if (This
->glDescription
.textureName
!= 0) { /* release the openGL texture.. */
220 TRACE("Deleting texture %d\n", This
->glDescription
.textureName
);
221 glDeleteTextures(1, &This
->glDescription
.textureName
);
225 if(This
->Flags
& SFLAG_DIBSECTION
) {
227 SelectObject(This
->hDC
, This
->dib
.holdbitmap
);
229 /* Release the DIB section */
230 DeleteObject(This
->dib
.DIBsection
);
231 This
->dib
.bitmap_data
= NULL
;
232 This
->resource
.allocatedMemory
= NULL
;
234 if(This
->Flags
& SFLAG_USERPTR
) IWineD3DSurface_SetMem(iface
, NULL
);
236 IWineD3DResourceImpl_CleanUp((IWineD3DResource
*)iface
);
237 if(iface
== device
->ddraw_primary
)
238 device
->ddraw_primary
= NULL
;
240 TRACE("(%p) Released\n", This
);
241 HeapFree(GetProcessHeap(), 0, This
);
247 /* ****************************************************
248 IWineD3DSurface IWineD3DResource parts follow
249 **************************************************** */
250 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface
*iface
, IWineD3DDevice
** ppDevice
) {
251 return IWineD3DResourceImpl_GetDevice((IWineD3DResource
*)iface
, ppDevice
);
254 HRESULT WINAPI
IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface
*iface
, REFGUID refguid
, CONST
void* pData
, DWORD SizeOfData
, DWORD Flags
) {
255 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource
*)iface
, refguid
, pData
, SizeOfData
, Flags
);
258 HRESULT WINAPI
IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface
*iface
, REFGUID refguid
, void* pData
, DWORD
* pSizeOfData
) {
259 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource
*)iface
, refguid
, pData
, pSizeOfData
);
262 HRESULT WINAPI
IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface
*iface
, REFGUID refguid
) {
263 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource
*)iface
, refguid
);
266 DWORD WINAPI
IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface
*iface
, DWORD PriorityNew
) {
267 return IWineD3DResourceImpl_SetPriority((IWineD3DResource
*)iface
, PriorityNew
);
270 DWORD WINAPI
IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface
*iface
) {
271 return IWineD3DResourceImpl_GetPriority((IWineD3DResource
*)iface
);
274 void WINAPI
IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface
*iface
) {
275 /* TODO: re-write the way textures and managed,
276 * use a 'opengl context manager' to manage RenderTarget surfaces
277 ** *********************************************************/
279 /* TODO: check for locks */
280 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
281 IWineD3DBaseTexture
*baseTexture
= NULL
;
282 TRACE("(%p)Checking to see if the container is a base texture\n", This
);
283 if (IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
) == WINED3D_OK
) {
284 TRACE("Passing to conatiner\n");
285 IWineD3DBaseTexture_PreLoad(baseTexture
);
286 IWineD3DBaseTexture_Release(baseTexture
);
288 TRACE("(%p) : About to load surface\n", This
);
290 #if 0 /* TODO: context manager support */
291 IWineD3DContextManager_PushState(This
->contextManager
, GL_TEXTURE_2D
, ENABLED
, NOW
/* make sure the state is applied now */);
293 glEnable(This
->glDescription
.target
);/* make sure texture support is enabled in this context */
294 if (!This
->glDescription
.level
) {
295 if (!This
->glDescription
.textureName
) {
296 glGenTextures(1, &This
->glDescription
.textureName
);
297 checkGLcall("glGenTextures");
298 TRACE("Surface %p given name %d\n", This
, This
->glDescription
.textureName
);
300 glBindTexture(This
->glDescription
.target
, This
->glDescription
.textureName
);
301 checkGLcall("glBindTexture");
302 IWineD3DSurface_LoadTexture(iface
);
303 /* This is where we should be reducing the amount of GLMemoryUsed */
304 } else if (This
->glDescription
.textureName
) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
305 /* assume this is a coding error not a real error for now */
306 FIXME("Mipmap surface has a glTexture bound to it!\n");
308 if (This
->resource
.pool
== WINED3DPOOL_DEFAULT
) {
309 /* Tell opengl to try and keep this texture in video ram (well mostly) */
312 glPrioritizeTextures(1, &This
->glDescription
.textureName
, &tmp
);
314 /* TODO: disable texture support, if it wastn't enabled when we entered. */
315 #if 0 /* TODO: context manager support */
316 IWineD3DContextManager_PopState(This
->contextManager
, GL_TEXTURE_2D
, DISABLED
,DELAYED
317 /* we don't care when the state is disabled(if atall) */);
324 WINED3DRESOURCETYPE WINAPI
IWineD3DSurfaceImpl_GetType(IWineD3DSurface
*iface
) {
325 TRACE("(%p) : calling resourceimpl_GetType\n", iface
);
326 return IWineD3DResourceImpl_GetType((IWineD3DResource
*)iface
);
329 HRESULT WINAPI
IWineD3DSurfaceImpl_GetParent(IWineD3DSurface
*iface
, IUnknown
**pParent
) {
330 TRACE("(%p) : calling resourceimpl_GetParent\n", iface
);
331 return IWineD3DResourceImpl_GetParent((IWineD3DResource
*)iface
, pParent
);
334 /* ******************************************************
335 IWineD3DSurface IWineD3DSurface parts follow
336 ****************************************************** */
338 HRESULT WINAPI
IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface
* iface
, REFIID riid
, void** ppContainer
) {
339 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
340 IWineD3DBase
*container
= 0;
342 TRACE("(This %p, riid %s, ppContainer %p)\n", This
, debugstr_guid(riid
), ppContainer
);
345 ERR("Called without a valid ppContainer.\n");
349 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
350 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
351 * GetContainer will return the Direct3D device used to create the surface.
353 if (This
->container
) {
354 container
= This
->container
;
356 container
= (IWineD3DBase
*)This
->resource
.wineD3DDevice
;
359 TRACE("Relaying to QueryInterface\n");
360 return IUnknown_QueryInterface(container
, riid
, ppContainer
);
363 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface
*iface
, WINED3DSURFACE_DESC
*pDesc
) {
364 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
366 TRACE("(%p) : copying into %p\n", This
, pDesc
);
367 if(pDesc
->Format
!= NULL
) *(pDesc
->Format
) = This
->resource
.format
;
368 if(pDesc
->Type
!= NULL
) *(pDesc
->Type
) = This
->resource
.resourceType
;
369 if(pDesc
->Usage
!= NULL
) *(pDesc
->Usage
) = This
->resource
.usage
;
370 if(pDesc
->Pool
!= NULL
) *(pDesc
->Pool
) = This
->resource
.pool
;
371 if(pDesc
->Size
!= NULL
) *(pDesc
->Size
) = This
->resource
.size
; /* dx8 only */
372 if(pDesc
->MultiSampleType
!= NULL
) *(pDesc
->MultiSampleType
) = This
->currentDesc
.MultiSampleType
;
373 if(pDesc
->MultiSampleQuality
!= NULL
) *(pDesc
->MultiSampleQuality
) = This
->currentDesc
.MultiSampleQuality
;
374 if(pDesc
->Width
!= NULL
) *(pDesc
->Width
) = This
->currentDesc
.Width
;
375 if(pDesc
->Height
!= NULL
) *(pDesc
->Height
) = This
->currentDesc
.Height
;
379 void WINAPI
IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface
*iface
, UINT textureName
, int target
) {
380 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
381 TRACE("(%p) : setting textureName %u, target %i\n", This
, textureName
, target
);
382 if (This
->glDescription
.textureName
== 0 && textureName
!= 0) {
383 This
->Flags
|= SFLAG_DIRTY
;
384 IWineD3DSurface_AddDirtyRect(iface
, NULL
);
386 This
->glDescription
.textureName
= textureName
;
387 This
->glDescription
.target
= target
;
390 void WINAPI
IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface
*iface
, glDescriptor
**glDescription
) {
391 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
392 TRACE("(%p) : returning %p\n", This
, &This
->glDescription
);
393 *glDescription
= &This
->glDescription
;
396 /* TODO: think about moving this down to resource? */
397 const void *WINAPI
IWineD3DSurfaceImpl_GetData(IWineD3DSurface
*iface
) {
398 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
399 /* 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 */
400 if (This
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
401 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface
);
403 return (CONST
void*)(This
->resource
.allocatedMemory
);
406 static void read_from_framebuffer(IWineD3DSurfaceImpl
*This
, CONST RECT
*rect
, void *dest
, UINT pitch
) {
412 switch(This
->resource
.format
)
416 /* GL can't return palettized data, so read ARGB pixels into a
417 * separate block of memory and convert them into palettized format
418 * in software. Slow, but if the app means to use palettized render
419 * targets and locks it...
421 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
422 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
423 * for the color channels when palettizing the colors.
426 type
= GL_UNSIGNED_BYTE
;
428 mem
= HeapAlloc(GetProcessHeap(), 0, (rect
->bottom
- rect
->top
) * pitch
);
430 ERR("Out of memory\n");
438 fmt
= This
->glDescription
.glFormat
;
439 type
= This
->glDescription
.glType
;
442 if (rect
->left
== 0 &&
443 rect
->right
== This
->currentDesc
.Width
) {
444 BYTE
*row
, *top
, *bottom
;
447 glReadPixels(0, rect
->top
,
448 This
->currentDesc
.Width
,
449 rect
->bottom
- rect
->top
,
454 /* glReadPixels returns the image upside down, and there is no way to prevent this.
455 Flip the lines in software */
456 row
= HeapAlloc(GetProcessHeap(), 0, pitch
);
458 ERR("Out of memory\n");
462 bottom
= ((BYTE
*) mem
) + pitch
* ( rect
->bottom
- rect
->top
- 1);
463 for(i
= 0; i
< (rect
->bottom
- rect
->top
) / 2; i
++) {
464 memcpy(row
, top
, pitch
);
465 memcpy(top
, bottom
, pitch
);
466 memcpy(bottom
, row
, pitch
);
470 HeapFree(GetProcessHeap(), 0, row
);
472 if(This
->lockedRect
.top
== 0 && This
->lockedRect
.bottom
== This
->currentDesc
.Height
) {
473 This
->Flags
&= ~SFLAG_GLDIRTY
;
476 for (j
= This
->lockedRect
.top
; j
< This
->lockedRect
.bottom
- This
->lockedRect
.top
; ++j
) {
477 glReadPixels(rect
->left
,
478 rect
->bottom
- j
- 1,
479 rect
->right
- rect
->left
,
483 (char *)mem
+ (pitch
* (j
-rect
->top
)));
487 vcheckGLcall("glReadPixels");
489 if(This
->resource
.format
== WINED3DFMT_P8
) {
491 DWORD width
= pitch
/ 3;
494 pal
= This
->palette
->palents
;
496 pal
= This
->resource
.wineD3DDevice
->palettes
[This
->resource
.wineD3DDevice
->currentPalette
];
499 for(y
= rect
->top
; y
< rect
->bottom
; y
++) {
500 for(x
= rect
->left
; x
< rect
->right
; x
++) {
501 /* start lines pixels */
502 BYTE
*blue
= (BYTE
*) ((BYTE
*) mem
) + y
* pitch
+ x
* (sizeof(BYTE
) * 3);
503 BYTE
*green
= blue
+ 1;
504 BYTE
*red
= green
+ 1;
506 for(c
= 0; c
< 256; c
++) {
507 if(*red
== pal
[c
].peRed
&&
508 *green
== pal
[c
].peGreen
&&
509 *blue
== pal
[c
].peBlue
)
511 *((BYTE
*) dest
+ y
* width
+ x
) = c
;
517 HeapFree(GetProcessHeap(), 0, mem
);
521 static HRESULT WINAPI
IWineD3DSurfaceImpl_LockRect(IWineD3DSurface
*iface
, WINED3DLOCKED_RECT
* pLockedRect
, CONST RECT
* pRect
, DWORD Flags
) {
522 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
523 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
524 IWineD3DSwapChainImpl
*swapchain
= NULL
;
525 static UINT messages
= 0; /* holds flags to disable fixme messages */
526 BOOL backbuf
= FALSE
;
528 /* fixme: should we really lock as such? */
529 if((This
->Flags
& (SFLAG_INTEXTURE
| SFLAG_INPBUFFER
)) ==
530 (SFLAG_INTEXTURE
| SFLAG_INPBUFFER
) ) {
531 FIXME("Warning: Surface is in texture memory or pbuffer\n");
532 This
->Flags
&= ~(SFLAG_INTEXTURE
| SFLAG_INPBUFFER
);
535 if (!(This
->Flags
& SFLAG_LOCKABLE
)) {
536 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
537 texture regions, and since the destination is an unlockable region we need
539 TRACE("Warning: trying to lock unlockable surf@%p\n", This
);
540 /*return WINED3DERR_INVALIDCALL; */
543 if (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
544 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
546 if (swapchain
!= NULL
|| iface
== myDevice
->render_targets
[0] || iface
== myDevice
->depthStencilBuffer
) {
547 if(swapchain
!= NULL
) {
549 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
550 if(iface
== swapchain
->backBuffer
[i
]) {
557 TRACE("(%p, backBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
558 } else if (swapchain
!= NULL
&& iface
== swapchain
->frontBuffer
) {
559 TRACE("(%p, frontBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
560 } else if (iface
== myDevice
->render_targets
[0]) {
561 TRACE("(%p, renderTarget) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
562 } else if (iface
== myDevice
->depthStencilBuffer
) {
563 TRACE("(%p, stencilBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
566 if (NULL
!= swapchain
) {
567 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
572 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
575 pLockedRect
->Pitch
= IWineD3DSurface_GetPitch(iface
);
578 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
579 This
->lockedRect
.left
= 0;
580 This
->lockedRect
.top
= 0;
581 This
->lockedRect
.right
= This
->currentDesc
.Width
;
582 This
->lockedRect
.bottom
= This
->currentDesc
.Height
;
583 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n", &This
->lockedRect
, This
->lockedRect
.left
, This
->lockedRect
.top
, This
->lockedRect
.right
, This
->lockedRect
.bottom
);
585 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
587 if ((pRect
->top
< 0) ||
589 (pRect
->left
>= pRect
->right
) ||
590 (pRect
->top
>= pRect
->bottom
) ||
591 (pRect
->right
> This
->currentDesc
.Width
) ||
592 (pRect
->bottom
> This
->currentDesc
.Height
))
594 WARN(" Invalid values in pRect !!!\n");
595 return D3DERR_INVALIDCALL
;
598 if (This
->resource
.format
== WINED3DFMT_DXT1
) { /* DXT1 is half byte per pixel */
599 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + ((pRect
->left
* This
->bytesPerPixel
/ 2));
601 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + (pRect
->left
* This
->bytesPerPixel
);
603 This
->lockedRect
.left
= pRect
->left
;
604 This
->lockedRect
.top
= pRect
->top
;
605 This
->lockedRect
.right
= pRect
->right
;
606 This
->lockedRect
.bottom
= pRect
->bottom
;
609 if (This
->Flags
& SFLAG_NONPOW2
) {
610 TRACE("Locking non-power 2 texture\n");
613 if (0 == This
->resource
.usage
|| This
->resource
.usage
& WINED3DUSAGE_DYNAMIC
) {
614 /* classic surface TODO: non 2d surfaces?
615 These resources may be POOL_SYSTEMMEM, so they must not access the device */
616 TRACE("locking an ordinarary surface\n");
617 /* Check to see if memory has already been allocated from the surface*/
618 if ((NULL
== This
->resource
.allocatedMemory
) ||
619 (This
->Flags
& SFLAG_GLDIRTY
) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
620 /* Non-system memory surfaces */
622 This
->Flags
&= ~SFLAG_GLDIRTY
;
624 /*Surface has no memory currently allocated to it!*/
625 TRACE("(%p) Locking rect\n" , This
);
626 if(!This
->resource
.allocatedMemory
) {
627 This
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap() ,0 , This
->pow2Size
);
629 if (0 != This
->glDescription
.textureName
) {
630 /* Now I have to copy thing bits back */
631 This
->Flags
|= SFLAG_ACTIVELOCK
; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
632 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
634 /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
635 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
637 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
638 checkGLcall("glActiveTextureARB");
641 IWineD3DDeviceImpl_MarkStateDirty(This
->resource
.wineD3DDevice
, STATE_SAMPLER(0));
642 IWineD3DSurface_PreLoad(iface
);
644 surface_download_data(This
);
646 } else { /* Nothing to do */
647 TRACE("Memory %p already allocted for texture\n", This
->resource
.allocatedMemory
);
651 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
653 if (This
->resource
.format
== WINED3DFMT_DXT1
) { /* DXT1 is half byte per pixel */
654 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + ((pRect
->left
* This
->bytesPerPixel
/ 2));
656 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + (pRect
->left
* This
->bytesPerPixel
);
660 } else if (WINED3DUSAGE_RENDERTARGET
& This
->resource
.usage
){ /* render surfaces */
661 if((!(Flags
&WINED3DLOCK_DISCARD
) && (This
->Flags
& SFLAG_GLDIRTY
)) || !This
->resource
.allocatedMemory
) {
664 BOOL notInContext
= FALSE
;
665 IWineD3DSwapChainImpl
*targetSwapChain
= NULL
;
671 * for render->surface copy begin to begin of allocatedMemory
672 * unlock can be more easy
675 TRACE("locking a render target\n");
677 if (This
->resource
.allocatedMemory
== NULL
)
678 This
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap() ,0 ,This
->resource
.size
);
680 This
->Flags
|= SFLAG_ACTIVELOCK
; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
681 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
684 vcheckGLcall("glFlush");
685 glGetIntegerv(GL_READ_BUFFER
, &prev_read
);
686 vcheckGLcall("glIntegerv");
687 glGetIntegerv(GL_PACK_SWAP_BYTES
, &prev_store
);
688 vcheckGLcall("glIntegerv");
690 /* Here's what we have to do:
691 See if the swapchain has the same context as the renderTarget or the surface is the render target.
692 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
693 and use the front back buffer as required.
694 if not, we need to switch contexts and then switchback at the end.
696 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
697 IWineD3DSurface_GetContainer(myDevice
->render_targets
[0], &IID_IWineD3DSwapChain
, (void **)&targetSwapChain
);
699 /* 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! */
700 if ((swapchain
== targetSwapChain
&& targetSwapChain
!= NULL
) || iface
== myDevice
->render_targets
[0]) {
701 if (swapchain
&& iface
== swapchain
->frontBuffer
) {
702 TRACE("locking front\n");
703 glReadBuffer(GL_FRONT
);
705 else if (iface
== myDevice
->render_targets
[0] || backbuf
) {
706 TRACE("locking back buffer\n");
707 glReadBuffer(GL_BACK
);
708 } else if (iface
== myDevice
->depthStencilBuffer
) {
709 FIXME("Stencil Buffer lock unsupported for now\n");
711 FIXME("(%p) Shouldn't have got here!\n", This
);
712 glReadBuffer(GL_BACK
);
714 } else if (swapchain
!= NULL
) {
715 IWineD3DSwapChainImpl
*implSwapChain
;
716 IWineD3DDevice_GetSwapChain((IWineD3DDevice
*)myDevice
, 0, (IWineD3DSwapChain
**)&implSwapChain
);
717 if (swapchain
->glCtx
== implSwapChain
->render_ctx
&& swapchain
->drawable
== implSwapChain
->win
) {
718 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
720 glReadBuffer(GL_BACK
);
721 } else if (iface
== swapchain
->frontBuffer
) {
722 glReadBuffer(GL_FRONT
);
723 } else if (iface
== myDevice
->depthStencilBuffer
) {
724 FIXME("Stencil Buffer lock unsupported for now\n");
726 FIXME("Should have got here!\n");
727 glReadBuffer(GL_BACK
);
730 /* We need to switch contexts to be able to read the buffer!!! */
731 FIXME("The buffer requested isn't in the current openGL context\n");
733 /* TODO: check the contexts, to see if were shared with the current context */
735 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)implSwapChain
);
737 if (swapchain
!= NULL
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
738 if (targetSwapChain
!= NULL
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*)targetSwapChain
);
740 /** the depth stencil in openGL has a format of GL_FLOAT
741 * which should be good for WINED3DFMT_D16_LOCKABLE
743 * it is unclear what format the stencil buffer is in except.
744 * 'Each index is converted to fixed point...
745 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
746 * mappings in the table GL_PIXEL_MAP_S_TO_S.
747 * glReadPixels(This->lockedRect.left,
748 * This->lockedRect.bottom - j - 1,
749 * This->lockedRect.right - This->lockedRect.left,
751 * GL_DEPTH_COMPONENT,
753 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
754 *****************************************/
755 if (!notInContext
) { /* Only read the buffer if it's in the current context */
756 switch(wined3d_settings
.rendertargetlock_mode
) {
760 read_from_framebuffer(This
, &This
->lockedRect
, pLockedRect
->pBits
, pLockedRect
->Pitch
);
765 read_from_framebuffer(This
, &This
->lockedRect
, pLockedRect
->pBits
, pLockedRect
->Pitch
);
766 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
771 static BOOL warned
= FALSE
;
773 ERR("Application tries to lock the render target, but render target locking is disabled\n");
780 TRACE("Resetting buffer\n");
782 glReadBuffer(prev_read
);
783 vcheckGLcall("glReadBuffer");
787 } else if (WINED3DUSAGE_DEPTHSTENCIL
& This
->resource
.usage
) { /* stencil surfaces */
790 FIXME("TODO stencil depth surface locking surf%p usage(%s)\n", This
, debug_d3dusage(This
->resource
.usage
));
793 glReadPixels(This->lockedRect.left,
794 This->lockedRect.bottom - j - 1,
795 This->lockedRect.right - This->lockedRect.left,
797 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
804 FIXME("unsupported locking to surface surf@%p usage(%s)\n", This
, debug_d3dusage(This
->resource
.usage
));
807 if (Flags
& (WINED3DLOCK_NO_DIRTY_UPDATE
| WINED3DLOCK_READONLY
)) {
810 IWineD3DBaseTexture
*pBaseTexture
;
813 * as seen in msdn docs
815 IWineD3DSurface_AddDirtyRect(iface
, &This
->lockedRect
);
817 /** Dirtify Container if needed */
818 if (WINED3D_OK
== IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&pBaseTexture
) && pBaseTexture
!= NULL
) {
819 TRACE("Making container dirty\n");
820 IWineD3DBaseTexture_SetDirty(pBaseTexture
, TRUE
);
821 IWineD3DBaseTexture_Release(pBaseTexture
);
823 TRACE("Surface is standalone, no need to dirty the container\n");
827 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect
->pBits
, pLockedRect
->Pitch
, This
->Flags
& SFLAG_DIRTY
? 0 : 1);
829 This
->Flags
|= SFLAG_LOCKED
;
833 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl
*This
) {
835 GLint prev_rasterpos
[4];
837 BOOL storechanged
= FALSE
;
841 glDisable(GL_TEXTURE_2D
);
842 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
843 glDisable(GL_TEXTURE_1D
);
844 vcheckGLcall("glDisable(GL_TEXTURE_1D)");
847 vcheckGLcall("glFlush");
848 glGetIntegerv(GL_PACK_SWAP_BYTES
, &prev_store
);
849 vcheckGLcall("glIntegerv");
850 glGetIntegerv(GL_CURRENT_RASTER_POSITION
, &prev_rasterpos
[0]);
851 vcheckGLcall("glIntegerv");
852 glPixelZoom(1.0, -1.0);
853 vcheckGLcall("glPixelZoom");
855 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
856 glGetIntegerv(GL_UNPACK_ROW_LENGTH
, &skipBytes
);
857 glPixelStorei(GL_UNPACK_ROW_LENGTH
, This
->currentDesc
.Width
);
859 glRasterPos3i(This
->lockedRect
.left
, This
->lockedRect
.top
, 1);
860 vcheckGLcall("glRasterPos2f");
862 /* Some drivers(radeon dri, others?) don't like exceptions during
863 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
864 * after ReleaseDC. Reading it will cause an exception, which x11drv will
865 * catch to put the dib section in InSync mode, which leads to a crash
866 * and a blocked x server on my radeon card.
868 * The following lines read the dib section so it is put in inSync mode
869 * before glDrawPixels is called and the crash is prevented. There won't
870 * be any interfering gdi accesses, because UnlockRect is called from
871 * ReleaseDC, and the app won't use the dc any more afterwards.
873 if(This
->Flags
& SFLAG_DIBSECTION
) {
875 read
= This
->resource
.allocatedMemory
[0];
878 switch (This
->resource
.format
) {
879 /* No special care needed */
880 case WINED3DFMT_A4R4G4B4
:
881 case WINED3DFMT_R5G6B5
:
882 case WINED3DFMT_A1R5G5B5
:
883 case WINED3DFMT_R8G8B8
:
884 type
= This
->glDescription
.glType
;
885 fmt
= This
->glDescription
.glFormat
;
886 mem
= This
->resource
.allocatedMemory
;
889 case WINED3DFMT_X4R4G4B4
:
892 unsigned short *data
;
893 data
= (unsigned short *)This
->resource
.allocatedMemory
;
894 size
= (This
->lockedRect
.bottom
- This
->lockedRect
.top
) * (This
->lockedRect
.right
- This
->lockedRect
.left
);
900 type
= This
->glDescription
.glType
;
901 fmt
= This
->glDescription
.glFormat
;
902 mem
= This
->resource
.allocatedMemory
;
906 case WINED3DFMT_X1R5G5B5
:
909 unsigned short *data
;
910 data
= (unsigned short *)This
->resource
.allocatedMemory
;
911 size
= (This
->lockedRect
.bottom
- This
->lockedRect
.top
) * (This
->lockedRect
.right
- This
->lockedRect
.left
);
917 type
= This
->glDescription
.glType
;
918 fmt
= This
->glDescription
.glFormat
;
919 mem
= This
->resource
.allocatedMemory
;
923 case WINED3DFMT_X8R8G8B8
:
925 /* make sure the X byte is set to alpha on, since it
926 could be any random value. This fixes the intro movie in Pirates! */
929 data
= (unsigned int *)This
->resource
.allocatedMemory
;
930 size
= (This
->lockedRect
.bottom
- This
->lockedRect
.top
) * (This
->lockedRect
.right
- This
->lockedRect
.left
);
939 case WINED3DFMT_A8R8G8B8
:
941 glPixelStorei(GL_PACK_SWAP_BYTES
, TRUE
);
942 vcheckGLcall("glPixelStorei");
944 type
= This
->glDescription
.glType
;
945 fmt
= This
->glDescription
.glFormat
;
946 mem
= This
->resource
.allocatedMemory
;
950 case WINED3DFMT_A2R10G10B10
:
952 glPixelStorei(GL_PACK_SWAP_BYTES
, TRUE
);
953 vcheckGLcall("glPixelStorei");
955 type
= This
->glDescription
.glType
;
956 fmt
= This
->glDescription
.glFormat
;
957 mem
= This
->resource
.allocatedMemory
;
963 UINT pitch
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) This
); /* target is argb, 4 byte */
964 int height
= This
->glRect
.bottom
- This
->glRect
.top
;
965 type
= GL_UNSIGNED_BYTE
;
968 mem
= HeapAlloc(GetProcessHeap(), 0, This
->resource
.size
* sizeof(DWORD
));
970 ERR("Out of memory\n");
973 d3dfmt_convert_surface(This
->resource
.allocatedMemory
,
985 FIXME("Unsupported Format %u in locking func\n", This
->resource
.format
);
988 type
= This
->glDescription
.glType
;
989 fmt
= This
->glDescription
.glFormat
;
990 mem
= This
->resource
.allocatedMemory
;
993 glDrawPixels(This
->lockedRect
.right
- This
->lockedRect
.left
,
994 (This
->lockedRect
.bottom
- This
->lockedRect
.top
)-1,
997 checkGLcall("glDrawPixels");
998 glPixelZoom(1.0,1.0);
999 vcheckGLcall("glPixelZoom");
1001 glRasterPos3iv(&prev_rasterpos
[0]);
1002 vcheckGLcall("glRasterPos3iv");
1004 /* Reset to previous pack row length */
1005 glPixelStorei(GL_UNPACK_ROW_LENGTH
, skipBytes
);
1006 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1008 glPixelStorei(GL_PACK_SWAP_BYTES
, prev_store
);
1009 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1012 if(mem
!= This
->resource
.allocatedMemory
) HeapFree(GetProcessHeap(), 0, mem
);
1016 static void flush_to_framebuffer_texture(IWineD3DSurface
*iface
) {
1017 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1018 float glTexCoord
[4];
1020 glTexCoord
[0] = 0.0; /* left */
1021 glTexCoord
[1] = (float) This
->currentDesc
.Width
/ (float) This
->pow2Width
; /* right */
1022 glTexCoord
[2] = 0.0; /* top */
1023 glTexCoord
[3] = (float) This
->currentDesc
.Height
/ (float) This
->pow2Height
; /* bottom */
1025 IWineD3DSurface_PreLoad(iface
);
1029 /* Disable some fancy graphics effects */
1030 glDisable(GL_LIGHTING
);
1031 checkGLcall("glDisable GL_LIGHTING");
1032 glDisable(GL_DEPTH_TEST
);
1033 checkGLcall("glDisable GL_DEPTH_TEST");
1035 checkGLcall("glDisable GL_FOG");
1036 glDisable(GL_CULL_FACE
);
1037 checkGLcall("glDisable GL_CULL_FACE");
1038 glDisable(GL_BLEND
);
1039 checkGLcall("glDisable GL_BLEND");
1040 glDisable(GL_STENCIL_TEST
);
1041 checkGLcall("glDisable GL_STENCIL_TEST");
1043 glEnable(GL_TEXTURE_2D
);
1044 glBindTexture(GL_TEXTURE_2D
, This
->glDescription
.textureName
);
1045 checkGLcall("glEnable glBindTexture");
1047 /* No filtering for blts */
1048 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
1049 checkGLcall("glTexParameteri");
1050 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
1051 checkGLcall("glTexParameteri");
1053 /* Start drawing a quad */
1056 glColor3d(1.0f
, 1.0f
, 1.0f
);
1057 glTexCoord2f(glTexCoord
[0], glTexCoord
[2]);
1058 glVertex3f(0, 0, 0.0);
1060 glTexCoord2f(glTexCoord
[0], glTexCoord
[3]);
1061 glVertex3f(0, This
->currentDesc
.Height
, 0.0);
1063 glTexCoord2f(glTexCoord
[1], glTexCoord
[3]);
1064 glVertex3d(This
->currentDesc
.Width
, This
->currentDesc
.Height
, 0.0);
1066 glTexCoord2f(glTexCoord
[1], glTexCoord
[2]);
1067 glVertex3f(This
->currentDesc
.Width
, 0, 0.0);
1070 checkGLcall("glEnd");
1072 /* Unbind the texture */
1073 glBindTexture(GL_TEXTURE_2D
, 0);
1074 checkGLcall("glEnable glBindTexture");
1079 static HRESULT WINAPI
IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface
*iface
) {
1080 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1081 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
1082 const char *buffername
= "";
1083 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1084 BOOL backbuf
= FALSE
;
1086 if (!(This
->Flags
& SFLAG_LOCKED
)) {
1087 WARN("trying to Unlock an unlocked surf@%p\n", This
);
1088 return WINED3DERR_INVALIDCALL
;
1091 if (WINED3DUSAGE_RENDERTARGET
& This
->resource
.usage
) {
1092 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
1096 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
1097 if(iface
== swapchain
->backBuffer
[i
]) {
1105 buffername
= "backBuffer";
1106 } else if ((swapchain
!= NULL
) && iface
== swapchain
->frontBuffer
) {
1107 buffername
= "frontBuffer";
1108 } else if (iface
== myDevice
->depthStencilBuffer
) {
1109 buffername
= "depthStencilBuffer";
1110 } else if (iface
== myDevice
->render_targets
[0]) {
1111 buffername
= "renderTarget";
1115 if (swapchain
!= NULL
) {
1116 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
1119 TRACE("(%p %s) : dirtyfied(%d)\n", This
, buffername
, This
->Flags
& SFLAG_DIRTY
? 1 : 0);
1121 if (!(This
->Flags
& SFLAG_DIRTY
)) {
1122 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This
);
1126 if (0 == This
->resource
.usage
) { /* classic surface */
1127 IWineD3DBaseTextureImpl
*impl
;
1128 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1129 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1130 * states need resetting
1132 if(IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&impl
) == WINED3D_OK
) {
1133 if(impl
->baseTexture
.bindCount
) {
1134 IWineD3DDeviceImpl_MarkStateDirty(myDevice
, STATE_SAMPLER(impl
->baseTexture
.sampler
));
1136 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*) impl
);
1138 } else if (WINED3DUSAGE_RENDERTARGET
& This
->resource
.usage
) { /* render surfaces */
1140 /****************************
1141 * TODO: Render targets are 'special' and
1142 * ?some? locking needs to be passed onto the context manager
1143 * so that it becomes possible to use auxiliary buffers, pbuffers
1144 * render-to-texture, shared, cached contexts etc...
1145 * ****************************/
1146 IWineD3DSwapChainImpl
*implSwapChain
;
1147 IWineD3DDevice_GetSwapChain((IWineD3DDevice
*)myDevice
, 0, (IWineD3DSwapChain
**)&implSwapChain
);
1149 if ((backbuf
|| iface
== implSwapChain
->frontBuffer
|| iface
== myDevice
->render_targets
[0]) && wined3d_settings
.rendertargetlock_mode
!= RTL_DISABLE
) {
1154 /* glDrawPixels transforms the raster position as though it was a vertex -
1155 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1156 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1157 myDevice
->last_was_rhw
= TRUE
;
1158 /* Apply the projection and world matrices, it sets up orthogonal projection due to last_was_rhw */
1159 StateTable
[STATE_TRANSFORM(WINED3DTS_PROJECTION
)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION
), myDevice
->stateBlock
);
1160 StateTable
[STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))].apply(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), myDevice
->stateBlock
);
1161 /* Will reapply the projection matrix too */
1162 IWineD3DDeviceImpl_MarkStateDirty(myDevice
, STATE_VDECL
);
1164 if (iface
== implSwapChain
->frontBuffer
) {
1165 glDrawBuffer(GL_FRONT
);
1166 checkGLcall("glDrawBuffer GL_FRONT");
1167 } else if (backbuf
|| iface
== myDevice
->render_targets
[0]) {
1168 glDrawBuffer(GL_BACK
);
1169 checkGLcall("glDrawBuffer GL_BACK");
1172 /* Disable higher textures before calling glDrawPixels */
1173 for(tex
= 1; tex
< GL_LIMITS(samplers
); tex
++) {
1174 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
1175 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ tex
));
1176 checkGLcall("glActiveTextureARB");
1178 IWineD3DDeviceImpl_MarkStateDirty(This
->resource
.wineD3DDevice
, STATE_SAMPLER(tex
));
1179 glDisable(GL_TEXTURE_2D
);
1180 checkGLcall("glDisable GL_TEXTURE_2D");
1181 glDisable(GL_TEXTURE_1D
);
1182 checkGLcall("glDisable GL_TEXTURE_1D");
1184 /* Activate texture 0, but don't disable it necessarily */
1185 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
1186 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
1187 checkGLcall("glActiveTextureARB");
1189 IWineD3DDeviceImpl_MarkStateDirty(This
->resource
.wineD3DDevice
, STATE_SAMPLER(0));
1191 /* And back buffers are not blended. Disable the depth test,
1192 that helps performance */
1193 glDisable(GL_BLEND
);
1194 glDisable(GL_DEPTH_TEST
);
1197 switch(wined3d_settings
.rendertargetlock_mode
) {
1201 flush_to_framebuffer_drawpixels(This
);
1206 flush_to_framebuffer_texture(iface
);
1211 static BOOL warned
= FALSE
;
1213 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1220 if(implSwapChain
->backBuffer
&& implSwapChain
->backBuffer
[0]) {
1221 glDrawBuffer(GL_BACK
);
1222 vcheckGLcall("glDrawBuffer");
1224 if(myDevice
->stateBlock
->renderState
[WINED3DRS_ZENABLE
] == WINED3DZB_TRUE
||
1225 myDevice
->stateBlock
->renderState
[WINED3DRS_ZENABLE
] == WINED3DZB_USEW
) glEnable(GL_DEPTH_TEST
);
1226 if (myDevice
->stateBlock
->renderState
[WINED3DRS_ALPHABLENDENABLE
]) glEnable(GL_BLEND
);
1227 if (myDevice
->stateBlock
->renderState
[WINED3DRS_FOGENABLE
]) glEnable(GL_FOG
);
1231 /** restore clean dirty state */
1232 IWineD3DSurface_CleanDirtyRect(iface
);
1234 } else if(wined3d_settings
.rendertargetlock_mode
!= RTL_DISABLE
) {
1235 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This
, debug_d3dusage(This
->resource
.usage
));
1237 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)implSwapChain
);
1239 } else if (WINED3DUSAGE_DEPTHSTENCIL
& This
->resource
.usage
) { /* stencil surfaces */
1241 if (iface
== myDevice
->depthStencilBuffer
) {
1242 FIXME("TODO stencil depth surface unlocking surf@%p usage(%s)\n", This
, debug_d3dusage(This
->resource
.usage
));
1244 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%s)\n", This
, debug_d3dusage(This
->resource
.usage
));
1248 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This
, debug_d3dusage(This
->resource
.usage
));
1252 This
->Flags
&= ~SFLAG_LOCKED
;
1253 memset(&This
->lockedRect
, 0, sizeof(RECT
));
1257 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDC(IWineD3DSurface
*iface
, HDC
*pHDC
) {
1258 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1259 WINED3DLOCKED_RECT lock
;
1266 const PixelFormatDesc
*formatEntry
= getFormatDescEntry(This
->resource
.format
);
1268 TRACE("(%p)->(%p)\n",This
,pHDC
);
1270 if(This
->Flags
& SFLAG_USERPTR
) {
1271 ERR("Not supported on surfaces with an application-provided surfaces\n");
1275 /* Give more detailed info for ddraw */
1276 if (This
->Flags
& SFLAG_DCINUSE
)
1277 return DDERR_DCALREADYCREATED
;
1279 /* Can't GetDC if the surface is locked */
1280 if (This
->Flags
& SFLAG_LOCKED
)
1281 return WINED3DERR_INVALIDCALL
;
1283 memset(&lock
, 0, sizeof(lock
)); /* To be sure */
1285 /* Create a DIB section if there isn't a hdc yet */
1288 SYSTEM_INFO sysInfo
;
1290 if(This
->Flags
& SFLAG_ACTIVELOCK
) {
1291 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1294 switch (This
->bytesPerPixel
) {
1297 /* Allocate extra space to store the RGB bit masks. */
1298 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
1302 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
1306 /* Allocate extra space for a palette. */
1307 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1308 sizeof(BITMAPINFOHEADER
)
1310 * (1 << (This
->bytesPerPixel
* 8)));
1315 return E_OUTOFMEMORY
;
1317 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1318 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1319 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1320 * add an extra line to the dib section
1322 GetSystemInfo(&sysInfo
);
1323 if( ((This
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4) {
1325 TRACE("Adding an extra line to the dib section\n");
1328 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1329 if( (NP2_REPACK
== wined3d_settings
.nonpower2_mode
|| This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
1330 b_info
->bmiHeader
.biWidth
= This
->currentDesc
.Width
;
1331 b_info
->bmiHeader
.biHeight
= -This
->currentDesc
.Height
-extraline
;
1332 b_info
->bmiHeader
.biSizeImage
= ( This
->currentDesc
.Height
+ extraline
) * IWineD3DSurface_GetPitch(iface
);
1333 /* Use the full pow2 image size(assigned below) because LockRect
1334 * will need it for a full glGetTexImage call
1337 b_info
->bmiHeader
.biWidth
= This
->pow2Width
;
1338 b_info
->bmiHeader
.biHeight
= -This
->pow2Height
-extraline
;
1339 b_info
->bmiHeader
.biSizeImage
= This
->resource
.size
+ extraline
* IWineD3DSurface_GetPitch(iface
);
1341 b_info
->bmiHeader
.biPlanes
= 1;
1342 b_info
->bmiHeader
.biBitCount
= This
->bytesPerPixel
* 8;
1344 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
1345 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
1346 b_info
->bmiHeader
.biClrUsed
= 0;
1347 b_info
->bmiHeader
.biClrImportant
= 0;
1349 /* Get the bit masks */
1350 masks
= (DWORD
*) &(b_info
->bmiColors
);
1351 switch (This
->resource
.format
) {
1352 case WINED3DFMT_R8G8B8
:
1353 usage
= DIB_RGB_COLORS
;
1354 b_info
->bmiHeader
.biCompression
= BI_RGB
;
1357 case WINED3DFMT_X1R5G5B5
:
1358 case WINED3DFMT_A1R5G5B5
:
1359 case WINED3DFMT_A4R4G4B4
:
1360 case WINED3DFMT_X4R4G4B4
:
1361 case WINED3DFMT_R3G3B2
:
1362 case WINED3DFMT_A8R3G3B2
:
1363 case WINED3DFMT_A2B10G10R10
:
1364 case WINED3DFMT_A8B8G8R8
:
1365 case WINED3DFMT_X8B8G8R8
:
1366 case WINED3DFMT_A2R10G10B10
:
1367 case WINED3DFMT_R5G6B5
:
1368 case WINED3DFMT_A16B16G16R16
:
1370 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1371 masks
[0] = formatEntry
->redMask
;
1372 masks
[1] = formatEntry
->greenMask
;
1373 masks
[2] = formatEntry
->blueMask
;
1377 /* Don't know palette */
1378 b_info
->bmiHeader
.biCompression
= BI_RGB
;
1385 HeapFree(GetProcessHeap(), 0, b_info
);
1386 return HRESULT_FROM_WIN32(GetLastError());
1389 TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info
->bmiHeader
.biWidth
, b_info
->bmiHeader
.biHeight
, b_info
->bmiHeader
.biBitCount
, b_info
->bmiHeader
.biSizeImage
);
1390 This
->dib
.DIBsection
= CreateDIBSection(ddc
, b_info
, usage
, &This
->dib
.bitmap_data
, 0 /* Handle */, 0 /* Offset */);
1393 if (!This
->dib
.DIBsection
) {
1394 ERR("CreateDIBSection failed!\n");
1395 HeapFree(GetProcessHeap(), 0, b_info
);
1396 return HRESULT_FROM_WIN32(GetLastError());
1399 TRACE("DIBSection at : %p\n", This
->dib
.bitmap_data
);
1401 /* copy the existing surface to the dib section */
1402 if(This
->resource
.allocatedMemory
) {
1403 memcpy(This
->dib
.bitmap_data
, This
->resource
.allocatedMemory
, b_info
->bmiHeader
.biSizeImage
);
1404 /* We won't need that any more */
1405 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
1407 /* This is to make LockRect read the gl Texture although memory is allocated */
1408 This
->Flags
|= SFLAG_GLDIRTY
;
1411 HeapFree(GetProcessHeap(), 0, b_info
);
1413 /* Use the dib section from now on */
1414 This
->resource
.allocatedMemory
= This
->dib
.bitmap_data
;
1416 /* Now allocate a HDC */
1417 This
->hDC
= CreateCompatibleDC(0);
1418 This
->dib
.holdbitmap
= SelectObject(This
->hDC
, This
->dib
.DIBsection
);
1419 TRACE("using wined3d palette %p\n", This
->palette
);
1420 SelectPalette(This
->hDC
,
1421 This
->palette
? This
->palette
->hpal
: 0,
1424 This
->Flags
|= SFLAG_DIBSECTION
;
1427 /* Lock the surface */
1428 hr
= IWineD3DSurface_LockRect(iface
,
1433 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr
);
1434 /* keep the dib section */
1438 if(This
->resource
.format
== WINED3DFMT_P8
||
1439 This
->resource
.format
== WINED3DFMT_A8P8
) {
1442 PALETTEENTRY ent
[256];
1444 GetPaletteEntries(This
->palette
->hpal
, 0, 256, ent
);
1445 for (n
=0; n
<256; n
++) {
1446 col
[n
].rgbRed
= ent
[n
].peRed
;
1447 col
[n
].rgbGreen
= ent
[n
].peGreen
;
1448 col
[n
].rgbBlue
= ent
[n
].peBlue
;
1449 col
[n
].rgbReserved
= 0;
1452 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
1454 for (n
=0; n
<256; n
++) {
1455 col
[n
].rgbRed
= device
->palettes
[device
->currentPalette
][n
].peRed
;
1456 col
[n
].rgbGreen
= device
->palettes
[device
->currentPalette
][n
].peGreen
;
1457 col
[n
].rgbBlue
= device
->palettes
[device
->currentPalette
][n
].peBlue
;
1458 col
[n
].rgbReserved
= 0;
1462 SetDIBColorTable(This
->hDC
, 0, 256, col
);
1466 TRACE("returning %p\n",*pHDC
);
1467 This
->Flags
|= SFLAG_DCINUSE
;
1472 HRESULT WINAPI
IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface
*iface
, HDC hDC
) {
1473 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1475 TRACE("(%p)->(%p)\n",This
,hDC
);
1477 if (!(This
->Flags
& SFLAG_DCINUSE
))
1478 return D3DERR_INVALIDCALL
;
1480 /* we locked first, so unlock now */
1481 IWineD3DSurface_UnlockRect(iface
);
1483 This
->Flags
&= ~SFLAG_DCINUSE
;
1488 /* ******************************************************
1489 IWineD3DSurface Internal (No mapping to directx api) parts follow
1490 ****************************************************** */
1492 HRESULT
d3dfmt_get_conv(IWineD3DSurfaceImpl
*This
, BOOL need_alpha_ck
, BOOL use_texturing
, GLenum
*format
, GLenum
*internal
, GLenum
*type
, CONVERT_TYPES
*convert
, int *target_bpp
) {
1493 BOOL colorkey_active
= need_alpha_ck
&& (This
->CKeyFlags
& DDSD_CKSRCBLT
);
1494 const PixelFormatDesc
*formatEntry
= getFormatDescEntry(This
->resource
.format
);
1496 /* Default values: From the surface */
1497 *format
= formatEntry
->glFormat
;
1498 *internal
= formatEntry
->glInternal
;
1499 *type
= formatEntry
->glType
;
1500 *convert
= NO_CONVERSION
;
1501 *target_bpp
= This
->bytesPerPixel
;
1503 /* Ok, now look if we have to do any conversion */
1504 switch(This
->resource
.format
) {
1509 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1510 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1512 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE
) || colorkey_active
|| (!use_texturing
&& GL_SUPPORT(EXT_PALETTED_TEXTURE
)) ) {
1514 *internal
= GL_RGBA
;
1515 *type
= GL_UNSIGNED_BYTE
;
1517 if(colorkey_active
) {
1518 *convert
= CONVERT_PALETTED_CK
;
1520 *convert
= CONVERT_PALETTED
;
1526 case WINED3DFMT_R3G3B2
:
1527 /* **********************
1528 GL_UNSIGNED_BYTE_3_3_2
1529 ********************** */
1530 if (colorkey_active
) {
1531 /* This texture format will never be used.. So do not care about color keying
1532 up until the point in time it will be needed :-) */
1533 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1537 case WINED3DFMT_R5G6B5
:
1538 if (colorkey_active
) {
1539 *convert
= CONVERT_CK_565
;
1541 *internal
= GL_RGBA
;
1542 *type
= GL_UNSIGNED_SHORT_5_5_5_1
;
1546 case WINED3DFMT_R8G8B8
:
1547 if (colorkey_active
) {
1548 *convert
= CONVERT_CK_RGB24
;
1550 *internal
= GL_RGBA
;
1551 *type
= GL_UNSIGNED_INT_8_8_8_8
;
1556 case WINED3DFMT_X8R8G8B8
:
1557 if (colorkey_active
) {
1558 *convert
= CONVERT_RGB32_888
;
1560 *internal
= GL_RGBA
;
1561 *type
= GL_UNSIGNED_INT_8_8_8_8
;
1572 HRESULT
d3dfmt_convert_surface(BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
, UINT height
, UINT outpitch
, CONVERT_TYPES convert
, IWineD3DSurfaceImpl
*surf
) {
1573 BYTE
*source
, *dest
;
1574 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src
, dst
, pitch
, height
, outpitch
, convert
, surf
);
1579 memcpy(dst
, src
, pitch
* height
);
1582 case CONVERT_PALETTED
:
1583 case CONVERT_PALETTED_CK
:
1585 IWineD3DPaletteImpl
* pal
= surf
->palette
;
1591 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1595 /* Still no palette? Use the device's palette */
1596 /* Get the surface's palette */
1597 for (i
= 0; i
< 256; i
++) {
1598 IWineD3DDeviceImpl
*device
= surf
->resource
.wineD3DDevice
;
1600 table
[i
][0] = device
->palettes
[device
->currentPalette
][i
].peRed
;
1601 table
[i
][1] = device
->palettes
[device
->currentPalette
][i
].peGreen
;
1602 table
[i
][2] = device
->palettes
[device
->currentPalette
][i
].peBlue
;
1603 if ((convert
== CONVERT_PALETTED_CK
) &&
1604 (i
>= surf
->SrcBltCKey
.dwColorSpaceLowValue
) &&
1605 (i
<= surf
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1606 /* We should maybe here put a more 'neutral' color than the standard bright purple
1607 one often used by application to prevent the nice purple borders when bi-linear
1615 TRACE("Using surface palette %p\n", pal
);
1616 /* Get the surface's palette */
1617 for (i
= 0; i
< 256; i
++) {
1618 table
[i
][0] = pal
->palents
[i
].peRed
;
1619 table
[i
][1] = pal
->palents
[i
].peGreen
;
1620 table
[i
][2] = pal
->palents
[i
].peBlue
;
1621 if ((convert
== CONVERT_PALETTED_CK
) &&
1622 (i
>= surf
->SrcBltCKey
.dwColorSpaceLowValue
) &&
1623 (i
<= surf
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1624 /* We should maybe here put a more 'neutral' color than the standard bright purple
1625 one often used by application to prevent the nice purple borders when bi-linear
1634 for (y
= 0; y
< height
; y
++)
1636 source
= src
+ pitch
* y
;
1637 dest
= dst
+ outpitch
* y
;
1638 /* This is an 1 bpp format, using the width here is fine */
1639 for (x
= 0; x
< width
; x
++) {
1640 BYTE color
= *source
++;
1641 *dest
++ = table
[color
][0];
1642 *dest
++ = table
[color
][1];
1643 *dest
++ = table
[color
][2];
1644 *dest
++ = table
[color
][3];
1650 case CONVERT_CK_565
:
1652 /* Converting the 565 format in 5551 packed to emulate color-keying.
1654 Note : in all these conversion, it would be best to average the averaging
1655 pixels to get the color of the pixel that will be color-keyed to
1656 prevent 'color bleeding'. This will be done later on if ever it is
1659 Note2: Nvidia documents say that their driver does not support alpha + color keying
1660 on the same surface and disables color keying in such a case
1666 TRACE("Color keyed 565\n");
1668 for (y
= 0; y
< height
; y
++) {
1669 Source
= (WORD
*) (src
+ y
* pitch
);
1670 Dest
= (WORD
*) (dst
+ y
* outpitch
);
1671 for (x
= 0; x
< width
; x
++ ) {
1672 WORD color
= *Source
++;
1673 *Dest
= ((color
& 0xFFC0) | ((color
& 0x1F) << 1));
1674 if ((color
< surf
->SrcBltCKey
.dwColorSpaceLowValue
) ||
1675 (color
> surf
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1685 ERR("Unsupported conversation type %d\n", convert
);
1690 /* This function is used in case of 8bit paletted textures to upload the palette.
1691 For now it only supports GL_EXT_paletted_texture extension but support for other
1692 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1694 void d3dfmt_p8_upload_palette(IWineD3DSurface
*iface
, CONVERT_TYPES convert
) {
1695 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1696 IWineD3DPaletteImpl
* pal
= This
->palette
;
1701 /* Still no palette? Use the device's palette */
1702 /* Get the surface's palette */
1703 for (i
= 0; i
< 256; i
++) {
1704 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
1706 table
[i
][0] = device
->palettes
[device
->currentPalette
][i
].peRed
;
1707 table
[i
][1] = device
->palettes
[device
->currentPalette
][i
].peGreen
;
1708 table
[i
][2] = device
->palettes
[device
->currentPalette
][i
].peBlue
;
1709 if ((convert
== CONVERT_PALETTED_CK
) &&
1710 (i
>= This
->SrcBltCKey
.dwColorSpaceLowValue
) &&
1711 (i
<= This
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1712 /* We should maybe here put a more 'neutral' color than the standard bright purple
1713 one often used by application to prevent the nice purple borders when bi-linear
1721 TRACE("Using surface palette %p\n", pal
);
1722 /* Get the surface's palette */
1723 for (i
= 0; i
< 256; i
++) {
1724 table
[i
][0] = pal
->palents
[i
].peRed
;
1725 table
[i
][1] = pal
->palents
[i
].peGreen
;
1726 table
[i
][2] = pal
->palents
[i
].peBlue
;
1727 if ((convert
== CONVERT_PALETTED_CK
) &&
1728 (i
>= This
->SrcBltCKey
.dwColorSpaceLowValue
) &&
1729 (i
<= This
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1730 /* We should maybe here put a more 'neutral' color than the standard bright purple
1731 one often used by application to prevent the nice purple borders when bi-linear
1739 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D
,GL_RGBA
,256,GL_RGBA
,GL_UNSIGNED_BYTE
, table
));
1742 static HRESULT WINAPI
IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface
*iface
) {
1743 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1744 GLenum format
, internal
, type
;
1745 CONVERT_TYPES convert
;
1747 int width
, pitch
, outpitch
;
1750 if (This
->Flags
& SFLAG_INTEXTURE
) {
1751 TRACE("Surface already in texture\n");
1754 if (This
->Flags
& SFLAG_DIRTY
) {
1755 TRACE("Reloading because surface is dirty\n");
1756 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1757 ((This
->Flags
& SFLAG_GLCKEY
) && (!(This
->CKeyFlags
& DDSD_CKSRCBLT
))) ||
1758 /* Reload: vice versa OR */
1759 ((!(This
->Flags
& SFLAG_GLCKEY
)) && (This
->CKeyFlags
& DDSD_CKSRCBLT
)) ||
1760 /* Also reload: Color key is active AND the color key has changed */
1761 ((This
->CKeyFlags
& DDSD_CKSRCBLT
) && (
1762 (This
->glCKey
.dwColorSpaceLowValue
!= This
->SrcBltCKey
.dwColorSpaceLowValue
) ||
1763 (This
->glCKey
.dwColorSpaceHighValue
!= This
->SrcBltCKey
.dwColorSpaceHighValue
)))) {
1764 TRACE("Reloading because of color keying\n");
1766 TRACE("surface isn't dirty\n");
1770 This
->Flags
&= ~SFLAG_DIRTY
;
1772 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1773 * These resources are not bound by device size or format restrictions. Because of this,
1774 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1775 * However, these resources can always be created, locked, and copied.
1777 if (This
->resource
.pool
== WINED3DPOOL_SCRATCH
&& !(This
->Flags
& SFLAG_FORCELOAD
) )
1779 FIXME("(%p) Operation not supported for scratch textures\n",This
);
1780 return WINED3DERR_INVALIDCALL
;
1783 if (This
->Flags
& SFLAG_INPBUFFER
) {
1784 if (This
->glDescription
.level
!= 0)
1785 FIXME("Surface in texture is only supported for level 0\n");
1786 else if (This
->resource
.format
== WINED3DFMT_P8
|| This
->resource
.format
== WINED3DFMT_A8P8
||
1787 This
->resource
.format
== WINED3DFMT_DXT1
|| This
->resource
.format
== WINED3DFMT_DXT2
||
1788 This
->resource
.format
== WINED3DFMT_DXT3
|| This
->resource
.format
== WINED3DFMT_DXT4
||
1789 This
->resource
.format
== WINED3DFMT_DXT5
)
1790 FIXME("Format %d not supported\n", This
->resource
.format
);
1796 glGetIntegerv(GL_READ_BUFFER
, &prevRead
);
1797 vcheckGLcall("glGetIntegerv");
1798 glReadBuffer(GL_BACK
);
1799 vcheckGLcall("glReadBuffer");
1801 glCopyTexImage2D(This
->glDescription
.target
,
1802 This
->glDescription
.level
,
1803 This
->glDescription
.glFormatInternal
,
1806 This
->currentDesc
.Width
,
1807 This
->currentDesc
.Height
,
1810 checkGLcall("glCopyTexImage2D");
1811 glReadBuffer(prevRead
);
1812 vcheckGLcall("glReadBuffer");
1816 TRACE("Updating target %d\n", This
->glDescription
.target
);
1817 This
->Flags
|= SFLAG_INTEXTURE
;
1822 if(This
->CKeyFlags
& DDSD_CKSRCBLT
) {
1823 This
->Flags
|= SFLAG_GLCKEY
;
1824 This
->glCKey
= This
->SrcBltCKey
;
1826 else This
->Flags
&= ~SFLAG_GLCKEY
;
1828 d3dfmt_get_conv(This
, TRUE
/* We need color keying */, TRUE
/* We will use textures */, &format
, &internal
, &type
, &convert
, &bpp
);
1830 /* The width is in 'length' not in bytes */
1831 if (NP2_REPACK
== wined3d_settings
.nonpower2_mode
|| This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
1832 width
= This
->currentDesc
.Width
;
1834 width
= This
->pow2Width
;
1836 pitch
= IWineD3DSurface_GetPitch(iface
);
1838 if((convert
!= NO_CONVERSION
) && This
->resource
.allocatedMemory
) {
1839 int height
= This
->glRect
.bottom
- This
->glRect
.top
;
1841 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1842 outpitch
= width
* bpp
;
1843 outpitch
= (outpitch
+ SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
1845 mem
= HeapAlloc(GetProcessHeap(), 0, outpitch
* height
);
1847 ERR("Out of memory %d, %d!\n", outpitch
, height
);
1848 return WINED3DERR_OUTOFVIDEOMEMORY
;
1850 d3dfmt_convert_surface(This
->resource
.allocatedMemory
, mem
, pitch
, width
, height
, outpitch
, convert
, This
);
1852 This
->Flags
|= SFLAG_CONVERTED
;
1853 } else if (This
->resource
.format
== WINED3DFMT_P8
&& GL_SUPPORT(EXT_PALETTED_TEXTURE
)) {
1854 d3dfmt_p8_upload_palette(iface
, convert
);
1855 This
->Flags
&= ~SFLAG_CONVERTED
;
1856 mem
= This
->resource
.allocatedMemory
;
1858 This
->Flags
&= ~SFLAG_CONVERTED
;
1859 mem
= This
->resource
.allocatedMemory
;
1862 /* Make sure the correct pitch is used */
1863 glPixelStorei(GL_UNPACK_ROW_LENGTH
, width
);
1865 if (NP2_REPACK
== wined3d_settings
.nonpower2_mode
&& (This
->Flags
& SFLAG_NONPOW2
) && !(This
->Flags
& SFLAG_OVERSIZE
)) {
1866 TRACE("non power of two support\n");
1867 surface_allocate_surface(This
, internal
, This
->pow2Width
, This
->pow2Height
, format
, type
);
1869 surface_upload_data(This
, This
->pow2Width
, This
->pow2Height
, format
, type
, mem
);
1872 surface_allocate_surface(This
, internal
, This
->glRect
.right
- This
->glRect
.left
, This
->glRect
.bottom
- This
->glRect
.top
, format
, type
);
1874 surface_upload_data(This
, This
->glRect
.right
- This
->glRect
.left
, This
->glRect
.bottom
- This
->glRect
.top
, format
, type
, mem
);
1878 /* Restore the default pitch */
1879 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1881 if (mem
!= This
->resource
.allocatedMemory
)
1882 HeapFree(GetProcessHeap(), 0, mem
);
1886 static unsigned int gen
= 0;
1889 if ((gen
% 10) == 0) {
1890 snprintf(buffer
, sizeof(buffer
), "/tmp/surface%p_type%u_level%u_%u.ppm", This
, This
->glDescription
.target
, This
->glDescription
.level
, gen
);
1891 IWineD3DSurfaceImpl_SaveSnapshot(iface
, buffer
);
1894 * debugging crash code
1903 if (!(This
->Flags
& SFLAG_DONOTFREE
)) {
1904 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
1905 This
->resource
.allocatedMemory
= NULL
;
1913 HRESULT WINAPI
IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface
*iface
, const char* filename
) {
1916 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1917 char *allocatedMemory
;
1919 IWineD3DSwapChain
*swapChain
= NULL
;
1921 GLuint tmpTexture
= 0;
1924 Textures my not be stored in ->allocatedgMemory and a GlTexture
1925 so we should lock the surface before saving a snapshot, or at least check that
1927 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1928 by calling GetTexImage and in compressed form by calling
1929 GetCompressedTexImageARB. Queried compressed images can be saved and
1930 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1931 texture images do not need to be processed by the GL and should
1932 significantly improve texture loading performance relative to uncompressed
1935 /* Setup the width and height to be the internal texture width and height. */
1936 width
= This
->pow2Width
;
1937 height
= This
->pow2Height
;
1938 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1939 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapChain
);
1941 if (swapChain
|| (This
->Flags
& SFLAG_INPBUFFER
)) { /* if were not a real texture then read the back buffer into a real texture*/
1942 /* we don't want to interfere with the back buffer so read the data into a temporary texture and then save the data out of the temporary texture */
1945 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This
);
1946 glEnable(GL_TEXTURE_2D
);
1948 glGenTextures(1, &tmpTexture
);
1949 glBindTexture(GL_TEXTURE_2D
, tmpTexture
);
1951 glTexImage2D(GL_TEXTURE_2D
,
1958 GL_UNSIGNED_INT_8_8_8_8_REV
,
1961 glGetIntegerv(GL_READ_BUFFER
, &prevRead
);
1962 vcheckGLcall("glGetIntegerv");
1963 glReadBuffer(GL_BACK
);
1964 vcheckGLcall("glReadBuffer");
1965 glCopyTexImage2D(GL_TEXTURE_2D
,
1974 checkGLcall("glCopyTexImage2D");
1975 glReadBuffer(prevRead
);
1978 } else { /* bind the real texture */
1979 IWineD3DSurface_PreLoad(iface
);
1981 allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, width
* height
* 4);
1983 FIXME("Saving texture level %d width %d height %d\n", This
->glDescription
.level
, width
, height
);
1984 glGetTexImage(GL_TEXTURE_2D
,
1985 This
->glDescription
.level
,
1987 GL_UNSIGNED_INT_8_8_8_8_REV
,
1989 checkGLcall("glTexImage2D");
1991 glBindTexture(GL_TEXTURE_2D
, 0);
1992 glDeleteTextures(1, &tmpTexture
);
1996 f
= fopen(filename
, "w+");
1998 ERR("opening of %s failed with: %s\n", filename
, strerror(errno
));
1999 return WINED3DERR_INVALIDCALL
;
2001 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
2002 TRACE("(%p) opened %s with format %s\n", This
, filename
, debug_d3dformat(This
->resource
.format
));
2017 fwrite(&width
,2,1,f
);
2019 fwrite(&height
,2,1,f
);
2024 /* 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*/
2026 textureRow
= allocatedMemory
+ (width
* (height
- 1) *4);
2028 textureRow
= allocatedMemory
;
2029 for (y
= 0 ; y
< height
; y
++) {
2030 for (i
= 0; i
< width
; i
++) {
2031 color
= *((DWORD
*)textureRow
);
2032 fputc((color
>> 16) & 0xFF, f
); /* B */
2033 fputc((color
>> 8) & 0xFF, f
); /* G */
2034 fputc((color
>> 0) & 0xFF, f
); /* R */
2035 fputc((color
>> 24) & 0xFF, f
); /* A */
2038 /* take two rows of the pointer to the texture memory */
2040 (textureRow
-= width
<< 3);
2043 TRACE("Closing file\n");
2047 IWineD3DSwapChain_Release(swapChain
);
2049 HeapFree(GetProcessHeap(), 0, allocatedMemory
);
2053 HRESULT WINAPI
IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface
*iface
) {
2054 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2055 This
->Flags
&= ~SFLAG_DIRTY
;
2056 This
->dirtyRect
.left
= This
->currentDesc
.Width
;
2057 This
->dirtyRect
.top
= This
->currentDesc
.Height
;
2058 This
->dirtyRect
.right
= 0;
2059 This
->dirtyRect
.bottom
= 0;
2060 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This
, This
->Flags
& SFLAG_DIRTY
? 1 : 0, This
->dirtyRect
.left
,
2061 This
->dirtyRect
.top
, This
->dirtyRect
.right
, This
->dirtyRect
.bottom
);
2066 * Slightly inefficient way to handle multiple dirty rects but it works :)
2068 extern HRESULT WINAPI
IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface
*iface
, CONST RECT
* pDirtyRect
) {
2069 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2070 IWineD3DBaseTexture
*baseTexture
= NULL
;
2071 This
->Flags
|= SFLAG_DIRTY
;
2072 if (NULL
!= pDirtyRect
) {
2073 This
->dirtyRect
.left
= min(This
->dirtyRect
.left
, pDirtyRect
->left
);
2074 This
->dirtyRect
.top
= min(This
->dirtyRect
.top
, pDirtyRect
->top
);
2075 This
->dirtyRect
.right
= max(This
->dirtyRect
.right
, pDirtyRect
->right
);
2076 This
->dirtyRect
.bottom
= max(This
->dirtyRect
.bottom
, pDirtyRect
->bottom
);
2078 This
->dirtyRect
.left
= 0;
2079 This
->dirtyRect
.top
= 0;
2080 This
->dirtyRect
.right
= This
->currentDesc
.Width
;
2081 This
->dirtyRect
.bottom
= This
->currentDesc
.Height
;
2083 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This
, This
->Flags
& SFLAG_DIRTY
, This
->dirtyRect
.left
,
2084 This
->dirtyRect
.top
, This
->dirtyRect
.right
, This
->dirtyRect
.bottom
);
2085 /* if the container is a basetexture then mark it dirty. */
2086 if (IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
) == WINED3D_OK
) {
2087 TRACE("Passing to conatiner\n");
2088 IWineD3DBaseTexture_SetDirty(baseTexture
, TRUE
);
2089 IWineD3DBaseTexture_Release(baseTexture
);
2094 HRESULT WINAPI
IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface
*iface
, IWineD3DBase
*container
) {
2095 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2097 TRACE("This %p, container %p\n", This
, container
);
2099 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2101 TRACE("Setting container to %p from %p\n", container
, This
->container
);
2102 This
->container
= container
;
2107 HRESULT WINAPI
IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface
*iface
, WINED3DFORMAT format
) {
2108 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2109 const PixelFormatDesc
*formatEntry
= getFormatDescEntry(format
);
2111 if (This
->resource
.format
!= WINED3DFMT_UNKNOWN
) {
2112 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This
);
2113 return WINED3DERR_INVALIDCALL
;
2116 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This
, format
, debug_d3dformat(format
));
2117 if (format
== WINED3DFMT_UNKNOWN
) {
2118 This
->resource
.size
= 0;
2119 } else if (format
== WINED3DFMT_DXT1
) {
2120 /* DXT1 is half byte per pixel */
2121 This
->resource
.size
= ((max(This
->pow2Width
, 4) * formatEntry
->bpp
) * max(This
->pow2Height
, 4)) >> 1;
2123 } else if (format
== WINED3DFMT_DXT2
|| format
== WINED3DFMT_DXT3
||
2124 format
== WINED3DFMT_DXT4
|| format
== WINED3DFMT_DXT5
) {
2125 This
->resource
.size
= ((max(This
->pow2Width
, 4) * formatEntry
->bpp
) * max(This
->pow2Height
, 4));
2127 This
->resource
.size
= ((This
->pow2Width
* formatEntry
->bpp
) + SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
2128 This
->resource
.size
*= This
->pow2Height
;
2132 /* Setup some glformat defaults */
2133 This
->glDescription
.glFormat
= formatEntry
->glFormat
;
2134 This
->glDescription
.glFormatInternal
= formatEntry
->glInternal
;
2135 This
->glDescription
.glType
= formatEntry
->glType
;
2137 if (format
!= WINED3DFMT_UNKNOWN
) {
2138 This
->bytesPerPixel
= formatEntry
->bpp
;
2139 This
->pow2Size
= (This
->pow2Width
* This
->bytesPerPixel
) * This
->pow2Height
;
2141 This
->bytesPerPixel
= 0;
2145 This
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== format
) ? SFLAG_LOCKABLE
: 0;
2147 This
->resource
.format
= format
;
2149 TRACE("(%p) : Size %d, pow2Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This
, This
->resource
.size
, This
->pow2Size
, This
->bytesPerPixel
, This
->glDescription
.glFormat
, This
->glDescription
.glFormatInternal
, This
->glDescription
.glType
);
2154 HRESULT WINAPI
IWineD3DSurfaceImpl_SetMem(IWineD3DSurface
*iface
, void *Mem
) {
2155 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2157 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2158 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
2159 ERR("Not supported on render targets\n");
2160 return WINED3DERR_INVALIDCALL
;
2163 if(This
->Flags
& (SFLAG_LOCKED
| SFLAG_DCINUSE
)) {
2164 WARN("Surface is locked or the HDC is in use\n");
2165 return WINED3DERR_INVALIDCALL
;
2168 if(Mem
&& Mem
!= This
->resource
.allocatedMemory
) {
2170 /* Do I have to copy the old surface content? */
2171 if(This
->Flags
& SFLAG_DIBSECTION
) {
2172 /* Release the DC. No need to hold the critical section for the update
2173 * Thread because this thread runs only on front buffers, but this method
2174 * fails for render targets in the check above.
2176 SelectObject(This
->hDC
, This
->dib
.holdbitmap
);
2177 DeleteDC(This
->hDC
);
2178 /* Release the DIB section */
2179 DeleteObject(This
->dib
.DIBsection
);
2180 This
->dib
.bitmap_data
= NULL
;
2181 This
->resource
.allocatedMemory
= NULL
;
2183 This
->Flags
&= ~SFLAG_DIBSECTION
;
2184 } else if(!(This
->Flags
& SFLAG_USERPTR
)) {
2185 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
2187 This
->resource
.allocatedMemory
= Mem
;
2188 This
->Flags
|= SFLAG_USERPTR
;
2189 } else if(This
->Flags
& SFLAG_USERPTR
) {
2190 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2191 This
->resource
.allocatedMemory
= NULL
;
2192 This
->Flags
&= ~SFLAG_USERPTR
;
2197 /* TODO: replace this function with context management routines */
2198 HRESULT WINAPI
IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface
*iface
, BOOL inPBuffer
, BOOL inTexture
) {
2199 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2202 This
->Flags
|= SFLAG_INPBUFFER
;
2204 This
->Flags
&= ~SFLAG_INPBUFFER
;
2208 This
->Flags
|= SFLAG_INTEXTURE
;
2210 This
->Flags
&= ~SFLAG_INTEXTURE
;
2216 static HRESULT WINAPI
IWineD3DSurfaceImpl_Flip(IWineD3DSurface
*iface
, IWineD3DSurface
*override
, DWORD Flags
) {
2217 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2218 IWineD3DDevice
*D3D
= (IWineD3DDevice
*) This
->resource
.wineD3DDevice
;
2219 TRACE("(%p)->(%p,%x)\n", This
, override
, Flags
);
2221 /* Flipping is only supported on RenderTargets */
2222 if( !(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) return DDERR_NOTFLIPPABLE
;
2225 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2226 * FIXME("(%p) Target override is not supported by now\n", This);
2227 * Additionally, it isn't really possible to support triple-buffering
2228 * properly on opengl at all
2232 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2233 return IWineD3DDevice_Present(D3D
, NULL
, NULL
, 0, NULL
);
2236 /* Not called from the VTable */
2237 static HRESULT
IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl
*This
, RECT
*DestRect
, IWineD3DSurface
*SrcSurface
, RECT
*SrcRect
, DWORD Flags
, DDBLTFX
*DDBltFx
) {
2239 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
2240 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2241 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
2244 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
);
2246 /* Get the swapchain. One of the surfaces has to be a primary surface */
2247 IWineD3DSurface_GetContainer( (IWineD3DSurface
*) This
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
2248 if(swapchain
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
2250 IWineD3DSurface_GetContainer( (IWineD3DSurface
*) Src
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
2251 if(swapchain
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
2252 else return WINED3DERR_INVALIDCALL
;
2258 rect
.x1
= DestRect
->left
;
2259 rect
.y1
= DestRect
->top
;
2260 rect
.x2
= DestRect
->right
;
2261 rect
.y2
= DestRect
->bottom
;
2265 rect
.x2
= This
->currentDesc
.Width
;
2266 rect
.y2
= This
->currentDesc
.Height
;
2269 /* Half-life does a Blt from the back buffer to the front buffer,
2270 * Full surface size, no flags... Use present instead
2274 /* First, check if we can do a Flip */
2276 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2278 if( (SrcRect
->left
== 0) && (SrcRect
->top
== 0) &&
2279 (SrcRect
->right
== Src
->currentDesc
.Width
) && (SrcRect
->bottom
== Src
->currentDesc
.Height
) ) {
2286 /* Check the Destination rect and the surface sizes */
2288 (rect
.x1
== 0) && (rect
.y1
== 0) &&
2289 (rect
.x2
== This
->currentDesc
.Width
) && (rect
.y2
== This
->currentDesc
.Height
) &&
2290 (This
->currentDesc
.Width
== Src
->currentDesc
.Width
) &&
2291 (This
->currentDesc
.Height
== Src
->currentDesc
.Height
)) {
2292 /* These flags are unimportant for the flag check, remove them */
2294 if((Flags
& ~(DDBLT_DONOTWAIT
| DDBLT_WAIT
)) == 0) {
2295 if( swapchain
->backBuffer
&& ((IWineD3DSurface
*) This
== swapchain
->frontBuffer
) && ((IWineD3DSurface
*) Src
== swapchain
->backBuffer
[0]) ) {
2297 D3DSWAPEFFECT orig_swap
= swapchain
->presentParms
.SwapEffect
;
2299 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2300 * take very long, while a flip is fast.
2301 * This applies to Half-Life, which does such Blts every time it finished
2302 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2303 * menu. This is also used by all apps when they do windowed rendering
2305 * The problem is that flipping is not really the same as copying. After a
2306 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2307 * untouched. Therefore it's necessary to override the swap effect
2308 * and to set it back after the flip.
2311 swapchain
->presentParms
.SwapEffect
= WINED3DSWAPEFFECT_COPY
;
2313 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2314 IWineD3DDevice_Present((IWineD3DDevice
*) This
->resource
.wineD3DDevice
,
2315 NULL
, NULL
, 0, NULL
);
2317 swapchain
->presentParms
.SwapEffect
= orig_swap
;
2324 /* Blt from texture to rendertarget? */
2325 if( ( ( (IWineD3DSurface
*) This
== swapchain
->frontBuffer
) ||
2326 ( swapchain
->backBuffer
&& (IWineD3DSurface
*) This
== swapchain
->backBuffer
[0]) )
2328 ( ( (IWineD3DSurface
*) Src
!= swapchain
->frontBuffer
) &&
2329 ( swapchain
->backBuffer
&& (IWineD3DSurface
*) Src
!= swapchain
->backBuffer
[0]) ) ) {
2330 float glTexCoord
[4];
2332 DDCOLORKEY oldBltCKey
= {0,0};
2333 GLint oldLight
, oldFog
, oldDepth
, oldBlend
, oldCull
, oldAlpha
;
2334 GLint oldStencil
, oldNVRegisterCombiners
= 0;
2337 RECT SourceRectangle
;
2340 TRACE("Blt from surface %p to rendertarget %p\n", Src
, This
);
2343 SourceRectangle
.left
= SrcRect
->left
;
2344 SourceRectangle
.right
= SrcRect
->right
;
2345 SourceRectangle
.top
= SrcRect
->top
;
2346 SourceRectangle
.bottom
= SrcRect
->bottom
;
2348 SourceRectangle
.left
= 0;
2349 SourceRectangle
.right
= Src
->currentDesc
.Width
;
2350 SourceRectangle
.top
= 0;
2351 SourceRectangle
.bottom
= Src
->currentDesc
.Height
;
2354 if(!CalculateTexRect(Src
, &SourceRectangle
, glTexCoord
)) {
2355 /* Fall back to software */
2356 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src
,
2357 SourceRectangle
.left
, SourceRectangle
.top
,
2358 SourceRectangle
.right
, SourceRectangle
.bottom
);
2359 return WINED3DERR_INVALIDCALL
;
2362 /* Color keying: Check if we have to do a color keyed blt,
2363 * and if not check if a color key is activated.
2365 oldCKey
= Src
->CKeyFlags
;
2366 if(!(Flags
& DDBLT_KEYSRC
) &&
2367 Src
->CKeyFlags
& DDSD_CKSRCBLT
) {
2368 /* Ok, the surface has a color key, but we shall not use it -
2369 * Deactivate it for now, LoadTexture will catch this
2371 Src
->CKeyFlags
&= ~DDSD_CKSRCBLT
;
2375 if(Flags
& DDBLT_KEYDEST
) {
2376 oldBltCKey
= This
->SrcBltCKey
;
2377 /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
2378 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
2380 This
->SrcBltCKey
= This
->DestBltCKey
;
2381 } else if (Flags
& DDBLT_KEYSRC
)
2382 oldBltCKey
= This
->SrcBltCKey
;
2384 /* Now load the surface */
2385 IWineD3DSurface_PreLoad((IWineD3DSurface
*) Src
);
2389 /* Save all the old stuff until we have a proper opengl state manager */
2390 oldLight
= glIsEnabled(GL_LIGHTING
);
2391 oldFog
= glIsEnabled(GL_FOG
);
2392 oldDepth
= glIsEnabled(GL_DEPTH_TEST
);
2393 oldBlend
= glIsEnabled(GL_BLEND
);
2394 oldCull
= glIsEnabled(GL_CULL_FACE
);
2395 oldAlpha
= glIsEnabled(GL_ALPHA_TEST
);
2396 oldStencil
= glIsEnabled(GL_STENCIL_TEST
);
2398 if (GL_SUPPORT(NV_REGISTER_COMBINERS
)) {
2399 oldNVRegisterCombiners
= glIsEnabled(GL_REGISTER_COMBINERS_NV
);
2402 glGetIntegerv(GL_ALPHA_TEST_FUNC
, &alphafunc
);
2403 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2404 glGetFloatv(GL_ALPHA_TEST_REF
, &alpharef
);
2405 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2407 glGetIntegerv(GL_DRAW_BUFFER
, &oldDraw
);
2408 if(This
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
) {
2409 TRACE("Drawing to front buffer\n");
2410 glDrawBuffer(GL_FRONT
);
2411 checkGLcall("glDrawBuffer GL_FRONT");
2414 /* Unbind the old texture */
2415 glBindTexture(GL_TEXTURE_2D
, 0);
2416 IWineD3DDeviceImpl_MarkStateDirty(This
->resource
.wineD3DDevice
, STATE_SAMPLER(0));
2418 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
2419 /* We use texture unit 0 for blts */
2420 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
2421 checkGLcall("glActiveTextureARB");
2423 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2426 /* Disable some fancy graphics effects */
2427 glDisable(GL_LIGHTING
);
2428 checkGLcall("glDisable GL_LIGHTING");
2429 glDisable(GL_DEPTH_TEST
);
2430 checkGLcall("glDisable GL_DEPTH_TEST");
2432 checkGLcall("glDisable GL_FOG");
2433 glDisable(GL_BLEND
);
2434 checkGLcall("glDisable GL_BLEND");
2435 glDisable(GL_CULL_FACE
);
2436 checkGLcall("glDisable GL_CULL_FACE");
2437 glDisable(GL_STENCIL_TEST
);
2438 checkGLcall("glDisable GL_STENCIL_TEST");
2439 if (GL_SUPPORT(NV_REGISTER_COMBINERS
)) {
2440 glDisable(GL_REGISTER_COMBINERS_NV
);
2441 checkGLcall("glDisable GL_REGISTER_COMBINERS_NV");
2444 /* Ok, we need 2d textures, but not 1D or 3D */
2445 glDisable(GL_TEXTURE_1D
);
2446 checkGLcall("glDisable GL_TEXTURE_1D");
2447 glEnable(GL_TEXTURE_2D
);
2448 checkGLcall("glEnable GL_TEXTURE_2D");
2449 glDisable(GL_TEXTURE_3D
);
2450 checkGLcall("glDisable GL_TEXTURE_3D");
2452 /* Bind the texture */
2453 glBindTexture(GL_TEXTURE_2D
, Src
->glDescription
.textureName
);
2454 checkGLcall("glBindTexture");
2456 glEnable(GL_SCISSOR_TEST
);
2458 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
2460 /* No filtering for blts */
2461 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
,
2463 checkGLcall("glTexParameteri");
2464 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
2466 checkGLcall("glTexParameteri");
2467 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
2468 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
2469 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
2470 checkGLcall("glTexEnvi");
2472 /* This is for color keying */
2473 if(Flags
& DDBLT_KEYSRC
) {
2474 glEnable(GL_ALPHA_TEST
);
2475 checkGLcall("glEnable GL_ALPHA_TEST");
2476 glAlphaFunc(GL_NOTEQUAL
, 0.0);
2477 checkGLcall("glAlphaFunc\n");
2479 glDisable(GL_ALPHA_TEST
);
2480 checkGLcall("glDisable GL_ALPHA_TEST");
2483 /* Draw a textured quad
2485 myDevice
->last_was_rhw
= TRUE
;
2486 /* Apply the projection matrix, it sets up orthogonal projection due to last_was_rhw */
2487 StateTable
[STATE_TRANSFORM(WINED3DTS_PROJECTION
)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION
), myDevice
->stateBlock
);
2488 StateTable
[STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))].apply(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), myDevice
->stateBlock
);
2489 /* That will reapply the projection matrix too */
2490 IWineD3DDeviceImpl_MarkStateDirty(myDevice
, STATE_VDECL
);
2494 glColor3d(1.0f
, 1.0f
, 1.0f
);
2495 glTexCoord2f(glTexCoord
[0], glTexCoord
[2]);
2500 glTexCoord2f(glTexCoord
[0], glTexCoord
[3]);
2501 glVertex3f(rect
.x1
, rect
.y2
, 0.0);
2503 glTexCoord2f(glTexCoord
[1], glTexCoord
[3]);
2508 glTexCoord2f(glTexCoord
[1], glTexCoord
[2]);
2513 checkGLcall("glEnd");
2515 /* Unbind the texture */
2516 glBindTexture(GL_TEXTURE_2D
, 0);
2517 checkGLcall("glEnable glBindTexture");
2519 /* Restore the old settings */
2521 glEnable(GL_LIGHTING
);
2522 checkGLcall("glEnable GL_LIGHTING");
2526 checkGLcall("glEnable GL_FOG");
2529 glEnable(GL_DEPTH_TEST
);
2530 checkGLcall("glEnable GL_DEPTH_TEST");
2534 checkGLcall("glEnable GL_BLEND");
2537 glEnable(GL_CULL_FACE
);
2538 checkGLcall("glEnable GL_CULL_FACE");
2541 glEnable(GL_STENCIL_TEST
);
2542 checkGLcall("glEnable GL_STENCIL_TEST");
2545 glDisable(GL_ALPHA_TEST
);
2546 checkGLcall("glDisable GL_ALPHA_TEST");
2548 glEnable(GL_ALPHA_TEST
);
2549 checkGLcall("glEnable GL_ALPHA_TEST");
2551 if (GL_SUPPORT(NV_REGISTER_COMBINERS
) && oldNVRegisterCombiners
) {
2552 glEnable(GL_REGISTER_COMBINERS_NV
);
2553 checkGLcall("glEnable GL_REGISTER_COMBINERS_NV");
2556 glAlphaFunc(alphafunc
, alpharef
);
2557 checkGLcall("glAlphaFunc\n");
2559 if(This
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
&& oldDraw
== GL_BACK
) {
2560 glDrawBuffer(oldDraw
);
2563 /* Restore the color key flags */
2564 if(oldCKey
!= Src
->CKeyFlags
) {
2565 Src
->CKeyFlags
= oldCKey
;
2568 /* Restore the old color key */
2569 if (Flags
& (DDBLT_KEYSRC
| DDBLT_KEYDEST
))
2570 This
->SrcBltCKey
= oldBltCKey
;
2574 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2575 This
->Flags
|= SFLAG_GLDIRTY
;
2581 /* Blt from rendertarget to texture? */
2582 if( (SrcSurface
== swapchain
->frontBuffer
) ||
2583 (swapchain
->backBuffer
&& SrcSurface
== swapchain
->backBuffer
[0]) ) {
2584 if( ( (IWineD3DSurface
*) This
!= swapchain
->frontBuffer
) &&
2585 ( swapchain
->backBuffer
&& (IWineD3DSurface
*) This
!= swapchain
->backBuffer
[0]) ) {
2590 TRACE("Blt from rendertarget to texture\n");
2592 /* Call preload for the surface to make sure it isn't dirty */
2593 IWineD3DSurface_PreLoad((IWineD3DSurface
*) This
);
2596 srect
.x1
= SrcRect
->left
;
2597 srect
.y1
= SrcRect
->top
;
2598 srect
.x2
= SrcRect
->right
;
2599 srect
.y2
= SrcRect
->bottom
;
2603 srect
.x2
= Src
->currentDesc
.Width
;
2604 srect
.y2
= Src
->currentDesc
.Height
;
2609 /* Bind the target texture */
2610 glBindTexture(GL_TEXTURE_2D
, This
->glDescription
.textureName
);
2611 checkGLcall("glBindTexture");
2612 if(swapchain
->backBuffer
&& SrcSurface
== swapchain
->backBuffer
[0]) {
2613 glReadBuffer(GL_BACK
);
2615 glReadBuffer(GL_FRONT
);
2617 checkGLcall("glReadBuffer");
2619 xrel
= (float) (srect
.x2
- srect
.x1
) / (float) (rect
.x2
- rect
.x1
);
2620 yrel
= (float) (srect
.y2
- srect
.y1
) / (float) (rect
.y2
- rect
.y1
);
2622 /* I have to process this row by row to swap the image,
2623 * otherwise it would be upside down, so streching in y direction
2624 * doesn't cost extra time
2626 * However, streching in x direction can be avoided if not necessary
2628 for(row
= rect
.y1
; row
< rect
.y2
; row
++) {
2629 if( (xrel
- 1.0 < -eps
) || (xrel
- 1.0 > eps
)) {
2630 /* Well, that stuff works, but it's very slow.
2631 * find a better way instead
2634 for(col
= rect
.x1
; col
< rect
.x2
; col
++) {
2635 glCopyTexSubImage2D(GL_TEXTURE_2D
,
2637 rect
.x1
+ col
, This
->currentDesc
.Height
- row
- 1, /* xoffset, yoffset */
2638 srect
.x1
+ col
* xrel
, Src
->currentDesc
.Height
- srect
.y2
+ row
* yrel
,
2642 glCopyTexSubImage2D(GL_TEXTURE_2D
,
2644 rect
.x1
, rect
.y2
+ rect
.y1
- row
- 1, /* xoffset, yoffset */
2645 srect
.x1
, row
- rect
.y1
,
2646 rect
.x2
-rect
.x1
, 1);
2650 vcheckGLcall("glCopyTexSubImage2D");
2653 if(!(This
->Flags
& SFLAG_DONOTFREE
)) {
2654 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
2655 This
->resource
.allocatedMemory
= NULL
;
2657 This
->Flags
|= SFLAG_GLDIRTY
;
2665 if (Flags
& DDBLT_COLORFILL
) {
2666 /* This is easy to handle for the D3D Device... */
2668 IWineD3DSwapChainImpl
*implSwapChain
;
2670 TRACE("Colorfill\n");
2672 /* The color as given in the Blt function is in the format of the frame-buffer...
2673 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2675 if (This
->resource
.format
== WINED3DFMT_P8
) {
2676 if (This
->palette
) {
2677 color
= ((0xFF000000) |
2678 (This
->palette
->palents
[DDBltFx
->u5
.dwFillColor
].peRed
<< 16) |
2679 (This
->palette
->palents
[DDBltFx
->u5
.dwFillColor
].peGreen
<< 8) |
2680 (This
->palette
->palents
[DDBltFx
->u5
.dwFillColor
].peBlue
));
2685 else if (This
->resource
.format
== WINED3DFMT_R5G6B5
) {
2686 if (DDBltFx
->u5
.dwFillColor
== 0xFFFF) {
2689 color
= ((0xFF000000) |
2690 ((DDBltFx
->u5
.dwFillColor
& 0xF800) << 8) |
2691 ((DDBltFx
->u5
.dwFillColor
& 0x07E0) << 5) |
2692 ((DDBltFx
->u5
.dwFillColor
& 0x001F) << 3));
2695 else if ((This
->resource
.format
== WINED3DFMT_R8G8B8
) ||
2696 (This
->resource
.format
== WINED3DFMT_X8R8G8B8
) ) {
2697 color
= 0xFF000000 | DDBltFx
->u5
.dwFillColor
;
2699 else if (This
->resource
.format
== WINED3DFMT_A8R8G8B8
) {
2700 color
= DDBltFx
->u5
.dwFillColor
;
2703 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2704 return WINED3DERR_INVALIDCALL
;
2707 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice
);
2708 IWineD3DDevice_GetSwapChain((IWineD3DDevice
*)myDevice
, 0, (IWineD3DSwapChain
**)&implSwapChain
);
2709 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) implSwapChain
);
2710 if(implSwapChain
->backBuffer
&& This
== (IWineD3DSurfaceImpl
*) implSwapChain
->backBuffer
[0]) {
2711 glDrawBuffer(GL_BACK
);
2712 checkGLcall("glDrawBuffer(GL_BACK)");
2714 else if (This
== (IWineD3DSurfaceImpl
*) implSwapChain
->frontBuffer
) {
2715 glDrawBuffer(GL_FRONT
);
2716 checkGLcall("glDrawBuffer(GL_FRONT)");
2719 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2720 return WINED3DERR_INVALIDCALL
;
2723 TRACE("(%p) executing Render Target override, color = %x\n", This
, color
);
2725 IWineD3DDevice_Clear( (IWineD3DDevice
*) myDevice
,
2726 1 /* Number of rectangles */,
2728 WINED3DCLEAR_TARGET
,
2733 /* Restore the original draw buffer */
2734 if(implSwapChain
->backBuffer
&& implSwapChain
->backBuffer
[0]) {
2735 glDrawBuffer(GL_BACK
);
2736 vcheckGLcall("glDrawBuffer");
2742 /* Default: Fall back to the generic blt */
2743 return WINED3DERR_INVALIDCALL
;
2746 static HRESULT WINAPI
IWineD3DSurfaceImpl_Blt(IWineD3DSurface
*iface
, RECT
*DestRect
, IWineD3DSurface
*SrcSurface
, RECT
*SrcRect
, DWORD Flags
, DDBLTFX
*DDBltFx
) {
2747 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2748 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
2749 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
);
2750 TRACE("(%p): Usage is %s\n", This
, debug_d3dusage(This
->resource
.usage
));
2752 /* Special cases for RenderTargets */
2753 if( (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ||
2754 ( Src
&& (Src
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) )) {
2755 if(IWineD3DSurfaceImpl_BltOverride(This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
) == WINED3D_OK
) return WINED3D_OK
;
2758 /* For the rest call the X11 surface implementation.
2759 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2760 * other Blts are rather rare
2762 return IWineGDISurfaceImpl_Blt(iface
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
);
2765 HRESULT WINAPI
IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface
*iface
, DWORD Flags
) {
2766 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2767 TRACE("(%p)->(%x)\n", This
, Flags
);
2772 case DDGBS_ISBLTDONE
:
2776 return DDERR_INVALIDPARAMS
;
2780 HRESULT WINAPI
IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface
*iface
, DWORD Flags
) {
2781 /* XXX: DDERR_INVALIDSURFACETYPE */
2783 TRACE("(%p)->(%08x)\n",iface
,Flags
);
2786 case DDGFS_ISFLIPDONE
:
2790 return DDERR_INVALIDPARAMS
;
2794 HRESULT WINAPI
IWineD3DSurfaceImpl_IsLost(IWineD3DSurface
*iface
) {
2795 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2796 TRACE("(%p)\n", This
);
2798 return This
->Flags
& SFLAG_LOST
? DDERR_SURFACELOST
: WINED3D_OK
;
2801 HRESULT WINAPI
IWineD3DSurfaceImpl_Restore(IWineD3DSurface
*iface
) {
2802 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2803 TRACE("(%p)\n", This
);
2805 /* So far we don't lose anything :) */
2806 This
->Flags
&= ~SFLAG_LOST
;
2810 HRESULT WINAPI
IWineD3DSurfaceImpl_BltFast(IWineD3DSurface
*iface
, DWORD dstx
, DWORD dsty
, IWineD3DSurface
*Source
, RECT
*rsrc
, DWORD trans
) {
2811 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2812 IWineD3DSurfaceImpl
*srcImpl
= (IWineD3DSurfaceImpl
*) Source
;
2813 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface
, dstx
, dsty
, Source
, rsrc
, trans
);
2815 /* Special cases for RenderTargets */
2816 if( (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ||
2817 ( srcImpl
&& (srcImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) )) {
2819 RECT SrcRect
, DstRect
;
2823 SrcRect
.left
= rsrc
->left
;
2824 SrcRect
.top
= rsrc
->top
;
2825 SrcRect
.bottom
= rsrc
->bottom
;
2826 SrcRect
.right
= rsrc
->right
;
2830 SrcRect
.right
= srcImpl
->currentDesc
.Width
;
2831 SrcRect
.bottom
= srcImpl
->currentDesc
.Height
;
2834 DstRect
.left
= dstx
;
2836 DstRect
.right
= dstx
+ SrcRect
.right
- SrcRect
.left
;
2837 DstRect
.bottom
= dsty
+ SrcRect
.bottom
- SrcRect
.top
;
2839 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2840 if(trans
& DDBLTFAST_SRCCOLORKEY
)
2841 Flags
|= DDBLT_KEYSRC
;
2842 if(trans
& DDBLTFAST_DESTCOLORKEY
)
2843 Flags
|= DDBLT_KEYDEST
;
2844 if(trans
& DDBLTFAST_WAIT
)
2845 Flags
|= DDBLT_WAIT
;
2846 if(trans
& DDBLTFAST_DONOTWAIT
)
2847 Flags
|= DDBLT_DONOTWAIT
;
2849 if(IWineD3DSurfaceImpl_BltOverride(This
, &DstRect
, Source
, &SrcRect
, Flags
, NULL
) == WINED3D_OK
) return WINED3D_OK
;
2853 return IWineGDISurfaceImpl_BltFast(iface
, dstx
, dsty
, Source
, rsrc
, trans
);
2856 HRESULT WINAPI
IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface
*iface
, IWineD3DPalette
**Pal
) {
2857 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2858 TRACE("(%p)->(%p)\n", This
, Pal
);
2860 *Pal
= (IWineD3DPalette
*) This
->palette
;
2864 HRESULT WINAPI
IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface
*iface
) {
2865 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2867 IWineD3DPaletteImpl
*pal
= This
->palette
;
2869 TRACE("(%p)\n", This
);
2871 if(This
->resource
.format
== WINED3DFMT_P8
||
2872 This
->resource
.format
== WINED3DFMT_A8P8
)
2874 TRACE("Dirtifying surface\n");
2875 This
->Flags
|= SFLAG_DIRTY
;
2878 if(This
->Flags
& SFLAG_DIBSECTION
) {
2879 TRACE("(%p): Updating the hdc's palette\n", This
);
2880 for (n
=0; n
<256; n
++) {
2882 col
[n
].rgbRed
= pal
->palents
[n
].peRed
;
2883 col
[n
].rgbGreen
= pal
->palents
[n
].peGreen
;
2884 col
[n
].rgbBlue
= pal
->palents
[n
].peBlue
;
2886 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
2887 /* Use the default device palette */
2888 col
[n
].rgbRed
= device
->palettes
[device
->currentPalette
][n
].peRed
;
2889 col
[n
].rgbGreen
= device
->palettes
[device
->currentPalette
][n
].peGreen
;
2890 col
[n
].rgbBlue
= device
->palettes
[device
->currentPalette
][n
].peBlue
;
2892 col
[n
].rgbReserved
= 0;
2894 SetDIBColorTable(This
->hDC
, 0, 256, col
);
2900 HRESULT WINAPI
IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface
*iface
, IWineD3DPalette
*Pal
) {
2901 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2902 IWineD3DPaletteImpl
*PalImpl
= (IWineD3DPaletteImpl
*) Pal
;
2903 TRACE("(%p)->(%p)\n", This
, Pal
);
2905 if(This
->palette
!= NULL
)
2906 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
2907 This
->palette
->Flags
&= ~DDPCAPS_PRIMARYSURFACE
;
2909 if(PalImpl
!= NULL
) {
2910 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
2911 /* Set the device's main palette if the palette
2912 * wasn't a primary palette before
2914 if(!(PalImpl
->Flags
& DDPCAPS_PRIMARYSURFACE
)) {
2915 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
2918 for(i
=0; i
< 256; i
++) {
2919 device
->palettes
[device
->currentPalette
][i
] = PalImpl
->palents
[i
];
2923 (PalImpl
)->Flags
|= DDPCAPS_PRIMARYSURFACE
;
2926 This
->palette
= PalImpl
;
2928 return IWineD3DSurface_RealizePalette(iface
);
2931 HRESULT WINAPI
IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface
*iface
, DWORD Flags
, DDCOLORKEY
*CKey
) {
2932 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2933 TRACE("(%p)->(%08x,%p)\n", This
, Flags
, CKey
);
2935 if ((Flags
& DDCKEY_COLORSPACE
) != 0) {
2936 FIXME(" colorkey value not supported (%08x) !\n", Flags
);
2937 return DDERR_INVALIDPARAMS
;
2940 /* Dirtify the surface, but only if a key was changed */
2942 switch (Flags
& ~DDCKEY_COLORSPACE
) {
2943 case DDCKEY_DESTBLT
:
2944 This
->DestBltCKey
= *CKey
;
2945 This
->CKeyFlags
|= DDSD_CKDESTBLT
;
2948 case DDCKEY_DESTOVERLAY
:
2949 This
->DestOverlayCKey
= *CKey
;
2950 This
->CKeyFlags
|= DDSD_CKDESTOVERLAY
;
2953 case DDCKEY_SRCOVERLAY
:
2954 This
->SrcOverlayCKey
= *CKey
;
2955 This
->CKeyFlags
|= DDSD_CKSRCOVERLAY
;
2959 This
->SrcBltCKey
= *CKey
;
2960 This
->CKeyFlags
|= DDSD_CKSRCBLT
;
2965 switch (Flags
& ~DDCKEY_COLORSPACE
) {
2966 case DDCKEY_DESTBLT
:
2967 This
->CKeyFlags
&= ~DDSD_CKDESTBLT
;
2970 case DDCKEY_DESTOVERLAY
:
2971 This
->CKeyFlags
&= ~DDSD_CKDESTOVERLAY
;
2974 case DDCKEY_SRCOVERLAY
:
2975 This
->CKeyFlags
&= ~DDSD_CKSRCOVERLAY
;
2979 This
->CKeyFlags
&= ~DDSD_CKSRCBLT
;
2987 static HRESULT WINAPI
IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface
*iface
) {
2988 /** Check against the maximum texture sizes supported by the video card **/
2989 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2991 TRACE("%p\n", This
);
2992 if ((This
->pow2Width
> GL_LIMITS(texture_size
) || This
->pow2Height
> GL_LIMITS(texture_size
)) && !(This
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
))) {
2993 /* one of three options
2994 1: Do the same as we do with nonpow 2 and scale the texture, (any texture ops would require the texture to be scaled which is potentially slow)
2995 2: Set the texture to the maxium size (bad idea)
2996 3: WARN and return WINED3DERR_NOTAVAILABLE;
2997 4: Create the surface, but allow it to be used only for DirectDraw Blts. Some apps(e.g. Swat 3) create textures with a Height of 16 and a Width > 3000 and blt 16x16 letter areas from them to the render target.
2999 WARN("(%p) Creating an oversized surface\n", This
);
3000 This
->Flags
|= SFLAG_OVERSIZE
;
3002 /* This will be initialized on the first blt */
3003 This
->glRect
.left
= 0;
3004 This
->glRect
.top
= 0;
3005 This
->glRect
.right
= 0;
3006 This
->glRect
.bottom
= 0;
3008 /* No oversize, gl rect is the full texture size */
3009 This
->Flags
&= ~SFLAG_OVERSIZE
;
3010 This
->glRect
.left
= 0;
3011 This
->glRect
.top
= 0;
3012 This
->glRect
.right
= This
->pow2Width
;
3013 This
->glRect
.bottom
= This
->pow2Height
;
3019 DWORD WINAPI
IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface
*iface
) {
3020 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3022 TRACE("(%p)\n", This
);
3024 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3025 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3026 ie pitch = (width/4) * bytes per block */
3027 if (This
->resource
.format
== WINED3DFMT_DXT1
) /* DXT1 is 8 bytes per block */
3028 ret
= ((This
->currentDesc
.Width
+ 3) >> 2) << 3;
3029 else if (This
->resource
.format
== WINED3DFMT_DXT2
|| This
->resource
.format
== WINED3DFMT_DXT3
||
3030 This
->resource
.format
== WINED3DFMT_DXT4
|| This
->resource
.format
== WINED3DFMT_DXT5
) /* DXT2/3/4/5 is 16 bytes per block */
3031 ret
= ((This
->currentDesc
.Width
+ 3) >> 2) << 4;
3033 if (NP2_REPACK
== wined3d_settings
.nonpower2_mode
|| This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
3034 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
3035 ret
= This
->bytesPerPixel
* This
->currentDesc
.Width
; /* Bytes / row */
3037 ret
= This
->bytesPerPixel
* This
->pow2Width
;
3039 /* Surfaces are 32 bit aligned */
3040 ret
= (ret
+ SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
3042 TRACE("(%p) Returning %d\n", This
, ret
);
3046 HRESULT WINAPI
IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface
*iface
, LONG X
, LONG Y
) {
3047 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3049 FIXME("(%p)->(%d,%d) Stub!\n", This
, X
, Y
);
3051 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3053 TRACE("(%p): Not an overlay surface\n", This
);
3054 return DDERR_NOTAOVERLAYSURFACE
;
3060 HRESULT WINAPI
IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface
*iface
, LONG
*X
, LONG
*Y
) {
3061 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3063 FIXME("(%p)->(%p,%p) Stub!\n", This
, X
, Y
);
3065 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3067 TRACE("(%p): Not an overlay surface\n", This
);
3068 return DDERR_NOTAOVERLAYSURFACE
;
3074 HRESULT WINAPI
IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface
*iface
, DWORD Flags
, IWineD3DSurface
*Ref
) {
3075 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3076 IWineD3DSurfaceImpl
*RefImpl
= (IWineD3DSurfaceImpl
*) Ref
;
3078 FIXME("(%p)->(%08x,%p) Stub!\n", This
, Flags
, RefImpl
);
3080 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3082 TRACE("(%p): Not an overlay surface\n", This
);
3083 return DDERR_NOTAOVERLAYSURFACE
;
3089 HRESULT WINAPI
IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface
*iface
, RECT
*SrcRect
, IWineD3DSurface
*DstSurface
, RECT
*DstRect
, DWORD Flags
, WINEDDOVERLAYFX
*FX
) {
3090 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3091 IWineD3DSurfaceImpl
*Dst
= (IWineD3DSurfaceImpl
*) DstSurface
;
3092 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This
, SrcRect
, Dst
, DstRect
, Flags
, FX
);
3094 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3096 TRACE("(%p): Not an overlay surface\n", This
);
3097 return DDERR_NOTAOVERLAYSURFACE
;
3103 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl
=
3106 IWineD3DSurfaceImpl_QueryInterface
,
3107 IWineD3DSurfaceImpl_AddRef
,
3108 IWineD3DSurfaceImpl_Release
,
3109 /* IWineD3DResource */
3110 IWineD3DSurfaceImpl_GetParent
,
3111 IWineD3DSurfaceImpl_GetDevice
,
3112 IWineD3DSurfaceImpl_SetPrivateData
,
3113 IWineD3DSurfaceImpl_GetPrivateData
,
3114 IWineD3DSurfaceImpl_FreePrivateData
,
3115 IWineD3DSurfaceImpl_SetPriority
,
3116 IWineD3DSurfaceImpl_GetPriority
,
3117 IWineD3DSurfaceImpl_PreLoad
,
3118 IWineD3DSurfaceImpl_GetType
,
3119 /* IWineD3DSurface */
3120 IWineD3DSurfaceImpl_GetContainer
,
3121 IWineD3DSurfaceImpl_GetDesc
,
3122 IWineD3DSurfaceImpl_LockRect
,
3123 IWineD3DSurfaceImpl_UnlockRect
,
3124 IWineD3DSurfaceImpl_GetDC
,
3125 IWineD3DSurfaceImpl_ReleaseDC
,
3126 IWineD3DSurfaceImpl_Flip
,
3127 IWineD3DSurfaceImpl_Blt
,
3128 IWineD3DSurfaceImpl_GetBltStatus
,
3129 IWineD3DSurfaceImpl_GetFlipStatus
,
3130 IWineD3DSurfaceImpl_IsLost
,
3131 IWineD3DSurfaceImpl_Restore
,
3132 IWineD3DSurfaceImpl_BltFast
,
3133 IWineD3DSurfaceImpl_GetPalette
,
3134 IWineD3DSurfaceImpl_SetPalette
,
3135 IWineD3DSurfaceImpl_RealizePalette
,
3136 IWineD3DSurfaceImpl_SetColorKey
,
3137 IWineD3DSurfaceImpl_GetPitch
,
3138 IWineD3DSurfaceImpl_SetMem
,
3139 IWineD3DSurfaceImpl_SetOverlayPosition
,
3140 IWineD3DSurfaceImpl_GetOverlayPosition
,
3141 IWineD3DSurfaceImpl_UpdateOverlayZOrder
,
3142 IWineD3DSurfaceImpl_UpdateOverlay
,
3144 IWineD3DSurfaceImpl_CleanDirtyRect
,
3145 IWineD3DSurfaceImpl_AddDirtyRect
,
3146 IWineD3DSurfaceImpl_LoadTexture
,
3147 IWineD3DSurfaceImpl_SaveSnapshot
,
3148 IWineD3DSurfaceImpl_SetContainer
,
3149 IWineD3DSurfaceImpl_SetPBufferState
,
3150 IWineD3DSurfaceImpl_SetGlTextureDesc
,
3151 IWineD3DSurfaceImpl_GetGlDesc
,
3152 IWineD3DSurfaceImpl_GetData
,
3153 IWineD3DSurfaceImpl_SetFormat
,
3154 IWineD3DSurfaceImpl_PrivateSetup