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
51 HRESULT
d3dfmt_convert_surface(BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
, UINT height
, UINT outpitch
, CONVERT_TYPES convert
, IWineD3DSurfaceImpl
*surf
);
53 static void surface_download_data(IWineD3DSurfaceImpl
*This
) {
54 if (This
->resource
.format
== WINED3DFMT_DXT1
||
55 This
->resource
.format
== WINED3DFMT_DXT2
|| This
->resource
.format
== WINED3DFMT_DXT3
||
56 This
->resource
.format
== WINED3DFMT_DXT4
|| This
->resource
.format
== WINED3DFMT_DXT5
) {
57 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) { /* We can assume this as the texture would not have been created otherwise */
58 FIXME("(%p) : Attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This
);
60 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This
, This
->glDescription
.level
,
61 This
->glDescription
.glFormat
, This
->glDescription
.glType
, This
->resource
.allocatedMemory
);
65 GL_EXTCALL(glGetCompressedTexImageARB(This
->glDescription
.target
, This
->glDescription
.level
, This
->resource
.allocatedMemory
));
66 checkGLcall("glGetCompressedTexImageARB()");
75 if(This
->Flags
& SFLAG_CONVERTED
) {
76 FIXME("Read back converted textures unsupported\n");
80 if (This
->Flags
& SFLAG_NONPOW2
) {
81 src_pitch
= This
->bytesPerPixel
* This
->pow2Width
;
82 dst_pitch
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) This
);
83 src_pitch
= (src_pitch
+ SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
84 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* This
->pow2Height
);
86 mem
= This
->resource
.allocatedMemory
;
89 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This
, This
->glDescription
.level
,
90 This
->glDescription
.glFormat
, This
->glDescription
.glType
, mem
);
94 glGetTexImage(This
->glDescription
.target
, This
->glDescription
.level
, This
->glDescription
.glFormat
,
95 This
->glDescription
.glType
, mem
);
96 checkGLcall("glGetTexImage()");
100 if (This
->Flags
& SFLAG_NONPOW2
) {
101 LPBYTE src_data
, dst_data
;
104 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
105 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
106 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
108 * We're doing this...
110 * instead of boxing the texture :
111 * |<-texture width ->| -->pow2width| /\
112 * |111111111111111111| | |
113 * |222 Texture 222222| boxed empty | texture height
114 * |3333 Data 33333333| | |
115 * |444444444444444444| | \/
116 * ----------------------------------- |
117 * | boxed empty | boxed empty | pow2height
119 * -----------------------------------
122 * we're repacking the data to the expected texture width
124 * |<-texture width ->| -->pow2width| /\
125 * |111111111111111111222222222222222| |
126 * |222333333333333333333444444444444| texture height
130 * | empty | pow2height
132 * -----------------------------------
136 * |<-texture width ->| /\
137 * |111111111111111111|
138 * |222222222222222222|texture height
139 * |333333333333333333|
140 * |444444444444444444| \/
141 * --------------------
143 * this also means that any references to allocatedMemory should work with the data as if were a
144 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
146 * internally the texture is still stored in a boxed format so any references to textureName will
147 * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
149 * Performance should not be an issue, because applications normally do not lock the surfaces when
150 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
151 * and doesn't have to be re-read.
154 dst_data
= This
->resource
.allocatedMemory
;
155 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This
, src_pitch
, dst_pitch
);
156 for (y
= 1 ; y
< This
->currentDesc
.Height
; y
++) {
157 /* skip the first row */
158 src_data
+= src_pitch
;
159 dst_data
+= dst_pitch
;
160 memcpy(dst_data
, src_data
, dst_pitch
);
163 HeapFree(GetProcessHeap(), 0, mem
);
168 static void surface_upload_data(IWineD3DSurfaceImpl
*This
, GLsizei width
, GLsizei height
, GLenum format
, GLenum type
, const GLvoid
*data
) {
169 if (This
->resource
.format
== WINED3DFMT_DXT1
||
170 This
->resource
.format
== WINED3DFMT_DXT2
|| This
->resource
.format
== WINED3DFMT_DXT3
||
171 This
->resource
.format
== WINED3DFMT_DXT4
|| This
->resource
.format
== WINED3DFMT_DXT5
) {
172 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
173 FIXME("Using DXT1/3/5 without advertized support\n");
175 TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This
, width
, height
, data
);
177 /* glCompressedTexSubImage2D for uploading and glTexImage2D for allocating does not work well on some drivers(r200 dri, MacOS ATI driver)
178 * glCompressedTexImage2D does not accept NULL pointers. So for compressed textures surface_allocate_surface does nothing, and this
179 * function uses glCompressedTexImage2D instead of the SubImage call
181 GL_EXTCALL(glCompressedTexImage2DARB(This
->glDescription
.target
, This
->glDescription
.level
, This
->glDescription
.glFormatInternal
,
182 width
, height
, 0 /* border */, This
->resource
.size
, data
));
183 checkGLcall("glCompressedTexSubImage2D");
187 TRACE("(%p) : Calling glTexSubImage2D w %d, h %d, data, %p\n", This
, width
, height
, data
);
189 glTexSubImage2D(This
->glDescription
.target
, This
->glDescription
.level
, 0, 0, width
, height
, format
, type
, data
);
190 checkGLcall("glTexSubImage2D");
195 static void surface_allocate_surface(IWineD3DSurfaceImpl
*This
, GLenum internal
, GLsizei width
, GLsizei height
, GLenum format
, GLenum type
) {
196 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
,
197 This
->glDescription
.target
, This
->glDescription
.level
, debug_d3dformat(This
->resource
.format
), internal
, width
, height
, format
, type
);
199 if (This
->resource
.format
== WINED3DFMT_DXT1
||
200 This
->resource
.format
== WINED3DFMT_DXT2
|| This
->resource
.format
== WINED3DFMT_DXT3
||
201 This
->resource
.format
== WINED3DFMT_DXT4
|| This
->resource
.format
== WINED3DFMT_DXT5
) {
202 /* glCompressedTexImage2D does not accept NULL pointers, so we cannot allocate a compressed texture without uploading data */
203 TRACE("Not allocating compressed surfaces, surface_upload_data will specify them\n");
209 glTexImage2D(This
->glDescription
.target
, This
->glDescription
.level
, internal
, width
, height
, 0, format
, type
, NULL
);
210 checkGLcall("glTexImage2D");
215 /* *******************************************
216 IWineD3DSurface IUnknown parts follow
217 ******************************************* */
218 HRESULT WINAPI
IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface
*iface
, REFIID riid
, LPVOID
*ppobj
)
220 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
221 /* Warn ,but be nice about things */
222 TRACE("(%p)->(%s,%p)\n", This
,debugstr_guid(riid
),ppobj
);
224 if (IsEqualGUID(riid
, &IID_IUnknown
)
225 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
226 || IsEqualGUID(riid
, &IID_IWineD3DResource
)
227 || IsEqualGUID(riid
, &IID_IWineD3DSurface
)) {
228 IUnknown_AddRef((IUnknown
*)iface
);
233 return E_NOINTERFACE
;
236 ULONG WINAPI
IWineD3DSurfaceImpl_AddRef(IWineD3DSurface
*iface
) {
237 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
238 ULONG ref
= InterlockedIncrement(&This
->resource
.ref
);
239 TRACE("(%p) : AddRef increasing from %d\n", This
,ref
- 1);
243 ULONG WINAPI
IWineD3DSurfaceImpl_Release(IWineD3DSurface
*iface
) {
244 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
245 ULONG ref
= InterlockedDecrement(&This
->resource
.ref
);
246 TRACE("(%p) : Releasing from %d\n", This
, ref
+ 1);
248 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*) This
->resource
.wineD3DDevice
;
249 TRACE("(%p) : cleaning up\n", This
);
251 if(iface
== device
->lastActiveRenderTarget
) {
252 IWineD3DSwapChainImpl
*swapchain
= device
->swapchains
? (IWineD3DSwapChainImpl
*) device
->swapchains
[0] : NULL
;
254 TRACE("Last active render target destroyed\n");
255 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
256 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
257 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
258 * and the lastActiveRenderTarget member shouldn't matter
261 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0] != iface
) {
262 TRACE("Activating primary back buffer\n");
263 ActivateContext(device
, swapchain
->backBuffer
[0], CTXUSAGE_RESOURCELOAD
);
264 } else if(!swapchain
->backBuffer
&& swapchain
->frontBuffer
!= iface
) {
265 /* Single buffering environment */
266 TRACE("Activating primary front buffer\n");
267 ActivateContext(device
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
269 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
270 /* Implicit render target destroyed, that means the device is being destroyed
271 * whatever we set here, it shouldn't matter
273 device
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadbabe;
276 /* May happen during ddraw uninitialization */
277 TRACE("Render target set, but swapchain does not exist!\n");
278 device
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadcafe;
282 if (This
->glDescription
.textureName
!= 0) { /* release the openGL texture.. */
284 TRACE("Deleting texture %d\n", This
->glDescription
.textureName
);
285 glDeleteTextures(1, &This
->glDescription
.textureName
);
289 if(This
->Flags
& SFLAG_DIBSECTION
) {
291 SelectObject(This
->hDC
, This
->dib
.holdbitmap
);
293 /* Release the DIB section */
294 DeleteObject(This
->dib
.DIBsection
);
295 This
->dib
.bitmap_data
= NULL
;
296 This
->resource
.allocatedMemory
= NULL
;
298 if(This
->Flags
& SFLAG_USERPTR
) IWineD3DSurface_SetMem(iface
, NULL
);
300 HeapFree(GetProcessHeap(), 0, This
->palette9
);
302 IWineD3DResourceImpl_CleanUp((IWineD3DResource
*)iface
);
303 if(iface
== device
->ddraw_primary
)
304 device
->ddraw_primary
= NULL
;
306 TRACE("(%p) Released\n", This
);
307 HeapFree(GetProcessHeap(), 0, This
);
313 /* ****************************************************
314 IWineD3DSurface IWineD3DResource parts follow
315 **************************************************** */
316 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface
*iface
, IWineD3DDevice
** ppDevice
) {
317 return IWineD3DResourceImpl_GetDevice((IWineD3DResource
*)iface
, ppDevice
);
320 HRESULT WINAPI
IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface
*iface
, REFGUID refguid
, CONST
void* pData
, DWORD SizeOfData
, DWORD Flags
) {
321 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource
*)iface
, refguid
, pData
, SizeOfData
, Flags
);
324 HRESULT WINAPI
IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface
*iface
, REFGUID refguid
, void* pData
, DWORD
* pSizeOfData
) {
325 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource
*)iface
, refguid
, pData
, pSizeOfData
);
328 HRESULT WINAPI
IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface
*iface
, REFGUID refguid
) {
329 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource
*)iface
, refguid
);
332 DWORD WINAPI
IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface
*iface
, DWORD PriorityNew
) {
333 return IWineD3DResourceImpl_SetPriority((IWineD3DResource
*)iface
, PriorityNew
);
336 DWORD WINAPI
IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface
*iface
) {
337 return IWineD3DResourceImpl_GetPriority((IWineD3DResource
*)iface
);
340 void WINAPI
IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface
*iface
) {
341 /* TODO: re-write the way textures and managed,
342 * use a 'opengl context manager' to manage RenderTarget surfaces
343 ** *********************************************************/
345 /* TODO: check for locks */
346 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
347 IWineD3DBaseTexture
*baseTexture
= NULL
;
348 TRACE("(%p)Checking to see if the container is a base texture\n", This
);
349 if (IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
) == WINED3D_OK
) {
350 TRACE("Passing to conatiner\n");
351 IWineD3DBaseTexture_PreLoad(baseTexture
);
352 IWineD3DBaseTexture_Release(baseTexture
);
354 TRACE("(%p) : About to load surface\n", This
);
356 #if 0 /* TODO: context manager support */
357 IWineD3DContextManager_PushState(This
->contextManager
, GL_TEXTURE_2D
, ENABLED
, NOW
/* make sure the state is applied now */);
359 glEnable(This
->glDescription
.target
);/* make sure texture support is enabled in this context */
360 if (!This
->glDescription
.level
) {
361 if (!This
->glDescription
.textureName
) {
362 glGenTextures(1, &This
->glDescription
.textureName
);
363 checkGLcall("glGenTextures");
364 TRACE("Surface %p given name %d\n", This
, This
->glDescription
.textureName
);
366 glBindTexture(This
->glDescription
.target
, This
->glDescription
.textureName
);
367 checkGLcall("glBindTexture");
368 IWineD3DSurface_LoadTexture(iface
);
369 /* This is where we should be reducing the amount of GLMemoryUsed */
370 } else if (This
->glDescription
.textureName
) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
371 /* assume this is a coding error not a real error for now */
372 FIXME("Mipmap surface has a glTexture bound to it!\n");
374 if (This
->resource
.pool
== WINED3DPOOL_DEFAULT
) {
375 /* Tell opengl to try and keep this texture in video ram (well mostly) */
378 glPrioritizeTextures(1, &This
->glDescription
.textureName
, &tmp
);
380 /* TODO: disable texture support, if it wastn't enabled when we entered. */
381 #if 0 /* TODO: context manager support */
382 IWineD3DContextManager_PopState(This
->contextManager
, GL_TEXTURE_2D
, DISABLED
,DELAYED
383 /* we don't care when the state is disabled(if atall) */);
390 WINED3DRESOURCETYPE WINAPI
IWineD3DSurfaceImpl_GetType(IWineD3DSurface
*iface
) {
391 TRACE("(%p) : calling resourceimpl_GetType\n", iface
);
392 return IWineD3DResourceImpl_GetType((IWineD3DResource
*)iface
);
395 HRESULT WINAPI
IWineD3DSurfaceImpl_GetParent(IWineD3DSurface
*iface
, IUnknown
**pParent
) {
396 TRACE("(%p) : calling resourceimpl_GetParent\n", iface
);
397 return IWineD3DResourceImpl_GetParent((IWineD3DResource
*)iface
, pParent
);
400 /* ******************************************************
401 IWineD3DSurface IWineD3DSurface parts follow
402 ****************************************************** */
404 HRESULT WINAPI
IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface
* iface
, REFIID riid
, void** ppContainer
) {
405 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
406 IWineD3DBase
*container
= 0;
408 TRACE("(This %p, riid %s, ppContainer %p)\n", This
, debugstr_guid(riid
), ppContainer
);
411 ERR("Called without a valid ppContainer.\n");
415 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
416 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
417 * GetContainer will return the Direct3D device used to create the surface.
419 if (This
->container
) {
420 container
= This
->container
;
422 container
= (IWineD3DBase
*)This
->resource
.wineD3DDevice
;
425 TRACE("Relaying to QueryInterface\n");
426 return IUnknown_QueryInterface(container
, riid
, ppContainer
);
429 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface
*iface
, WINED3DSURFACE_DESC
*pDesc
) {
430 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
432 TRACE("(%p) : copying into %p\n", This
, pDesc
);
433 if(pDesc
->Format
!= NULL
) *(pDesc
->Format
) = This
->resource
.format
;
434 if(pDesc
->Type
!= NULL
) *(pDesc
->Type
) = This
->resource
.resourceType
;
435 if(pDesc
->Usage
!= NULL
) *(pDesc
->Usage
) = This
->resource
.usage
;
436 if(pDesc
->Pool
!= NULL
) *(pDesc
->Pool
) = This
->resource
.pool
;
437 if(pDesc
->Size
!= NULL
) *(pDesc
->Size
) = This
->resource
.size
; /* dx8 only */
438 if(pDesc
->MultiSampleType
!= NULL
) *(pDesc
->MultiSampleType
) = This
->currentDesc
.MultiSampleType
;
439 if(pDesc
->MultiSampleQuality
!= NULL
) *(pDesc
->MultiSampleQuality
) = This
->currentDesc
.MultiSampleQuality
;
440 if(pDesc
->Width
!= NULL
) *(pDesc
->Width
) = This
->currentDesc
.Width
;
441 if(pDesc
->Height
!= NULL
) *(pDesc
->Height
) = This
->currentDesc
.Height
;
445 void WINAPI
IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface
*iface
, UINT textureName
, int target
) {
446 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
447 TRACE("(%p) : setting textureName %u, target %i\n", This
, textureName
, target
);
448 if (This
->glDescription
.textureName
== 0 && textureName
!= 0) {
449 This
->Flags
|= SFLAG_DIRTY
;
450 IWineD3DSurface_AddDirtyRect(iface
, NULL
);
452 This
->glDescription
.textureName
= textureName
;
453 This
->glDescription
.target
= target
;
456 void WINAPI
IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface
*iface
, glDescriptor
**glDescription
) {
457 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
458 TRACE("(%p) : returning %p\n", This
, &This
->glDescription
);
459 *glDescription
= &This
->glDescription
;
462 /* TODO: think about moving this down to resource? */
463 const void *WINAPI
IWineD3DSurfaceImpl_GetData(IWineD3DSurface
*iface
) {
464 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
465 /* 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 */
466 if (This
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
467 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface
);
469 return (CONST
void*)(This
->resource
.allocatedMemory
);
472 static void read_from_framebuffer(IWineD3DSurfaceImpl
*This
, CONST RECT
*rect
, void *dest
, UINT pitch
, BOOL srcUpsideDown
) {
476 BYTE
*row
, *top
, *bottom
;
480 switch(This
->resource
.format
)
484 /* GL can't return palettized data, so read ARGB pixels into a
485 * separate block of memory and convert them into palettized format
486 * in software. Slow, but if the app means to use palettized render
487 * targets and locks it...
489 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
490 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
491 * for the color channels when palettizing the colors.
494 type
= GL_UNSIGNED_BYTE
;
496 mem
= HeapAlloc(GetProcessHeap(), 0, This
->resource
.size
* 3);
498 ERR("Out of memory\n");
501 bpp
= This
->bytesPerPixel
* 3;
507 fmt
= This
->glDescription
.glFormat
;
508 type
= This
->glDescription
.glType
;
509 bpp
= This
->bytesPerPixel
;
512 glReadPixels(rect
->left
, rect
->top
,
513 rect
->right
- rect
->left
,
514 rect
->bottom
- rect
->top
,
516 vcheckGLcall("glReadPixels");
518 /* TODO: Merge this with the palettization loop below for P8 targets */
522 /* glReadPixels returns the image upside down, and there is no way to prevent this.
523 Flip the lines in software */
524 len
= (rect
->right
- rect
->left
) * bpp
;
525 off
= rect
->left
* bpp
;
527 row
= HeapAlloc(GetProcessHeap(), 0, len
);
529 ERR("Out of memory\n");
530 if(This
->resource
.format
== WINED3DFMT_P8
) HeapFree(GetProcessHeap(), 0, mem
);
534 top
= mem
+ pitch
* rect
->top
;
535 bottom
= ((BYTE
*) mem
) + pitch
* ( rect
->bottom
- rect
->top
- 1);
536 for(i
= 0; i
< (rect
->bottom
- rect
->top
) / 2; i
++) {
537 memcpy(row
, top
+ off
, len
);
538 memcpy(top
+ off
, bottom
+ off
, len
);
539 memcpy(bottom
+ off
, row
, len
);
543 HeapFree(GetProcessHeap(), 0, row
);
546 if(This
->resource
.format
== WINED3DFMT_P8
) {
548 DWORD width
= pitch
/ 3;
551 pal
= This
->palette
->palents
;
553 pal
= This
->resource
.wineD3DDevice
->palettes
[This
->resource
.wineD3DDevice
->currentPalette
];
556 for(y
= rect
->top
; y
< rect
->bottom
; y
++) {
557 for(x
= rect
->left
; x
< rect
->right
; x
++) {
558 /* start lines pixels */
559 BYTE
*blue
= (BYTE
*) ((BYTE
*) mem
) + y
* pitch
+ x
* (sizeof(BYTE
) * 3);
560 BYTE
*green
= blue
+ 1;
561 BYTE
*red
= green
+ 1;
563 for(c
= 0; c
< 256; c
++) {
564 if(*red
== pal
[c
].peRed
&&
565 *green
== pal
[c
].peGreen
&&
566 *blue
== pal
[c
].peBlue
)
568 *((BYTE
*) dest
+ y
* width
+ x
) = c
;
574 HeapFree(GetProcessHeap(), 0, mem
);
578 static HRESULT WINAPI
IWineD3DSurfaceImpl_LockRect(IWineD3DSurface
*iface
, WINED3DLOCKED_RECT
* pLockedRect
, CONST RECT
* pRect
, DWORD Flags
) {
579 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
580 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
581 IWineD3DSwapChainImpl
*swapchain
= NULL
;
583 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
585 if (!(This
->Flags
& SFLAG_LOCKABLE
)) {
586 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
587 texture regions, and since the destination is an unlockable region we need
589 TRACE("Warning: trying to lock unlockable surf@%p\n", This
);
590 /*return WINED3DERR_INVALIDCALL; */
593 pLockedRect
->Pitch
= IWineD3DSurface_GetPitch(iface
);
595 /* Mark the surface locked */
596 This
->Flags
|= SFLAG_LOCKED
;
598 /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy */
599 if(!This
->resource
.allocatedMemory
) {
600 This
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap() ,0 , This
->resource
.size
+ 4);
601 This
->Flags
|= SFLAG_GLDIRTY
; /* This is the marker that surface data has to be downloaded */
604 /* Calculate the correct start address to report */
606 pLockedRect
->pBits
= This
->resource
.allocatedMemory
;
607 This
->lockedRect
.left
= 0;
608 This
->lockedRect
.top
= 0;
609 This
->lockedRect
.right
= This
->currentDesc
.Width
;
610 This
->lockedRect
.bottom
= This
->currentDesc
.Height
;
611 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
);
613 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
615 if ((pRect
->top
< 0) ||
617 (pRect
->left
>= pRect
->right
) ||
618 (pRect
->top
>= pRect
->bottom
) ||
619 (pRect
->right
> This
->currentDesc
.Width
) ||
620 (pRect
->bottom
> This
->currentDesc
.Height
))
622 WARN(" Invalid values in pRect !!!\n");
623 return WINED3DERR_INVALIDCALL
;
626 if (This
->resource
.format
== WINED3DFMT_DXT1
) { /* DXT1 is half byte per pixel */
627 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + ((pRect
->left
* This
->bytesPerPixel
/ 2));
629 pLockedRect
->pBits
= This
->resource
.allocatedMemory
+ (pLockedRect
->Pitch
* pRect
->top
) + (pRect
->left
* This
->bytesPerPixel
);
631 This
->lockedRect
.left
= pRect
->left
;
632 This
->lockedRect
.top
= pRect
->top
;
633 This
->lockedRect
.right
= pRect
->right
;
634 This
->lockedRect
.bottom
= pRect
->bottom
;
637 if (This
->Flags
& SFLAG_NONPOW2
) {
638 TRACE("Locking non-power 2 texture\n");
641 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
642 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
645 if(!(This
->Flags
& SFLAG_DYNLOCK
)) {
647 /* MAXLOCKCOUNT is defined in wined3d_private.h */
648 if(This
->lockCount
> MAXLOCKCOUNT
) {
649 TRACE("Surface is locked regularily, not freeing the system memory copy any more\n");
650 This
->Flags
|= SFLAG_DYNLOCK
;
654 if((Flags
& WINED3DLOCK_DISCARD
) || !(This
->Flags
& SFLAG_GLDIRTY
) ) {
655 TRACE("WINED3DLOCK_DISCARD flag passed, or local copy is up to date, not downloading data\n");
659 /* Now download the surface content from opengl
660 * Use the render target readback if the surface is on a swapchain(=onscreen render target) or the current primary target
661 * Offscreen targets which are not active at the moment or are higher targets(fbos) can be locked with the texture path
663 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
664 if(swapchain
|| iface
== myDevice
->render_targets
[0]) {
665 BOOL srcIsUpsideDown
;
667 if(wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
) {
668 static BOOL warned
= FALSE
;
670 ERR("The application tries to lock the render target, but render target locking is disabled\n");
673 if(swapchain
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
677 /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
678 * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
679 * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
680 * context->last_was_blit set on the unlock.
683 ActivateContext(myDevice
, iface
, CTXUSAGE_BLIT
);
685 /* Select the correct read buffer, and give some debug output.
686 * There is no need to keep track of the current read buffer or reset it, every part of the code
687 * that reads sets the read buffer as desired.
690 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
691 * Read from the back buffer
693 TRACE("Locking offscreen render target\n");
694 glReadBuffer(myDevice
->offscreenBuffer
);
695 srcIsUpsideDown
= TRUE
;
697 if(iface
== swapchain
->frontBuffer
) {
698 TRACE("Locking the front buffer\n");
699 glReadBuffer(GL_FRONT
);
700 } else if(swapchain
->backBuffer
&& iface
== swapchain
->backBuffer
[0]) {
701 TRACE("Locking the back buffer\n");
702 glReadBuffer(GL_BACK
);
704 /* Ok, there is an issue: OpenGL does not guarant any back buffer number, so all we can do is to read GL_BACK
705 * and hope it gives what the app wants
707 FIXME("Application is locking a 2nd or higher back buffer\n");
708 glReadBuffer(GL_BACK
);
710 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
711 srcIsUpsideDown
= FALSE
;
714 switch(wined3d_settings
.rendertargetlock_mode
) {
718 read_from_framebuffer(This
, &This
->lockedRect
, This
->resource
.allocatedMemory
, pLockedRect
->Pitch
, srcIsUpsideDown
);
723 read_from_framebuffer(This
, &This
->lockedRect
, This
->resource
.allocatedMemory
, pLockedRect
->Pitch
, srcIsUpsideDown
);
724 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
729 /* Mark the local copy up to date if a full download was done */
730 if(This
->lockedRect
.left
== 0 &&
731 This
->lockedRect
.top
== 0 &&
732 This
->lockedRect
.right
== This
->currentDesc
.Width
&&
733 This
->lockedRect
.bottom
== This
->currentDesc
.Height
) {
734 This
->Flags
&= ~SFLAG_GLDIRTY
;
736 } else if(iface
== myDevice
->stencilBufferTarget
) {
737 /** the depth stencil in openGL has a format of GL_FLOAT
738 * which should be good for WINED3DFMT_D16_LOCKABLE
740 * it is unclear what format the stencil buffer is in except.
741 * 'Each index is converted to fixed point...
742 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
743 * mappings in the table GL_PIXEL_MAP_S_TO_S.
744 * glReadPixels(This->lockedRect.left,
745 * This->lockedRect.bottom - j - 1,
746 * This->lockedRect.right - This->lockedRect.left,
748 * GL_DEPTH_COMPONENT,
750 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
752 * Depth Stencil surfaces which are not the current depth stencil target should have their data in a
753 * gl texture(next path), or in local memory(early return because of missing SFLAG_GLDIRTY above). If
754 * none of that is the case the problem is not in this function :-)
755 ********************************************/
756 FIXME("Depth stencil locking not supported yet\n");
758 /* This path is for normal surfaces, offscreen render targets and everything else that is in a gl texture */
759 TRACE("locking an ordinarary surface\n");
761 /* TODO: Make sure that *any* context is active for this thread. It is not important which context that is,
762 * nor that is has any special setup(CTXUSAGE_LOADRESOURCE is fine), but the code below needs a context.
763 * A context is guaranteed to be there in a single threaded environment, but not with multithreading
765 if (0 != This
->glDescription
.textureName
) {
766 /* Now I have to copy thing bits back */
768 /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
769 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
771 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
772 checkGLcall("glActiveTextureARB");
775 IWineD3DDeviceImpl_MarkStateDirty(This
->resource
.wineD3DDevice
, STATE_SAMPLER(0));
776 IWineD3DSurface_PreLoad(iface
);
778 surface_download_data(This
);
781 /* The local copy is now up to date to the opengl one because a full download was done */
782 This
->Flags
&= ~SFLAG_GLDIRTY
;
786 if (Flags
& (WINED3DLOCK_NO_DIRTY_UPDATE
| WINED3DLOCK_READONLY
)) {
789 IWineD3DBaseTexture
*pBaseTexture
;
792 * as seen in msdn docs
794 IWineD3DSurface_AddDirtyRect(iface
, &This
->lockedRect
);
796 /** Dirtify Container if needed */
797 if (WINED3D_OK
== IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&pBaseTexture
) && pBaseTexture
!= NULL
) {
798 TRACE("Making container dirty\n");
799 IWineD3DBaseTexture_SetDirty(pBaseTexture
, TRUE
);
800 IWineD3DBaseTexture_Release(pBaseTexture
);
802 TRACE("Surface is standalone, no need to dirty the container\n");
806 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect
->pBits
, pLockedRect
->Pitch
, This
->Flags
& SFLAG_DIRTY
? 0 : 1);
810 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl
*This
) {
812 GLint prev_rasterpos
[4];
814 BOOL storechanged
= FALSE
, memory_allocated
= FALSE
;
818 UINT pitch
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) This
); /* target is argb, 4 byte */
820 glDisable(GL_TEXTURE_2D
);
821 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
824 vcheckGLcall("glFlush");
825 glGetIntegerv(GL_PACK_SWAP_BYTES
, &prev_store
);
826 vcheckGLcall("glIntegerv");
827 glGetIntegerv(GL_CURRENT_RASTER_POSITION
, &prev_rasterpos
[0]);
828 vcheckGLcall("glIntegerv");
829 glPixelZoom(1.0, -1.0);
830 vcheckGLcall("glPixelZoom");
832 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
833 glGetIntegerv(GL_UNPACK_ROW_LENGTH
, &skipBytes
);
834 glPixelStorei(GL_UNPACK_ROW_LENGTH
, This
->currentDesc
.Width
);
836 glRasterPos3i(This
->lockedRect
.left
, This
->lockedRect
.top
, 1);
837 vcheckGLcall("glRasterPos2f");
839 /* Some drivers(radeon dri, others?) don't like exceptions during
840 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
841 * after ReleaseDC. Reading it will cause an exception, which x11drv will
842 * catch to put the dib section in InSync mode, which leads to a crash
843 * and a blocked x server on my radeon card.
845 * The following lines read the dib section so it is put in inSync mode
846 * before glDrawPixels is called and the crash is prevented. There won't
847 * be any interfering gdi accesses, because UnlockRect is called from
848 * ReleaseDC, and the app won't use the dc any more afterwards.
850 if(This
->Flags
& SFLAG_DIBSECTION
) {
852 read
= This
->resource
.allocatedMemory
[0];
855 switch (This
->resource
.format
) {
856 /* No special care needed */
857 case WINED3DFMT_A4R4G4B4
:
858 case WINED3DFMT_R5G6B5
:
859 case WINED3DFMT_A1R5G5B5
:
860 case WINED3DFMT_R8G8B8
:
861 type
= This
->glDescription
.glType
;
862 fmt
= This
->glDescription
.glFormat
;
863 mem
= This
->resource
.allocatedMemory
;
864 bpp
= This
->bytesPerPixel
;
867 case WINED3DFMT_X4R4G4B4
:
870 unsigned short *data
;
871 data
= (unsigned short *)This
->resource
.allocatedMemory
;
872 size
= (This
->lockedRect
.bottom
- This
->lockedRect
.top
) * (This
->lockedRect
.right
- This
->lockedRect
.left
);
878 type
= This
->glDescription
.glType
;
879 fmt
= This
->glDescription
.glFormat
;
880 mem
= This
->resource
.allocatedMemory
;
881 bpp
= This
->bytesPerPixel
;
885 case WINED3DFMT_X1R5G5B5
:
888 unsigned short *data
;
889 data
= (unsigned short *)This
->resource
.allocatedMemory
;
890 size
= (This
->lockedRect
.bottom
- This
->lockedRect
.top
) * (This
->lockedRect
.right
- This
->lockedRect
.left
);
896 type
= This
->glDescription
.glType
;
897 fmt
= This
->glDescription
.glFormat
;
898 mem
= This
->resource
.allocatedMemory
;
899 bpp
= This
->bytesPerPixel
;
903 case WINED3DFMT_X8R8G8B8
:
905 /* make sure the X byte is set to alpha on, since it
906 could be any random value. This fixes the intro movie in Pirates! */
909 data
= (unsigned int *)This
->resource
.allocatedMemory
;
910 size
= (This
->lockedRect
.bottom
- This
->lockedRect
.top
) * (This
->lockedRect
.right
- This
->lockedRect
.left
);
919 case WINED3DFMT_A8R8G8B8
:
921 glPixelStorei(GL_PACK_SWAP_BYTES
, TRUE
);
922 vcheckGLcall("glPixelStorei");
924 type
= This
->glDescription
.glType
;
925 fmt
= This
->glDescription
.glFormat
;
926 mem
= This
->resource
.allocatedMemory
;
927 bpp
= This
->bytesPerPixel
;
931 case WINED3DFMT_A2R10G10B10
:
933 glPixelStorei(GL_PACK_SWAP_BYTES
, TRUE
);
934 vcheckGLcall("glPixelStorei");
936 type
= This
->glDescription
.glType
;
937 fmt
= This
->glDescription
.glFormat
;
938 mem
= This
->resource
.allocatedMemory
;
939 bpp
= This
->bytesPerPixel
;
945 int height
= This
->glRect
.bottom
- This
->glRect
.top
;
946 type
= GL_UNSIGNED_BYTE
;
949 mem
= HeapAlloc(GetProcessHeap(), 0, This
->resource
.size
* sizeof(DWORD
));
951 ERR("Out of memory\n");
954 memory_allocated
= TRUE
;
955 d3dfmt_convert_surface(This
->resource
.allocatedMemory
,
963 bpp
= This
->bytesPerPixel
* 4;
969 FIXME("Unsupported Format %u in locking func\n", This
->resource
.format
);
972 type
= This
->glDescription
.glType
;
973 fmt
= This
->glDescription
.glFormat
;
974 mem
= This
->resource
.allocatedMemory
;
975 bpp
= This
->bytesPerPixel
;
978 glDrawPixels(This
->lockedRect
.right
- This
->lockedRect
.left
,
979 (This
->lockedRect
.bottom
- This
->lockedRect
.top
)-1,
981 mem
+ bpp
* This
->lockedRect
.left
+ pitch
* This
->lockedRect
.top
);
982 checkGLcall("glDrawPixels");
983 glPixelZoom(1.0,1.0);
984 vcheckGLcall("glPixelZoom");
986 glRasterPos3iv(&prev_rasterpos
[0]);
987 vcheckGLcall("glRasterPos3iv");
989 /* Reset to previous pack row length */
990 glPixelStorei(GL_UNPACK_ROW_LENGTH
, skipBytes
);
991 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
993 glPixelStorei(GL_PACK_SWAP_BYTES
, prev_store
);
994 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
997 /* Blitting environment requires that 2D texturing is enabled. It was turned off before,
1000 glEnable(GL_TEXTURE_2D
);
1001 checkGLcall("glEnable(GL_TEXTURE_2D)");
1003 if(memory_allocated
) HeapFree(GetProcessHeap(), 0, mem
);
1007 static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl
*This
) {
1008 float glTexCoord
[4];
1010 glTexCoord
[0] = (float) This
->lockedRect
.left
/ (float) This
->pow2Width
; /* left */
1011 glTexCoord
[1] = (float) This
->lockedRect
.right
/ (float) This
->pow2Width
; /* right */
1012 glTexCoord
[2] = (float) This
->lockedRect
.top
/ (float) This
->pow2Height
; /* top */
1013 glTexCoord
[3] = (float) This
->lockedRect
.bottom
/ (float) This
->pow2Height
; /* bottom */
1015 IWineD3DSurface_PreLoad((IWineD3DSurface
*) This
);
1019 glBindTexture(GL_TEXTURE_2D
, This
->glDescription
.textureName
);
1020 checkGLcall("glEnable glBindTexture");
1022 /* No filtering for blts */
1023 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
1024 checkGLcall("glTexParameteri");
1025 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
1026 checkGLcall("glTexParameteri");
1028 /* Start drawing a quad */
1031 glColor3d(1.0f
, 1.0f
, 1.0f
);
1032 glTexCoord2f(glTexCoord
[0], glTexCoord
[2]);
1033 glVertex3f(This
->lockedRect
.left
, This
->lockedRect
.top
, 0.0);
1035 glTexCoord2f(glTexCoord
[0], glTexCoord
[3]);
1036 glVertex3f(This
->lockedRect
.left
, This
->lockedRect
.bottom
, 0.0);
1038 glTexCoord2f(glTexCoord
[1], glTexCoord
[3]);
1039 glVertex3d(This
->lockedRect
.right
, This
->lockedRect
.bottom
, 0.0);
1041 glTexCoord2f(glTexCoord
[1], glTexCoord
[2]);
1042 glVertex3f(This
->lockedRect
.right
, This
->lockedRect
.top
, 0.0);
1045 checkGLcall("glEnd");
1047 /* Unbind the texture */
1048 glBindTexture(GL_TEXTURE_2D
, 0);
1049 checkGLcall("glEnable glBindTexture");
1054 static HRESULT WINAPI
IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface
*iface
) {
1055 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1056 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
1057 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1059 if (!(This
->Flags
& SFLAG_LOCKED
)) {
1060 WARN("trying to Unlock an unlocked surf@%p\n", This
);
1061 return WINED3DERR_INVALIDCALL
;
1064 TRACE("(%p) : dirtyfied(%d)\n", This
, This
->Flags
& SFLAG_DIRTY
? 1 : 0);
1066 if (!(This
->Flags
& SFLAG_DIRTY
)) {
1067 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This
);
1071 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
1072 if(swapchain
|| iface
== myDevice
->render_targets
[0]) {
1073 if(wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
) {
1074 static BOOL warned
= FALSE
;
1076 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1079 if(swapchain
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
1083 /* Activate the correct context for the render target */
1085 ActivateContext(myDevice
, iface
, CTXUSAGE_BLIT
);
1088 /* Primary offscreen render target */
1089 TRACE("Offscreen render target\n");
1090 glDrawBuffer(myDevice
->offscreenBuffer
);
1091 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1093 if(iface
== swapchain
->frontBuffer
) {
1094 TRACE("Onscreen front buffer\n");
1095 glDrawBuffer(GL_FRONT
);
1096 checkGLcall("glDrawBuffer(GL_FRONT)");
1097 } else if(iface
== swapchain
->backBuffer
[0]) {
1098 TRACE("Onscreen back buffer\n");
1099 glDrawBuffer(GL_BACK
);
1100 checkGLcall("glDrawBuffer(GL_BACK)");
1102 FIXME("Unlocking a higher back buffer\n");
1103 glDrawBuffer(GL_BACK
);
1104 checkGLcall("glDrawBuffer(GL_BACK)");
1106 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
1109 switch(wined3d_settings
.rendertargetlock_mode
) {
1113 flush_to_framebuffer_drawpixels(This
);
1118 flush_to_framebuffer_texture(This
);
1122 glDrawBuffer(myDevice
->offscreenBuffer
);
1123 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1124 } else if(swapchain
->backBuffer
) {
1125 glDrawBuffer(GL_BACK
);
1126 checkGLcall("glDrawBuffer(GL_BACK)");
1128 glDrawBuffer(GL_FRONT
);
1129 checkGLcall("glDrawBuffer(GL_FRONT)");
1133 /** restore clean dirty state */
1134 IWineD3DSurface_CleanDirtyRect(iface
);
1135 } else if(iface
== myDevice
->stencilBufferTarget
) {
1136 FIXME("Depth Stencil buffer locking is not implemented\n");
1138 /* The rest should be a normal texture */
1139 IWineD3DBaseTextureImpl
*impl
;
1140 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1141 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1142 * states need resetting
1144 if(IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&impl
) == WINED3D_OK
) {
1145 if(impl
->baseTexture
.bindCount
) {
1146 IWineD3DDeviceImpl_MarkStateDirty(myDevice
, STATE_SAMPLER(impl
->baseTexture
.sampler
));
1148 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*) impl
);
1153 This
->Flags
&= ~SFLAG_LOCKED
;
1154 memset(&This
->lockedRect
, 0, sizeof(RECT
));
1158 HRESULT WINAPI
IWineD3DSurfaceImpl_GetDC(IWineD3DSurface
*iface
, HDC
*pHDC
) {
1159 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1160 WINED3DLOCKED_RECT lock
;
1167 const PixelFormatDesc
*formatEntry
= getFormatDescEntry(This
->resource
.format
);
1169 TRACE("(%p)->(%p)\n",This
,pHDC
);
1171 if(This
->Flags
& SFLAG_USERPTR
) {
1172 ERR("Not supported on surfaces with an application-provided surfaces\n");
1176 /* Give more detailed info for ddraw */
1177 if (This
->Flags
& SFLAG_DCINUSE
)
1178 return DDERR_DCALREADYCREATED
;
1180 /* Can't GetDC if the surface is locked */
1181 if (This
->Flags
& SFLAG_LOCKED
)
1182 return WINED3DERR_INVALIDCALL
;
1184 memset(&lock
, 0, sizeof(lock
)); /* To be sure */
1186 /* Create a DIB section if there isn't a hdc yet */
1189 SYSTEM_INFO sysInfo
;
1191 switch (This
->bytesPerPixel
) {
1194 /* Allocate extra space to store the RGB bit masks. */
1195 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
1199 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
1203 /* Allocate extra space for a palette. */
1204 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1205 sizeof(BITMAPINFOHEADER
)
1207 * (1 << (This
->bytesPerPixel
* 8)));
1212 return E_OUTOFMEMORY
;
1214 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1215 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1216 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1217 * add an extra line to the dib section
1219 GetSystemInfo(&sysInfo
);
1220 if( ((This
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4) {
1222 TRACE("Adding an extra line to the dib section\n");
1225 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1226 b_info
->bmiHeader
.biWidth
= This
->currentDesc
.Width
;
1227 b_info
->bmiHeader
.biHeight
= -This
->currentDesc
.Height
-extraline
;
1228 b_info
->bmiHeader
.biSizeImage
= ( This
->currentDesc
.Height
+ extraline
) * IWineD3DSurface_GetPitch(iface
);
1229 b_info
->bmiHeader
.biPlanes
= 1;
1230 b_info
->bmiHeader
.biBitCount
= This
->bytesPerPixel
* 8;
1232 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
1233 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
1234 b_info
->bmiHeader
.biClrUsed
= 0;
1235 b_info
->bmiHeader
.biClrImportant
= 0;
1237 /* Get the bit masks */
1238 masks
= (DWORD
*) &(b_info
->bmiColors
);
1239 switch (This
->resource
.format
) {
1240 case WINED3DFMT_R8G8B8
:
1241 usage
= DIB_RGB_COLORS
;
1242 b_info
->bmiHeader
.biCompression
= BI_RGB
;
1245 case WINED3DFMT_X1R5G5B5
:
1246 case WINED3DFMT_A1R5G5B5
:
1247 case WINED3DFMT_A4R4G4B4
:
1248 case WINED3DFMT_X4R4G4B4
:
1249 case WINED3DFMT_R3G3B2
:
1250 case WINED3DFMT_A8R3G3B2
:
1251 case WINED3DFMT_A2B10G10R10
:
1252 case WINED3DFMT_A8B8G8R8
:
1253 case WINED3DFMT_X8B8G8R8
:
1254 case WINED3DFMT_A2R10G10B10
:
1255 case WINED3DFMT_R5G6B5
:
1256 case WINED3DFMT_A16B16G16R16
:
1258 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
1259 masks
[0] = formatEntry
->redMask
;
1260 masks
[1] = formatEntry
->greenMask
;
1261 masks
[2] = formatEntry
->blueMask
;
1265 /* Don't know palette */
1266 b_info
->bmiHeader
.biCompression
= BI_RGB
;
1273 HeapFree(GetProcessHeap(), 0, b_info
);
1274 return HRESULT_FROM_WIN32(GetLastError());
1277 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
);
1278 This
->dib
.DIBsection
= CreateDIBSection(ddc
, b_info
, usage
, &This
->dib
.bitmap_data
, 0 /* Handle */, 0 /* Offset */);
1281 if (!This
->dib
.DIBsection
) {
1282 ERR("CreateDIBSection failed!\n");
1283 HeapFree(GetProcessHeap(), 0, b_info
);
1284 return HRESULT_FROM_WIN32(GetLastError());
1287 TRACE("DIBSection at : %p\n", This
->dib
.bitmap_data
);
1289 /* copy the existing surface to the dib section */
1290 if(This
->resource
.allocatedMemory
) {
1291 memcpy(This
->dib
.bitmap_data
, This
->resource
.allocatedMemory
, b_info
->bmiHeader
.biSizeImage
);
1292 /* We won't need that any more */
1293 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
1295 /* This is to make LockRect read the gl Texture although memory is allocated */
1296 This
->Flags
|= SFLAG_GLDIRTY
;
1299 HeapFree(GetProcessHeap(), 0, b_info
);
1301 /* Use the dib section from now on */
1302 This
->resource
.allocatedMemory
= This
->dib
.bitmap_data
;
1304 /* Now allocate a HDC */
1305 This
->hDC
= CreateCompatibleDC(0);
1306 This
->dib
.holdbitmap
= SelectObject(This
->hDC
, This
->dib
.DIBsection
);
1307 TRACE("using wined3d palette %p\n", This
->palette
);
1308 SelectPalette(This
->hDC
,
1309 This
->palette
? This
->palette
->hpal
: 0,
1312 This
->Flags
|= SFLAG_DIBSECTION
;
1315 /* Lock the surface */
1316 hr
= IWineD3DSurface_LockRect(iface
,
1321 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr
);
1322 /* keep the dib section */
1326 if(This
->resource
.format
== WINED3DFMT_P8
||
1327 This
->resource
.format
== WINED3DFMT_A8P8
) {
1330 PALETTEENTRY ent
[256];
1332 GetPaletteEntries(This
->palette
->hpal
, 0, 256, ent
);
1333 for (n
=0; n
<256; n
++) {
1334 col
[n
].rgbRed
= ent
[n
].peRed
;
1335 col
[n
].rgbGreen
= ent
[n
].peGreen
;
1336 col
[n
].rgbBlue
= ent
[n
].peBlue
;
1337 col
[n
].rgbReserved
= 0;
1340 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
1342 for (n
=0; n
<256; n
++) {
1343 col
[n
].rgbRed
= device
->palettes
[device
->currentPalette
][n
].peRed
;
1344 col
[n
].rgbGreen
= device
->palettes
[device
->currentPalette
][n
].peGreen
;
1345 col
[n
].rgbBlue
= device
->palettes
[device
->currentPalette
][n
].peBlue
;
1346 col
[n
].rgbReserved
= 0;
1350 SetDIBColorTable(This
->hDC
, 0, 256, col
);
1354 TRACE("returning %p\n",*pHDC
);
1355 This
->Flags
|= SFLAG_DCINUSE
;
1360 HRESULT WINAPI
IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface
*iface
, HDC hDC
) {
1361 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1363 TRACE("(%p)->(%p)\n",This
,hDC
);
1365 if (!(This
->Flags
& SFLAG_DCINUSE
))
1366 return WINED3DERR_INVALIDCALL
;
1368 /* we locked first, so unlock now */
1369 IWineD3DSurface_UnlockRect(iface
);
1371 This
->Flags
&= ~SFLAG_DCINUSE
;
1376 /* ******************************************************
1377 IWineD3DSurface Internal (No mapping to directx api) parts follow
1378 ****************************************************** */
1380 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
) {
1381 BOOL colorkey_active
= need_alpha_ck
&& (This
->CKeyFlags
& DDSD_CKSRCBLT
);
1382 const PixelFormatDesc
*formatEntry
= getFormatDescEntry(This
->resource
.format
);
1384 /* Default values: From the surface */
1385 *format
= formatEntry
->glFormat
;
1386 *internal
= formatEntry
->glInternal
;
1387 *type
= formatEntry
->glType
;
1388 *convert
= NO_CONVERSION
;
1389 *target_bpp
= This
->bytesPerPixel
;
1391 /* Ok, now look if we have to do any conversion */
1392 switch(This
->resource
.format
) {
1397 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1398 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1400 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE
) || colorkey_active
|| (!use_texturing
&& GL_SUPPORT(EXT_PALETTED_TEXTURE
)) ) {
1402 *internal
= GL_RGBA
;
1403 *type
= GL_UNSIGNED_BYTE
;
1405 if(colorkey_active
) {
1406 *convert
= CONVERT_PALETTED_CK
;
1408 *convert
= CONVERT_PALETTED
;
1414 case WINED3DFMT_R3G3B2
:
1415 /* **********************
1416 GL_UNSIGNED_BYTE_3_3_2
1417 ********************** */
1418 if (colorkey_active
) {
1419 /* This texture format will never be used.. So do not care about color keying
1420 up until the point in time it will be needed :-) */
1421 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1425 case WINED3DFMT_R5G6B5
:
1426 if (colorkey_active
) {
1427 *convert
= CONVERT_CK_565
;
1429 *internal
= GL_RGBA
;
1430 *type
= GL_UNSIGNED_SHORT_5_5_5_1
;
1434 case WINED3DFMT_R8G8B8
:
1435 if (colorkey_active
) {
1436 *convert
= CONVERT_CK_RGB24
;
1438 *internal
= GL_RGBA
;
1439 *type
= GL_UNSIGNED_INT_8_8_8_8
;
1444 case WINED3DFMT_X8R8G8B8
:
1445 if (colorkey_active
) {
1446 *convert
= CONVERT_RGB32_888
;
1448 *internal
= GL_RGBA
;
1449 *type
= GL_UNSIGNED_INT_8_8_8_8
;
1453 case WINED3DFMT_V8U8
:
1454 *convert
= CONVERT_V8U8
;
1456 *internal
= GL_RGB8
;
1468 HRESULT
d3dfmt_convert_surface(BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
, UINT height
, UINT outpitch
, CONVERT_TYPES convert
, IWineD3DSurfaceImpl
*surf
) {
1469 BYTE
*source
, *dest
;
1470 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src
, dst
, pitch
, height
, outpitch
, convert
, surf
);
1475 memcpy(dst
, src
, pitch
* height
);
1478 case CONVERT_PALETTED
:
1479 case CONVERT_PALETTED_CK
:
1481 IWineD3DPaletteImpl
* pal
= surf
->palette
;
1487 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1491 /* Still no palette? Use the device's palette */
1492 /* Get the surface's palette */
1493 for (i
= 0; i
< 256; i
++) {
1494 IWineD3DDeviceImpl
*device
= surf
->resource
.wineD3DDevice
;
1496 table
[i
][0] = device
->palettes
[device
->currentPalette
][i
].peRed
;
1497 table
[i
][1] = device
->palettes
[device
->currentPalette
][i
].peGreen
;
1498 table
[i
][2] = device
->palettes
[device
->currentPalette
][i
].peBlue
;
1499 if ((convert
== CONVERT_PALETTED_CK
) &&
1500 (i
>= surf
->SrcBltCKey
.dwColorSpaceLowValue
) &&
1501 (i
<= surf
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1502 /* We should maybe here put a more 'neutral' color than the standard bright purple
1503 one often used by application to prevent the nice purple borders when bi-linear
1511 TRACE("Using surface palette %p\n", pal
);
1512 /* Get the surface's palette */
1513 for (i
= 0; i
< 256; i
++) {
1514 table
[i
][0] = pal
->palents
[i
].peRed
;
1515 table
[i
][1] = pal
->palents
[i
].peGreen
;
1516 table
[i
][2] = pal
->palents
[i
].peBlue
;
1517 if ((convert
== CONVERT_PALETTED_CK
) &&
1518 (i
>= surf
->SrcBltCKey
.dwColorSpaceLowValue
) &&
1519 (i
<= surf
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1520 /* We should maybe here put a more 'neutral' color than the standard bright purple
1521 one often used by application to prevent the nice purple borders when bi-linear
1530 for (y
= 0; y
< height
; y
++)
1532 source
= src
+ pitch
* y
;
1533 dest
= dst
+ outpitch
* y
;
1534 /* This is an 1 bpp format, using the width here is fine */
1535 for (x
= 0; x
< width
; x
++) {
1536 BYTE color
= *source
++;
1537 *dest
++ = table
[color
][0];
1538 *dest
++ = table
[color
][1];
1539 *dest
++ = table
[color
][2];
1540 *dest
++ = table
[color
][3];
1546 case CONVERT_CK_565
:
1548 /* Converting the 565 format in 5551 packed to emulate color-keying.
1550 Note : in all these conversion, it would be best to average the averaging
1551 pixels to get the color of the pixel that will be color-keyed to
1552 prevent 'color bleeding'. This will be done later on if ever it is
1555 Note2: Nvidia documents say that their driver does not support alpha + color keying
1556 on the same surface and disables color keying in such a case
1562 TRACE("Color keyed 565\n");
1564 for (y
= 0; y
< height
; y
++) {
1565 Source
= (WORD
*) (src
+ y
* pitch
);
1566 Dest
= (WORD
*) (dst
+ y
* outpitch
);
1567 for (x
= 0; x
< width
; x
++ ) {
1568 WORD color
= *Source
++;
1569 *Dest
= ((color
& 0xFFC0) | ((color
& 0x1F) << 1));
1570 if ((color
< surf
->SrcBltCKey
.dwColorSpaceLowValue
) ||
1571 (color
> surf
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1585 for(y
= 0; y
< height
; y
++) {
1586 Source
= (short *) (src
+ y
* pitch
);
1587 Dest
= (char *) (dst
+ y
* outpitch
);
1588 for (x
= 0; x
< width
; x
++ ) {
1589 long color
= (*Source
++);
1590 Dest
[0] = color
>> 8;
1600 ERR("Unsupported conversation type %d\n", convert
);
1605 /* This function is used in case of 8bit paletted textures to upload the palette.
1606 For now it only supports GL_EXT_paletted_texture extension but support for other
1607 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1609 void d3dfmt_p8_upload_palette(IWineD3DSurface
*iface
, CONVERT_TYPES convert
) {
1610 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1611 IWineD3DPaletteImpl
* pal
= This
->palette
;
1616 /* Still no palette? Use the device's palette */
1617 /* Get the surface's palette */
1618 for (i
= 0; i
< 256; i
++) {
1619 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
1621 table
[i
][0] = device
->palettes
[device
->currentPalette
][i
].peRed
;
1622 table
[i
][1] = device
->palettes
[device
->currentPalette
][i
].peGreen
;
1623 table
[i
][2] = device
->palettes
[device
->currentPalette
][i
].peBlue
;
1624 if ((convert
== CONVERT_PALETTED_CK
) &&
1625 (i
>= This
->SrcBltCKey
.dwColorSpaceLowValue
) &&
1626 (i
<= This
->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
1636 TRACE("Using surface palette %p\n", pal
);
1637 /* Get the surface's palette */
1638 for (i
= 0; i
< 256; i
++) {
1639 table
[i
][0] = pal
->palents
[i
].peRed
;
1640 table
[i
][1] = pal
->palents
[i
].peGreen
;
1641 table
[i
][2] = pal
->palents
[i
].peBlue
;
1642 if ((convert
== CONVERT_PALETTED_CK
) &&
1643 (i
>= This
->SrcBltCKey
.dwColorSpaceLowValue
) &&
1644 (i
<= This
->SrcBltCKey
.dwColorSpaceHighValue
)) {
1645 /* We should maybe here put a more 'neutral' color than the standard bright purple
1646 one often used by application to prevent the nice purple borders when bi-linear
1654 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D
,GL_RGBA
,256,GL_RGBA
,GL_UNSIGNED_BYTE
, table
));
1657 static BOOL
palette9_changed(IWineD3DSurfaceImpl
*This
) {
1658 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
1660 if(This
->palette
|| (This
->resource
.format
!= WINED3DFMT_P8
&& This
->resource
.format
!= WINED3DFMT_A8P8
)) {
1661 /* If a ddraw-style palette is attached assume no d3d9 palette change.
1662 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
1667 if(This
->palette9
) {
1668 if(memcmp(This
->palette9
, &device
->palettes
[device
->currentPalette
], sizeof(PALETTEENTRY
) * 256) == 0) {
1672 This
->palette9
= (PALETTEENTRY
*) HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
1674 memcpy(This
->palette9
, &device
->palettes
[device
->currentPalette
], sizeof(PALETTEENTRY
) * 256);
1678 static HRESULT WINAPI
IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface
*iface
) {
1679 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1680 GLenum format
, internal
, type
;
1681 CONVERT_TYPES convert
;
1683 int width
, pitch
, outpitch
;
1686 if (This
->Flags
& SFLAG_INTEXTURE
) {
1687 TRACE("Surface already in texture\n");
1690 if (This
->Flags
& SFLAG_DIRTY
) {
1691 TRACE("Reloading because surface is dirty\n");
1692 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1693 ((This
->Flags
& SFLAG_GLCKEY
) && (!(This
->CKeyFlags
& DDSD_CKSRCBLT
))) ||
1694 /* Reload: vice versa OR */
1695 ((!(This
->Flags
& SFLAG_GLCKEY
)) && (This
->CKeyFlags
& DDSD_CKSRCBLT
)) ||
1696 /* Also reload: Color key is active AND the color key has changed */
1697 ((This
->CKeyFlags
& DDSD_CKSRCBLT
) && (
1698 (This
->glCKey
.dwColorSpaceLowValue
!= This
->SrcBltCKey
.dwColorSpaceLowValue
) ||
1699 (This
->glCKey
.dwColorSpaceHighValue
!= This
->SrcBltCKey
.dwColorSpaceHighValue
)))) {
1700 TRACE("Reloading because of color keying\n");
1701 } else if(palette9_changed(This
)) {
1702 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
1704 TRACE("surface isn't dirty\n");
1708 This
->Flags
&= ~SFLAG_DIRTY
;
1710 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1711 * These resources are not bound by device size or format restrictions. Because of this,
1712 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1713 * However, these resources can always be created, locked, and copied.
1715 if (This
->resource
.pool
== WINED3DPOOL_SCRATCH
&& !(This
->Flags
& SFLAG_FORCELOAD
) )
1717 FIXME("(%p) Operation not supported for scratch textures\n",This
);
1718 return WINED3DERR_INVALIDCALL
;
1721 if (This
->Flags
& SFLAG_INPBUFFER
) {
1722 if (This
->glDescription
.level
!= 0)
1723 FIXME("Surface in texture is only supported for level 0\n");
1724 else if (This
->resource
.format
== WINED3DFMT_P8
|| This
->resource
.format
== WINED3DFMT_A8P8
||
1725 This
->resource
.format
== WINED3DFMT_DXT1
|| This
->resource
.format
== WINED3DFMT_DXT2
||
1726 This
->resource
.format
== WINED3DFMT_DXT3
|| This
->resource
.format
== WINED3DFMT_DXT4
||
1727 This
->resource
.format
== WINED3DFMT_DXT5
)
1728 FIXME("Format %d not supported\n", This
->resource
.format
);
1734 glGetIntegerv(GL_READ_BUFFER
, &prevRead
);
1735 vcheckGLcall("glGetIntegerv");
1736 glReadBuffer(This
->resource
.wineD3DDevice
->offscreenBuffer
);
1737 vcheckGLcall("glReadBuffer");
1739 glCopyTexImage2D(This
->glDescription
.target
,
1740 This
->glDescription
.level
,
1741 This
->glDescription
.glFormatInternal
,
1744 This
->currentDesc
.Width
,
1745 This
->currentDesc
.Height
,
1748 checkGLcall("glCopyTexImage2D");
1749 glReadBuffer(prevRead
);
1750 vcheckGLcall("glReadBuffer");
1754 TRACE("Updating target %d\n", This
->glDescription
.target
);
1755 This
->Flags
|= SFLAG_INTEXTURE
;
1760 if(This
->CKeyFlags
& DDSD_CKSRCBLT
) {
1761 This
->Flags
|= SFLAG_GLCKEY
;
1762 This
->glCKey
= This
->SrcBltCKey
;
1764 else This
->Flags
&= ~SFLAG_GLCKEY
;
1766 d3dfmt_get_conv(This
, TRUE
/* We need color keying */, TRUE
/* We will use textures */, &format
, &internal
, &type
, &convert
, &bpp
);
1768 /* The width is in 'length' not in bytes */
1769 width
= This
->currentDesc
.Width
;
1770 pitch
= IWineD3DSurface_GetPitch(iface
);
1772 if((convert
!= NO_CONVERSION
) && This
->resource
.allocatedMemory
) {
1773 int height
= This
->currentDesc
.Height
;
1775 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1776 outpitch
= width
* bpp
;
1777 outpitch
= (outpitch
+ SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
1779 mem
= HeapAlloc(GetProcessHeap(), 0, outpitch
* height
);
1781 ERR("Out of memory %d, %d!\n", outpitch
, height
);
1782 return WINED3DERR_OUTOFVIDEOMEMORY
;
1784 d3dfmt_convert_surface(This
->resource
.allocatedMemory
, mem
, pitch
, width
, height
, outpitch
, convert
, This
);
1786 This
->Flags
|= SFLAG_CONVERTED
;
1787 } else if (This
->resource
.format
== WINED3DFMT_P8
&& GL_SUPPORT(EXT_PALETTED_TEXTURE
)) {
1788 d3dfmt_p8_upload_palette(iface
, convert
);
1789 This
->Flags
&= ~SFLAG_CONVERTED
;
1790 mem
= This
->resource
.allocatedMemory
;
1792 This
->Flags
&= ~SFLAG_CONVERTED
;
1793 mem
= This
->resource
.allocatedMemory
;
1796 /* Make sure the correct pitch is used */
1797 glPixelStorei(GL_UNPACK_ROW_LENGTH
, width
);
1799 if ((This
->Flags
& SFLAG_NONPOW2
) && !(This
->Flags
& SFLAG_OVERSIZE
)) {
1800 TRACE("non power of two support\n");
1801 surface_allocate_surface(This
, internal
, This
->pow2Width
, This
->pow2Height
, format
, type
);
1803 surface_upload_data(This
, This
->currentDesc
.Width
, This
->currentDesc
.Height
, format
, type
, mem
);
1806 surface_allocate_surface(This
, internal
, This
->glRect
.right
- This
->glRect
.left
, This
->glRect
.bottom
- This
->glRect
.top
, format
, type
);
1808 surface_upload_data(This
, This
->glRect
.right
- This
->glRect
.left
, This
->glRect
.bottom
- This
->glRect
.top
, format
, type
, mem
);
1812 /* Restore the default pitch */
1813 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1815 if (mem
!= This
->resource
.allocatedMemory
)
1816 HeapFree(GetProcessHeap(), 0, mem
);
1820 static unsigned int gen
= 0;
1823 if ((gen
% 10) == 0) {
1824 snprintf(buffer
, sizeof(buffer
), "/tmp/surface%p_type%u_level%u_%u.ppm", This
, This
->glDescription
.target
, This
->glDescription
.level
, gen
);
1825 IWineD3DSurfaceImpl_SaveSnapshot(iface
, buffer
);
1828 * debugging crash code
1837 if (!(This
->Flags
& SFLAG_DONOTFREE
)) {
1838 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
1839 This
->resource
.allocatedMemory
= NULL
;
1847 HRESULT WINAPI
IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface
*iface
, const char* filename
) {
1850 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1851 char *allocatedMemory
;
1853 IWineD3DSwapChain
*swapChain
= NULL
;
1855 GLuint tmpTexture
= 0;
1858 Textures my not be stored in ->allocatedgMemory and a GlTexture
1859 so we should lock the surface before saving a snapshot, or at least check that
1861 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1862 by calling GetTexImage and in compressed form by calling
1863 GetCompressedTexImageARB. Queried compressed images can be saved and
1864 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1865 texture images do not need to be processed by the GL and should
1866 significantly improve texture loading performance relative to uncompressed
1869 /* Setup the width and height to be the internal texture width and height. */
1870 width
= This
->pow2Width
;
1871 height
= This
->pow2Height
;
1872 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1873 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapChain
);
1875 if (swapChain
|| (This
->Flags
& SFLAG_INPBUFFER
)) { /* if were not a real texture then read the back buffer into a real texture*/
1876 /* 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 */
1879 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This
);
1880 glEnable(GL_TEXTURE_2D
);
1882 glGenTextures(1, &tmpTexture
);
1883 glBindTexture(GL_TEXTURE_2D
, tmpTexture
);
1885 glTexImage2D(GL_TEXTURE_2D
,
1892 GL_UNSIGNED_INT_8_8_8_8_REV
,
1895 glGetIntegerv(GL_READ_BUFFER
, &prevRead
);
1896 vcheckGLcall("glGetIntegerv");
1897 glReadBuffer(swapChain
? GL_BACK
: This
->resource
.wineD3DDevice
->offscreenBuffer
);
1898 vcheckGLcall("glReadBuffer");
1899 glCopyTexImage2D(GL_TEXTURE_2D
,
1908 checkGLcall("glCopyTexImage2D");
1909 glReadBuffer(prevRead
);
1912 } else { /* bind the real texture */
1913 IWineD3DSurface_PreLoad(iface
);
1915 allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, width
* height
* 4);
1917 FIXME("Saving texture level %d width %d height %d\n", This
->glDescription
.level
, width
, height
);
1918 glGetTexImage(GL_TEXTURE_2D
,
1919 This
->glDescription
.level
,
1921 GL_UNSIGNED_INT_8_8_8_8_REV
,
1923 checkGLcall("glTexImage2D");
1925 glBindTexture(GL_TEXTURE_2D
, 0);
1926 glDeleteTextures(1, &tmpTexture
);
1930 f
= fopen(filename
, "w+");
1932 ERR("opening of %s failed with: %s\n", filename
, strerror(errno
));
1933 return WINED3DERR_INVALIDCALL
;
1935 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1936 TRACE("(%p) opened %s with format %s\n", This
, filename
, debug_d3dformat(This
->resource
.format
));
1951 fwrite(&width
,2,1,f
);
1953 fwrite(&height
,2,1,f
);
1958 /* 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*/
1960 textureRow
= allocatedMemory
+ (width
* (height
- 1) *4);
1962 textureRow
= allocatedMemory
;
1963 for (y
= 0 ; y
< height
; y
++) {
1964 for (i
= 0; i
< width
; i
++) {
1965 color
= *((DWORD
*)textureRow
);
1966 fputc((color
>> 16) & 0xFF, f
); /* B */
1967 fputc((color
>> 8) & 0xFF, f
); /* G */
1968 fputc((color
>> 0) & 0xFF, f
); /* R */
1969 fputc((color
>> 24) & 0xFF, f
); /* A */
1972 /* take two rows of the pointer to the texture memory */
1974 (textureRow
-= width
<< 3);
1977 TRACE("Closing file\n");
1981 IWineD3DSwapChain_Release(swapChain
);
1983 HeapFree(GetProcessHeap(), 0, allocatedMemory
);
1987 HRESULT WINAPI
IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface
*iface
) {
1988 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1989 This
->Flags
&= ~SFLAG_DIRTY
;
1990 This
->dirtyRect
.left
= This
->currentDesc
.Width
;
1991 This
->dirtyRect
.top
= This
->currentDesc
.Height
;
1992 This
->dirtyRect
.right
= 0;
1993 This
->dirtyRect
.bottom
= 0;
1994 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This
, This
->Flags
& SFLAG_DIRTY
? 1 : 0, This
->dirtyRect
.left
,
1995 This
->dirtyRect
.top
, This
->dirtyRect
.right
, This
->dirtyRect
.bottom
);
2000 * Slightly inefficient way to handle multiple dirty rects but it works :)
2002 extern HRESULT WINAPI
IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface
*iface
, CONST RECT
* pDirtyRect
) {
2003 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2004 IWineD3DBaseTexture
*baseTexture
= NULL
;
2005 This
->Flags
|= SFLAG_DIRTY
;
2006 if (NULL
!= pDirtyRect
) {
2007 This
->dirtyRect
.left
= min(This
->dirtyRect
.left
, pDirtyRect
->left
);
2008 This
->dirtyRect
.top
= min(This
->dirtyRect
.top
, pDirtyRect
->top
);
2009 This
->dirtyRect
.right
= max(This
->dirtyRect
.right
, pDirtyRect
->right
);
2010 This
->dirtyRect
.bottom
= max(This
->dirtyRect
.bottom
, pDirtyRect
->bottom
);
2012 This
->dirtyRect
.left
= 0;
2013 This
->dirtyRect
.top
= 0;
2014 This
->dirtyRect
.right
= This
->currentDesc
.Width
;
2015 This
->dirtyRect
.bottom
= This
->currentDesc
.Height
;
2017 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This
, This
->Flags
& SFLAG_DIRTY
, This
->dirtyRect
.left
,
2018 This
->dirtyRect
.top
, This
->dirtyRect
.right
, This
->dirtyRect
.bottom
);
2019 /* if the container is a basetexture then mark it dirty. */
2020 if (IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
) == WINED3D_OK
) {
2021 TRACE("Passing to conatiner\n");
2022 IWineD3DBaseTexture_SetDirty(baseTexture
, TRUE
);
2023 IWineD3DBaseTexture_Release(baseTexture
);
2028 HRESULT WINAPI
IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface
*iface
, IWineD3DBase
*container
) {
2029 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2031 TRACE("This %p, container %p\n", This
, container
);
2033 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2035 TRACE("Setting container to %p from %p\n", container
, This
->container
);
2036 This
->container
= container
;
2041 HRESULT WINAPI
IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface
*iface
, WINED3DFORMAT format
) {
2042 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2043 const PixelFormatDesc
*formatEntry
= getFormatDescEntry(format
);
2045 if (This
->resource
.format
!= WINED3DFMT_UNKNOWN
) {
2046 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This
);
2047 return WINED3DERR_INVALIDCALL
;
2050 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This
, format
, debug_d3dformat(format
));
2051 if (format
== WINED3DFMT_UNKNOWN
) {
2052 This
->resource
.size
= 0;
2053 } else if (format
== WINED3DFMT_DXT1
) {
2054 /* DXT1 is half byte per pixel */
2055 This
->resource
.size
= ((max(This
->pow2Width
, 4) * formatEntry
->bpp
) * max(This
->pow2Height
, 4)) >> 1;
2057 } else if (format
== WINED3DFMT_DXT2
|| format
== WINED3DFMT_DXT3
||
2058 format
== WINED3DFMT_DXT4
|| format
== WINED3DFMT_DXT5
) {
2059 This
->resource
.size
= ((max(This
->pow2Width
, 4) * formatEntry
->bpp
) * max(This
->pow2Height
, 4));
2061 This
->resource
.size
= ((This
->pow2Width
* formatEntry
->bpp
) + SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
2062 This
->resource
.size
*= This
->pow2Height
;
2066 /* Setup some glformat defaults */
2067 This
->glDescription
.glFormat
= formatEntry
->glFormat
;
2068 This
->glDescription
.glFormatInternal
= formatEntry
->glInternal
;
2069 This
->glDescription
.glType
= formatEntry
->glType
;
2071 if (format
!= WINED3DFMT_UNKNOWN
) {
2072 This
->bytesPerPixel
= formatEntry
->bpp
;
2074 This
->bytesPerPixel
= 0;
2077 This
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== format
) ? SFLAG_LOCKABLE
: 0;
2079 This
->resource
.format
= format
;
2081 TRACE("(%p) : Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This
, This
->resource
.size
, This
->bytesPerPixel
, This
->glDescription
.glFormat
, This
->glDescription
.glFormatInternal
, This
->glDescription
.glType
);
2086 HRESULT WINAPI
IWineD3DSurfaceImpl_SetMem(IWineD3DSurface
*iface
, void *Mem
) {
2087 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2089 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2090 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
2091 ERR("Not supported on render targets\n");
2092 return WINED3DERR_INVALIDCALL
;
2095 if(This
->Flags
& (SFLAG_LOCKED
| SFLAG_DCINUSE
)) {
2096 WARN("Surface is locked or the HDC is in use\n");
2097 return WINED3DERR_INVALIDCALL
;
2100 if(Mem
&& Mem
!= This
->resource
.allocatedMemory
) {
2102 /* Do I have to copy the old surface content? */
2103 if(This
->Flags
& SFLAG_DIBSECTION
) {
2104 /* Release the DC. No need to hold the critical section for the update
2105 * Thread because this thread runs only on front buffers, but this method
2106 * fails for render targets in the check above.
2108 SelectObject(This
->hDC
, This
->dib
.holdbitmap
);
2109 DeleteDC(This
->hDC
);
2110 /* Release the DIB section */
2111 DeleteObject(This
->dib
.DIBsection
);
2112 This
->dib
.bitmap_data
= NULL
;
2113 This
->resource
.allocatedMemory
= NULL
;
2115 This
->Flags
&= ~SFLAG_DIBSECTION
;
2116 } else if(!(This
->Flags
& SFLAG_USERPTR
)) {
2117 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
2119 This
->resource
.allocatedMemory
= Mem
;
2120 This
->Flags
|= SFLAG_USERPTR
;
2121 } else if(This
->Flags
& SFLAG_USERPTR
) {
2122 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2123 This
->resource
.allocatedMemory
= NULL
;
2124 This
->Flags
&= ~SFLAG_USERPTR
;
2129 /* TODO: replace this function with context management routines */
2130 HRESULT WINAPI
IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface
*iface
, BOOL inPBuffer
, BOOL inTexture
) {
2131 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2134 This
->Flags
|= SFLAG_INPBUFFER
;
2136 This
->Flags
&= ~SFLAG_INPBUFFER
;
2140 This
->Flags
|= SFLAG_INTEXTURE
;
2142 This
->Flags
&= ~SFLAG_INTEXTURE
;
2148 static HRESULT WINAPI
IWineD3DSurfaceImpl_Flip(IWineD3DSurface
*iface
, IWineD3DSurface
*override
, DWORD Flags
) {
2149 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2150 IWineD3DDevice
*D3D
= (IWineD3DDevice
*) This
->resource
.wineD3DDevice
;
2151 TRACE("(%p)->(%p,%x)\n", This
, override
, Flags
);
2153 /* Flipping is only supported on RenderTargets */
2154 if( !(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) return DDERR_NOTFLIPPABLE
;
2157 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2158 * FIXME("(%p) Target override is not supported by now\n", This);
2159 * Additionally, it isn't really possible to support triple-buffering
2160 * properly on opengl at all
2164 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2165 return IWineD3DDevice_Present(D3D
, NULL
, NULL
, 0, NULL
);
2168 /* Does a direct frame buffer -> texture copy. Stretching is done
2169 * with single pixel copy calls
2171 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl
*This
, IWineD3DSurface
*SrcSurface
, IWineD3DSwapChainImpl
*swapchain
, WINED3DRECT
*srect
, WINED3DRECT
*drect
, BOOL upsidedown
) {
2172 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
2175 BOOL warned
= FALSE
; /* deliberately not static */
2176 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
2180 ActivateContext(myDevice
, SrcSurface
, CTXUSAGE_BLIT
);
2182 /* Bind the target texture */
2183 glBindTexture(GL_TEXTURE_2D
, This
->glDescription
.textureName
);
2184 checkGLcall("glBindTexture");
2186 glReadBuffer(myDevice
->offscreenBuffer
);
2187 } else if(swapchain
->backBuffer
&& SrcSurface
== swapchain
->backBuffer
[0]) {
2188 glReadBuffer(GL_BACK
);
2190 glReadBuffer(GL_FRONT
);
2192 checkGLcall("glReadBuffer");
2194 xrel
= (float) (srect
->x2
- srect
->x1
) / (float) (drect
->x2
- drect
->x1
);
2195 yrel
= (float) (srect
->y2
- srect
->y1
) / (float) (drect
->y2
- drect
->y1
);
2197 if( (xrel
- 1.0 < -eps
) || (xrel
- 1.0 > eps
)) {
2198 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2202 !((xrel
- 1.0 < -eps
) || (xrel
- 1.0 > eps
)) &&
2203 !((yrel
- 1.0 < -eps
) || (yrel
- 1.0 > eps
))) {
2204 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2206 glCopyTexSubImage2D(This
->glDescription
.target
,
2207 This
->glDescription
.level
,
2208 drect
->x1
, drect
->y1
, /* xoffset, yoffset */
2209 srect
->x1
, Src
->currentDesc
.Height
- srect
->y2
,
2210 drect
->x2
- drect
->x1
, drect
->y2
- drect
->y1
);
2212 UINT yoffset
= Src
->currentDesc
.Height
- srect
->y1
+ drect
->y1
- 1;
2213 /* I have to process this row by row to swap the image,
2214 * otherwise it would be upside down, so streching in y direction
2215 * doesn't cost extra time
2217 * However, streching in x direction can be avoided if not necessary
2219 for(row
= drect
->y1
; row
< drect
->y2
; row
++) {
2220 if( (xrel
- 1.0 < -eps
) || (xrel
- 1.0 > eps
)) {
2221 /* Well, that stuff works, but it's very slow.
2222 * find a better way instead
2228 FIXME("Doing a pixel by pixel render target -> texture copy, expect performance issues\n");
2231 for(col
= drect
->x1
; col
< drect
->x2
; col
++) {
2232 glCopyTexSubImage2D(This
->glDescription
.target
,
2233 This
->glDescription
.level
,
2234 drect
->x1
+ col
, row
, /* xoffset, yoffset */
2235 srect
->x1
+ col
* xrel
, yoffset
- (int) (row
* yrel
),
2239 glCopyTexSubImage2D(This
->glDescription
.target
,
2240 This
->glDescription
.level
,
2241 drect
->x1
, row
, /* xoffset, yoffset */
2242 srect
->x1
, yoffset
- (int) (row
* yrel
),
2243 drect
->x2
-drect
->x1
, 1);
2248 vcheckGLcall("glCopyTexSubImage2D");
2252 /* Uses the hardware to stretch and flip the image */
2253 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl
*This
, IWineD3DSurface
*SrcSurface
, IWineD3DSwapChainImpl
*swapchain
, WINED3DRECT
*srect
, WINED3DRECT
*drect
, BOOL upsidedown
) {
2254 GLuint src
, backup
= 0;
2255 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
2256 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
2257 float left
, right
, top
, bottom
; /* Texture coordinates */
2258 UINT fbwidth
= Src
->currentDesc
.Width
;
2259 UINT fbheight
= Src
->currentDesc
.Height
;
2261 TRACE("Using hwstretch blit\n");
2262 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2264 ActivateContext(myDevice
, SrcSurface
, CTXUSAGE_BLIT
);
2266 if(!swapchain
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
2267 glGenTextures(1, &backup
);
2268 checkGLcall("glGenTextures\n");
2269 glBindTexture(GL_TEXTURE_2D
, backup
);
2270 checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2272 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2273 * we are reading from the back buffer, the backup can be used as source texture
2275 if(Src
->glDescription
.textureName
== 0) {
2276 /* Get it a description */
2277 IWineD3DSurface_PreLoad(SrcSurface
);
2279 glBindTexture(GL_TEXTURE_2D
, Src
->glDescription
.textureName
);
2280 checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2283 glReadBuffer(GL_BACK
);
2284 checkGLcall("glReadBuffer(GL_BACK)");
2286 /* TODO: Only back up the part that will be overwritten */
2287 glCopyTexSubImage2D(GL_TEXTURE_2D
, 0,
2288 0, 0 /* read offsets */,
2293 checkGLcall("glCopyTexSubImage2D");
2295 /* No issue with overriding these - the sampler is dirty due to blit usage */
2296 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
2297 checkGLcall("glTexParameteri");
2298 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2299 checkGLcall("glTexParameteri");
2301 if(!swapchain
|| (IWineD3DSurface
*) Src
== swapchain
->backBuffer
[0]) {
2302 src
= backup
? backup
: Src
->glDescription
.textureName
;
2304 glReadBuffer(GL_FRONT
);
2305 checkGLcall("glReadBuffer(GL_FRONT)");
2307 glGenTextures(1, &src
);
2308 checkGLcall("glGenTextures(1, &src)");
2309 glBindTexture(GL_TEXTURE_2D
, src
);
2310 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
2312 /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
2313 * out for power of 2 sizes
2315 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, Src
->pow2Width
, Src
->pow2Height
, 0,
2316 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
2317 checkGLcall("glTexImage2D");
2318 glCopyTexSubImage2D(GL_TEXTURE_2D
, 0,
2319 0, 0 /* read offsets */,
2324 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
2325 checkGLcall("glTexParameteri");
2326 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2327 checkGLcall("glTexParameteri");
2329 glReadBuffer(GL_BACK
);
2330 checkGLcall("glReadBuffer(GL_BACK)");
2332 checkGLcall("glEnd and previous");
2334 left
= (float) srect
->x1
/ (float) Src
->pow2Width
;
2335 right
= (float) srect
->x2
/ (float) Src
->pow2Width
;
2338 top
= (float) (Src
->currentDesc
.Height
- srect
->y1
) / (float) Src
->pow2Height
;
2339 bottom
= (float) (Src
->currentDesc
.Height
- srect
->y2
) / (float) Src
->pow2Height
;
2341 top
= (float) (Src
->currentDesc
.Height
- srect
->y2
) / (float) Src
->pow2Height
;
2342 bottom
= (float) (Src
->currentDesc
.Height
- srect
->y1
) / (float) Src
->pow2Height
;
2345 /* draw the source texture stretched and upside down. The correct surface is bound already */
2346 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
2347 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
2351 glTexCoord2f(left
, bottom
);
2352 glVertex2i(0, fbheight
);
2355 glTexCoord2f(left
, top
);
2356 glVertex2i(0, fbheight
- drect
->y2
- drect
->y1
);
2359 glTexCoord2f(right
, top
);
2360 glVertex2i(drect
->x2
- drect
->x1
, fbheight
- drect
->y2
- drect
->y1
);
2363 glTexCoord2f(right
, bottom
);
2364 glVertex2i(drect
->x2
- drect
->x1
, fbheight
);
2366 checkGLcall("glEnd and previous");
2368 /* Now read the stretched and upside down image into the destination texture */
2369 glBindTexture(This
->glDescription
.target
, This
->glDescription
.textureName
);
2370 checkGLcall("glBindTexture");
2371 glCopyTexSubImage2D(This
->glDescription
.target
,
2373 drect
->x1
, drect
->y1
, /* xoffset, yoffset */
2374 0, 0, /* We blitted the image to the origin */
2375 drect
->x2
- drect
->x1
, drect
->y2
- drect
->y1
);
2376 checkGLcall("glCopyTexSubImage2D");
2378 /* Write the back buffer backup back */
2379 glBindTexture(GL_TEXTURE_2D
, backup
? backup
: Src
->glDescription
.textureName
);
2380 checkGLcall("glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName)");
2384 glTexCoord2f(0.0, (float) fbheight
/ (float) Src
->pow2Height
);
2388 glTexCoord2f(0.0, 0.0);
2389 glVertex2i(0, fbheight
);
2392 glTexCoord2f((float) fbwidth
/ (float) Src
->pow2Width
, 0.0);
2393 glVertex2i(fbwidth
, Src
->currentDesc
.Height
);
2396 glTexCoord2f((float) fbwidth
/ (float) Src
->pow2Width
, (float) fbheight
/ (float) Src
->pow2Height
);
2397 glVertex2i(fbwidth
, 0);
2401 if(src
!= Src
->glDescription
.textureName
&& src
!= backup
) {
2402 glDeleteTextures(1, &src
);
2403 checkGLcall("glDeleteTextures(1, &src)");
2406 glDeleteTextures(1, &backup
);
2407 checkGLcall("glDeleteTextures(1, &backup)");
2412 /* Not called from the VTable */
2413 static HRESULT
IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl
*This
, RECT
*DestRect
, IWineD3DSurface
*SrcSurface
, RECT
*SrcRect
, DWORD Flags
, DDBLTFX
*DDBltFx
) {
2415 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
2416 IWineD3DSwapChainImpl
*srcSwapchain
= NULL
, *dstSwapchain
= NULL
;
2417 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
2420 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
);
2422 /* Get the swapchain. One of the surfaces has to be a primary surface */
2423 IWineD3DSurface_GetContainer( (IWineD3DSurface
*) This
, &IID_IWineD3DSwapChain
, (void **)&dstSwapchain
);
2424 if(dstSwapchain
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*) dstSwapchain
);
2426 IWineD3DSurface_GetContainer( (IWineD3DSurface
*) Src
, &IID_IWineD3DSwapChain
, (void **)&srcSwapchain
);
2427 if(srcSwapchain
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*) srcSwapchain
);
2430 /* Early sort out of cases where no render target is used */
2431 if(!dstSwapchain
&& !srcSwapchain
&&
2432 SrcSurface
!= myDevice
->render_targets
[0] && This
!= (IWineD3DSurfaceImpl
*) myDevice
->render_targets
[0]) {
2433 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src
, This
);
2434 return WINED3DERR_INVALIDCALL
;
2437 /* No destination color keying supported */
2438 if(Flags
& (DDBLT_KEYDEST
| DDBLT_KEYDESTOVERRIDE
)) {
2439 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2440 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2441 return WINED3DERR_INVALIDCALL
;
2445 rect
.x1
= DestRect
->left
;
2446 rect
.y1
= DestRect
->top
;
2447 rect
.x2
= DestRect
->right
;
2448 rect
.y2
= DestRect
->bottom
;
2452 rect
.x2
= This
->currentDesc
.Width
;
2453 rect
.y2
= This
->currentDesc
.Height
;
2456 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
2457 if(dstSwapchain
&& dstSwapchain
== srcSwapchain
) {
2458 /* Half-life does a Blt from the back buffer to the front buffer,
2459 * Full surface size, no flags... Use present instead
2462 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2464 if( (SrcRect
->left
== 0) && (SrcRect
->top
== 0) &&
2465 (SrcRect
->right
== Src
->currentDesc
.Width
) && (SrcRect
->bottom
== Src
->currentDesc
.Height
) ) {
2472 /* Check the Destination rect and the surface sizes */
2474 (rect
.x1
== 0) && (rect
.y1
== 0) &&
2475 (rect
.x2
== This
->currentDesc
.Width
) && (rect
.y2
== This
->currentDesc
.Height
) &&
2476 (This
->currentDesc
.Width
== Src
->currentDesc
.Width
) &&
2477 (This
->currentDesc
.Height
== Src
->currentDesc
.Height
)) {
2478 /* These flags are unimportant for the flag check, remove them */
2480 if((Flags
& ~(DDBLT_DONOTWAIT
| DDBLT_WAIT
)) == 0) {
2481 if( dstSwapchain
->backBuffer
&& ((IWineD3DSurface
*) This
== dstSwapchain
->frontBuffer
) &&
2482 SrcSurface
== dstSwapchain
->backBuffer
[0] ) {
2484 WINED3DSWAPEFFECT orig_swap
= dstSwapchain
->presentParms
.SwapEffect
;
2486 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2487 * take very long, while a flip is fast.
2488 * This applies to Half-Life, which does such Blts every time it finished
2489 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2490 * menu. This is also used by all apps when they do windowed rendering
2492 * The problem is that flipping is not really the same as copying. After a
2493 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2494 * untouched. Therefore it's necessary to override the swap effect
2495 * and to set it back after the flip.
2498 dstSwapchain
->presentParms
.SwapEffect
= WINED3DSWAPEFFECT_COPY
;
2500 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2501 IWineD3DDevice_Present((IWineD3DDevice
*) This
->resource
.wineD3DDevice
,
2502 NULL
, NULL
, 0, NULL
);
2504 dstSwapchain
->presentParms
.SwapEffect
= orig_swap
;
2511 TRACE("Unsupported blit between buffers on the same swapchain\n");
2512 return WINED3DERR_INVALIDCALL
;
2513 } else if((dstSwapchain
|| This
== (IWineD3DSurfaceImpl
*) myDevice
->render_targets
[0]) &&
2514 (srcSwapchain
|| SrcSurface
== myDevice
->render_targets
[0]) ) {
2515 ERR("Can't perform hardware blit between 2 different swapchains, falling back to software\n");
2516 return WINED3DERR_INVALIDCALL
;
2519 if(srcSwapchain
|| SrcSurface
== myDevice
->render_targets
[0]) {
2520 /* Blit from render target to texture */
2522 BOOL upsideDown
, stretchx
;
2524 if(Flags
& (DDBLT_KEYSRC
| DDBLT_KEYSRCOVERRIDE
)) {
2525 TRACE("Color keying not supported by frame buffer to texture blit\n");
2526 return WINED3DERR_INVALIDCALL
;
2527 /* Destination color key is checked above */
2530 /* Call preload for the surface to make sure it isn't dirty */
2531 IWineD3DSurface_PreLoad((IWineD3DSurface
*) This
);
2533 /* Make sure that the top pixel is always above the bottom pixel, and keep a seperate upside down flag
2534 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2537 if(SrcRect
->top
< SrcRect
->bottom
) {
2538 srect
.y1
= SrcRect
->top
;
2539 srect
.y2
= SrcRect
->bottom
;
2542 srect
.y1
= SrcRect
->bottom
;
2543 srect
.y2
= SrcRect
->top
;
2546 srect
.x1
= SrcRect
->left
;
2547 srect
.x2
= SrcRect
->right
;
2551 srect
.x2
= Src
->currentDesc
.Width
;
2552 srect
.y2
= Src
->currentDesc
.Height
;
2555 if(rect
.x1
> rect
.x2
) {
2559 upsideDown
= !upsideDown
;
2562 TRACE("Reading from an offscreen target\n");
2563 upsideDown
= !upsideDown
;
2566 if(rect
.x2
- rect
.x1
!= srect
.x2
- srect
.x1
) {
2572 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2573 * flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully,
2574 * not implemented by now). Otherwise:
2576 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2577 * -> If the app wants a image width an unscaled width, copy it line per line
2578 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
2579 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2580 * back buffer. This is slower than reading line per line, thus not used for flipping
2581 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2584 if(FALSE
/* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */) {
2585 TRACE("Using GL_EXT_framebuffer_blit for copying\n");
2586 } else if((!stretchx
) || rect
.x2
- rect
.x1
> Src
->currentDesc
.Width
||
2587 rect
.y2
- rect
.y1
> Src
->currentDesc
.Height
) {
2588 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
2589 fb_copy_to_texture_direct(This
, SrcSurface
, srcSwapchain
, &srect
, &rect
, upsideDown
);
2591 TRACE("Using hardware stretching to flip / stretch the texture\n");
2592 fb_copy_to_texture_hwstretch(This
, SrcSurface
, srcSwapchain
, &srect
, &rect
, upsideDown
);
2595 if(!(This
->Flags
& SFLAG_DONOTFREE
)) {
2596 HeapFree(GetProcessHeap(), 0, This
->resource
.allocatedMemory
);
2597 This
->resource
.allocatedMemory
= NULL
;
2599 This
->Flags
|= SFLAG_GLDIRTY
;
2604 /* Blit from offscreen surface to render target */
2605 float glTexCoord
[4];
2606 DWORD oldCKeyFlags
= Src
->CKeyFlags
;
2607 DDCOLORKEY oldBltCKey
= This
->SrcBltCKey
;
2608 RECT SourceRectangle
;
2611 TRACE("Blt from surface %p to rendertarget %p\n", Src
, This
);
2614 SourceRectangle
.left
= SrcRect
->left
;
2615 SourceRectangle
.right
= SrcRect
->right
;
2616 SourceRectangle
.top
= SrcRect
->top
;
2617 SourceRectangle
.bottom
= SrcRect
->bottom
;
2619 SourceRectangle
.left
= 0;
2620 SourceRectangle
.right
= Src
->currentDesc
.Width
;
2621 SourceRectangle
.top
= 0;
2622 SourceRectangle
.bottom
= Src
->currentDesc
.Height
;
2625 if(!CalculateTexRect(Src
, &SourceRectangle
, glTexCoord
)) {
2626 /* Fall back to software */
2627 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src
,
2628 SourceRectangle
.left
, SourceRectangle
.top
,
2629 SourceRectangle
.right
, SourceRectangle
.bottom
);
2630 return WINED3DERR_INVALIDCALL
;
2633 /* Color keying: Check if we have to do a color keyed blt,
2634 * and if not check if a color key is activated.
2636 * Just modify the color keying parameters in the surface and restore them afterwards
2637 * The surface keeps track of the color key last used to load the opengl surface.
2638 * PreLoad will catch the change to the flags and color key and reload if neccessary.
2640 if(Flags
& DDBLT_KEYSRC
) {
2641 /* Use color key from surface */
2642 } else if(Flags
& DDBLT_KEYSRCOVERRIDE
) {
2643 /* Use color key from DDBltFx */
2644 Src
->CKeyFlags
|= DDSD_CKSRCBLT
;
2645 This
->SrcBltCKey
= DDBltFx
->ddckSrcColorkey
;
2647 /* Do not use color key */
2648 Src
->CKeyFlags
&= ~DDSD_CKSRCBLT
;
2651 /* Now load the surface */
2652 IWineD3DSurface_PreLoad((IWineD3DSurface
*) Src
);
2656 /* Activate the destination context, set it up for blitting */
2657 ActivateContext(myDevice
, (IWineD3DSurface
*) This
, CTXUSAGE_BLIT
);
2659 glGetIntegerv(GL_DRAW_BUFFER
, &oldDraw
);
2660 if(This
== (IWineD3DSurfaceImpl
*) dstSwapchain
->frontBuffer
) {
2661 TRACE("Drawing to front buffer\n");
2662 glDrawBuffer(GL_FRONT
);
2663 checkGLcall("glDrawBuffer GL_FRONT");
2666 /* Bind the texture */
2667 glBindTexture(GL_TEXTURE_2D
, Src
->glDescription
.textureName
);
2668 checkGLcall("glBindTexture");
2670 /* No filtering for blts */
2671 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
,
2673 checkGLcall("glTexParameteri");
2674 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
2676 checkGLcall("glTexParameteri");
2677 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
2678 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
2679 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
2680 checkGLcall("glTexEnvi");
2682 /* This is for color keying */
2683 if(Flags
& (DDBLT_KEYSRC
| DDBLT_KEYSRCOVERRIDE
)) {
2684 glEnable(GL_ALPHA_TEST
);
2685 checkGLcall("glEnable GL_ALPHA_TEST");
2686 glAlphaFunc(GL_NOTEQUAL
, 0.0);
2687 checkGLcall("glAlphaFunc\n");
2689 glDisable(GL_ALPHA_TEST
);
2690 checkGLcall("glDisable GL_ALPHA_TEST");
2693 /* Draw a textured quad
2697 glColor3d(1.0f
, 1.0f
, 1.0f
);
2698 glTexCoord2f(glTexCoord
[0], glTexCoord
[2]);
2703 glTexCoord2f(glTexCoord
[0], glTexCoord
[3]);
2704 glVertex3f(rect
.x1
, rect
.y2
, 0.0);
2706 glTexCoord2f(glTexCoord
[1], glTexCoord
[3]);
2711 glTexCoord2f(glTexCoord
[1], glTexCoord
[2]);
2716 checkGLcall("glEnd");
2718 if(Flags
& (DDBLT_KEYSRC
| DDBLT_KEYSRCOVERRIDE
)) {
2719 glDisable(GL_ALPHA_TEST
);
2720 checkGLcall("glDisable(GL_ALPHA_TEST)");
2723 /* Unbind the texture */
2724 glBindTexture(GL_TEXTURE_2D
, 0);
2725 checkGLcall("glEnable glBindTexture");
2727 if(This
== (IWineD3DSurfaceImpl
*) dstSwapchain
->frontBuffer
&& oldDraw
== GL_BACK
) {
2728 glDrawBuffer(oldDraw
);
2730 /* Restore the color key parameters */
2731 Src
->CKeyFlags
= oldCKeyFlags
;
2732 This
->SrcBltCKey
= oldBltCKey
;
2736 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2737 This
->Flags
|= SFLAG_GLDIRTY
;
2741 /* Source-Less Blit to render target */
2742 if (Flags
& DDBLT_COLORFILL
) {
2743 /* This is easy to handle for the D3D Device... */
2746 TRACE("Colorfill\n");
2748 /* The color as given in the Blt function is in the format of the frame-buffer...
2749 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2751 if (This
->resource
.format
== WINED3DFMT_P8
) {
2752 if (This
->palette
) {
2753 color
= ((0xFF000000) |
2754 (This
->palette
->palents
[DDBltFx
->u5
.dwFillColor
].peRed
<< 16) |
2755 (This
->palette
->palents
[DDBltFx
->u5
.dwFillColor
].peGreen
<< 8) |
2756 (This
->palette
->palents
[DDBltFx
->u5
.dwFillColor
].peBlue
));
2761 else if (This
->resource
.format
== WINED3DFMT_R5G6B5
) {
2762 if (DDBltFx
->u5
.dwFillColor
== 0xFFFF) {
2765 color
= ((0xFF000000) |
2766 ((DDBltFx
->u5
.dwFillColor
& 0xF800) << 8) |
2767 ((DDBltFx
->u5
.dwFillColor
& 0x07E0) << 5) |
2768 ((DDBltFx
->u5
.dwFillColor
& 0x001F) << 3));
2771 else if ((This
->resource
.format
== WINED3DFMT_R8G8B8
) ||
2772 (This
->resource
.format
== WINED3DFMT_X8R8G8B8
) ) {
2773 color
= 0xFF000000 | DDBltFx
->u5
.dwFillColor
;
2775 else if (This
->resource
.format
== WINED3DFMT_A8R8G8B8
) {
2776 color
= DDBltFx
->u5
.dwFillColor
;
2779 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2780 return WINED3DERR_INVALIDCALL
;
2783 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice
);
2784 if(dstSwapchain
&& dstSwapchain
->backBuffer
&& This
== (IWineD3DSurfaceImpl
*) dstSwapchain
->backBuffer
[0]) {
2785 glDrawBuffer(GL_BACK
);
2786 checkGLcall("glDrawBuffer(GL_BACK)");
2787 } else if (dstSwapchain
&& This
== (IWineD3DSurfaceImpl
*) dstSwapchain
->frontBuffer
) {
2788 glDrawBuffer(GL_FRONT
);
2789 checkGLcall("glDrawBuffer(GL_FRONT)");
2790 } else if(This
== (IWineD3DSurfaceImpl
*) myDevice
->render_targets
[0]) {
2791 glDrawBuffer(myDevice
->offscreenBuffer
);
2792 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer3)");
2794 TRACE("Surface is higher back buffer, falling back to software\n");
2795 return WINED3DERR_INVALIDCALL
;
2798 TRACE("(%p) executing Render Target override, color = %x\n", This
, color
);
2800 IWineD3DDevice_Clear( (IWineD3DDevice
*) myDevice
,
2801 1 /* Number of rectangles */,
2803 WINED3DCLEAR_TARGET
,
2808 /* Restore the original draw buffer */
2810 glDrawBuffer(myDevice
->offscreenBuffer
);
2811 } else if(dstSwapchain
->backBuffer
&& dstSwapchain
->backBuffer
[0]) {
2812 glDrawBuffer(GL_BACK
);
2814 vcheckGLcall("glDrawBuffer");
2820 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2821 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2822 return WINED3DERR_INVALIDCALL
;
2825 static HRESULT WINAPI
IWineD3DSurfaceImpl_Blt(IWineD3DSurface
*iface
, RECT
*DestRect
, IWineD3DSurface
*SrcSurface
, RECT
*SrcRect
, DWORD Flags
, DDBLTFX
*DDBltFx
) {
2826 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2827 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
2828 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
2829 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
);
2830 TRACE("(%p): Usage is %s\n", This
, debug_d3dusage(This
->resource
.usage
));
2832 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair */
2833 if(myDevice
->inScene
&&
2834 (iface
== myDevice
->stencilBufferTarget
||
2835 (SrcSurface
&& SrcSurface
== myDevice
->stencilBufferTarget
))) {
2836 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2837 return WINED3DERR_INVALIDCALL
;
2840 /* Special cases for RenderTargets */
2841 if( (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ||
2842 ( Src
&& (Src
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) )) {
2843 if(IWineD3DSurfaceImpl_BltOverride(This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
) == WINED3D_OK
) return WINED3D_OK
;
2846 /* For the rest call the X11 surface implementation.
2847 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2848 * other Blts are rather rare
2850 return IWineGDISurfaceImpl_Blt(iface
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
);
2853 HRESULT WINAPI
IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface
*iface
, DWORD Flags
) {
2854 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2855 TRACE("(%p)->(%x)\n", This
, Flags
);
2860 case DDGBS_ISBLTDONE
:
2864 return DDERR_INVALIDPARAMS
;
2868 HRESULT WINAPI
IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface
*iface
, DWORD Flags
) {
2869 /* XXX: DDERR_INVALIDSURFACETYPE */
2871 TRACE("(%p)->(%08x)\n",iface
,Flags
);
2874 case DDGFS_ISFLIPDONE
:
2878 return DDERR_INVALIDPARAMS
;
2882 HRESULT WINAPI
IWineD3DSurfaceImpl_IsLost(IWineD3DSurface
*iface
) {
2883 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2884 TRACE("(%p)\n", This
);
2886 return This
->Flags
& SFLAG_LOST
? DDERR_SURFACELOST
: WINED3D_OK
;
2889 HRESULT WINAPI
IWineD3DSurfaceImpl_Restore(IWineD3DSurface
*iface
) {
2890 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2891 TRACE("(%p)\n", This
);
2893 /* So far we don't lose anything :) */
2894 This
->Flags
&= ~SFLAG_LOST
;
2898 HRESULT WINAPI
IWineD3DSurfaceImpl_BltFast(IWineD3DSurface
*iface
, DWORD dstx
, DWORD dsty
, IWineD3DSurface
*Source
, RECT
*rsrc
, DWORD trans
) {
2899 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2900 IWineD3DSurfaceImpl
*srcImpl
= (IWineD3DSurfaceImpl
*) Source
;
2901 IWineD3DDeviceImpl
*myDevice
= This
->resource
.wineD3DDevice
;
2902 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface
, dstx
, dsty
, Source
, rsrc
, trans
);
2904 if(myDevice
->inScene
&&
2905 (iface
== myDevice
->stencilBufferTarget
||
2906 (Source
&& Source
== myDevice
->stencilBufferTarget
))) {
2907 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2908 return WINED3DERR_INVALIDCALL
;
2911 /* Special cases for RenderTargets */
2912 if( (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ||
2913 ( srcImpl
&& (srcImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) )) {
2915 RECT SrcRect
, DstRect
;
2919 SrcRect
.left
= rsrc
->left
;
2920 SrcRect
.top
= rsrc
->top
;
2921 SrcRect
.bottom
= rsrc
->bottom
;
2922 SrcRect
.right
= rsrc
->right
;
2926 SrcRect
.right
= srcImpl
->currentDesc
.Width
;
2927 SrcRect
.bottom
= srcImpl
->currentDesc
.Height
;
2930 DstRect
.left
= dstx
;
2932 DstRect
.right
= dstx
+ SrcRect
.right
- SrcRect
.left
;
2933 DstRect
.bottom
= dsty
+ SrcRect
.bottom
- SrcRect
.top
;
2935 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2936 if(trans
& DDBLTFAST_SRCCOLORKEY
)
2937 Flags
|= DDBLT_KEYSRC
;
2938 if(trans
& DDBLTFAST_DESTCOLORKEY
)
2939 Flags
|= DDBLT_KEYDEST
;
2940 if(trans
& DDBLTFAST_WAIT
)
2941 Flags
|= DDBLT_WAIT
;
2942 if(trans
& DDBLTFAST_DONOTWAIT
)
2943 Flags
|= DDBLT_DONOTWAIT
;
2945 if(IWineD3DSurfaceImpl_BltOverride(This
, &DstRect
, Source
, &SrcRect
, Flags
, NULL
) == WINED3D_OK
) return WINED3D_OK
;
2949 return IWineGDISurfaceImpl_BltFast(iface
, dstx
, dsty
, Source
, rsrc
, trans
);
2952 HRESULT WINAPI
IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface
*iface
, IWineD3DPalette
**Pal
) {
2953 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2954 TRACE("(%p)->(%p)\n", This
, Pal
);
2956 *Pal
= (IWineD3DPalette
*) This
->palette
;
2960 HRESULT WINAPI
IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface
*iface
) {
2961 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2963 IWineD3DPaletteImpl
*pal
= This
->palette
;
2965 TRACE("(%p)\n", This
);
2967 if(This
->resource
.format
== WINED3DFMT_P8
||
2968 This
->resource
.format
== WINED3DFMT_A8P8
)
2970 TRACE("Dirtifying surface\n");
2971 This
->Flags
|= SFLAG_DIRTY
;
2974 if(This
->Flags
& SFLAG_DIBSECTION
) {
2975 TRACE("(%p): Updating the hdc's palette\n", This
);
2976 for (n
=0; n
<256; n
++) {
2978 col
[n
].rgbRed
= pal
->palents
[n
].peRed
;
2979 col
[n
].rgbGreen
= pal
->palents
[n
].peGreen
;
2980 col
[n
].rgbBlue
= pal
->palents
[n
].peBlue
;
2982 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
2983 /* Use the default device palette */
2984 col
[n
].rgbRed
= device
->palettes
[device
->currentPalette
][n
].peRed
;
2985 col
[n
].rgbGreen
= device
->palettes
[device
->currentPalette
][n
].peGreen
;
2986 col
[n
].rgbBlue
= device
->palettes
[device
->currentPalette
][n
].peBlue
;
2988 col
[n
].rgbReserved
= 0;
2990 SetDIBColorTable(This
->hDC
, 0, 256, col
);
2996 HRESULT WINAPI
IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface
*iface
, IWineD3DPalette
*Pal
) {
2997 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2998 IWineD3DPaletteImpl
*PalImpl
= (IWineD3DPaletteImpl
*) Pal
;
2999 TRACE("(%p)->(%p)\n", This
, Pal
);
3001 if(This
->palette
!= NULL
)
3002 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
3003 This
->palette
->Flags
&= ~DDPCAPS_PRIMARYSURFACE
;
3005 if(PalImpl
!= NULL
) {
3006 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
3007 /* Set the device's main palette if the palette
3008 * wasn't a primary palette before
3010 if(!(PalImpl
->Flags
& DDPCAPS_PRIMARYSURFACE
)) {
3011 IWineD3DDeviceImpl
*device
= This
->resource
.wineD3DDevice
;
3014 for(i
=0; i
< 256; i
++) {
3015 device
->palettes
[device
->currentPalette
][i
] = PalImpl
->palents
[i
];
3019 (PalImpl
)->Flags
|= DDPCAPS_PRIMARYSURFACE
;
3022 This
->palette
= PalImpl
;
3024 return IWineD3DSurface_RealizePalette(iface
);
3027 HRESULT WINAPI
IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface
*iface
, DWORD Flags
, DDCOLORKEY
*CKey
) {
3028 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3029 TRACE("(%p)->(%08x,%p)\n", This
, Flags
, CKey
);
3031 if ((Flags
& DDCKEY_COLORSPACE
) != 0) {
3032 FIXME(" colorkey value not supported (%08x) !\n", Flags
);
3033 return DDERR_INVALIDPARAMS
;
3036 /* Dirtify the surface, but only if a key was changed */
3038 switch (Flags
& ~DDCKEY_COLORSPACE
) {
3039 case DDCKEY_DESTBLT
:
3040 This
->DestBltCKey
= *CKey
;
3041 This
->CKeyFlags
|= DDSD_CKDESTBLT
;
3044 case DDCKEY_DESTOVERLAY
:
3045 This
->DestOverlayCKey
= *CKey
;
3046 This
->CKeyFlags
|= DDSD_CKDESTOVERLAY
;
3049 case DDCKEY_SRCOVERLAY
:
3050 This
->SrcOverlayCKey
= *CKey
;
3051 This
->CKeyFlags
|= DDSD_CKSRCOVERLAY
;
3055 This
->SrcBltCKey
= *CKey
;
3056 This
->CKeyFlags
|= DDSD_CKSRCBLT
;
3061 switch (Flags
& ~DDCKEY_COLORSPACE
) {
3062 case DDCKEY_DESTBLT
:
3063 This
->CKeyFlags
&= ~DDSD_CKDESTBLT
;
3066 case DDCKEY_DESTOVERLAY
:
3067 This
->CKeyFlags
&= ~DDSD_CKDESTOVERLAY
;
3070 case DDCKEY_SRCOVERLAY
:
3071 This
->CKeyFlags
&= ~DDSD_CKSRCOVERLAY
;
3075 This
->CKeyFlags
&= ~DDSD_CKSRCBLT
;
3083 static HRESULT WINAPI
IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface
*iface
) {
3084 /** Check against the maximum texture sizes supported by the video card **/
3085 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3087 TRACE("%p\n", This
);
3088 if ((This
->pow2Width
> GL_LIMITS(texture_size
) || This
->pow2Height
> GL_LIMITS(texture_size
)) && !(This
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
))) {
3089 /* one of three options
3090 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)
3091 2: Set the texture to the maxium size (bad idea)
3092 3: WARN and return WINED3DERR_NOTAVAILABLE;
3093 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.
3095 WARN("(%p) Creating an oversized surface\n", This
);
3096 This
->Flags
|= SFLAG_OVERSIZE
;
3098 /* This will be initialized on the first blt */
3099 This
->glRect
.left
= 0;
3100 This
->glRect
.top
= 0;
3101 This
->glRect
.right
= 0;
3102 This
->glRect
.bottom
= 0;
3104 /* No oversize, gl rect is the full texture size */
3105 This
->Flags
&= ~SFLAG_OVERSIZE
;
3106 This
->glRect
.left
= 0;
3107 This
->glRect
.top
= 0;
3108 This
->glRect
.right
= This
->pow2Width
;
3109 This
->glRect
.bottom
= This
->pow2Height
;
3115 DWORD WINAPI
IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface
*iface
) {
3116 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3118 TRACE("(%p)\n", This
);
3120 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3121 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3122 ie pitch = (width/4) * bytes per block */
3123 if (This
->resource
.format
== WINED3DFMT_DXT1
) /* DXT1 is 8 bytes per block */
3124 ret
= ((This
->currentDesc
.Width
+ 3) >> 2) << 3;
3125 else if (This
->resource
.format
== WINED3DFMT_DXT2
|| This
->resource
.format
== WINED3DFMT_DXT3
||
3126 This
->resource
.format
== WINED3DFMT_DXT4
|| This
->resource
.format
== WINED3DFMT_DXT5
) /* DXT2/3/4/5 is 16 bytes per block */
3127 ret
= ((This
->currentDesc
.Width
+ 3) >> 2) << 4;
3129 ret
= This
->bytesPerPixel
* This
->currentDesc
.Width
; /* Bytes / row */
3130 /* Surfaces are 32 bit aligned */
3131 ret
= (ret
+ SURFACE_ALIGNMENT
- 1) & ~(SURFACE_ALIGNMENT
- 1);
3133 TRACE("(%p) Returning %d\n", This
, ret
);
3137 HRESULT WINAPI
IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface
*iface
, LONG X
, LONG Y
) {
3138 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3140 FIXME("(%p)->(%d,%d) Stub!\n", This
, X
, Y
);
3142 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3144 TRACE("(%p): Not an overlay surface\n", This
);
3145 return DDERR_NOTAOVERLAYSURFACE
;
3151 HRESULT WINAPI
IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface
*iface
, LONG
*X
, LONG
*Y
) {
3152 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3154 FIXME("(%p)->(%p,%p) Stub!\n", This
, X
, Y
);
3156 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3158 TRACE("(%p): Not an overlay surface\n", This
);
3159 return DDERR_NOTAOVERLAYSURFACE
;
3165 HRESULT WINAPI
IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface
*iface
, DWORD Flags
, IWineD3DSurface
*Ref
) {
3166 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3167 IWineD3DSurfaceImpl
*RefImpl
= (IWineD3DSurfaceImpl
*) Ref
;
3169 FIXME("(%p)->(%08x,%p) Stub!\n", This
, Flags
, RefImpl
);
3171 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3173 TRACE("(%p): Not an overlay surface\n", This
);
3174 return DDERR_NOTAOVERLAYSURFACE
;
3180 HRESULT WINAPI
IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface
*iface
, RECT
*SrcRect
, IWineD3DSurface
*DstSurface
, RECT
*DstRect
, DWORD Flags
, WINEDDOVERLAYFX
*FX
) {
3181 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
3182 IWineD3DSurfaceImpl
*Dst
= (IWineD3DSurfaceImpl
*) DstSurface
;
3183 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This
, SrcRect
, Dst
, DstRect
, Flags
, FX
);
3185 if(!(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3187 TRACE("(%p): Not an overlay surface\n", This
);
3188 return DDERR_NOTAOVERLAYSURFACE
;
3194 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl
=
3197 IWineD3DSurfaceImpl_QueryInterface
,
3198 IWineD3DSurfaceImpl_AddRef
,
3199 IWineD3DSurfaceImpl_Release
,
3200 /* IWineD3DResource */
3201 IWineD3DSurfaceImpl_GetParent
,
3202 IWineD3DSurfaceImpl_GetDevice
,
3203 IWineD3DSurfaceImpl_SetPrivateData
,
3204 IWineD3DSurfaceImpl_GetPrivateData
,
3205 IWineD3DSurfaceImpl_FreePrivateData
,
3206 IWineD3DSurfaceImpl_SetPriority
,
3207 IWineD3DSurfaceImpl_GetPriority
,
3208 IWineD3DSurfaceImpl_PreLoad
,
3209 IWineD3DSurfaceImpl_GetType
,
3210 /* IWineD3DSurface */
3211 IWineD3DSurfaceImpl_GetContainer
,
3212 IWineD3DSurfaceImpl_GetDesc
,
3213 IWineD3DSurfaceImpl_LockRect
,
3214 IWineD3DSurfaceImpl_UnlockRect
,
3215 IWineD3DSurfaceImpl_GetDC
,
3216 IWineD3DSurfaceImpl_ReleaseDC
,
3217 IWineD3DSurfaceImpl_Flip
,
3218 IWineD3DSurfaceImpl_Blt
,
3219 IWineD3DSurfaceImpl_GetBltStatus
,
3220 IWineD3DSurfaceImpl_GetFlipStatus
,
3221 IWineD3DSurfaceImpl_IsLost
,
3222 IWineD3DSurfaceImpl_Restore
,
3223 IWineD3DSurfaceImpl_BltFast
,
3224 IWineD3DSurfaceImpl_GetPalette
,
3225 IWineD3DSurfaceImpl_SetPalette
,
3226 IWineD3DSurfaceImpl_RealizePalette
,
3227 IWineD3DSurfaceImpl_SetColorKey
,
3228 IWineD3DSurfaceImpl_GetPitch
,
3229 IWineD3DSurfaceImpl_SetMem
,
3230 IWineD3DSurfaceImpl_SetOverlayPosition
,
3231 IWineD3DSurfaceImpl_GetOverlayPosition
,
3232 IWineD3DSurfaceImpl_UpdateOverlayZOrder
,
3233 IWineD3DSurfaceImpl_UpdateOverlay
,
3235 IWineD3DSurfaceImpl_CleanDirtyRect
,
3236 IWineD3DSurfaceImpl_AddDirtyRect
,
3237 IWineD3DSurfaceImpl_LoadTexture
,
3238 IWineD3DSurfaceImpl_SaveSnapshot
,
3239 IWineD3DSurfaceImpl_SetContainer
,
3240 IWineD3DSurfaceImpl_SetPBufferState
,
3241 IWineD3DSurfaceImpl_SetGlTextureDesc
,
3242 IWineD3DSurfaceImpl_GetGlDesc
,
3243 IWineD3DSurfaceImpl_GetData
,
3244 IWineD3DSurfaceImpl_SetFormat
,
3245 IWineD3DSurfaceImpl_PrivateSetup