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 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 ERR("Probably FIXME: Calling query interface with NULL riid\n");
194 if (IsEqualGUID(riid
, &IID_IUnknown
)
195 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
196 || IsEqualGUID(riid
, &IID_IWineD3DResource
)
197 || IsEqualGUID(riid
, &IID_IWineD3DSurface
)) {
198 IUnknown_AddRef((IUnknown
*)iface
);
203 return E_NOINTERFACE
;
206 ULONG WINAPI
IWineD3DSurfaceImpl_AddRef(IWineD3DSurface
*iface
) {
207 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
208 ULONG ref
= InterlockedIncrement(&This
->resource
.ref
);
209 TRACE("(%p) : AddRef increasing from %d\n", This
,ref
- 1);
213 ULONG WINAPI
IWineD3DSurfaceImpl_Release(IWineD3DSurface
*iface
) {
214 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
215 ULONG ref
= InterlockedDecrement(&This
->resource
.ref
);
216 TRACE("(%p) : Releasing from %d\n", This
, ref
+ 1);
218 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*) This
->resource
.wineD3DDevice
;
219 TRACE("(%p) : cleaning up\n", This
);
220 if (This
->glDescription
.textureName
!= 0) { /* release the openGL texture.. */
222 TRACE("Deleting texture %d\n", This
->glDescription
.textureName
);
223 glDeleteTextures(1, &This
->glDescription
.textureName
);
227 if(This
->Flags
& SFLAG_DIBSECTION
) {
229 SelectObject(This
->hDC
, This
->dib
.holdbitmap
);
231 /* Release the DIB section */
232 DeleteObject(This
->dib
.DIBsection
);
233 This
->dib
.bitmap_data
= NULL
;
234 This
->resource
.allocatedMemory
= NULL
;
236 if(This
->Flags
& SFLAG_USERPTR
) IWineD3DSurface_SetMem(iface
, NULL
);
238 IWineD3DResourceImpl_CleanUp((IWineD3DResource
*)iface
);
239 if(iface
== device
->ddraw_primary
)
240 device
->ddraw_primary
= NULL
;
242 TRACE("(%p) Released\n", This
);
243 HeapFree(GetProcessHeap(), 0, This
);
249 /* ****************************************************
250 IWineD3DSurface IWineD3DResource parts follow
251 **************************************************** */
252 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface
*iface
, IWineD3DDevice
** ppDevice
) {
253 return IWineD3DResourceImpl_GetDevice((IWineD3DResource
*)iface
, ppDevice
);
256 HRESULT WINAPI
IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface
*iface
, REFGUID refguid
, CONST
void* pData
, DWORD SizeOfData
, DWORD Flags
) {
257 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource
*)iface
, refguid
, pData
, SizeOfData
, Flags
);
260 HRESULT WINAPI
IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface
*iface
, REFGUID refguid
, void* pData
, DWORD
* pSizeOfData
) {
261 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource
*)iface
, refguid
, pData
, pSizeOfData
);
264 HRESULT WINAPI
IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface
*iface
, REFGUID refguid
) {
265 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource
*)iface
, refguid
);
268 DWORD WINAPI
IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface
*iface
, DWORD PriorityNew
) {
269 return IWineD3DResourceImpl_SetPriority((IWineD3DResource
*)iface
, PriorityNew
);
272 DWORD WINAPI
IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface
*iface
) {
273 return IWineD3DResourceImpl_GetPriority((IWineD3DResource
*)iface
);
276 void WINAPI
IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface
*iface
) {
277 /* TODO: re-write the way textures and managed,
278 * use a 'opengl context manager' to manage RenderTarget surfaces
279 ** *********************************************************/
281 /* TODO: check for locks */
282 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
283 IWineD3DBaseTexture
*baseTexture
= NULL
;
284 TRACE("(%p)Checking to see if the container is a base texture\n", This
);
285 if (IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
) == WINED3D_OK
) {
286 TRACE("Passing to conatiner\n");
287 IWineD3DBaseTexture_PreLoad(baseTexture
);
288 IWineD3DBaseTexture_Release(baseTexture
);
290 TRACE("(%p) : About to load surface\n", This
);
292 #if 0 /* TODO: context manager support */
293 IWineD3DContextManager_PushState(This
->contextManager
, GL_TEXTURE_2D
, ENABLED
, NOW
/* make sure the state is applied now */);
295 glEnable(This
->glDescription
.target
);/* make sure texture support is enabled in this context */
296 if (!This
->glDescription
.level
) {
297 if (!This
->glDescription
.textureName
) {
298 glGenTextures(1, &This
->glDescription
.textureName
);
299 checkGLcall("glGenTextures");
300 TRACE("Surface %p given name %d\n", This
, This
->glDescription
.textureName
);
302 glBindTexture(This
->glDescription
.target
, This
->glDescription
.textureName
);
303 checkGLcall("glBindTexture");
304 IWineD3DSurface_LoadTexture(iface
);
305 /* This is where we should be reducing the amount of GLMemoryUsed */
306 } else if (This
->glDescription
.textureName
) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
307 /* assume this is a coding error not a real error for now */
308 FIXME("Mipmap surface has a glTexture bound to it!\n");
310 if (This
->resource
.pool
== WINED3DPOOL_DEFAULT
) {
311 /* Tell opengl to try and keep this texture in video ram (well mostly) */
314 glPrioritizeTextures(1, &This
->glDescription
.textureName
, &tmp
);
316 /* TODO: disable texture support, if it wastn't enabled when we entered. */
317 #if 0 /* TODO: context manager support */
318 IWineD3DContextManager_PopState(This
->contextManager
, GL_TEXTURE_2D
, DISABLED
,DELAYED
319 /* we don't care when the state is disabled(if atall) */);
326 WINED3DRESOURCETYPE WINAPI
IWineD3DSurfaceImpl_GetType(IWineD3DSurface
*iface
) {
327 TRACE("(%p) : calling resourceimpl_GetType\n", iface
);
328 return IWineD3DResourceImpl_GetType((IWineD3DResource
*)iface
);
331 HRESULT WINAPI
IWineD3DSurfaceImpl_GetParent(IWineD3DSurface
*iface
, IUnknown
**pParent
) {
332 TRACE("(%p) : calling resourceimpl_GetParent\n", iface
);
333 return IWineD3DResourceImpl_GetParent((IWineD3DResource
*)iface
, pParent
);
336 /* ******************************************************
337 IWineD3DSurface IWineD3DSurface parts follow
338 ****************************************************** */
340 HRESULT WINAPI
IWineD3DSurfaceImpl_GetContainerParent(IWineD3DSurface
* iface
, IUnknown
**ppContainerParent
) {
341 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
343 TRACE("(%p) : ppContainerParent %p)\n", This
, ppContainerParent
);
345 if (!ppContainerParent
) {
346 ERR("(%p) : Called without a valid ppContainerParent.\n", This
);
349 if (This
->container
) {
350 IWineD3DBase_GetParent(This
->container
, ppContainerParent
);
351 if (!ppContainerParent
) {
352 /* WineD3D objects should always have a parent */
353 ERR("(%p) : GetParent returned NULL\n", This
);
355 IUnknown_Release(*ppContainerParent
); /* GetParent adds a reference; we want just the pointer */
357 *ppContainerParent
= NULL
;
363 HRESULT WINAPI
IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface
* iface
, REFIID riid
, void** ppContainer
) {
364 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
365 IWineD3DBase
*container
= 0;
367 TRACE("(This %p, riid %s, ppContainer %p)\n", This
, debugstr_guid(riid
), ppContainer
);
370 ERR("Called without a valid ppContainer.\n");
374 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
375 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
376 * GetContainer will return the Direct3D device used to create the surface.
378 if (This
->container
) {
379 container
= This
->container
;
381 container
= (IWineD3DBase
*)This
->resource
.wineD3DDevice
;
384 TRACE("Relaying to QueryInterface\n");
385 return IUnknown_QueryInterface(container
, riid
, ppContainer
);
388 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface
*iface
, WINED3DSURFACE_DESC
*pDesc
) {
389 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
391 TRACE("(%p) : copying into %p\n", This
, pDesc
);
392 if(pDesc
->Format
!= NULL
) *(pDesc
->Format
) = This
->resource
.format
;
393 if(pDesc
->Type
!= NULL
) *(pDesc
->Type
) = This
->resource
.resourceType
;
394 if(pDesc
->Usage
!= NULL
) *(pDesc
->Usage
) = This
->resource
.usage
;
395 if(pDesc
->Pool
!= NULL
) *(pDesc
->Pool
) = This
->resource
.pool
;
396 if(pDesc
->Size
!= NULL
) *(pDesc
->Size
) = This
->resource
.size
; /* dx8 only */
397 if(pDesc
->MultiSampleType
!= NULL
) *(pDesc
->MultiSampleType
) = This
->currentDesc
.MultiSampleType
;
398 if(pDesc
->MultiSampleQuality
!= NULL
) *(pDesc
->MultiSampleQuality
) = This
->currentDesc
.MultiSampleQuality
;
399 if(pDesc
->Width
!= NULL
) *(pDesc
->Width
) = This
->currentDesc
.Width
;
400 if(pDesc
->Height
!= NULL
) *(pDesc
->Height
) = This
->currentDesc
.Height
;
404 void WINAPI
IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface
*iface
, UINT textureName
, int target
) {
405 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
406 TRACE("(%p) : setting textureName %u, target %i\n", This
, textureName
, target
);
407 if (This
->glDescription
.textureName
== 0 && textureName
!= 0) {
408 This
->Flags
|= SFLAG_DIRTY
;
409 IWineD3DSurface_AddDirtyRect(iface
, NULL
);
411 This
->glDescription
.textureName
= textureName
;
412 This
->glDescription
.target
= target
;
415 void WINAPI
IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface
*iface
, glDescriptor
**glDescription
) {
416 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
417 TRACE("(%p) : returning %p\n", This
, &This
->glDescription
);
418 *glDescription
= &This
->glDescription
;
421 /* TODO: think about moving this down to resource? */
422 const void *WINAPI
IWineD3DSurfaceImpl_GetData(IWineD3DSurface
*iface
) {
423 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
424 /* 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 */
425 if (This
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
426 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface
);
428 return (CONST
void*)(This
->resource
.allocatedMemory
);
431 static void read_from_framebuffer(IWineD3DSurfaceImpl
*This
, CONST RECT
*rect
, void *dest
, UINT pitch
) {
437 switch(This
->resource
.format
)
441 /* GL can't return palettized data, so read ARGB pixels into a
442 * separate block of memory and convert them into palettized format
443 * in software. Slow, but if the app means to use palettized render
444 * targets and locks it...
446 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
447 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
448 * for the color channels when palettizing the colors.
451 type
= GL_UNSIGNED_BYTE
;
453 mem
= HeapAlloc(GetProcessHeap(), 0, (rect
->bottom
- rect
->top
) * pitch
);
455 ERR("Out of memory\n");
463 fmt
= This
->glDescription
.glFormat
;
464 type
= This
->glDescription
.glType
;
467 if (rect
->left
== 0 &&
468 rect
->right
== This
->currentDesc
.Width
) {
469 BYTE
*row
, *top
, *bottom
;
472 glReadPixels(0, rect
->top
,
473 This
->currentDesc
.Width
,
474 rect
->bottom
- rect
->top
,
479 /* glReadPixels returns the image upside down, and there is no way to prevent this.
480 Flip the lines in software */
481 row
= HeapAlloc(GetProcessHeap(), 0, pitch
);
483 ERR("Out of memory\n");
487 bottom
= ((BYTE
*) mem
) + pitch
* ( rect
->bottom
- rect
->top
- 1);
488 for(i
= 0; i
< (rect
->bottom
- rect
->top
) / 2; i
++) {
489 memcpy(row
, top
, pitch
);
490 memcpy(top
, bottom
, pitch
);
491 memcpy(bottom
, row
, pitch
);
495 HeapFree(GetProcessHeap(), 0, row
);
497 if(This
->lockedRect
.top
== 0 && This
->lockedRect
.bottom
== This
->currentDesc
.Height
) {
498 This
->Flags
&= ~SFLAG_GLDIRTY
;
501 for (j
= This
->lockedRect
.top
; j
< This
->lockedRect
.bottom
- This
->lockedRect
.top
; ++j
) {
502 glReadPixels(rect
->left
,
503 rect
->bottom
- j
- 1,
504 rect
->right
- rect
->left
,
508 (char *)mem
+ (pitch
* (j
-rect
->top
)));
512 vcheckGLcall("glReadPixels");
514 if(This
->resource
.format
== WINED3DFMT_P8
) {
516 DWORD width
= pitch
/ 3;
519 pal
= This
->palette
->palents
;
521 pal
= This
->resource
.wineD3DDevice
->palettes
[This
->resource
.wineD3DDevice
->currentPalette
];
524 for(y
= rect
->top
; y
< rect
->bottom
; y
++) {
525 for(x
= rect
->left
; x
< rect
->right
; x
++) {
526 /* start lines pixels */
527 BYTE
*blue
= (BYTE
*) ((BYTE
*) mem
) + y
* pitch
+ x
* (sizeof(BYTE
) * 3);
528 BYTE
*green
= blue
+ 1;
529 BYTE
*red
= green
+ 1;
531 for(c
= 0; c
< 256; c
++) {
532 if(*red
== pal
[c
].peRed
&&
533 *green
== pal
[c
].peGreen
&&
534 *blue
== pal
[c
].peBlue
)
536 *((BYTE
*) dest
+ y
* width
+ x
) = c
;
542 HeapFree(GetProcessHeap(), 0, mem
);
546 static HRESULT WINAPI
IWineD3DSurfaceImpl_LockRect(IWineD3DSurface
*iface
, WINED3DLOCKED_RECT
* pLockedRect
, CONST RECT
* pRect
, DWORD Flags
) {
547 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
548 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
549 IWineD3DSwapChainImpl
*swapchain
= NULL
;
550 static UINT messages
= 0; /* holds flags to disable fixme messages */
551 BOOL backbuf
= FALSE
;
553 /* fixme: should we really lock as such? */
554 if((This
->Flags
& (SFLAG_INTEXTURE
| SFLAG_INPBUFFER
)) ==
555 (SFLAG_INTEXTURE
| SFLAG_INPBUFFER
) ) {
556 FIXME("Warning: Surface is in texture memory or pbuffer\n");
557 This
->Flags
&= ~(SFLAG_INTEXTURE
| SFLAG_INPBUFFER
);
560 if (!(This
->Flags
& SFLAG_LOCKABLE
)) {
561 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
562 texture regions, and since the destination is an unlockable region we need
564 TRACE("Warning: trying to lock unlockable surf@%p\n", This
);
565 /*return WINED3DERR_INVALIDCALL; */
568 if (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
569 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
571 if (swapchain
!= NULL
|| iface
== myDevice
->renderTarget
|| iface
== myDevice
->depthStencilBuffer
) {
572 if(swapchain
!= NULL
) {
574 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
575 if(iface
== swapchain
->backBuffer
[i
]) {
582 TRACE("(%p, backBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
583 } else if (swapchain
!= NULL
&& iface
== swapchain
->frontBuffer
) {
584 TRACE("(%p, frontBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
585 } else if (iface
== myDevice
->renderTarget
) {
586 TRACE("(%p, renderTarget) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
587 } else if (iface
== myDevice
->depthStencilBuffer
) {
588 TRACE("(%p, stencilBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
591 if (NULL
!= swapchain
) {
592 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
597 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
600 pLockedRect
->Pitch
= IWineD3DSurface_GetPitch(iface
);
603 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
604 This
->lockedRect
.left
= 0;
605 This
->lockedRect
.top
= 0;
606 This
->lockedRect
.right
= This
->currentDesc
.Width
;
607 This
->lockedRect
.bottom
= This
->currentDesc
.Height
;
608 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
);
610 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
612 if ((pRect
->top
< 0) ||
614 (pRect
->left
>= pRect
->right
) ||
615 (pRect
->top
>= pRect
->bottom
) ||
616 (pRect
->right
> This
->currentDesc
.Width
) ||
617 (pRect
->bottom
> This
->currentDesc
.Height
))
619 WARN(" Invalid values in pRect !!!\n");
620 return D3DERR_INVALIDCALL
;
623 if (This
->resource
.format
== WINED3DFMT_DXT1
) { /* DXT1 is half byte per pixel */
624 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + ((pRect
->left
* This
->bytesPerPixel
/ 2));
626 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + (pRect
->left
* This
->bytesPerPixel
);
628 This
->lockedRect
.left
= pRect
->left
;
629 This
->lockedRect
.top
= pRect
->top
;
630 This
->lockedRect
.right
= pRect
->right
;
631 This
->lockedRect
.bottom
= pRect
->bottom
;
634 if (This
->Flags
& SFLAG_NONPOW2
) {
635 TRACE("Locking non-power 2 texture\n");
638 if (0 == This
->resource
.usage
|| This
->resource
.usage
& WINED3DUSAGE_DYNAMIC
) {
639 /* classic surface TODO: non 2d surfaces?
640 These resources may be POOL_SYSTEMMEM, so they must not access the device */
641 TRACE("locking an ordinarary surface\n");
642 /* Check to see if memory has already been allocated from the surface*/
643 if ((NULL
== This
->resource
.allocatedMemory
) ||
644 (This
->Flags
& SFLAG_GLDIRTY
) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
645 /* Non-system memory surfaces */
647 This
->Flags
&= ~SFLAG_GLDIRTY
;
649 /*Surface has no memory currently allocated to it!*/
650 TRACE("(%p) Locking rect\n" , This
);
651 if(!This
->resource
.allocatedMemory
) {
652 This
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap() ,0 , This
->pow2Size
);
654 if (0 != This
->glDescription
.textureName
) {
655 /* Now I have to copy thing bits back */
656 This
->Flags
|= SFLAG_ACTIVELOCK
; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
657 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
659 /* Make sure that the texture is loaded */
660 IWineD3DSurface_PreLoad(iface
); /* Make sure there is a texture to bind! */
662 surface_download_data(This
);
664 } else { /* Nothing to do */
665 TRACE("Memory %p already allocted for texture\n", This
->resource
.allocatedMemory
);
669 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
671 if (This
->resource
.format
== WINED3DFMT_DXT1
) { /* DXT1 is half byte per pixel */
672 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + ((pRect
->left
* This
->bytesPerPixel
/ 2));
674 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + (pRect
->left
* This
->bytesPerPixel
);
678 } else if (WINED3DUSAGE_RENDERTARGET
& This
->resource
.usage
){ /* render surfaces */
679 if((!(Flags
&WINED3DLOCK_DISCARD
) && (This
->Flags
& SFLAG_GLDIRTY
)) || !This
->resource
.allocatedMemory
) {
682 BOOL notInContext
= FALSE
;
683 IWineD3DSwapChainImpl
*targetSwapChain
= NULL
;
689 * for render->surface copy begin to begin of allocatedMemory
690 * unlock can be more easy
693 TRACE("locking a render target\n");
695 if (This
->resource
.allocatedMemory
== NULL
)
696 This
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap() ,0 ,This
->resource
.size
);
698 This
->Flags
|= SFLAG_ACTIVELOCK
; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
699 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
702 vcheckGLcall("glFlush");
703 glGetIntegerv(GL_READ_BUFFER
, &prev_read
);
704 vcheckGLcall("glIntegerv");
705 glGetIntegerv(GL_PACK_SWAP_BYTES
, &prev_store
);
706 vcheckGLcall("glIntegerv");
708 /* Here's what we have to do:
709 See if the swapchain has the same context as the renderTarget or the surface is the render target.
710 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
711 and use the front back buffer as required.
712 if not, we need to switch contexts and then switchback at the end.
714 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
715 IWineD3DSurface_GetContainer(myDevice
->renderTarget
, &IID_IWineD3DSwapChain
, (void **)&targetSwapChain
);
717 /* 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! */
718 if ((swapchain
== targetSwapChain
&& targetSwapChain
!= NULL
) || iface
== myDevice
->renderTarget
) {
719 if (swapchain
&& iface
== swapchain
->frontBuffer
) {
720 TRACE("locking front\n");
721 glReadBuffer(GL_FRONT
);
723 else if (iface
== myDevice
->renderTarget
|| backbuf
) {
724 TRACE("locking back buffer\n");
725 glReadBuffer(GL_BACK
);
726 } else if (iface
== myDevice
->depthStencilBuffer
) {
727 FIXME("Stencil Buffer lock unsupported for now\n");
729 FIXME("(%p) Shouldn't have got here!\n", This
);
730 glReadBuffer(GL_BACK
);
732 } else if (swapchain
!= NULL
) {
733 IWineD3DSwapChainImpl
*implSwapChain
;
734 IWineD3DDevice_GetSwapChain((IWineD3DDevice
*)myDevice
, 0, (IWineD3DSwapChain
**)&implSwapChain
);
735 if (swapchain
->glCtx
== implSwapChain
->render_ctx
&& swapchain
->drawable
== implSwapChain
->win
) {
736 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
738 glReadBuffer(GL_BACK
);
739 } else if (iface
== swapchain
->frontBuffer
) {
740 glReadBuffer(GL_FRONT
);
741 } else if (iface
== myDevice
->depthStencilBuffer
) {
742 FIXME("Stencil Buffer lock unsupported for now\n");
744 FIXME("Should have got here!\n");
745 glReadBuffer(GL_BACK
);
748 /* We need to switch contexts to be able to read the buffer!!! */
749 FIXME("The buffer requested isn't in the current openGL context\n");
751 /* TODO: check the contexts, to see if were shared with the current context */
753 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)implSwapChain
);
755 if (swapchain
!= NULL
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
756 if (targetSwapChain
!= NULL
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*)targetSwapChain
);
758 /** the depth stencil in openGL has a format of GL_FLOAT
759 * which should be good for WINED3DFMT_D16_LOCKABLE
761 * it is unclear what format the stencil buffer is in except.
762 * 'Each index is converted to fixed point...
763 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
764 * mappings in the table GL_PIXEL_MAP_S_TO_S.
765 * glReadPixels(This->lockedRect.left,
766 * This->lockedRect.bottom - j - 1,
767 * This->lockedRect.right - This->lockedRect.left,
769 * GL_DEPTH_COMPONENT,
771 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
772 *****************************************/
773 if (!notInContext
) { /* Only read the buffer if it's in the current context */
774 switch(wined3d_settings
.rendertargetlock_mode
) {
778 read_from_framebuffer(This
, &This
->lockedRect
, pLockedRect
->pBits
, pLockedRect
->Pitch
);
783 read_from_framebuffer(This
, &This
->lockedRect
, pLockedRect
->pBits
, pLockedRect
->Pitch
);
784 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
789 static BOOL warned
= FALSE
;
791 ERR("Application tries to lock the render target, but render target locking is disabled\n");
798 TRACE("Resetting buffer\n");
800 glReadBuffer(prev_read
);
801 vcheckGLcall("glReadBuffer");
805 } else if (WINED3DUSAGE_DEPTHSTENCIL
& This
->resource
.usage
) { /* stencil surfaces */
808 FIXME("TODO stencil depth surface locking surf%p usage(%s)\n", This
, debug_d3dusage(This
->resource
.usage
));
811 glReadPixels(This->lockedRect.left,
812 This->lockedRect.bottom - j - 1,
813 This->lockedRect.right - This->lockedRect.left,
815 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
822 FIXME("unsupported locking to surface surf@%p usage(%s)\n", This
, debug_d3dusage(This
->resource
.usage
));
825 if (Flags
& (WINED3DLOCK_NO_DIRTY_UPDATE
| WINED3DLOCK_READONLY
)) {
828 IWineD3DBaseTexture
*pBaseTexture
;
831 * as seen in msdn docs
833 IWineD3DSurface_AddDirtyRect(iface
, &This
->lockedRect
);
835 /** Dirtify Container if needed */
836 if (WINED3D_OK
== IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&pBaseTexture
) && pBaseTexture
!= NULL
) {
837 TRACE("Making container dirty\n");
838 IWineD3DBaseTexture_SetDirty(pBaseTexture
, TRUE
);
839 IWineD3DBaseTexture_Release(pBaseTexture
);
841 TRACE("Surface is standalone, no need to dirty the container\n");
845 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect
->pBits
, pLockedRect
->Pitch
, This
->Flags
& SFLAG_DIRTY
? 0 : 1);
847 This
->Flags
|= SFLAG_LOCKED
;
851 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl
*This
) {
853 GLint prev_rasterpos
[4];
855 BOOL storechanged
= FALSE
;
859 glDisable(GL_TEXTURE_2D
);
860 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
861 glDisable(GL_TEXTURE_1D
);
862 vcheckGLcall("glDisable(GL_TEXTURE_1D)");
865 vcheckGLcall("glFlush");
866 glGetIntegerv(GL_PACK_SWAP_BYTES
, &prev_store
);
867 vcheckGLcall("glIntegerv");
868 glGetIntegerv(GL_CURRENT_RASTER_POSITION
, &prev_rasterpos
[0]);
869 vcheckGLcall("glIntegerv");
870 glPixelZoom(1.0, -1.0);
871 vcheckGLcall("glPixelZoom");
873 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
874 glGetIntegerv(GL_UNPACK_ROW_LENGTH
, &skipBytes
);
875 glPixelStorei(GL_UNPACK_ROW_LENGTH
, This
->currentDesc
.Width
);
877 glRasterPos3i(This
->lockedRect
.left
, This
->lockedRect
.top
, 1);
878 vcheckGLcall("glRasterPos2f");
880 /* Some drivers(radeon dri, others?) don't like exceptions during
881 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
882 * after ReleaseDC. Reading it will cause an exception, which x11drv will
883 * catch to put the dib section in InSync mode, which leads to a crash
884 * and a blocked x server on my radeon card.
886 * The following lines read the dib section so it is put in inSync mode
887 * before glDrawPixels is called and the crash is prevented. There won't
888 * be any interfering gdi accesses, because UnlockRect is called from
889 * ReleaseDC, and the app won't use the dc any more afterwards.
891 if(This
->Flags
& SFLAG_DIBSECTION
) {
893 read
= This
->resource
.allocatedMemory
[0];
896 switch (This
->resource
.format
) {
897 /* No special care needed */
898 case WINED3DFMT_A4R4G4B4
:
899 case WINED3DFMT_R5G6B5
:
900 case WINED3DFMT_A1R5G5B5
:
901 case WINED3DFMT_R8G8B8
:
902 type
= This
->glDescription
.glType
;
903 fmt
= This
->glDescription
.glFormat
;
904 mem
= This
->resource
.allocatedMemory
;
907 case WINED3DFMT_X4R4G4B4
:
910 unsigned short *data
;
911 data
= (unsigned short *)This
->resource
.allocatedMemory
;
912 size
= (This
->lockedRect
.bottom
- This
->lockedRect
.top
) * (This
->lockedRect
.right
- This
->lockedRect
.left
);
918 type
= This
->glDescription
.glType
;
919 fmt
= This
->glDescription
.glFormat
;
920 mem
= This
->resource
.allocatedMemory
;
924 case WINED3DFMT_X1R5G5B5
:
927 unsigned short *data
;
928 data
= (unsigned short *)This
->resource
.allocatedMemory
;
929 size
= (This
->lockedRect
.bottom
- This
->lockedRect
.top
) * (This
->lockedRect
.right
- This
->lockedRect
.left
);
935 type
= This
->glDescription
.glType
;
936 fmt
= This
->glDescription
.glFormat
;
937 mem
= This
->resource
.allocatedMemory
;
941 case WINED3DFMT_X8R8G8B8
:
943 /* make sure the X byte is set to alpha on, since it
944 could be any random value. This fixes the intro movie in Pirates! */
947 data
= (unsigned int *)This
->resource
.allocatedMemory
;
948 size
= (This
->lockedRect
.bottom
- This
->lockedRect
.top
) * (This
->lockedRect
.right
- This
->lockedRect
.left
);
957 case WINED3DFMT_A8R8G8B8
:
959 glPixelStorei(GL_PACK_SWAP_BYTES
, TRUE
);
960 vcheckGLcall("glPixelStorei");
962 type
= This
->glDescription
.glType
;
963 fmt
= This
->glDescription
.glFormat
;
964 mem
= This
->resource
.allocatedMemory
;
968 case WINED3DFMT_A2R10G10B10
:
970 glPixelStorei(GL_PACK_SWAP_BYTES
, TRUE
);
971 vcheckGLcall("glPixelStorei");
973 type
= This
->glDescription
.glType
;
974 fmt
= This
->glDescription
.glFormat
;
975 mem
= This
->resource
.allocatedMemory
;
981 UINT pitch
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) This
); /* target is argb, 4 byte */
982 int height
= This
->glRect
.bottom
- This
->glRect
.top
;
983 type
= GL_UNSIGNED_BYTE
;
986 mem
= HeapAlloc(GetProcessHeap(), 0, This
->resource
.size
* sizeof(DWORD
));
988 ERR("Out of memory\n");
991 d3dfmt_convert_surface(This
->resource
.allocatedMemory
,
1002 FIXME("Unsupported Format %u in locking func\n", This
->resource
.format
);
1005 type
= This
->glDescription
.glType
;
1006 fmt
= This
->glDescription
.glFormat
;
1007 mem
= This
->resource
.allocatedMemory
;
1010 glDrawPixels(This
->lockedRect
.right
- This
->lockedRect
.left
,
1011 (This
->lockedRect
.bottom
- This
->lockedRect
.top
)-1,
1014 checkGLcall("glDrawPixels");
1015 glPixelZoom(1.0,1.0);
1016 vcheckGLcall("glPixelZoom");
1018 glRasterPos3iv(&prev_rasterpos
[0]);
1019 vcheckGLcall("glRasterPos3iv");
1021 /* Reset to previous pack row length */
1022 glPixelStorei(GL_UNPACK_ROW_LENGTH
, skipBytes
);
1023 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1025 glPixelStorei(GL_PACK_SWAP_BYTES
, prev_store
);
1026 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1029 if(mem
!= This
->resource
.allocatedMemory
) HeapFree(GetProcessHeap(), 0, mem
);
1033 static void flush_to_framebuffer_texture(IWineD3DSurface
*iface
) {
1034 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1035 float glTexCoord
[4];
1037 glTexCoord
[0] = 0.0; /* left */
1038 glTexCoord
[1] = (float) This
->currentDesc
.Width
/ (float) This
->pow2Width
; /* right */
1039 glTexCoord
[2] = 0.0; /* top */
1040 glTexCoord
[3] = (float) This
->currentDesc
.Height
/ (float) This
->pow2Height
; /* bottom */
1042 IWineD3DSurface_PreLoad(iface
);
1046 /* Disable some fancy graphics effects */
1047 glDisable(GL_LIGHTING
);
1048 checkGLcall("glDisable GL_LIGHTING");
1049 glDisable(GL_DEPTH_TEST
);
1050 checkGLcall("glDisable GL_DEPTH_TEST");
1052 checkGLcall("glDisable GL_FOG");
1053 glDisable(GL_CULL_FACE
);
1054 checkGLcall("glDisable GL_CULL_FACE");
1055 glDisable(GL_BLEND
);
1056 checkGLcall("glDisable GL_BLEND");
1057 glDisable(GL_STENCIL_TEST
);
1058 checkGLcall("glDisable GL_STENCIL_TEST");
1060 glEnable(GL_TEXTURE_2D
);
1061 glBindTexture(GL_TEXTURE_2D
, This
->glDescription
.textureName
);
1062 checkGLcall("glEnable glBindTexture");
1064 /* No filtering for blts */
1065 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
1066 checkGLcall("glTexParameteri");
1067 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
1068 checkGLcall("glTexParameteri");
1070 /* Start drawing a quad */
1073 glColor3d(1.0f
, 1.0f
, 1.0f
);
1074 glTexCoord2f(glTexCoord
[0], glTexCoord
[2]);
1075 glVertex3f(0, 0, 0.0);
1077 glTexCoord2f(glTexCoord
[0], glTexCoord
[3]);
1078 glVertex3f(0, This
->currentDesc
.Height
, 0.0);
1080 glTexCoord2f(glTexCoord
[1], glTexCoord
[3]);
1081 glVertex3d(This
->currentDesc
.Width
, This
->currentDesc
.Height
, 0.0);
1083 glTexCoord2f(glTexCoord
[1], glTexCoord
[2]);
1084 glVertex3f(This
->currentDesc
.Width
, 0, 0.0);
1087 checkGLcall("glEnd");
1089 /* Unbind the texture */
1090 glBindTexture(GL_TEXTURE_2D
, 0);
1091 checkGLcall("glEnable glBindTexture");
1096 static HRESULT WINAPI
IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface
*iface
) {
1097 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1098 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
1099 const char *buffername
= "";
1100 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1101 BOOL backbuf
= FALSE
;
1103 if (!(This
->Flags
& SFLAG_LOCKED
)) {
1104 WARN("trying to Unlock an unlocked surf@%p\n", This
);
1105 return WINED3DERR_INVALIDCALL
;
1108 if (WINED3DUSAGE_RENDERTARGET
& This
->resource
.usage
) {
1109 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
1113 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
1114 if(iface
== swapchain
->backBuffer
[i
]) {
1122 buffername
= "backBuffer";
1123 } else if ((swapchain
!= NULL
) && iface
== swapchain
->frontBuffer
) {
1124 buffername
= "frontBuffer";
1125 } else if (iface
== myDevice
->depthStencilBuffer
) {
1126 buffername
= "depthStencilBuffer";
1127 } else if (iface
== myDevice
->renderTarget
) {
1128 buffername
= "renderTarget";
1132 if (swapchain
!= NULL
) {
1133 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
1136 TRACE("(%p %s) : dirtyfied(%d)\n", This
, buffername
, This
->Flags
& SFLAG_DIRTY
? 1 : 0);
1138 if (!(This
->Flags
& SFLAG_DIRTY
)) {
1139 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This
);
1143 if (0 == This
->resource
.usage
) { /* classic surface */
1146 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
1148 } else if (WINED3DUSAGE_RENDERTARGET
& This
->resource
.usage
) { /* render surfaces */
1150 /****************************
1151 * TODO: Render targets are 'special' and
1152 * ?some? locking needs to be passed onto the context manager
1153 * so that it becomes possible to use auxiliary buffers, pbuffers
1154 * render-to-texture, shared, cached contexts etc...
1155 * ****************************/
1156 IWineD3DSwapChainImpl
*implSwapChain
;
1157 IWineD3DDevice_GetSwapChain((IWineD3DDevice
*)myDevice
, 0, (IWineD3DSwapChain
**)&implSwapChain
);
1159 if (backbuf
|| iface
== implSwapChain
->frontBuffer
|| iface
== myDevice
->renderTarget
) {
1164 /* glDrawPixels transforms the raster position as though it was a vertex -
1165 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1166 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1167 d3ddevice_set_ortho(This
->resource
.wineD3DDevice
);
1169 if (iface
== implSwapChain
->frontBuffer
) {
1170 glDrawBuffer(GL_FRONT
);
1171 checkGLcall("glDrawBuffer GL_FRONT");
1172 } else if (backbuf
|| iface
== myDevice
->renderTarget
) {
1173 glDrawBuffer(GL_BACK
);
1174 checkGLcall("glDrawBuffer GL_BACK");
1177 /* Disable higher textures before calling glDrawPixels */
1178 for(tex
= 1; tex
< GL_LIMITS(samplers
); tex
++) {
1179 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
1180 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ tex
));
1181 checkGLcall("glActiveTextureARB");
1183 glDisable(GL_TEXTURE_2D
);
1184 checkGLcall("glDisable GL_TEXTURE_2D");
1185 glDisable(GL_TEXTURE_1D
);
1186 checkGLcall("glDisable GL_TEXTURE_1D");
1188 /* Activate texture 0, but don't disable it necessarilly */
1189 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
1190 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
1191 checkGLcall("glActiveTextureARB");
1194 /* And back buffers are not blended. Disable the depth test,
1195 that helps performance */
1196 glDisable(GL_BLEND
);
1197 glDisable(GL_DEPTH_TEST
);
1200 switch(wined3d_settings
.rendertargetlock_mode
) {
1204 flush_to_framebuffer_drawpixels(This
);
1209 flush_to_framebuffer_texture(iface
);
1214 static BOOL warned
= FALSE
;
1216 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1223 if(implSwapChain
->backBuffer
&& implSwapChain
->backBuffer
[0]) {
1224 glDrawBuffer(GL_BACK
);
1225 vcheckGLcall("glDrawBuffer");
1227 if(myDevice
->stateBlock
->renderState
[WINED3DRS_ZENABLE
] == WINED3DZB_TRUE
||
1228 myDevice
->stateBlock
->renderState
[WINED3DRS_ZENABLE
] == WINED3DZB_USEW
) glEnable(GL_DEPTH_TEST
);
1229 if (myDevice
->stateBlock
->renderState
[WINED3DRS_ALPHABLENDENABLE
]) glEnable(GL_BLEND
);
1230 if (myDevice
->stateBlock
->renderState
[WINED3DRS_FOGENABLE
]) glEnable(GL_FOG
);
1234 /** restore clean dirty state */
1235 IWineD3DSurface_CleanDirtyRect(iface
);
1238 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This
, debug_d3dusage(This
->resource
.usage
));
1240 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)implSwapChain
);
1242 } else if (WINED3DUSAGE_DEPTHSTENCIL
& This
->resource
.usage
) { /* stencil surfaces */
1244 if (iface
== myDevice
->depthStencilBuffer
) {
1245 FIXME("TODO stencil depth surface unlocking surf@%p usage(%s)\n", This
, debug_d3dusage(This
->resource
.usage
));
1247 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%s)\n", This
, debug_d3dusage(This
->resource
.usage
));
1251 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This
, debug_d3dusage(This
->resource
.usage
));
1255 This
->Flags
&= ~SFLAG_LOCKED
;
1256 memset(&This
->lockedRect
, 0, sizeof(RECT
));
1260 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDC(IWineD3DSurface
*iface
, HDC
*pHDC
) {
1261 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1262 WINED3DLOCKED_RECT lock
;
1269 const PixelFormatDesc
*formatEntry
= getFormatDescEntry(This
->resource
.format
);
1271 TRACE("(%p)->(%p)\n",This
,pHDC
);
1273 if(This
->Flags
& SFLAG_USERPTR
) {
1274 ERR("Not supported on surfaces with an application-provided surfaces\n");
1278 /* Give more detailed info for ddraw */
1279 if (This
->Flags
& SFLAG_DCINUSE
)
1280 return DDERR_DCALREADYCREATED
;
1282 /* Can't GetDC if the surface is locked */
1283 if (This
->Flags
& SFLAG_LOCKED
)
1284 return WINED3DERR_INVALIDCALL
;
1286 memset(&lock
, 0, sizeof(lock
)); /* To be sure */
1288 /* Create a DIB section if there isn't a hdc yet */
1291 SYSTEM_INFO sysInfo
;
1293 if(This
->Flags
& SFLAG_ACTIVELOCK
) {
1294 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1297 switch (This
->bytesPerPixel
) {
1300 /* Allocate extra space to store the RGB bit masks. */
1301 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
1305 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
1309 /* Allocate extra space for a palette. */
1310 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1311 sizeof(BITMAPINFOHEADER
)
1313 * (1 << (This
->bytesPerPixel
* 8)));
1318 return E_OUTOFMEMORY
;
1320 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1321 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1322 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1323 * add an extra line to the dib section
1325 GetSystemInfo(&sysInfo
);
1326 if( ((This
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4) {
1328 TRACE("Adding an extra line to the dib section\n");
1331 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1332 if( (NP2_REPACK
== wined3d_settings
.nonpower2_mode
|| This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
1333 b_info
->bmiHeader
.biWidth
= This
->currentDesc
.Width
;
1334 b_info
->bmiHeader
.biHeight
= -This
->currentDesc
.Height
-extraline
;
1335 b_info
->bmiHeader
.biSizeImage
= ( This
->currentDesc
.Height
+ extraline
) * IWineD3DSurface_GetPitch(iface
);
1336 /* Use the full pow2 image size(assigned below) because LockRect
1337 * will need it for a full glGetTexImage call
1340 b_info
->bmiHeader
.biWidth
= This
->pow2Width
;
1341 b_info
->bmiHeader
.biHeight
= -This
->pow2Height
-extraline
;
1342 b_info
->bmiHeader
.biSizeImage
= This
->resource
.size
+ extraline
* IWineD3DSurface_GetPitch(iface
);
1344 b_info
->bmiHeader
.biPlanes
= 1;
1345 b_info
->bmiHeader
.biBitCount
= This
->bytesPerPixel
* 8;
1347 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
1348 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
1349 b_info
->bmiHeader
.biClrUsed
= 0;
1350 b_info
->bmiHeader
.biClrImportant
= 0;
1352 /* Get the bit masks */
1353 masks
= (DWORD
*) &(b_info
->bmiColors
);
1354 switch (This
->resource
.format
) {
1355 case WINED3DFMT_R8G8B8
:
1356 usage
= DIB_RGB_COLORS
;
1357 b_info
->bmiHeader
.biCompression
= BI_RGB
;
1360 case WINED3DFMT_X1R5G5B5
:
1361 case WINED3DFMT_A1R5G5B5
:
1362 case WINED3DFMT_A4R4G4B4
:
1363 case WINED3DFMT_X4R4G4B4
:
1364 case WINED3DFMT_R3G3B2
:
1365 case WINED3DFMT_A8R3G3B2
:
1366 case WINED3DFMT_A2B10G10R10
:
1367 case WINED3DFMT_A8B8G8R8
:
1368 case WINED3DFMT_X8B8G8R8
:
1369 case WINED3DFMT_A2R10G10B10
:
1370 case WINED3DFMT_R5G6B5
:
1371 case WINED3DFMT_A16B16G16R16
:
1373 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1374 masks
[0] = formatEntry
->redMask
;
1375 masks
[1] = formatEntry
->greenMask
;
1376 masks
[2] = formatEntry
->blueMask
;
1380 /* Don't know palette */
1381 b_info
->bmiHeader
.biCompression
= BI_RGB
;
1386 ddc
= CreateDCA("DISPLAY", NULL
, NULL
, NULL
);
1388 HeapFree(GetProcessHeap(), 0, b_info
);
1389 return HRESULT_FROM_WIN32(GetLastError());
1392 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
);
1393 This
->dib
.DIBsection
= CreateDIBSection(ddc
, b_info
, usage
, &This
->dib
.bitmap_data
, 0 /* Handle */, 0 /* Offset */);
1396 if (!This
->dib
.DIBsection
) {
1397 ERR("CreateDIBSection failed!\n");
1398 HeapFree(GetProcessHeap(), 0, b_info
);
1399 return HRESULT_FROM_WIN32(GetLastError());
1402 TRACE("DIBSection at : %p\n", This
->dib
.bitmap_data
);
1404 /* copy the existing surface to the dib section */
1405 if(This
->resource
.allocatedMemory
) {
1406 memcpy(This
->dib
.bitmap_data
, This
->resource
.allocatedMemory
, b_info
->bmiHeader
.biSizeImage
);
1407 /* We won't need that any more */
1408 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
1410 /* This is to make LockRect read the gl Texture although memory is allocated */
1411 This
->Flags
|= SFLAG_GLDIRTY
;
1414 HeapFree(GetProcessHeap(), 0, b_info
);
1416 /* Use the dib section from now on */
1417 This
->resource
.allocatedMemory
= This
->dib
.bitmap_data
;
1419 /* Now allocate a HDC */
1420 This
->hDC
= CreateCompatibleDC(0);
1421 This
->dib
.holdbitmap
= SelectObject(This
->hDC
, This
->dib
.DIBsection
);
1422 TRACE("using wined3d palette %p\n", This
->palette
);
1423 SelectPalette(This
->hDC
,
1424 This
->palette
? This
->palette
->hpal
: 0,
1427 This
->Flags
|= SFLAG_DIBSECTION
;
1430 /* Lock the surface */
1431 hr
= IWineD3DSurface_LockRect(iface
,
1436 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr
);
1437 /* keep the dib section */
1441 if(This
->resource
.format
== WINED3DFMT_P8
||
1442 This
->resource
.format
== WINED3DFMT_A8P8
) {
1445 PALETTEENTRY ent
[256];
1447 GetPaletteEntries(This
->palette
->hpal
, 0, 256, ent
);
1448 for (n
=0; n
<256; n
++) {
1449 col
[n
].rgbRed
= ent
[n
].peRed
;
1450 col
[n
].rgbGreen
= ent
[n
].peGreen
;
1451 col
[n
].rgbBlue
= ent
[n
].peBlue
;
1452 col
[n
].rgbReserved
= 0;
1455 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
1457 for (n
=0; n
<256; n
++) {
1458 col
[n
].rgbRed
= device
->palettes
[device
->currentPalette
][n
].peRed
;
1459 col
[n
].rgbGreen
= device
->palettes
[device
->currentPalette
][n
].peGreen
;
1460 col
[n
].rgbBlue
= device
->palettes
[device
->currentPalette
][n
].peBlue
;
1461 col
[n
].rgbReserved
= 0;
1465 SetDIBColorTable(This
->hDC
, 0, 256, col
);
1469 TRACE("returning %p\n",*pHDC
);
1470 This
->Flags
|= SFLAG_DCINUSE
;
1475 HRESULT WINAPI
IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface
*iface
, HDC hDC
) {
1476 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1478 TRACE("(%p)->(%p)\n",This
,hDC
);
1480 if (!(This
->Flags
& SFLAG_DCINUSE
))
1481 return D3DERR_INVALIDCALL
;
1483 /* we locked first, so unlock now */
1484 IWineD3DSurface_UnlockRect(iface
);
1486 This
->Flags
&= ~SFLAG_DCINUSE
;
1491 /* ******************************************************
1492 IWineD3DSurface Internal (No mapping to directx api) parts follow
1493 ****************************************************** */
1495 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
) {
1496 BOOL colorkey_active
= need_alpha_ck
&& (This
->CKeyFlags
& DDSD_CKSRCBLT
);
1497 const PixelFormatDesc
*formatEntry
= getFormatDescEntry(This
->resource
.format
);
1499 /* Default values: From the surface */
1500 *format
= formatEntry
->glFormat
;
1501 *internal
= formatEntry
->glInternal
;
1502 *type
= formatEntry
->glType
;
1503 *convert
= NO_CONVERSION
;
1504 *target_bpp
= This
->bytesPerPixel
;
1506 /* Ok, now look if we have to do any conversion */
1507 switch(This
->resource
.format
) {
1512 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1513 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1515 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE
) || colorkey_active
|| (!use_texturing
&& GL_SUPPORT(EXT_PALETTED_TEXTURE
)) ) {
1517 *internal
= GL_RGBA
;
1518 *type
= GL_UNSIGNED_BYTE
;
1520 if(colorkey_active
) {
1521 *convert
= CONVERT_PALETTED_CK
;
1523 *convert
= CONVERT_PALETTED
;
1529 case WINED3DFMT_R3G3B2
:
1530 /* **********************
1531 GL_UNSIGNED_BYTE_3_3_2
1532 ********************** */
1533 if (colorkey_active
) {
1534 /* This texture format will never be used.. So do not care about color keying
1535 up until the point in time it will be needed :-) */
1536 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1540 case WINED3DFMT_R5G6B5
:
1541 if (colorkey_active
) {
1542 *convert
= CONVERT_CK_565
;
1544 *internal
= GL_RGBA
;
1545 *type
= GL_UNSIGNED_SHORT_5_5_5_1
;
1549 case WINED3DFMT_R8G8B8
:
1550 if (colorkey_active
) {
1551 *convert
= CONVERT_CK_RGB24
;
1553 *internal
= GL_RGBA
;
1554 *type
= GL_UNSIGNED_INT_8_8_8_8
;
1559 case WINED3DFMT_X8R8G8B8
:
1560 if (colorkey_active
) {
1561 *convert
= CONVERT_RGB32_888
;
1563 *internal
= GL_RGBA
;
1564 *type
= GL_UNSIGNED_INT_8_8_8_8
;
1575 HRESULT
d3dfmt_convert_surface(BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT height
, UINT outpitch
, CONVERT_TYPES convert
, IWineD3DSurfaceImpl
*surf
) {
1577 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src
, dst
, pitch
, height
, outpitch
, convert
, surf
);
1582 memcpy(dst
, src
, pitch
* height
);
1585 case CONVERT_PALETTED
:
1586 case CONVERT_PALETTED_CK
:
1588 IWineD3DPaletteImpl
* pal
= surf
->palette
;
1594 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1598 /* Still no palette? Use the device's palette */
1599 /* Get the surface's palette */
1600 for (i
= 0; i
< 256; i
++) {
1601 IWineD3DDeviceImpl
*device
= surf
->resource
.wineD3DDevice
;
1603 table
[i
][0] = device
->palettes
[device
->currentPalette
][i
].peRed
;
1604 table
[i
][1] = device
->palettes
[device
->currentPalette
][i
].peGreen
;
1605 table
[i
][2] = device
->palettes
[device
->currentPalette
][i
].peBlue
;
1606 if ((convert
== CONVERT_PALETTED_CK
) &&
1607 (i
>= surf
->SrcBltCKey
.dwColorSpaceLowValue
) &&
1608 (i
<= surf
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1609 /* We should maybe here put a more 'neutral' color than the standard bright purple
1610 one often used by application to prevent the nice purple borders when bi-linear
1618 TRACE("Using surface palette %p\n", pal
);
1619 /* Get the surface's palette */
1620 for (i
= 0; i
< 256; i
++) {
1621 table
[i
][0] = pal
->palents
[i
].peRed
;
1622 table
[i
][1] = pal
->palents
[i
].peGreen
;
1623 table
[i
][2] = pal
->palents
[i
].peBlue
;
1624 if ((convert
== CONVERT_PALETTED_CK
) &&
1625 (i
>= surf
->SrcBltCKey
.dwColorSpaceLowValue
) &&
1626 (i
<= surf
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1627 /* We should maybe here put a more 'neutral' color than the standard bright purple
1628 one often used by application to prevent the nice purple borders when bi-linear
1637 for (y
= 0; y
< height
; y
++)
1639 dest
= dst
+ outpitch
* y
;
1640 /* This is an 1 bpp format, using the pitch here is fine */
1641 for (x
= 0; x
< pitch
; x
++) {
1642 BYTE color
= *src
++;
1643 *dest
++ = table
[color
][0];
1644 *dest
++ = table
[color
][1];
1645 *dest
++ = table
[color
][2];
1646 *dest
++ = table
[color
][3];
1652 case CONVERT_CK_565
:
1654 /* Converting the 565 format in 5551 packed to emulate color-keying.
1656 Note : in all these conversion, it would be best to average the averaging
1657 pixels to get the color of the pixel that will be color-keyed to
1658 prevent 'color bleeding'. This will be done later on if ever it is
1661 Note2: Nvidia documents say that their driver does not support alpha + color keying
1662 on the same surface and disables color keying in such a case
1668 TRACE("Color keyed 565\n");
1670 for (y
= 0; y
< height
; y
++) {
1671 Source
= (WORD
*) (src
+ y
* pitch
);
1672 Dest
= (WORD
*) (dst
+ y
* outpitch
);
1673 for (x
= 0; x
< pitch
/ 2; x
++ ) {
1674 WORD color
= *Source
++;
1675 *Dest
= ((color
& 0xFFC0) | ((color
& 0x1F) << 1));
1676 if ((color
< surf
->SrcBltCKey
.dwColorSpaceLowValue
) ||
1677 (color
> surf
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1687 ERR("Unsupported conversation type %d\n", convert
);
1692 /* This function is used in case of 8bit paletted textures to upload the palette.
1693 For now it only supports GL_EXT_paletted_texture extension but support for other
1694 extensions like ARB_fragment_program and ATI_fragment_shaders will be added aswell.
1696 void d3dfmt_p8_upload_palette(IWineD3DSurface
*iface
, CONVERT_TYPES convert
) {
1697 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1698 IWineD3DPaletteImpl
* pal
= This
->palette
;
1703 /* Still no palette? Use the device's palette */
1704 /* Get the surface's palette */
1705 for (i
= 0; i
< 256; i
++) {
1706 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
1708 table
[i
][0] = device
->palettes
[device
->currentPalette
][i
].peRed
;
1709 table
[i
][1] = device
->palettes
[device
->currentPalette
][i
].peGreen
;
1710 table
[i
][2] = device
->palettes
[device
->currentPalette
][i
].peBlue
;
1711 if ((convert
== CONVERT_PALETTED_CK
) &&
1712 (i
>= This
->SrcBltCKey
.dwColorSpaceLowValue
) &&
1713 (i
<= This
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1714 /* We should maybe here put a more 'neutral' color than the standard bright purple
1715 one often used by application to prevent the nice purple borders when bi-linear
1723 TRACE("Using surface palette %p\n", pal
);
1724 /* Get the surface's palette */
1725 for (i
= 0; i
< 256; i
++) {
1726 table
[i
][0] = pal
->palents
[i
].peRed
;
1727 table
[i
][1] = pal
->palents
[i
].peGreen
;
1728 table
[i
][2] = pal
->palents
[i
].peBlue
;
1729 if ((convert
== CONVERT_PALETTED_CK
) &&
1730 (i
>= This
->SrcBltCKey
.dwColorSpaceLowValue
) &&
1731 (i
<= This
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1732 /* We should maybe here put a more 'neutral' color than the standard bright purple
1733 one often used by application to prevent the nice purple borders when bi-linear
1741 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D
,GL_RGBA
,256,GL_RGBA
,GL_UNSIGNED_BYTE
, table
));
1744 static HRESULT WINAPI
IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface
*iface
) {
1745 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1746 GLenum format
, internal
, type
;
1747 CONVERT_TYPES convert
;
1749 int width
, pitch
, outpitch
;
1752 if (This
->Flags
& SFLAG_INTEXTURE
) {
1753 TRACE("Surface already in texture\n");
1756 if (This
->Flags
& SFLAG_DIRTY
) {
1757 TRACE("Reloading because surface is dirty\n");
1758 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1759 ((This
->Flags
& SFLAG_GLCKEY
) && (!(This
->CKeyFlags
& DDSD_CKSRCBLT
))) ||
1760 /* Reload: vice versa OR */
1761 ((!(This
->Flags
& SFLAG_GLCKEY
)) && (This
->CKeyFlags
& DDSD_CKSRCBLT
)) ||
1762 /* Also reload: Color key is active AND the color key has changed */
1763 ((This
->CKeyFlags
& DDSD_CKSRCBLT
) && (
1764 (This
->glCKey
.dwColorSpaceLowValue
!= This
->SrcBltCKey
.dwColorSpaceLowValue
) ||
1765 (This
->glCKey
.dwColorSpaceHighValue
!= This
->SrcBltCKey
.dwColorSpaceHighValue
)))) {
1766 TRACE("Reloading because of color keying\n");
1768 TRACE("surface isn't dirty\n");
1772 This
->Flags
&= ~SFLAG_DIRTY
;
1774 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1775 * These resources are not bound by device size or format restrictions. Because of this,
1776 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1777 * However, these resources can always be created, locked, and copied.
1779 if (This
->resource
.pool
== WINED3DPOOL_SCRATCH
&& !(This
->Flags
& SFLAG_FORCELOAD
) )
1781 FIXME("(%p) Operation not supported for scratch textures\n",This
);
1782 return WINED3DERR_INVALIDCALL
;
1785 if (This
->Flags
& SFLAG_INPBUFFER
) {
1786 if (This
->glDescription
.level
!= 0)
1787 FIXME("Surface in texture is only supported for level 0\n");
1788 else if (This
->resource
.format
== WINED3DFMT_P8
|| This
->resource
.format
== WINED3DFMT_A8P8
||
1789 This
->resource
.format
== WINED3DFMT_DXT1
|| This
->resource
.format
== WINED3DFMT_DXT2
||
1790 This
->resource
.format
== WINED3DFMT_DXT3
|| This
->resource
.format
== WINED3DFMT_DXT4
||
1791 This
->resource
.format
== WINED3DFMT_DXT5
)
1792 FIXME("Format %d not supported\n", This
->resource
.format
);
1798 glGetIntegerv(GL_READ_BUFFER
, &prevRead
);
1799 vcheckGLcall("glGetIntegerv");
1800 glReadBuffer(GL_BACK
);
1801 vcheckGLcall("glReadBuffer");
1803 glCopyTexImage2D(This
->glDescription
.target
,
1804 This
->glDescription
.level
,
1805 This
->glDescription
.glFormatInternal
,
1808 This
->currentDesc
.Width
,
1809 This
->currentDesc
.Height
,
1812 checkGLcall("glCopyTexImage2D");
1813 glReadBuffer(prevRead
);
1814 vcheckGLcall("glReadBuffer");
1818 TRACE("Updating target %d\n", This
->glDescription
.target
);
1819 This
->Flags
|= SFLAG_INTEXTURE
;
1824 if(This
->CKeyFlags
& DDSD_CKSRCBLT
) {
1825 This
->Flags
|= SFLAG_GLCKEY
;
1826 This
->glCKey
= This
->SrcBltCKey
;
1828 else This
->Flags
&= ~SFLAG_GLCKEY
;
1830 d3dfmt_get_conv(This
, TRUE
/* We need color keying */, TRUE
/* We will use textures */, &format
, &internal
, &type
, &convert
, &bpp
);
1832 /* The width is in 'length' not in bytes */
1833 if (NP2_REPACK
== wined3d_settings
.nonpower2_mode
|| This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
1834 width
= This
->currentDesc
.Width
;
1836 width
= This
->pow2Width
;
1838 pitch
= IWineD3DSurface_GetPitch(iface
);
1840 if((convert
!= NO_CONVERSION
) && This
->resource
.allocatedMemory
) {
1841 int height
= This
->glRect
.bottom
- This
->glRect
.top
;
1843 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1844 outpitch
= width
* bpp
;
1845 outpitch
= (outpitch
+ SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
1847 mem
= HeapAlloc(GetProcessHeap(), 0, outpitch
* height
);
1849 ERR("Out of memory %d, %d!\n", outpitch
, height
);
1850 return WINED3DERR_OUTOFVIDEOMEMORY
;
1852 d3dfmt_convert_surface(This
->resource
.allocatedMemory
, mem
, pitch
, height
, outpitch
, convert
, This
);
1854 This
->Flags
|= SFLAG_CONVERTED
;
1855 } else if (This
->resource
.format
== WINED3DFMT_P8
&& GL_SUPPORT(EXT_PALETTED_TEXTURE
)) {
1856 d3dfmt_p8_upload_palette(iface
, convert
);
1857 This
->Flags
&= ~SFLAG_CONVERTED
;
1858 mem
= This
->resource
.allocatedMemory
;
1860 This
->Flags
&= ~SFLAG_CONVERTED
;
1861 mem
= This
->resource
.allocatedMemory
;
1864 /* Make sure the correct pitch is used */
1865 glPixelStorei(GL_UNPACK_ROW_LENGTH
, width
);
1867 if (NP2_REPACK
== wined3d_settings
.nonpower2_mode
&& (This
->Flags
& SFLAG_NONPOW2
) && !(This
->Flags
& SFLAG_OVERSIZE
)) {
1868 TRACE("non power of two support\n");
1869 surface_allocate_surface(This
, internal
, This
->pow2Width
, This
->pow2Height
, format
, type
);
1871 surface_upload_data(This
, This
->pow2Width
, This
->pow2Height
, format
, type
, mem
);
1874 surface_allocate_surface(This
, internal
, This
->glRect
.right
- This
->glRect
.left
, This
->glRect
.bottom
- This
->glRect
.top
, format
, type
);
1876 surface_upload_data(This
, This
->glRect
.right
- This
->glRect
.left
, This
->glRect
.bottom
- This
->glRect
.top
, format
, type
, mem
);
1880 /* Restore the default pitch */
1881 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1883 if (mem
!= This
->resource
.allocatedMemory
)
1884 HeapFree(GetProcessHeap(), 0, mem
);
1888 static unsigned int gen
= 0;
1891 if ((gen
% 10) == 0) {
1892 snprintf(buffer
, sizeof(buffer
), "/tmp/surface%p_type%u_level%u_%u.ppm", This
, This
->glDescription
.target
, This
->glDescription
.level
, gen
);
1893 IWineD3DSurfaceImpl_SaveSnapshot(iface
, buffer
);
1896 * debugging crash code
1905 if (!(This
->Flags
& SFLAG_DONOTFREE
)) {
1906 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
1907 This
->resource
.allocatedMemory
= NULL
;
1915 HRESULT WINAPI
IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface
*iface
, const char* filename
) {
1918 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1919 char *allocatedMemory
;
1921 IWineD3DSwapChain
*swapChain
= NULL
;
1923 GLuint tmpTexture
= 0;
1926 Textures my not be stored in ->allocatedgMemory and a GlTexture
1927 so we should lock the surface before saving a snapshot, or at least check that
1929 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1930 by calling GetTexImage and in compressed form by calling
1931 GetCompressedTexImageARB. Queried compressed images can be saved and
1932 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1933 texture images do not need to be processed by the GL and should
1934 significantly improve texture loading performance relative to uncompressed
1937 /* Setup the width and height to be the internal texture width and height. */
1938 width
= This
->pow2Width
;
1939 height
= This
->pow2Height
;
1940 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1941 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapChain
);
1943 if (swapChain
|| (This
->Flags
& SFLAG_INPBUFFER
)) { /* if were not a real texture then read the back buffer into a real texture*/
1944 /* 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 */
1947 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This
);
1948 glEnable(GL_TEXTURE_2D
);
1950 glGenTextures(1, &tmpTexture
);
1951 glBindTexture(GL_TEXTURE_2D
, tmpTexture
);
1953 glTexImage2D(GL_TEXTURE_2D
,
1960 GL_UNSIGNED_INT_8_8_8_8_REV
,
1963 glGetIntegerv(GL_READ_BUFFER
, &prevRead
);
1964 vcheckGLcall("glGetIntegerv");
1965 glReadBuffer(GL_BACK
);
1966 vcheckGLcall("glReadBuffer");
1967 glCopyTexImage2D(GL_TEXTURE_2D
,
1976 checkGLcall("glCopyTexImage2D");
1977 glReadBuffer(prevRead
);
1980 } else { /* bind the real texture */
1981 IWineD3DSurface_PreLoad(iface
);
1983 allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, width
* height
* 4);
1985 FIXME("Saving texture level %d width %d height %d\n", This
->glDescription
.level
, width
, height
);
1986 glGetTexImage(GL_TEXTURE_2D
,
1987 This
->glDescription
.level
,
1989 GL_UNSIGNED_INT_8_8_8_8_REV
,
1991 checkGLcall("glTexImage2D");
1993 glBindTexture(GL_TEXTURE_2D
, 0);
1994 glDeleteTextures(1, &tmpTexture
);
1998 f
= fopen(filename
, "w+");
2000 ERR("opening of %s failed with: %s\n", filename
, strerror(errno
));
2001 return WINED3DERR_INVALIDCALL
;
2003 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
2004 TRACE("(%p) opened %s with format %s\n", This
, filename
, debug_d3dformat(This
->resource
.format
));
2019 fwrite(&width
,2,1,f
);
2021 fwrite(&height
,2,1,f
);
2026 /* 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*/
2028 textureRow
= allocatedMemory
+ (width
* (height
- 1) *4);
2030 textureRow
= allocatedMemory
;
2031 for (y
= 0 ; y
< height
; y
++) {
2032 for (i
= 0; i
< width
; i
++) {
2033 color
= *((DWORD
*)textureRow
);
2034 fputc((color
>> 16) & 0xFF, f
); /* B */
2035 fputc((color
>> 8) & 0xFF, f
); /* G */
2036 fputc((color
>> 0) & 0xFF, f
); /* R */
2037 fputc((color
>> 24) & 0xFF, f
); /* A */
2040 /* take two rows of the pointer to the texture memory */
2042 (textureRow
-= width
<< 3);
2045 TRACE("Closing file\n");
2049 IWineD3DSwapChain_Release(swapChain
);
2051 HeapFree(GetProcessHeap(), 0, allocatedMemory
);
2055 HRESULT WINAPI
IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface
*iface
) {
2056 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2057 This
->Flags
&= ~SFLAG_DIRTY
;
2058 This
->dirtyRect
.left
= This
->currentDesc
.Width
;
2059 This
->dirtyRect
.top
= This
->currentDesc
.Height
;
2060 This
->dirtyRect
.right
= 0;
2061 This
->dirtyRect
.bottom
= 0;
2062 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This
, This
->Flags
& SFLAG_DIRTY
? 1 : 0, This
->dirtyRect
.left
,
2063 This
->dirtyRect
.top
, This
->dirtyRect
.right
, This
->dirtyRect
.bottom
);
2068 * Slightly inefficient way to handle multiple dirty rects but it works :)
2070 extern HRESULT WINAPI
IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface
*iface
, CONST RECT
* pDirtyRect
) {
2071 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2072 IWineD3DBaseTexture
*baseTexture
= NULL
;
2073 This
->Flags
|= SFLAG_DIRTY
;
2074 if (NULL
!= pDirtyRect
) {
2075 This
->dirtyRect
.left
= min(This
->dirtyRect
.left
, pDirtyRect
->left
);
2076 This
->dirtyRect
.top
= min(This
->dirtyRect
.top
, pDirtyRect
->top
);
2077 This
->dirtyRect
.right
= max(This
->dirtyRect
.right
, pDirtyRect
->right
);
2078 This
->dirtyRect
.bottom
= max(This
->dirtyRect
.bottom
, pDirtyRect
->bottom
);
2080 This
->dirtyRect
.left
= 0;
2081 This
->dirtyRect
.top
= 0;
2082 This
->dirtyRect
.right
= This
->currentDesc
.Width
;
2083 This
->dirtyRect
.bottom
= This
->currentDesc
.Height
;
2085 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This
, This
->Flags
& SFLAG_DIRTY
, This
->dirtyRect
.left
,
2086 This
->dirtyRect
.top
, This
->dirtyRect
.right
, This
->dirtyRect
.bottom
);
2087 /* if the container is a basetexture then mark it dirty. */
2088 if (IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
) == WINED3D_OK
) {
2089 TRACE("Passing to conatiner\n");
2090 IWineD3DBaseTexture_SetDirty(baseTexture
, TRUE
);
2091 IWineD3DBaseTexture_Release(baseTexture
);
2096 HRESULT WINAPI
IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface
*iface
, IWineD3DBase
*container
) {
2097 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2099 TRACE("This %p, container %p\n", This
, container
);
2101 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2103 TRACE("Setting container to %p from %p\n", container
, This
->container
);
2104 This
->container
= container
;
2109 HRESULT WINAPI
IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface
*iface
, WINED3DFORMAT format
) {
2110 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2111 const PixelFormatDesc
*formatEntry
= getFormatDescEntry(format
);
2113 if (This
->resource
.format
!= WINED3DFMT_UNKNOWN
) {
2114 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This
);
2115 return WINED3DERR_INVALIDCALL
;
2118 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This
, format
, debug_d3dformat(format
));
2119 if (format
== WINED3DFMT_UNKNOWN
) {
2120 This
->resource
.size
= 0;
2121 } else if (format
== WINED3DFMT_DXT1
) {
2122 /* DXT1 is half byte per pixel */
2123 This
->resource
.size
= ((max(This
->pow2Width
, 4) * formatEntry
->bpp
) * max(This
->pow2Height
, 4)) >> 1;
2125 } else if (format
== WINED3DFMT_DXT2
|| format
== WINED3DFMT_DXT3
||
2126 format
== WINED3DFMT_DXT4
|| format
== WINED3DFMT_DXT5
) {
2127 This
->resource
.size
= ((max(This
->pow2Width
, 4) * formatEntry
->bpp
) * max(This
->pow2Height
, 4));
2129 This
->resource
.size
= ((This
->pow2Width
* formatEntry
->bpp
) + SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
2130 This
->resource
.size
*= This
->pow2Height
;
2134 /* Setup some glformat defaults */
2135 This
->glDescription
.glFormat
= formatEntry
->glFormat
;
2136 This
->glDescription
.glFormatInternal
= formatEntry
->glInternal
;
2137 This
->glDescription
.glType
= formatEntry
->glType
;
2139 if (format
!= WINED3DFMT_UNKNOWN
) {
2140 This
->bytesPerPixel
= formatEntry
->bpp
;
2141 This
->pow2Size
= (This
->pow2Width
* This
->bytesPerPixel
) * This
->pow2Height
;
2143 This
->bytesPerPixel
= 0;
2147 This
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== format
) ? SFLAG_LOCKABLE
: 0;
2149 This
->resource
.format
= format
;
2151 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
);
2156 HRESULT WINAPI
IWineD3DSurfaceImpl_SetMem(IWineD3DSurface
*iface
, void *Mem
) {
2157 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2159 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2160 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
2161 ERR("Not supported on render targets\n");
2162 return WINED3DERR_INVALIDCALL
;
2165 if(This
->Flags
& (SFLAG_LOCKED
| SFLAG_DCINUSE
)) {
2166 WARN("Surface is locked or the HDC is in use\n");
2167 return WINED3DERR_INVALIDCALL
;
2170 if(Mem
&& Mem
!= This
->resource
.allocatedMemory
) {
2172 /* Do I have to copy the old surface content? */
2173 if(This
->Flags
& SFLAG_DIBSECTION
) {
2174 /* Release the DC. No need to hold the critical section for the update
2175 * Thread because this thread runs only on front buffers, but this method
2176 * fails for render targets in the check above.
2178 SelectObject(This
->hDC
, This
->dib
.holdbitmap
);
2179 DeleteDC(This
->hDC
);
2180 /* Release the DIB section */
2181 DeleteObject(This
->dib
.DIBsection
);
2182 This
->dib
.bitmap_data
= NULL
;
2183 This
->resource
.allocatedMemory
= NULL
;
2185 This
->Flags
&= ~SFLAG_DIBSECTION
;
2186 } else if(!(This
->Flags
& SFLAG_USERPTR
)) {
2187 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
2189 This
->resource
.allocatedMemory
= Mem
;
2190 This
->Flags
|= SFLAG_USERPTR
;
2191 } else if(This
->Flags
& SFLAG_USERPTR
) {
2192 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2193 This
->resource
.allocatedMemory
= NULL
;
2194 This
->Flags
&= ~SFLAG_USERPTR
;
2199 /* TODO: replace this function with context management routines */
2200 HRESULT WINAPI
IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface
*iface
, BOOL inPBuffer
, BOOL inTexture
) {
2201 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2204 This
->Flags
|= SFLAG_INPBUFFER
;
2206 This
->Flags
&= ~SFLAG_INPBUFFER
;
2210 This
->Flags
|= SFLAG_INTEXTURE
;
2212 This
->Flags
&= ~SFLAG_INTEXTURE
;
2218 static HRESULT WINAPI
IWineD3DSurfaceImpl_Flip(IWineD3DSurface
*iface
, IWineD3DSurface
*override
, DWORD Flags
) {
2219 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2220 IWineD3DDevice
*D3D
= (IWineD3DDevice
*) This
->resource
.wineD3DDevice
;
2221 TRACE("(%p)->(%p,%x)\n", This
, override
, Flags
);
2223 /* Flipping is only supported on RenderTargets */
2224 if( !(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) return DDERR_NOTFLIPPABLE
;
2227 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2228 * FIXME("(%p) Target override is not supported by now\n", This);
2229 * Additionally, it isn't really possible to support triple-buffering
2230 * properly on opengl at all
2234 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2235 return IWineD3DDevice_Present(D3D
, NULL
, NULL
, 0, NULL
);
2238 /* Not called from the VTable */
2239 static HRESULT
IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl
*This
, RECT
*DestRect
, IWineD3DSurface
*SrcSurface
, RECT
*SrcRect
, DWORD Flags
, DDBLTFX
*DDBltFx
) {
2241 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
2242 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2243 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
2246 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
);
2248 /* Get the swapchain. One of the surfaces has to be a primary surface */
2249 IWineD3DSurface_GetContainer( (IWineD3DSurface
*) This
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
2250 if(swapchain
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
2252 IWineD3DSurface_GetContainer( (IWineD3DSurface
*) Src
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
2253 if(swapchain
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
2254 else return WINED3DERR_INVALIDCALL
;
2260 rect
.x1
= DestRect
->left
;
2261 rect
.y1
= DestRect
->top
;
2262 rect
.x2
= DestRect
->right
;
2263 rect
.y2
= DestRect
->bottom
;
2267 rect
.x2
= This
->currentDesc
.Width
;
2268 rect
.y2
= This
->currentDesc
.Height
;
2271 /* Half-life does a Blt from the back buffer to the front buffer,
2272 * Full surface size, no flags... Use present instead
2276 /* First, check if we can do a Flip */
2278 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2280 if( (SrcRect
->left
== 0) && (SrcRect
->top
== 0) &&
2281 (SrcRect
->right
== Src
->currentDesc
.Width
) && (SrcRect
->bottom
== Src
->currentDesc
.Height
) ) {
2288 /* Check the Destination rect and the surface sizes */
2290 (rect
.x1
== 0) && (rect
.y1
== 0) &&
2291 (rect
.x2
== This
->currentDesc
.Width
) && (rect
.y2
== This
->currentDesc
.Height
) &&
2292 (This
->currentDesc
.Width
== Src
->currentDesc
.Width
) &&
2293 (This
->currentDesc
.Height
== Src
->currentDesc
.Height
)) {
2294 /* These flags are unimportant for the flag check, remove them */
2296 if((Flags
& ~(DDBLT_DONOTWAIT
| DDBLT_WAIT
)) == 0) {
2297 if( swapchain
->backBuffer
&& ((IWineD3DSurface
*) This
== swapchain
->frontBuffer
) && ((IWineD3DSurface
*) Src
== swapchain
->backBuffer
[0]) ) {
2299 D3DSWAPEFFECT orig_swap
= swapchain
->presentParms
.SwapEffect
;
2301 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2302 * take very long, while a flip is fast.
2303 * This applies to Half-Life, which does such Blts every time it finished
2304 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2305 * menu. This is also used by all apps when they do windowed rendering
2307 * The problem is that flipping is not really the same as copying. After a
2308 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2309 * untouched. Therefore it's necessary to override the swap effect
2310 * and to set it back after the flip.
2313 swapchain
->presentParms
.SwapEffect
= WINED3DSWAPEFFECT_COPY
;
2315 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2316 IWineD3DDevice_Present((IWineD3DDevice
*) This
->resource
.wineD3DDevice
,
2317 NULL
, NULL
, 0, NULL
);
2319 swapchain
->presentParms
.SwapEffect
= orig_swap
;
2326 /* Blt from texture to rendertarget? */
2327 if( ( ( (IWineD3DSurface
*) This
== swapchain
->frontBuffer
) ||
2328 ( swapchain
->backBuffer
&& (IWineD3DSurface
*) This
== swapchain
->backBuffer
[0]) )
2330 ( ( (IWineD3DSurface
*) Src
!= swapchain
->frontBuffer
) &&
2331 ( swapchain
->backBuffer
&& (IWineD3DSurface
*) Src
!= swapchain
->backBuffer
[0]) ) ) {
2332 float glTexCoord
[4];
2334 DDCOLORKEY oldBltCKey
= {0,0};
2335 GLint oldLight
, oldFog
, oldDepth
, oldBlend
, oldCull
, oldAlpha
;
2336 GLint oldStencil
, oldNVRegisterCombiners
= 0;
2339 RECT SourceRectangle
;
2342 TRACE("Blt from surface %p to rendertarget %p\n", Src
, This
);
2345 SourceRectangle
.left
= SrcRect
->left
;
2346 SourceRectangle
.right
= SrcRect
->right
;
2347 SourceRectangle
.top
= SrcRect
->top
;
2348 SourceRectangle
.bottom
= SrcRect
->bottom
;
2350 SourceRectangle
.left
= 0;
2351 SourceRectangle
.right
= Src
->currentDesc
.Width
;
2352 SourceRectangle
.top
= 0;
2353 SourceRectangle
.bottom
= Src
->currentDesc
.Height
;
2356 if(!CalculateTexRect(Src
, &SourceRectangle
, glTexCoord
)) {
2357 /* Fall back to software */
2358 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src
,
2359 SourceRectangle
.left
, SourceRectangle
.top
,
2360 SourceRectangle
.right
, SourceRectangle
.bottom
);
2361 return WINED3DERR_INVALIDCALL
;
2364 /* Color keying: Check if we have to do a color keyed blt,
2365 * and if not check if a color key is activated.
2367 oldCKey
= Src
->CKeyFlags
;
2368 if(!(Flags
& DDBLT_KEYSRC
) &&
2369 Src
->CKeyFlags
& DDSD_CKSRCBLT
) {
2370 /* Ok, the surface has a color key, but we shall not use it -
2371 * Deactivate it for now, LoadTexture will catch this
2373 Src
->CKeyFlags
&= ~DDSD_CKSRCBLT
;
2377 if(Flags
& DDBLT_KEYDEST
) {
2378 oldBltCKey
= This
->SrcBltCKey
;
2379 /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
2380 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
2382 This
->SrcBltCKey
= This
->DestBltCKey
;
2383 } else if (Flags
& DDBLT_KEYSRC
)
2384 oldBltCKey
= This
->SrcBltCKey
;
2386 /* Now load the surface */
2387 IWineD3DSurface_PreLoad((IWineD3DSurface
*) Src
);
2391 /* Save all the old stuff until we have a proper opengl state manager */
2392 oldLight
= glIsEnabled(GL_LIGHTING
);
2393 oldFog
= glIsEnabled(GL_FOG
);
2394 oldDepth
= glIsEnabled(GL_DEPTH_TEST
);
2395 oldBlend
= glIsEnabled(GL_BLEND
);
2396 oldCull
= glIsEnabled(GL_CULL_FACE
);
2397 oldAlpha
= glIsEnabled(GL_ALPHA_TEST
);
2398 oldStencil
= glIsEnabled(GL_STENCIL_TEST
);
2400 if (GL_SUPPORT(NV_REGISTER_COMBINERS
)) {
2401 oldNVRegisterCombiners
= glIsEnabled(GL_REGISTER_COMBINERS_NV
);
2404 glGetIntegerv(GL_ALPHA_TEST_FUNC
, &alphafunc
);
2405 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2406 glGetFloatv(GL_ALPHA_TEST_REF
, &alpharef
);
2407 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2409 glGetIntegerv(GL_DRAW_BUFFER
, &oldDraw
);
2410 if(This
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
) {
2411 TRACE("Drawing to front buffer\n");
2412 glDrawBuffer(GL_FRONT
);
2413 checkGLcall("glDrawBuffer GL_FRONT");
2416 /* Unbind the old texture */
2417 glBindTexture(GL_TEXTURE_2D
, 0);
2419 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
2420 /* We use texture unit 0 for blts */
2421 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
2422 checkGLcall("glActiveTextureARB");
2424 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2427 /* Disable some fancy graphics effects */
2428 glDisable(GL_LIGHTING
);
2429 checkGLcall("glDisable GL_LIGHTING");
2430 glDisable(GL_DEPTH_TEST
);
2431 checkGLcall("glDisable GL_DEPTH_TEST");
2433 checkGLcall("glDisable GL_FOG");
2434 glDisable(GL_BLEND
);
2435 checkGLcall("glDisable GL_BLEND");
2436 glDisable(GL_CULL_FACE
);
2437 checkGLcall("glDisable GL_CULL_FACE");
2438 glDisable(GL_STENCIL_TEST
);
2439 checkGLcall("glDisable GL_STENCIL_TEST");
2440 if (GL_SUPPORT(NV_REGISTER_COMBINERS
)) {
2441 glDisable(GL_REGISTER_COMBINERS_NV
);
2442 checkGLcall("glDisable GL_REGISTER_COMBINERS_NV");
2445 /* Ok, we need 2d textures, but not 1D or 3D */
2446 glDisable(GL_TEXTURE_1D
);
2447 checkGLcall("glDisable GL_TEXTURE_1D");
2448 glEnable(GL_TEXTURE_2D
);
2449 checkGLcall("glEnable GL_TEXTURE_2D");
2450 glDisable(GL_TEXTURE_3D
);
2451 checkGLcall("glDisable GL_TEXTURE_3D");
2453 /* Bind the texture */
2454 glBindTexture(GL_TEXTURE_2D
, Src
->glDescription
.textureName
);
2455 checkGLcall("glBindTexture");
2457 glEnable(GL_SCISSOR_TEST
);
2459 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
2461 /* No filtering for blts */
2462 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
,
2464 checkGLcall("glTexParameteri");
2465 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
2467 checkGLcall("glTexParameteri");
2468 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
2469 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
2470 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
2471 checkGLcall("glTexEnvi");
2473 /* This is for color keying */
2474 if(Flags
& DDBLT_KEYSRC
) {
2475 glEnable(GL_ALPHA_TEST
);
2476 checkGLcall("glEnable GL_ALPHA_TEST");
2477 glAlphaFunc(GL_NOTEQUAL
, 0.0);
2478 checkGLcall("glAlphaFunc\n");
2480 glDisable(GL_ALPHA_TEST
);
2481 checkGLcall("glDisable GL_ALPHA_TEST");
2484 /* Draw a textured quad
2486 d3ddevice_set_ortho(This
->resource
.wineD3DDevice
);
2490 glColor3d(1.0f
, 1.0f
, 1.0f
);
2491 glTexCoord2f(glTexCoord
[0], glTexCoord
[2]);
2496 glTexCoord2f(glTexCoord
[0], glTexCoord
[3]);
2497 glVertex3f(rect
.x1
, rect
.y2
, 0.0);
2499 glTexCoord2f(glTexCoord
[1], glTexCoord
[3]);
2504 glTexCoord2f(glTexCoord
[1], glTexCoord
[2]);
2509 checkGLcall("glEnd");
2511 /* Unbind the texture */
2512 glBindTexture(GL_TEXTURE_2D
, 0);
2513 checkGLcall("glEnable glBindTexture");
2515 /* Restore the old settings */
2517 glEnable(GL_LIGHTING
);
2518 checkGLcall("glEnable GL_LIGHTING");
2522 checkGLcall("glEnable GL_FOG");
2525 glEnable(GL_DEPTH_TEST
);
2526 checkGLcall("glEnable GL_DEPTH_TEST");
2530 checkGLcall("glEnable GL_BLEND");
2533 glEnable(GL_CULL_FACE
);
2534 checkGLcall("glEnable GL_CULL_FACE");
2537 glEnable(GL_STENCIL_TEST
);
2538 checkGLcall("glEnable GL_STENCIL_TEST");
2541 glDisable(GL_ALPHA_TEST
);
2542 checkGLcall("glDisable GL_ALPHA_TEST");
2544 glEnable(GL_ALPHA_TEST
);
2545 checkGLcall("glEnable GL_ALPHA_TEST");
2547 if (GL_SUPPORT(NV_REGISTER_COMBINERS
) && oldNVRegisterCombiners
) {
2548 glEnable(GL_REGISTER_COMBINERS_NV
);
2549 checkGLcall("glEnable GL_REGISTER_COMBINERS_NV");
2552 glAlphaFunc(alphafunc
, alpharef
);
2553 checkGLcall("glAlphaFunc\n");
2555 if(This
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
&& oldDraw
== GL_BACK
) {
2556 glDrawBuffer(oldDraw
);
2559 /* Restore the color key flags */
2560 if(oldCKey
!= Src
->CKeyFlags
) {
2561 Src
->CKeyFlags
= oldCKey
;
2564 /* Restore the old color key */
2565 if (Flags
& (DDBLT_KEYSRC
| DDBLT_KEYDEST
))
2566 This
->SrcBltCKey
= oldBltCKey
;
2570 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2571 This
->Flags
|= SFLAG_GLDIRTY
;
2577 /* Blt from rendertarget to texture? */
2578 if( (SrcSurface
== swapchain
->frontBuffer
) ||
2579 (swapchain
->backBuffer
&& SrcSurface
== swapchain
->backBuffer
[0]) ) {
2580 if( ( (IWineD3DSurface
*) This
!= swapchain
->frontBuffer
) &&
2581 ( swapchain
->backBuffer
&& (IWineD3DSurface
*) This
!= swapchain
->backBuffer
[0]) ) {
2586 TRACE("Blt from rendertarget to texture\n");
2588 /* Call preload for the surface to make sure it isn't dirty */
2589 IWineD3DSurface_PreLoad((IWineD3DSurface
*) This
);
2592 srect
.x1
= SrcRect
->left
;
2593 srect
.y1
= SrcRect
->top
;
2594 srect
.x2
= SrcRect
->right
;
2595 srect
.y2
= SrcRect
->bottom
;
2599 srect
.x2
= Src
->currentDesc
.Width
;
2600 srect
.y2
= Src
->currentDesc
.Height
;
2605 /* Bind the target texture */
2606 glBindTexture(GL_TEXTURE_2D
, This
->glDescription
.textureName
);
2607 checkGLcall("glBindTexture");
2608 if(swapchain
->backBuffer
&& SrcSurface
== swapchain
->backBuffer
[0]) {
2609 glReadBuffer(GL_BACK
);
2611 glReadBuffer(GL_FRONT
);
2613 checkGLcall("glReadBuffer");
2615 xrel
= (float) (srect
.x2
- srect
.x1
) / (float) (rect
.x2
- rect
.x1
);
2616 yrel
= (float) (srect
.y2
- srect
.y1
) / (float) (rect
.y2
- rect
.y1
);
2618 /* I have to process this row by row to swap the image,
2619 * otherwise it would be upside down, so streching in y direction
2620 * doesn't cost extra time
2622 * However, streching in x direction can be avoided if not necessary
2624 for(row
= rect
.y1
; row
< rect
.y2
; row
++) {
2625 if( (xrel
- 1.0 < -eps
) || (xrel
- 1.0 > eps
)) {
2626 /* Well, that stuff works, but it's very slow.
2627 * find a better way instead
2630 for(col
= rect
.x1
; col
< rect
.x2
; col
++) {
2631 glCopyTexSubImage2D(GL_TEXTURE_2D
,
2633 rect
.x1
+ col
, This
->currentDesc
.Height
- row
- 1, /* xoffset, yoffset */
2634 srect
.x1
+ col
* xrel
, Src
->currentDesc
.Height
- srect
.y2
+ row
* yrel
,
2638 glCopyTexSubImage2D(GL_TEXTURE_2D
,
2640 rect
.x1
, rect
.y2
+ rect
.y1
- row
- 1, /* xoffset, yoffset */
2641 srect
.x1
, row
- rect
.y1
,
2642 rect
.x2
-rect
.x1
, 1);
2646 vcheckGLcall("glCopyTexSubImage2D");
2649 if(!(This
->Flags
& SFLAG_DONOTFREE
)) {
2650 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
2651 This
->resource
.allocatedMemory
= NULL
;
2653 This
->Flags
|= SFLAG_GLDIRTY
;
2661 if (Flags
& DDBLT_COLORFILL
) {
2662 /* This is easy to handle for the D3D Device... */
2664 IWineD3DSwapChainImpl
*implSwapChain
;
2666 TRACE("Colorfill\n");
2668 /* The color as given in the Blt function is in the format of the frame-buffer...
2669 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2671 if (This
->resource
.format
== WINED3DFMT_P8
) {
2672 if (This
->palette
) {
2673 color
= ((0xFF000000) |
2674 (This
->palette
->palents
[DDBltFx
->u5
.dwFillColor
].peRed
<< 16) |
2675 (This
->palette
->palents
[DDBltFx
->u5
.dwFillColor
].peGreen
<< 8) |
2676 (This
->palette
->palents
[DDBltFx
->u5
.dwFillColor
].peBlue
));
2681 else if (This
->resource
.format
== WINED3DFMT_R5G6B5
) {
2682 if (DDBltFx
->u5
.dwFillColor
== 0xFFFF) {
2685 color
= ((0xFF000000) |
2686 ((DDBltFx
->u5
.dwFillColor
& 0xF800) << 8) |
2687 ((DDBltFx
->u5
.dwFillColor
& 0x07E0) << 5) |
2688 ((DDBltFx
->u5
.dwFillColor
& 0x001F) << 3));
2691 else if ((This
->resource
.format
== WINED3DFMT_R8G8B8
) ||
2692 (This
->resource
.format
== WINED3DFMT_X8R8G8B8
) ) {
2693 color
= 0xFF000000 | DDBltFx
->u5
.dwFillColor
;
2695 else if (This
->resource
.format
== WINED3DFMT_A8R8G8B8
) {
2696 color
= DDBltFx
->u5
.dwFillColor
;
2699 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2700 return WINED3DERR_INVALIDCALL
;
2703 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice
);
2704 IWineD3DDevice_GetSwapChain((IWineD3DDevice
*)myDevice
, 0, (IWineD3DSwapChain
**)&implSwapChain
);
2705 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) implSwapChain
);
2706 if(implSwapChain
->backBuffer
&& This
== (IWineD3DSurfaceImpl
*) implSwapChain
->backBuffer
[0]) {
2707 glDrawBuffer(GL_BACK
);
2708 checkGLcall("glDrawBuffer(GL_BACK)");
2710 else if (This
== (IWineD3DSurfaceImpl
*) implSwapChain
->frontBuffer
) {
2711 glDrawBuffer(GL_FRONT
);
2712 checkGLcall("glDrawBuffer(GL_FRONT)");
2715 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2716 return WINED3DERR_INVALIDCALL
;
2719 TRACE("(%p) executing Render Target override, color = %x\n", This
, color
);
2721 IWineD3DDevice_Clear( (IWineD3DDevice
*) myDevice
,
2722 1 /* Number of rectangles */,
2724 WINED3DCLEAR_TARGET
,
2729 /* Restore the original draw buffer */
2730 if(implSwapChain
->backBuffer
&& implSwapChain
->backBuffer
[0]) {
2731 glDrawBuffer(GL_BACK
);
2732 vcheckGLcall("glDrawBuffer");
2738 /* Default: Fall back to the generic blt */
2739 return WINED3DERR_INVALIDCALL
;
2742 static HRESULT WINAPI
IWineD3DSurfaceImpl_Blt(IWineD3DSurface
*iface
, RECT
*DestRect
, IWineD3DSurface
*SrcSurface
, RECT
*SrcRect
, DWORD Flags
, DDBLTFX
*DDBltFx
) {
2743 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2744 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
2745 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
);
2746 TRACE("(%p): Usage is %s\n", This
, debug_d3dusage(This
->resource
.usage
));
2748 /* Special cases for RenderTargets */
2749 if( (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ||
2750 ( Src
&& (Src
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) )) {
2751 if(IWineD3DSurfaceImpl_BltOverride(This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
) == WINED3D_OK
) return WINED3D_OK
;
2754 /* For the rest call the X11 surface implementation.
2755 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2756 * other Blts are rather rare
2758 return IWineGDISurfaceImpl_Blt(iface
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
);
2761 HRESULT WINAPI
IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface
*iface
, DWORD Flags
) {
2762 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2763 TRACE("(%p)->(%x)\n", This
, Flags
);
2768 case DDGBS_ISBLTDONE
:
2772 return DDERR_INVALIDPARAMS
;
2776 HRESULT WINAPI
IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface
*iface
, DWORD Flags
) {
2777 /* XXX: DDERR_INVALIDSURFACETYPE */
2779 TRACE("(%p)->(%08x)\n",iface
,Flags
);
2782 case DDGFS_ISFLIPDONE
:
2786 return DDERR_INVALIDPARAMS
;
2790 HRESULT WINAPI
IWineD3DSurfaceImpl_IsLost(IWineD3DSurface
*iface
) {
2791 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2792 TRACE("(%p)\n", This
);
2794 return This
->Flags
& SFLAG_LOST
? DDERR_SURFACELOST
: WINED3D_OK
;
2797 HRESULT WINAPI
IWineD3DSurfaceImpl_Restore(IWineD3DSurface
*iface
) {
2798 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2799 TRACE("(%p)\n", This
);
2801 /* So far we don't lose anything :) */
2802 This
->Flags
&= ~SFLAG_LOST
;
2806 HRESULT WINAPI
IWineD3DSurfaceImpl_BltFast(IWineD3DSurface
*iface
, DWORD dstx
, DWORD dsty
, IWineD3DSurface
*Source
, RECT
*rsrc
, DWORD trans
) {
2807 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2808 IWineD3DSurfaceImpl
*srcImpl
= (IWineD3DSurfaceImpl
*) Source
;
2809 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface
, dstx
, dsty
, Source
, rsrc
, trans
);
2811 /* Special cases for RenderTargets */
2812 if( (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ||
2813 ( srcImpl
&& (srcImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) )) {
2815 RECT SrcRect
, DstRect
;
2819 SrcRect
.left
= rsrc
->left
;
2820 SrcRect
.top
= rsrc
->top
;
2821 SrcRect
.bottom
= rsrc
->bottom
;
2822 SrcRect
.right
= rsrc
->right
;
2826 SrcRect
.right
= srcImpl
->currentDesc
.Width
;
2827 SrcRect
.bottom
= srcImpl
->currentDesc
.Height
;
2830 DstRect
.left
= dstx
;
2832 DstRect
.right
= dstx
+ SrcRect
.right
- SrcRect
.left
;
2833 DstRect
.bottom
= dsty
+ SrcRect
.bottom
- SrcRect
.top
;
2835 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2836 if(trans
& DDBLTFAST_SRCCOLORKEY
)
2837 Flags
|= DDBLT_KEYSRC
;
2838 if(trans
& DDBLTFAST_DESTCOLORKEY
)
2839 Flags
|= DDBLT_KEYDEST
;
2840 if(trans
& DDBLTFAST_WAIT
)
2841 Flags
|= DDBLT_WAIT
;
2842 if(trans
& DDBLTFAST_DONOTWAIT
)
2843 Flags
|= DDBLT_DONOTWAIT
;
2845 if(IWineD3DSurfaceImpl_BltOverride(This
, &DstRect
, Source
, &SrcRect
, Flags
, NULL
) == WINED3D_OK
) return WINED3D_OK
;
2849 return IWineGDISurfaceImpl_BltFast(iface
, dstx
, dsty
, Source
, rsrc
, trans
);
2852 HRESULT WINAPI
IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface
*iface
, IWineD3DPalette
**Pal
) {
2853 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2854 TRACE("(%p)->(%p)\n", This
, Pal
);
2856 *Pal
= (IWineD3DPalette
*) This
->palette
;
2860 HRESULT WINAPI
IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface
*iface
) {
2861 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2863 IWineD3DPaletteImpl
*pal
= This
->palette
;
2865 TRACE("(%p)\n", This
);
2867 if(This
->resource
.format
== WINED3DFMT_P8
||
2868 This
->resource
.format
== WINED3DFMT_A8P8
)
2870 TRACE("Dirtifying surface\n");
2871 This
->Flags
|= SFLAG_DIRTY
;
2874 if(This
->Flags
& SFLAG_DIBSECTION
) {
2875 TRACE("(%p): Updating the hdc's palette\n", This
);
2876 for (n
=0; n
<256; n
++) {
2878 col
[n
].rgbRed
= pal
->palents
[n
].peRed
;
2879 col
[n
].rgbGreen
= pal
->palents
[n
].peGreen
;
2880 col
[n
].rgbBlue
= pal
->palents
[n
].peBlue
;
2882 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
2883 /* Use the default device palette */
2884 col
[n
].rgbRed
= device
->palettes
[device
->currentPalette
][n
].peRed
;
2885 col
[n
].rgbGreen
= device
->palettes
[device
->currentPalette
][n
].peGreen
;
2886 col
[n
].rgbBlue
= device
->palettes
[device
->currentPalette
][n
].peBlue
;
2888 col
[n
].rgbReserved
= 0;
2890 SetDIBColorTable(This
->hDC
, 0, 256, col
);
2896 HRESULT WINAPI
IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface
*iface
, IWineD3DPalette
*Pal
) {
2897 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2898 IWineD3DPaletteImpl
*PalImpl
= (IWineD3DPaletteImpl
*) Pal
;
2899 TRACE("(%p)->(%p)\n", This
, Pal
);
2901 if(This
->palette
!= NULL
)
2902 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
2903 This
->palette
->Flags
&= ~DDPCAPS_PRIMARYSURFACE
;
2905 if(PalImpl
!= NULL
) {
2906 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
2907 /* Set the device's main palette if the palette
2908 * wasn't a primary palette before
2910 if(!(PalImpl
->Flags
& DDPCAPS_PRIMARYSURFACE
)) {
2911 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
2914 for(i
=0; i
< 256; i
++) {
2915 device
->palettes
[device
->currentPalette
][i
] = PalImpl
->palents
[i
];
2919 (PalImpl
)->Flags
|= DDPCAPS_PRIMARYSURFACE
;
2922 This
->palette
= PalImpl
;
2924 return IWineD3DSurface_RealizePalette(iface
);
2927 HRESULT WINAPI
IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface
*iface
, DWORD Flags
, DDCOLORKEY
*CKey
) {
2928 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2929 TRACE("(%p)->(%08x,%p)\n", This
, Flags
, CKey
);
2931 if ((Flags
& DDCKEY_COLORSPACE
) != 0) {
2932 FIXME(" colorkey value not supported (%08x) !\n", Flags
);
2933 return DDERR_INVALIDPARAMS
;
2936 /* Dirtify the surface, but only if a key was changed */
2938 switch (Flags
& ~DDCKEY_COLORSPACE
) {
2939 case DDCKEY_DESTBLT
:
2940 This
->DestBltCKey
= *CKey
;
2941 This
->CKeyFlags
|= DDSD_CKDESTBLT
;
2944 case DDCKEY_DESTOVERLAY
:
2945 This
->DestOverlayCKey
= *CKey
;
2946 This
->CKeyFlags
|= DDSD_CKDESTOVERLAY
;
2949 case DDCKEY_SRCOVERLAY
:
2950 This
->SrcOverlayCKey
= *CKey
;
2951 This
->CKeyFlags
|= DDSD_CKSRCOVERLAY
;
2955 This
->SrcBltCKey
= *CKey
;
2956 This
->CKeyFlags
|= DDSD_CKSRCBLT
;
2961 switch (Flags
& ~DDCKEY_COLORSPACE
) {
2962 case DDCKEY_DESTBLT
:
2963 This
->CKeyFlags
&= ~DDSD_CKDESTBLT
;
2966 case DDCKEY_DESTOVERLAY
:
2967 This
->CKeyFlags
&= ~DDSD_CKDESTOVERLAY
;
2970 case DDCKEY_SRCOVERLAY
:
2971 This
->CKeyFlags
&= ~DDSD_CKSRCOVERLAY
;
2975 This
->CKeyFlags
&= ~DDSD_CKSRCBLT
;
2983 static HRESULT WINAPI
IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface
*iface
) {
2984 /** Check against the maximum texture sizes supported by the video card **/
2985 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2987 TRACE("%p\n", This
);
2988 if ((This
->pow2Width
> GL_LIMITS(texture_size
) || This
->pow2Height
> GL_LIMITS(texture_size
)) && !(This
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
))) {
2989 /* one of three options
2990 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)
2991 2: Set the texture to the maxium size (bad idea)
2992 3: WARN and return WINED3DERR_NOTAVAILABLE;
2993 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.
2995 WARN("(%p) Creating an oversized surface\n", This
);
2996 This
->Flags
|= SFLAG_OVERSIZE
;
2998 /* This will be initialized on the first blt */
2999 This
->glRect
.left
= 0;
3000 This
->glRect
.top
= 0;
3001 This
->glRect
.right
= 0;
3002 This
->glRect
.bottom
= 0;
3004 /* No oversize, gl rect is the full texture size */
3005 This
->Flags
&= ~SFLAG_OVERSIZE
;
3006 This
->glRect
.left
= 0;
3007 This
->glRect
.top
= 0;
3008 This
->glRect
.right
= This
->pow2Width
;
3009 This
->glRect
.bottom
= This
->pow2Height
;
3015 DWORD WINAPI
IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface
*iface
) {
3016 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3018 TRACE("(%p)\n", This
);
3020 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3021 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3022 ie pitch = (width/4) * bytes per block */
3023 if (This
->resource
.format
== WINED3DFMT_DXT1
) /* DXT1 is 8 bytes per block */
3024 ret
= (This
->currentDesc
.Width
>> 2) << 3;
3025 else if (This
->resource
.format
== WINED3DFMT_DXT2
|| This
->resource
.format
== WINED3DFMT_DXT3
||
3026 This
->resource
.format
== WINED3DFMT_DXT4
|| This
->resource
.format
== WINED3DFMT_DXT5
) /* DXT2/3/4/5 is 16 bytes per block */
3027 ret
= (This
->currentDesc
.Width
>> 2) << 4;
3029 if (NP2_REPACK
== wined3d_settings
.nonpower2_mode
|| This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
3030 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
3031 ret
= This
->bytesPerPixel
* This
->currentDesc
.Width
; /* Bytes / row */
3033 ret
= This
->bytesPerPixel
* This
->pow2Width
;
3035 /* Surfaces are 32 bit aligned */
3036 ret
= (ret
+ SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
3038 TRACE("(%p) Returning %d\n", This
, ret
);
3042 HRESULT WINAPI
IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface
*iface
, LONG X
, LONG Y
) {
3043 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3045 FIXME("(%p)->(%d,%d) Stub!\n", This
, X
, Y
);
3047 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3049 TRACE("(%p): Not an overlay surface\n", This
);
3050 return DDERR_NOTAOVERLAYSURFACE
;
3056 HRESULT WINAPI
IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface
*iface
, LONG
*X
, LONG
*Y
) {
3057 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3059 FIXME("(%p)->(%p,%p) Stub!\n", This
, X
, Y
);
3061 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3063 TRACE("(%p): Not an overlay surface\n", This
);
3064 return DDERR_NOTAOVERLAYSURFACE
;
3070 HRESULT WINAPI
IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface
*iface
, DWORD Flags
, IWineD3DSurface
*Ref
) {
3071 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3072 IWineD3DSurfaceImpl
*RefImpl
= (IWineD3DSurfaceImpl
*) Ref
;
3074 FIXME("(%p)->(%08x,%p) Stub!\n", This
, Flags
, RefImpl
);
3076 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3078 TRACE("(%p): Not an overlay surface\n", This
);
3079 return DDERR_NOTAOVERLAYSURFACE
;
3085 HRESULT WINAPI
IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface
*iface
, RECT
*SrcRect
, IWineD3DSurface
*DstSurface
, RECT
*DstRect
, DWORD Flags
, WINEDDOVERLAYFX
*FX
) {
3086 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3087 IWineD3DSurfaceImpl
*Dst
= (IWineD3DSurfaceImpl
*) DstSurface
;
3088 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This
, SrcRect
, Dst
, DstRect
, Flags
, FX
);
3090 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3092 TRACE("(%p): Not an overlay surface\n", This
);
3093 return DDERR_NOTAOVERLAYSURFACE
;
3099 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl
=
3102 IWineD3DSurfaceImpl_QueryInterface
,
3103 IWineD3DSurfaceImpl_AddRef
,
3104 IWineD3DSurfaceImpl_Release
,
3105 /* IWineD3DResource */
3106 IWineD3DSurfaceImpl_GetParent
,
3107 IWineD3DSurfaceImpl_GetDevice
,
3108 IWineD3DSurfaceImpl_SetPrivateData
,
3109 IWineD3DSurfaceImpl_GetPrivateData
,
3110 IWineD3DSurfaceImpl_FreePrivateData
,
3111 IWineD3DSurfaceImpl_SetPriority
,
3112 IWineD3DSurfaceImpl_GetPriority
,
3113 IWineD3DSurfaceImpl_PreLoad
,
3114 IWineD3DSurfaceImpl_GetType
,
3115 /* IWineD3DSurface */
3116 IWineD3DSurfaceImpl_GetContainerParent
,
3117 IWineD3DSurfaceImpl_GetContainer
,
3118 IWineD3DSurfaceImpl_GetDesc
,
3119 IWineD3DSurfaceImpl_LockRect
,
3120 IWineD3DSurfaceImpl_UnlockRect
,
3121 IWineD3DSurfaceImpl_GetDC
,
3122 IWineD3DSurfaceImpl_ReleaseDC
,
3123 IWineD3DSurfaceImpl_Flip
,
3124 IWineD3DSurfaceImpl_Blt
,
3125 IWineD3DSurfaceImpl_GetBltStatus
,
3126 IWineD3DSurfaceImpl_GetFlipStatus
,
3127 IWineD3DSurfaceImpl_IsLost
,
3128 IWineD3DSurfaceImpl_Restore
,
3129 IWineD3DSurfaceImpl_BltFast
,
3130 IWineD3DSurfaceImpl_GetPalette
,
3131 IWineD3DSurfaceImpl_SetPalette
,
3132 IWineD3DSurfaceImpl_RealizePalette
,
3133 IWineD3DSurfaceImpl_SetColorKey
,
3134 IWineD3DSurfaceImpl_GetPitch
,
3135 IWineD3DSurfaceImpl_SetMem
,
3136 IWineD3DSurfaceImpl_SetOverlayPosition
,
3137 IWineD3DSurfaceImpl_GetOverlayPosition
,
3138 IWineD3DSurfaceImpl_UpdateOverlayZOrder
,
3139 IWineD3DSurfaceImpl_UpdateOverlay
,
3141 IWineD3DSurfaceImpl_CleanDirtyRect
,
3142 IWineD3DSurfaceImpl_AddDirtyRect
,
3143 IWineD3DSurfaceImpl_LoadTexture
,
3144 IWineD3DSurfaceImpl_SaveSnapshot
,
3145 IWineD3DSurfaceImpl_SetContainer
,
3146 IWineD3DSurfaceImpl_SetPBufferState
,
3147 IWineD3DSurfaceImpl_SetGlTextureDesc
,
3148 IWineD3DSurfaceImpl_GetGlDesc
,
3149 IWineD3DSurfaceImpl_GetData
,
3150 IWineD3DSurfaceImpl_SetFormat
,
3151 IWineD3DSurfaceImpl_PrivateSetup