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_INTEXTURE;
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_INSYSMEM; /* 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_INSYSMEM)) {
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_INSYSMEM;
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 set SFLAG_INSYSMEM 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_INSYSMEM;
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,
807 This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
811 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
813 GLint prev_rasterpos[4];
815 BOOL storechanged = FALSE, memory_allocated = FALSE;
819 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
821 glDisable(GL_TEXTURE_2D);
822 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
825 vcheckGLcall("glFlush");
826 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
827 vcheckGLcall("glIntegerv");
828 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
829 vcheckGLcall("glIntegerv");
830 glPixelZoom(1.0, -1.0);
831 vcheckGLcall("glPixelZoom");
833 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
834 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
835 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
837 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
838 vcheckGLcall("glRasterPos2f");
840 /* Some drivers(radeon dri, others?) don't like exceptions during
841 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
842 * after ReleaseDC. Reading it will cause an exception, which x11drv will
843 * catch to put the dib section in InSync mode, which leads to a crash
844 * and a blocked x server on my radeon card.
846 * The following lines read the dib section so it is put in inSync mode
847 * before glDrawPixels is called and the crash is prevented. There won't
848 * be any interfering gdi accesses, because UnlockRect is called from
849 * ReleaseDC, and the app won't use the dc any more afterwards.
851 if(This->Flags & SFLAG_DIBSECTION) {
853 read = This->resource.allocatedMemory[0];
856 switch (This->resource.format) {
857 /* No special care needed */
858 case WINED3DFMT_A4R4G4B4:
859 case WINED3DFMT_R5G6B5:
860 case WINED3DFMT_A1R5G5B5:
861 case WINED3DFMT_R8G8B8:
862 type = This->glDescription.glType;
863 fmt = This->glDescription.glFormat;
864 mem = This->resource.allocatedMemory;
865 bpp = This->bytesPerPixel;
868 case WINED3DFMT_X4R4G4B4:
871 unsigned short *data;
872 data = (unsigned short *)This->resource.allocatedMemory;
873 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
879 type = This->glDescription.glType;
880 fmt = This->glDescription.glFormat;
881 mem = This->resource.allocatedMemory;
882 bpp = This->bytesPerPixel;
886 case WINED3DFMT_X1R5G5B5:
889 unsigned short *data;
890 data = (unsigned short *)This->resource.allocatedMemory;
891 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
897 type = This->glDescription.glType;
898 fmt = This->glDescription.glFormat;
899 mem = This->resource.allocatedMemory;
900 bpp = This->bytesPerPixel;
904 case WINED3DFMT_X8R8G8B8:
906 /* make sure the X byte is set to alpha on, since it
907 could be any random value. This fixes the intro movie in Pirates! */
910 data = (unsigned int *)This->resource.allocatedMemory;
911 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
920 case WINED3DFMT_A8R8G8B8:
922 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
923 vcheckGLcall("glPixelStorei");
925 type = This->glDescription.glType;
926 fmt = This->glDescription.glFormat;
927 mem = This->resource.allocatedMemory;
928 bpp = This->bytesPerPixel;
932 case WINED3DFMT_A2R10G10B10:
934 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
935 vcheckGLcall("glPixelStorei");
937 type = This->glDescription.glType;
938 fmt = This->glDescription.glFormat;
939 mem = This->resource.allocatedMemory;
940 bpp = This->bytesPerPixel;
946 int height = This->glRect.bottom - This->glRect.top;
947 type = GL_UNSIGNED_BYTE;
950 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
952 ERR("Out of memory\n");
955 memory_allocated = TRUE;
956 d3dfmt_convert_surface(This->resource.allocatedMemory,
964 bpp = This->bytesPerPixel * 4;
970 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
973 type = This->glDescription.glType;
974 fmt = This->glDescription.glFormat;
975 mem = This->resource.allocatedMemory;
976 bpp = This->bytesPerPixel;
979 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
980 (This->lockedRect.bottom - This->lockedRect.top)-1,
982 mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
983 checkGLcall("glDrawPixels");
984 glPixelZoom(1.0,1.0);
985 vcheckGLcall("glPixelZoom");
987 glRasterPos3iv(&prev_rasterpos[0]);
988 vcheckGLcall("glRasterPos3iv");
990 /* Reset to previous pack row length */
991 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
992 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
994 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
995 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
998 /* Blitting environment requires that 2D texturing is enabled. It was turned off before,
1001 glEnable(GL_TEXTURE_2D);
1002 checkGLcall("glEnable(GL_TEXTURE_2D)");
1004 if(memory_allocated) HeapFree(GetProcessHeap(), 0, mem);
1008 static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl *This) {
1009 float glTexCoord[4];
1011 glTexCoord[0] = (float) This->lockedRect.left / (float) This->pow2Width; /* left */
1012 glTexCoord[1] = (float) This->lockedRect.right / (float) This->pow2Width; /* right */
1013 glTexCoord[2] = (float) This->lockedRect.top / (float) This->pow2Height; /* top */
1014 glTexCoord[3] = (float) This->lockedRect.bottom / (float) This->pow2Height; /* bottom */
1016 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
1020 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1021 checkGLcall("glEnable glBindTexture");
1023 /* No filtering for blts */
1024 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1025 checkGLcall("glTexParameteri");
1026 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1027 checkGLcall("glTexParameteri");
1029 /* Start drawing a quad */
1032 glColor3d(1.0f, 1.0f, 1.0f);
1033 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1034 glVertex3f(This->lockedRect.left, This->lockedRect.top, 0.0);
1036 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1037 glVertex3f(This->lockedRect.left, This->lockedRect.bottom, 0.0);
1039 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1040 glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.0);
1042 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1043 glVertex3f(This->lockedRect.right, This->lockedRect.top, 0.0);
1046 checkGLcall("glEnd");
1048 /* Unbind the texture */
1049 glBindTexture(GL_TEXTURE_2D, 0);
1050 checkGLcall("glEnable glBindTexture");
1055 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1056 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1057 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1058 IWineD3DSwapChainImpl *swapchain = NULL;
1060 if (!(This->Flags & SFLAG_LOCKED)) {
1061 WARN("trying to Unlock an unlocked surf@%p\n", This);
1062 return WINED3DERR_INVALIDCALL;
1065 TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1067 if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) {
1068 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1072 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1073 if(swapchain || iface == myDevice->render_targets[0]) {
1074 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1075 static BOOL warned = FALSE;
1077 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1080 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1084 /* Activate the correct context for the render target */
1086 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
1089 /* Primary offscreen render target */
1090 TRACE("Offscreen render target\n");
1091 glDrawBuffer(myDevice->offscreenBuffer);
1092 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1094 if(iface == swapchain->frontBuffer) {
1095 TRACE("Onscreen front buffer\n");
1096 glDrawBuffer(GL_FRONT);
1097 checkGLcall("glDrawBuffer(GL_FRONT)");
1098 } else if(iface == swapchain->backBuffer[0]) {
1099 TRACE("Onscreen back buffer\n");
1100 glDrawBuffer(GL_BACK);
1101 checkGLcall("glDrawBuffer(GL_BACK)");
1103 FIXME("Unlocking a higher back buffer\n");
1104 glDrawBuffer(GL_BACK);
1105 checkGLcall("glDrawBuffer(GL_BACK)");
1107 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1110 switch(wined3d_settings.rendertargetlock_mode) {
1114 flush_to_framebuffer_drawpixels(This);
1119 flush_to_framebuffer_texture(This);
1123 glDrawBuffer(myDevice->offscreenBuffer);
1124 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1125 } else if(swapchain->backBuffer) {
1126 glDrawBuffer(GL_BACK);
1127 checkGLcall("glDrawBuffer(GL_BACK)");
1129 glDrawBuffer(GL_FRONT);
1130 checkGLcall("glDrawBuffer(GL_FRONT)");
1134 This->dirtyRect.left = This->currentDesc.Width;
1135 This->dirtyRect.top = This->currentDesc.Height;
1136 This->dirtyRect.right = 0;
1137 This->dirtyRect.bottom = 0;
1138 This->Flags |= SFLAG_INDRAWABLE;
1139 } else if(iface == myDevice->stencilBufferTarget) {
1140 FIXME("Depth Stencil buffer locking is not implemented\n");
1142 /* The rest should be a normal texture */
1143 IWineD3DBaseTextureImpl *impl;
1144 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1145 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1146 * states need resetting
1148 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1149 if(impl->baseTexture.bindCount) {
1150 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1152 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1157 This->Flags &= ~SFLAG_LOCKED;
1158 memset(&This->lockedRect, 0, sizeof(RECT));
1162 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1163 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1164 WINED3DLOCKED_RECT lock;
1171 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1173 TRACE("(%p)->(%p)\n",This,pHDC);
1175 if(This->Flags & SFLAG_USERPTR) {
1176 ERR("Not supported on surfaces with an application-provided surfaces\n");
1180 /* Give more detailed info for ddraw */
1181 if (This->Flags & SFLAG_DCINUSE)
1182 return DDERR_DCALREADYCREATED;
1184 /* Can't GetDC if the surface is locked */
1185 if (This->Flags & SFLAG_LOCKED)
1186 return WINED3DERR_INVALIDCALL;
1188 memset(&lock, 0, sizeof(lock)); /* To be sure */
1190 /* Create a DIB section if there isn't a hdc yet */
1193 SYSTEM_INFO sysInfo;
1195 switch (This->bytesPerPixel) {
1198 /* Allocate extra space to store the RGB bit masks. */
1199 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1203 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1207 /* Allocate extra space for a palette. */
1208 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1209 sizeof(BITMAPINFOHEADER)
1211 * (1 << (This->bytesPerPixel * 8)));
1216 return E_OUTOFMEMORY;
1218 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1219 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1220 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1221 * add an extra line to the dib section
1223 GetSystemInfo(&sysInfo);
1224 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1226 TRACE("Adding an extra line to the dib section\n");
1229 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1230 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1231 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1232 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1233 b_info->bmiHeader.biPlanes = 1;
1234 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1236 b_info->bmiHeader.biXPelsPerMeter = 0;
1237 b_info->bmiHeader.biYPelsPerMeter = 0;
1238 b_info->bmiHeader.biClrUsed = 0;
1239 b_info->bmiHeader.biClrImportant = 0;
1241 /* Get the bit masks */
1242 masks = (DWORD *) &(b_info->bmiColors);
1243 switch (This->resource.format) {
1244 case WINED3DFMT_R8G8B8:
1245 usage = DIB_RGB_COLORS;
1246 b_info->bmiHeader.biCompression = BI_RGB;
1249 case WINED3DFMT_X1R5G5B5:
1250 case WINED3DFMT_A1R5G5B5:
1251 case WINED3DFMT_A4R4G4B4:
1252 case WINED3DFMT_X4R4G4B4:
1253 case WINED3DFMT_R3G3B2:
1254 case WINED3DFMT_A8R3G3B2:
1255 case WINED3DFMT_A2B10G10R10:
1256 case WINED3DFMT_A8B8G8R8:
1257 case WINED3DFMT_X8B8G8R8:
1258 case WINED3DFMT_A2R10G10B10:
1259 case WINED3DFMT_R5G6B5:
1260 case WINED3DFMT_A16B16G16R16:
1262 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1263 masks[0] = formatEntry->redMask;
1264 masks[1] = formatEntry->greenMask;
1265 masks[2] = formatEntry->blueMask;
1269 /* Don't know palette */
1270 b_info->bmiHeader.biCompression = BI_RGB;
1277 HeapFree(GetProcessHeap(), 0, b_info);
1278 return HRESULT_FROM_WIN32(GetLastError());
1281 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);
1282 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1285 if (!This->dib.DIBsection) {
1286 ERR("CreateDIBSection failed!\n");
1287 HeapFree(GetProcessHeap(), 0, b_info);
1288 return HRESULT_FROM_WIN32(GetLastError());
1291 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1293 /* copy the existing surface to the dib section */
1294 if(This->resource.allocatedMemory) {
1295 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1296 /* We won't need that any more */
1297 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1299 /* This is to make LockRect read the gl Texture although memory is allocated */
1300 This->Flags &= ~SFLAG_INSYSMEM;
1303 HeapFree(GetProcessHeap(), 0, b_info);
1305 /* Use the dib section from now on */
1306 This->resource.allocatedMemory = This->dib.bitmap_data;
1308 /* Now allocate a HDC */
1309 This->hDC = CreateCompatibleDC(0);
1310 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1311 TRACE("using wined3d palette %p\n", This->palette);
1312 SelectPalette(This->hDC,
1313 This->palette ? This->palette->hpal : 0,
1316 This->Flags |= SFLAG_DIBSECTION;
1319 /* Lock the surface */
1320 hr = IWineD3DSurface_LockRect(iface,
1325 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1326 /* keep the dib section */
1330 if(This->resource.format == WINED3DFMT_P8 ||
1331 This->resource.format == WINED3DFMT_A8P8) {
1334 PALETTEENTRY ent[256];
1336 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1337 for (n=0; n<256; n++) {
1338 col[n].rgbRed = ent[n].peRed;
1339 col[n].rgbGreen = ent[n].peGreen;
1340 col[n].rgbBlue = ent[n].peBlue;
1341 col[n].rgbReserved = 0;
1344 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1346 for (n=0; n<256; n++) {
1347 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1348 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1349 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1350 col[n].rgbReserved = 0;
1354 SetDIBColorTable(This->hDC, 0, 256, col);
1358 TRACE("returning %p\n",*pHDC);
1359 This->Flags |= SFLAG_DCINUSE;
1364 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1365 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1367 TRACE("(%p)->(%p)\n",This,hDC);
1369 if (!(This->Flags & SFLAG_DCINUSE))
1370 return WINED3DERR_INVALIDCALL;
1372 /* we locked first, so unlock now */
1373 IWineD3DSurface_UnlockRect(iface);
1375 This->Flags &= ~SFLAG_DCINUSE;
1380 /* ******************************************************
1381 IWineD3DSurface Internal (No mapping to directx api) parts follow
1382 ****************************************************** */
1384 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) {
1385 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1386 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1388 /* Default values: From the surface */
1389 *format = formatEntry->glFormat;
1390 *internal = formatEntry->glInternal;
1391 *type = formatEntry->glType;
1392 *convert = NO_CONVERSION;
1393 *target_bpp = This->bytesPerPixel;
1395 /* Ok, now look if we have to do any conversion */
1396 switch(This->resource.format) {
1401 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1402 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1404 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1406 *internal = GL_RGBA;
1407 *type = GL_UNSIGNED_BYTE;
1409 if(colorkey_active) {
1410 *convert = CONVERT_PALETTED_CK;
1412 *convert = CONVERT_PALETTED;
1418 case WINED3DFMT_R3G3B2:
1419 /* **********************
1420 GL_UNSIGNED_BYTE_3_3_2
1421 ********************** */
1422 if (colorkey_active) {
1423 /* This texture format will never be used.. So do not care about color keying
1424 up until the point in time it will be needed :-) */
1425 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1429 case WINED3DFMT_R5G6B5:
1430 if (colorkey_active) {
1431 *convert = CONVERT_CK_565;
1433 *internal = GL_RGBA;
1434 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1438 case WINED3DFMT_R8G8B8:
1439 if (colorkey_active) {
1440 *convert = CONVERT_CK_RGB24;
1442 *internal = GL_RGBA;
1443 *type = GL_UNSIGNED_INT_8_8_8_8;
1448 case WINED3DFMT_X8R8G8B8:
1449 if (colorkey_active) {
1450 *convert = CONVERT_RGB32_888;
1452 *internal = GL_RGBA;
1453 *type = GL_UNSIGNED_INT_8_8_8_8;
1457 case WINED3DFMT_V8U8:
1458 /* TODO: GL_NV_texture_shader and GL_ATI_envmap_bumpmap provide suitable formats.
1459 * use one of them instead of converting
1460 * Remember to adjust the texbem instruction in the shader
1462 *convert = CONVERT_V8U8;
1464 *internal = GL_RGB8;
1476 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1477 BYTE *source, *dest;
1478 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1483 memcpy(dst, src, pitch * height);
1486 case CONVERT_PALETTED:
1487 case CONVERT_PALETTED_CK:
1489 IWineD3DPaletteImpl* pal = surf->palette;
1495 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1499 /* Still no palette? Use the device's palette */
1500 /* Get the surface's palette */
1501 for (i = 0; i < 256; i++) {
1502 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1504 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1505 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1506 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1507 if ((convert == CONVERT_PALETTED_CK) &&
1508 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1509 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1510 /* We should maybe here put a more 'neutral' color than the standard bright purple
1511 one often used by application to prevent the nice purple borders when bi-linear
1519 TRACE("Using surface palette %p\n", pal);
1520 /* Get the surface's palette */
1521 for (i = 0; i < 256; i++) {
1522 table[i][0] = pal->palents[i].peRed;
1523 table[i][1] = pal->palents[i].peGreen;
1524 table[i][2] = pal->palents[i].peBlue;
1525 if ((convert == CONVERT_PALETTED_CK) &&
1526 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1527 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1528 /* We should maybe here put a more 'neutral' color than the standard bright purple
1529 one often used by application to prevent the nice purple borders when bi-linear
1538 for (y = 0; y < height; y++)
1540 source = src + pitch * y;
1541 dest = dst + outpitch * y;
1542 /* This is an 1 bpp format, using the width here is fine */
1543 for (x = 0; x < width; x++) {
1544 BYTE color = *source++;
1545 *dest++ = table[color][0];
1546 *dest++ = table[color][1];
1547 *dest++ = table[color][2];
1548 *dest++ = table[color][3];
1554 case CONVERT_CK_565:
1556 /* Converting the 565 format in 5551 packed to emulate color-keying.
1558 Note : in all these conversion, it would be best to average the averaging
1559 pixels to get the color of the pixel that will be color-keyed to
1560 prevent 'color bleeding'. This will be done later on if ever it is
1563 Note2: Nvidia documents say that their driver does not support alpha + color keying
1564 on the same surface and disables color keying in such a case
1570 TRACE("Color keyed 565\n");
1572 for (y = 0; y < height; y++) {
1573 Source = (WORD *) (src + y * pitch);
1574 Dest = (WORD *) (dst + y * outpitch);
1575 for (x = 0; x < width; x++ ) {
1576 WORD color = *Source++;
1577 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1578 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1579 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1592 unsigned char *Dest;
1593 for(y = 0; y < height; y++) {
1594 Source = (short *) (src + y * pitch);
1595 Dest = (unsigned char *) (dst + y * outpitch);
1596 for (x = 0; x < width; x++ ) {
1597 long color = (*Source++);
1598 /* B */ Dest[0] = 0xff;
1599 /* G */ Dest[1] = (color >> 8) + 128; /* V */
1600 /* R */ Dest[2] = (color) + 128; /* U */
1608 ERR("Unsupported conversation type %d\n", convert);
1613 /* This function is used in case of 8bit paletted textures to upload the palette.
1614 For now it only supports GL_EXT_paletted_texture extension but support for other
1615 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1617 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1618 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1619 IWineD3DPaletteImpl* pal = This->palette;
1624 /* Still no palette? Use the device's palette */
1625 /* Get the surface's palette */
1626 for (i = 0; i < 256; i++) {
1627 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1629 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1630 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1631 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1632 if ((convert == CONVERT_PALETTED_CK) &&
1633 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1634 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1635 /* We should maybe here put a more 'neutral' color than the standard bright purple
1636 one often used by application to prevent the nice purple borders when bi-linear
1644 TRACE("Using surface palette %p\n", pal);
1645 /* Get the surface's palette */
1646 for (i = 0; i < 256; i++) {
1647 table[i][0] = pal->palents[i].peRed;
1648 table[i][1] = pal->palents[i].peGreen;
1649 table[i][2] = pal->palents[i].peBlue;
1650 if ((convert == CONVERT_PALETTED_CK) &&
1651 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1652 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1653 /* We should maybe here put a more 'neutral' color than the standard bright purple
1654 one often used by application to prevent the nice purple borders when bi-linear
1662 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1665 static BOOL palette9_changed(IWineD3DSurfaceImpl *This) {
1666 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1668 if(This->palette || (This->resource.format != WINED3DFMT_P8 && This->resource.format != WINED3DFMT_A8P8)) {
1669 /* If a ddraw-style palette is attached assume no d3d9 palette change.
1670 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
1675 if(This->palette9) {
1676 if(memcmp(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256) == 0) {
1680 This->palette9 = (PALETTEENTRY *) HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1682 memcpy(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
1686 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1687 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1688 GLenum format, internal, type;
1689 CONVERT_TYPES convert;
1691 int width, pitch, outpitch;
1694 if (!(This->Flags & SFLAG_INTEXTURE)) {
1695 TRACE("Reloading because surface is dirty\n");
1696 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1697 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1698 /* Reload: vice versa OR */
1699 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1700 /* Also reload: Color key is active AND the color key has changed */
1701 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1702 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1703 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1704 TRACE("Reloading because of color keying\n");
1705 } else if(palette9_changed(This)) {
1706 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
1708 TRACE("surface is already in texture\n");
1712 This->Flags |= SFLAG_INTEXTURE;
1714 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1715 * These resources are not bound by device size or format restrictions. Because of this,
1716 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1717 * However, these resources can always be created, locked, and copied.
1719 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1721 FIXME("(%p) Operation not supported for scratch textures\n",This);
1722 return WINED3DERR_INVALIDCALL;
1725 if (This->Flags & SFLAG_INDRAWABLE) {
1726 if (This->glDescription.level != 0)
1727 FIXME("Surface in texture is only supported for level 0\n");
1728 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1729 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1730 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1731 This->resource.format == WINED3DFMT_DXT5)
1732 FIXME("Format %d not supported\n", This->resource.format);
1737 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1738 vcheckGLcall("glGetIntegerv");
1739 glReadBuffer(This->resource.wineD3DDevice->offscreenBuffer);
1740 vcheckGLcall("glReadBuffer");
1742 glCopyTexImage2D(This->glDescription.target,
1743 This->glDescription.level,
1744 This->glDescription.glFormatInternal,
1747 This->currentDesc.Width,
1748 This->currentDesc.Height,
1751 checkGLcall("glCopyTexImage2D");
1752 glReadBuffer(prevRead);
1753 vcheckGLcall("glReadBuffer");
1757 TRACE("Updated target %d\n", This->glDescription.target);
1761 /* Otherwise: System memory copy must be most up to date */
1763 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1764 This->Flags |= SFLAG_GLCKEY;
1765 This->glCKey = This->SrcBltCKey;
1767 else This->Flags &= ~SFLAG_GLCKEY;
1769 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1771 /* The width is in 'length' not in bytes */
1772 width = This->currentDesc.Width;
1773 pitch = IWineD3DSurface_GetPitch(iface);
1775 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1776 int height = This->currentDesc.Height;
1778 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1779 outpitch = width * bpp;
1780 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1782 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1784 ERR("Out of memory %d, %d!\n", outpitch, height);
1785 return WINED3DERR_OUTOFVIDEOMEMORY;
1787 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1789 This->Flags |= SFLAG_CONVERTED;
1790 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1791 d3dfmt_p8_upload_palette(iface, convert);
1792 This->Flags &= ~SFLAG_CONVERTED;
1793 mem = This->resource.allocatedMemory;
1795 This->Flags &= ~SFLAG_CONVERTED;
1796 mem = This->resource.allocatedMemory;
1799 /* Make sure the correct pitch is used */
1800 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1802 if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1803 TRACE("non power of two support\n");
1804 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1806 surface_upload_data(This, This->currentDesc.Width, This->currentDesc.Height, format, type, mem);
1809 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1811 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1815 /* Restore the default pitch */
1816 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1818 if (mem != This->resource.allocatedMemory)
1819 HeapFree(GetProcessHeap(), 0, mem);
1823 static unsigned int gen = 0;
1826 if ((gen % 10) == 0) {
1827 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1828 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1831 * debugging crash code
1840 if (!(This->Flags & SFLAG_DONOTFREE)) {
1841 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1842 This->resource.allocatedMemory = NULL;
1843 This->Flags &= ~SFLAG_INSYSMEM;
1851 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1854 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1855 char *allocatedMemory;
1857 IWineD3DSwapChain *swapChain = NULL;
1859 GLuint tmpTexture = 0;
1862 Textures my not be stored in ->allocatedgMemory and a GlTexture
1863 so we should lock the surface before saving a snapshot, or at least check that
1865 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1866 by calling GetTexImage and in compressed form by calling
1867 GetCompressedTexImageARB. Queried compressed images can be saved and
1868 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1869 texture images do not need to be processed by the GL and should
1870 significantly improve texture loading performance relative to uncompressed
1873 /* Setup the width and height to be the internal texture width and height. */
1874 width = This->pow2Width;
1875 height = This->pow2Height;
1876 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1877 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1879 if (This->Flags & SFLAG_INDRAWABLE && !(This->Flags & SFLAG_INTEXTURE)) {
1880 /* if were not a real texture then read the back buffer into a real texture */
1881 /* we don't want to interfere with the back buffer so read the data into a temporary
1882 * texture and then save the data out of the temporary texture
1886 TRACE("(%p) Reading render target into texture\n", This);
1887 glEnable(GL_TEXTURE_2D);
1889 glGenTextures(1, &tmpTexture);
1890 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1892 glTexImage2D(GL_TEXTURE_2D,
1899 GL_UNSIGNED_INT_8_8_8_8_REV,
1902 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1903 vcheckGLcall("glGetIntegerv");
1904 glReadBuffer(swapChain ? GL_BACK : This->resource.wineD3DDevice->offscreenBuffer);
1905 vcheckGLcall("glReadBuffer");
1906 glCopyTexImage2D(GL_TEXTURE_2D,
1915 checkGLcall("glCopyTexImage2D");
1916 glReadBuffer(prevRead);
1919 } else { /* bind the real texture, and make sure it up to date */
1920 IWineD3DSurface_PreLoad(iface);
1922 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1924 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1925 glGetTexImage(GL_TEXTURE_2D,
1926 This->glDescription.level,
1928 GL_UNSIGNED_INT_8_8_8_8_REV,
1930 checkGLcall("glTexImage2D");
1932 glBindTexture(GL_TEXTURE_2D, 0);
1933 glDeleteTextures(1, &tmpTexture);
1937 f = fopen(filename, "w+");
1939 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1940 return WINED3DERR_INVALIDCALL;
1942 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1943 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1958 fwrite(&width,2,1,f);
1960 fwrite(&height,2,1,f);
1965 /* 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*/
1967 textureRow = allocatedMemory + (width * (height - 1) *4);
1969 textureRow = allocatedMemory;
1970 for (y = 0 ; y < height; y++) {
1971 for (i = 0; i < width; i++) {
1972 color = *((DWORD*)textureRow);
1973 fputc((color >> 16) & 0xFF, f); /* B */
1974 fputc((color >> 8) & 0xFF, f); /* G */
1975 fputc((color >> 0) & 0xFF, f); /* R */
1976 fputc((color >> 24) & 0xFF, f); /* A */
1979 /* take two rows of the pointer to the texture memory */
1981 (textureRow-= width << 3);
1984 TRACE("Closing file\n");
1988 IWineD3DSwapChain_Release(swapChain);
1990 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1995 * Slightly inefficient way to handle multiple dirty rects but it works :)
1997 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1998 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1999 IWineD3DBaseTexture *baseTexture = NULL;
2000 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
2001 if (NULL != pDirtyRect) {
2002 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2003 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2004 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2005 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2007 This->dirtyRect.left = 0;
2008 This->dirtyRect.top = 0;
2009 This->dirtyRect.right = This->currentDesc.Width;
2010 This->dirtyRect.bottom = This->currentDesc.Height;
2012 TRACE("(%p) : Dirty: yes, Rect:(%d,%d,%d,%d)\n", This, This->dirtyRect.left,
2013 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2014 /* if the container is a basetexture then mark it dirty. */
2015 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2016 TRACE("Passing to conatiner\n");
2017 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2018 IWineD3DBaseTexture_Release(baseTexture);
2023 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2024 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2026 TRACE("This %p, container %p\n", This, container);
2028 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2030 TRACE("Setting container to %p from %p\n", container, This->container);
2031 This->container = container;
2036 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2037 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2038 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2040 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2041 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2042 return WINED3DERR_INVALIDCALL;
2045 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2046 if (format == WINED3DFMT_UNKNOWN) {
2047 This->resource.size = 0;
2048 } else if (format == WINED3DFMT_DXT1) {
2049 /* DXT1 is half byte per pixel */
2050 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2052 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2053 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2054 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2056 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
2057 This->resource.size *= This->pow2Height;
2061 /* Setup some glformat defaults */
2062 This->glDescription.glFormat = formatEntry->glFormat;
2063 This->glDescription.glFormatInternal = formatEntry->glInternal;
2064 This->glDescription.glType = formatEntry->glType;
2066 if (format != WINED3DFMT_UNKNOWN) {
2067 This->bytesPerPixel = formatEntry->bpp;
2069 This->bytesPerPixel = 0;
2072 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2074 This->resource.format = format;
2076 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);
2081 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2082 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2084 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2085 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2086 ERR("Not supported on render targets\n");
2087 return WINED3DERR_INVALIDCALL;
2090 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2091 WARN("Surface is locked or the HDC is in use\n");
2092 return WINED3DERR_INVALIDCALL;
2095 if(Mem && Mem != This->resource.allocatedMemory) {
2097 /* Do I have to copy the old surface content? */
2098 if(This->Flags & SFLAG_DIBSECTION) {
2099 /* Release the DC. No need to hold the critical section for the update
2100 * Thread because this thread runs only on front buffers, but this method
2101 * fails for render targets in the check above.
2103 SelectObject(This->hDC, This->dib.holdbitmap);
2104 DeleteDC(This->hDC);
2105 /* Release the DIB section */
2106 DeleteObject(This->dib.DIBsection);
2107 This->dib.bitmap_data = NULL;
2108 This->resource.allocatedMemory = NULL;
2110 This->Flags &= ~SFLAG_DIBSECTION;
2111 } else if(!(This->Flags & SFLAG_USERPTR)) {
2112 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2114 This->resource.allocatedMemory = Mem;
2115 This->Flags |= SFLAG_USERPTR;
2116 } else if(This->Flags & SFLAG_USERPTR) {
2117 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2118 This->resource.allocatedMemory = NULL;
2119 This->Flags &= ~SFLAG_USERPTR;
2124 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2125 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2126 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2127 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2129 /* Flipping is only supported on RenderTargets */
2130 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2133 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2134 * FIXME("(%p) Target override is not supported by now\n", This);
2135 * Additionally, it isn't really possible to support triple-buffering
2136 * properly on opengl at all
2140 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2141 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2144 /* Does a direct frame buffer -> texture copy. Stretching is done
2145 * with single pixel copy calls
2147 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2148 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2151 BOOL warned = FALSE; /* deliberately not static */
2152 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2156 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2158 /* Bind the target texture */
2159 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2160 checkGLcall("glBindTexture");
2162 glReadBuffer(myDevice->offscreenBuffer);
2163 } else if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2164 glReadBuffer(GL_BACK);
2166 glReadBuffer(GL_FRONT);
2168 checkGLcall("glReadBuffer");
2170 xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1);
2171 yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1);
2173 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2174 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2178 !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) &&
2179 !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2180 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2182 glCopyTexSubImage2D(This->glDescription.target,
2183 This->glDescription.level,
2184 drect->x1, drect->y1, /* xoffset, yoffset */
2185 srect->x1, Src->currentDesc.Height - srect->y2,
2186 drect->x2 - drect->x1, drect->y2 - drect->y1);
2188 UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1;
2189 /* I have to process this row by row to swap the image,
2190 * otherwise it would be upside down, so streching in y direction
2191 * doesn't cost extra time
2193 * However, streching in x direction can be avoided if not necessary
2195 for(row = drect->y1; row < drect->y2; row++) {
2196 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2197 /* Well, that stuff works, but it's very slow.
2198 * find a better way instead
2204 FIXME("Doing a pixel by pixel render target -> texture copy, expect performance issues\n");
2207 for(col = drect->x1; col < drect->x2; col++) {
2208 glCopyTexSubImage2D(This->glDescription.target,
2209 This->glDescription.level,
2210 drect->x1 + col, row, /* xoffset, yoffset */
2211 srect->x1 + col * xrel, yoffset - (int) (row * yrel),
2215 glCopyTexSubImage2D(This->glDescription.target,
2216 This->glDescription.level,
2217 drect->x1, row, /* xoffset, yoffset */
2218 srect->x1, yoffset - (int) (row * yrel),
2219 drect->x2-drect->x1, 1);
2224 vcheckGLcall("glCopyTexSubImage2D");
2228 /* Uses the hardware to stretch and flip the image */
2229 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2230 GLuint src, backup = 0;
2231 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2232 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2233 float left, right, top, bottom; /* Texture coordinates */
2234 UINT fbwidth = Src->currentDesc.Width;
2235 UINT fbheight = Src->currentDesc.Height;
2236 GLenum drawBuffer = GL_BACK;
2238 TRACE("Using hwstretch blit\n");
2239 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2241 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2243 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2244 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2246 if(GL_LIMITS(aux_buffers) >= 2) {
2247 /* Got more than one aux buffer? Use the 2nd aux buffer */
2248 drawBuffer = GL_AUX1;
2249 } else if((swapchain || myDevice->offscreenBuffer == GL_BACK) && GL_LIMITS(aux_buffers) >= 1) {
2250 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2251 drawBuffer = GL_AUX0;
2254 if(!swapchain && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2255 glGenTextures(1, &backup);
2256 checkGLcall("glGenTextures\n");
2257 glBindTexture(GL_TEXTURE_2D, backup);
2258 checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2260 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2261 * we are reading from the back buffer, the backup can be used as source texture
2263 if(Src->glDescription.textureName == 0) {
2264 /* Get it a description */
2265 IWineD3DSurface_PreLoad(SrcSurface);
2267 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2268 checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2270 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2271 Src->Flags &= ~SFLAG_INTEXTURE;
2274 glReadBuffer(GL_BACK);
2275 checkGLcall("glReadBuffer(GL_BACK)");
2277 /* TODO: Only back up the part that will be overwritten */
2278 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2279 0, 0 /* read offsets */,
2284 checkGLcall("glCopyTexSubImage2D");
2286 /* No issue with overriding these - the sampler is dirty due to blit usage */
2287 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2288 checkGLcall("glTexParameteri");
2289 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2290 checkGLcall("glTexParameteri");
2292 if(!swapchain || (IWineD3DSurface *) Src == swapchain->backBuffer[0]) {
2293 src = backup ? backup : Src->glDescription.textureName;
2295 glReadBuffer(GL_FRONT);
2296 checkGLcall("glReadBuffer(GL_FRONT)");
2298 glGenTextures(1, &src);
2299 checkGLcall("glGenTextures(1, &src)");
2300 glBindTexture(GL_TEXTURE_2D, src);
2301 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
2303 /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
2304 * out for power of 2 sizes
2306 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2307 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2308 checkGLcall("glTexImage2D");
2309 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2310 0, 0 /* read offsets */,
2315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2316 checkGLcall("glTexParameteri");
2317 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2318 checkGLcall("glTexParameteri");
2320 glReadBuffer(GL_BACK);
2321 checkGLcall("glReadBuffer(GL_BACK)");
2323 checkGLcall("glEnd and previous");
2325 left = (float) srect->x1 / (float) Src->pow2Width;
2326 right = (float) srect->x2 / (float) Src->pow2Width;
2329 top = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2330 bottom = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2332 top = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2333 bottom = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2336 /* draw the source texture stretched and upside down. The correct surface is bound already */
2337 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2338 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2340 glDrawBuffer(drawBuffer);
2341 glReadBuffer(drawBuffer);
2345 glTexCoord2f(left, bottom);
2346 glVertex2i(0, fbheight);
2349 glTexCoord2f(left, top);
2350 glVertex2i(0, fbheight - drect->y2 - drect->y1);
2353 glTexCoord2f(right, top);
2354 glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1);
2357 glTexCoord2f(right, bottom);
2358 glVertex2i(drect->x2 - drect->x1, fbheight);
2360 checkGLcall("glEnd and previous");
2362 /* Now read the stretched and upside down image into the destination texture */
2363 glBindTexture(This->glDescription.target, This->glDescription.textureName);
2364 checkGLcall("glBindTexture");
2365 glCopyTexSubImage2D(This->glDescription.target,
2367 drect->x1, drect->y1, /* xoffset, yoffset */
2368 0, 0, /* We blitted the image to the origin */
2369 drect->x2 - drect->x1, drect->y2 - drect->y1);
2370 checkGLcall("glCopyTexSubImage2D");
2372 /* Write the back buffer backup back */
2373 glBindTexture(GL_TEXTURE_2D, backup ? backup : Src->glDescription.textureName);
2374 checkGLcall("glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName)");
2376 if(drawBuffer == GL_BACK) {
2379 glTexCoord2f(0.0, (float) fbheight / (float) Src->pow2Height);
2383 glTexCoord2f(0.0, 0.0);
2384 glVertex2i(0, fbheight);
2387 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, 0.0);
2388 glVertex2i(fbwidth, Src->currentDesc.Height);
2391 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
2392 glVertex2i(fbwidth, 0);
2395 /* Restore the old draw buffer */
2396 glDrawBuffer(GL_BACK);
2400 if(src != Src->glDescription.textureName && src != backup) {
2401 glDeleteTextures(1, &src);
2402 checkGLcall("glDeleteTextures(1, &src)");
2405 glDeleteTextures(1, &backup);
2406 checkGLcall("glDeleteTextures(1, &backup)");
2411 /* Not called from the VTable */
2412 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2414 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2415 IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
2416 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2419 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2421 /* Get the swapchain. One of the surfaces has to be a primary surface */
2422 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
2423 if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
2425 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
2426 if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
2429 /* Early sort out of cases where no render target is used */
2430 if(!dstSwapchain && !srcSwapchain &&
2431 SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2432 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
2433 return WINED3DERR_INVALIDCALL;
2436 /* No destination color keying supported */
2437 if(Flags & (DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE)) {
2438 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2439 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2440 return WINED3DERR_INVALIDCALL;
2444 rect.x1 = DestRect->left;
2445 rect.y1 = DestRect->top;
2446 rect.x2 = DestRect->right;
2447 rect.y2 = DestRect->bottom;
2451 rect.x2 = This->currentDesc.Width;
2452 rect.y2 = This->currentDesc.Height;
2455 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
2456 if(dstSwapchain && dstSwapchain == srcSwapchain) {
2457 /* Half-life does a Blt from the back buffer to the front buffer,
2458 * Full surface size, no flags... Use present instead
2461 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2463 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2464 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2471 /* Check the Destination rect and the surface sizes */
2473 (rect.x1 == 0) && (rect.y1 == 0) &&
2474 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2475 (This->currentDesc.Width == Src->currentDesc.Width) &&
2476 (This->currentDesc.Height == Src->currentDesc.Height)) {
2477 /* These flags are unimportant for the flag check, remove them */
2479 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2480 if( dstSwapchain->backBuffer && ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) &&
2481 SrcSurface == dstSwapchain->backBuffer[0] ) {
2483 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
2485 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2486 * take very long, while a flip is fast.
2487 * This applies to Half-Life, which does such Blts every time it finished
2488 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2489 * menu. This is also used by all apps when they do windowed rendering
2491 * The problem is that flipping is not really the same as copying. After a
2492 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2493 * untouched. Therefore it's necessary to override the swap effect
2494 * and to set it back after the flip.
2497 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2499 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2500 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2501 NULL, NULL, 0, NULL);
2503 dstSwapchain->presentParms.SwapEffect = orig_swap;
2510 TRACE("Unsupported blit between buffers on the same swapchain\n");
2511 return WINED3DERR_INVALIDCALL;
2512 } else if((dstSwapchain || This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) &&
2513 (srcSwapchain || SrcSurface == myDevice->render_targets[0]) ) {
2514 ERR("Can't perform hardware blit between 2 different swapchains, falling back to software\n");
2515 return WINED3DERR_INVALIDCALL;
2518 if(srcSwapchain || SrcSurface == myDevice->render_targets[0]) {
2519 /* Blit from render target to texture */
2521 BOOL upsideDown, stretchx;
2523 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2524 TRACE("Color keying not supported by frame buffer to texture blit\n");
2525 return WINED3DERR_INVALIDCALL;
2526 /* Destination color key is checked above */
2529 /* Call preload for the surface to make sure it isn't dirty */
2530 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2532 /* Make sure that the top pixel is always above the bottom pixel, and keep a seperate upside down flag
2533 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2536 if(SrcRect->top < SrcRect->bottom) {
2537 srect.y1 = SrcRect->top;
2538 srect.y2 = SrcRect->bottom;
2541 srect.y1 = SrcRect->bottom;
2542 srect.y2 = SrcRect->top;
2545 srect.x1 = SrcRect->left;
2546 srect.x2 = SrcRect->right;
2550 srect.x2 = Src->currentDesc.Width;
2551 srect.y2 = Src->currentDesc.Height;
2554 if(rect.x1 > rect.x2) {
2558 upsideDown = !upsideDown;
2561 TRACE("Reading from an offscreen target\n");
2562 upsideDown = !upsideDown;
2565 if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
2571 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2572 * flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully,
2573 * not implemented by now). Otherwise:
2575 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2576 * -> If the app wants a image width an unscaled width, copy it line per line
2577 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
2578 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2579 * back buffer. This is slower than reading line per line, thus not used for flipping
2580 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2583 if(FALSE /* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */) {
2584 TRACE("Using GL_EXT_framebuffer_blit for copying\n");
2585 } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
2586 rect.y2 - rect.y1 > Src->currentDesc.Height) {
2587 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
2588 fb_copy_to_texture_direct(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
2590 TRACE("Using hardware stretching to flip / stretch the texture\n");
2591 fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
2594 if(!(This->Flags & SFLAG_DONOTFREE)) {
2595 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2596 This->resource.allocatedMemory = NULL;
2598 This->Flags &= ~SFLAG_INSYSMEM;
2600 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
2601 * path is never entered
2603 This->Flags |= SFLAG_INTEXTURE;
2607 /* Blit from offscreen surface to render target */
2608 float glTexCoord[4];
2609 DWORD oldCKeyFlags = Src->CKeyFlags;
2610 DDCOLORKEY oldBltCKey = This->SrcBltCKey;
2611 RECT SourceRectangle;
2614 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2617 SourceRectangle.left = SrcRect->left;
2618 SourceRectangle.right = SrcRect->right;
2619 SourceRectangle.top = SrcRect->top;
2620 SourceRectangle.bottom = SrcRect->bottom;
2622 SourceRectangle.left = 0;
2623 SourceRectangle.right = Src->currentDesc.Width;
2624 SourceRectangle.top = 0;
2625 SourceRectangle.bottom = Src->currentDesc.Height;
2628 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2629 /* Fall back to software */
2630 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2631 SourceRectangle.left, SourceRectangle.top,
2632 SourceRectangle.right, SourceRectangle.bottom);
2633 return WINED3DERR_INVALIDCALL;
2636 /* Color keying: Check if we have to do a color keyed blt,
2637 * and if not check if a color key is activated.
2639 * Just modify the color keying parameters in the surface and restore them afterwards
2640 * The surface keeps track of the color key last used to load the opengl surface.
2641 * PreLoad will catch the change to the flags and color key and reload if neccessary.
2643 if(Flags & DDBLT_KEYSRC) {
2644 /* Use color key from surface */
2645 } else if(Flags & DDBLT_KEYSRCOVERRIDE) {
2646 /* Use color key from DDBltFx */
2647 Src->CKeyFlags |= DDSD_CKSRCBLT;
2648 This->SrcBltCKey = DDBltFx->ddckSrcColorkey;
2650 /* Do not use color key */
2651 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2654 /* Now load the surface */
2655 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2659 /* Activate the destination context, set it up for blitting */
2660 ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
2662 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2663 if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer) {
2664 TRACE("Drawing to front buffer\n");
2665 glDrawBuffer(GL_FRONT);
2666 checkGLcall("glDrawBuffer GL_FRONT");
2669 /* Bind the texture */
2670 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2671 checkGLcall("glBindTexture");
2673 /* No filtering for blts */
2674 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2676 checkGLcall("glTexParameteri");
2677 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2679 checkGLcall("glTexParameteri");
2680 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2681 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2682 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2683 checkGLcall("glTexEnvi");
2685 /* This is for color keying */
2686 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2687 glEnable(GL_ALPHA_TEST);
2688 checkGLcall("glEnable GL_ALPHA_TEST");
2689 glAlphaFunc(GL_NOTEQUAL, 0.0);
2690 checkGLcall("glAlphaFunc\n");
2692 glDisable(GL_ALPHA_TEST);
2693 checkGLcall("glDisable GL_ALPHA_TEST");
2696 /* Draw a textured quad
2700 glColor3d(1.0f, 1.0f, 1.0f);
2701 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2706 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2707 glVertex3f(rect.x1, rect.y2, 0.0);
2709 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2714 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2719 checkGLcall("glEnd");
2721 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2722 glDisable(GL_ALPHA_TEST);
2723 checkGLcall("glDisable(GL_ALPHA_TEST)");
2726 /* Unbind the texture */
2727 glBindTexture(GL_TEXTURE_2D, 0);
2728 checkGLcall("glEnable glBindTexture");
2730 if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer && oldDraw == GL_BACK) {
2731 glDrawBuffer(oldDraw);
2733 /* Restore the color key parameters */
2734 Src->CKeyFlags = oldCKeyFlags;
2735 This->SrcBltCKey = oldBltCKey;
2739 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2740 This->Flags &= ~SFLAG_INSYSMEM;
2741 /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
2744 if(dstSwapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO) {
2745 This->Flags |= SFLAG_INDRAWABLE;
2746 This->Flags &= ~SFLAG_INTEXTURE;
2748 This->Flags |= SFLAG_INTEXTURE;
2753 /* Source-Less Blit to render target */
2754 if (Flags & DDBLT_COLORFILL) {
2755 /* This is easy to handle for the D3D Device... */
2758 TRACE("Colorfill\n");
2760 /* The color as given in the Blt function is in the format of the frame-buffer...
2761 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2763 if (This->resource.format == WINED3DFMT_P8) {
2764 if (This->palette) {
2765 color = ((0xFF000000) |
2766 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2767 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2768 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2773 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2774 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2777 color = ((0xFF000000) |
2778 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2779 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2780 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2783 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2784 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2785 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2787 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2788 color = DDBltFx->u5.dwFillColor;
2791 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2792 return WINED3DERR_INVALIDCALL;
2795 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2796 if(dstSwapchain && dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]) {
2797 glDrawBuffer(GL_BACK);
2798 checkGLcall("glDrawBuffer(GL_BACK)");
2799 } else if (dstSwapchain && This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer) {
2800 glDrawBuffer(GL_FRONT);
2801 checkGLcall("glDrawBuffer(GL_FRONT)");
2802 } else if(This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2803 glDrawBuffer(myDevice->offscreenBuffer);
2804 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer3)");
2806 TRACE("Surface is higher back buffer, falling back to software\n");
2807 return WINED3DERR_INVALIDCALL;
2810 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2812 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2813 1 /* Number of rectangles */,
2815 WINED3DCLEAR_TARGET,
2820 /* Restore the original draw buffer */
2822 glDrawBuffer(myDevice->offscreenBuffer);
2823 } else if(dstSwapchain->backBuffer && dstSwapchain->backBuffer[0]) {
2824 glDrawBuffer(GL_BACK);
2826 vcheckGLcall("glDrawBuffer");
2832 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2833 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2834 return WINED3DERR_INVALIDCALL;
2837 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2838 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2839 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2840 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2841 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2842 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2844 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair */
2845 if(myDevice->inScene &&
2846 (iface == myDevice->stencilBufferTarget ||
2847 (SrcSurface && SrcSurface == myDevice->stencilBufferTarget))) {
2848 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2849 return WINED3DERR_INVALIDCALL;
2852 /* Special cases for RenderTargets */
2853 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2854 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2855 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2858 /* For the rest call the X11 surface implementation.
2859 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2860 * other Blts are rather rare
2862 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2865 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2866 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2867 TRACE("(%p)->(%x)\n", This, Flags);
2872 case DDGBS_ISBLTDONE:
2876 return DDERR_INVALIDPARAMS;
2880 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2881 /* XXX: DDERR_INVALIDSURFACETYPE */
2883 TRACE("(%p)->(%08x)\n",iface,Flags);
2886 case DDGFS_ISFLIPDONE:
2890 return DDERR_INVALIDPARAMS;
2894 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2895 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2896 TRACE("(%p)\n", This);
2898 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2901 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2902 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2903 TRACE("(%p)\n", This);
2905 /* So far we don't lose anything :) */
2906 This->Flags &= ~SFLAG_LOST;
2910 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2911 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2912 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2913 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2914 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2916 if(myDevice->inScene &&
2917 (iface == myDevice->stencilBufferTarget ||
2918 (Source && Source == myDevice->stencilBufferTarget))) {
2919 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2920 return WINED3DERR_INVALIDCALL;
2923 /* Special cases for RenderTargets */
2924 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2925 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2927 RECT SrcRect, DstRect;
2931 SrcRect.left = rsrc->left;
2932 SrcRect.top= rsrc->top;
2933 SrcRect.bottom = rsrc->bottom;
2934 SrcRect.right = rsrc->right;
2938 SrcRect.right = srcImpl->currentDesc.Width;
2939 SrcRect.bottom = srcImpl->currentDesc.Height;
2942 DstRect.left = dstx;
2944 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2945 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2947 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2948 if(trans & DDBLTFAST_SRCCOLORKEY)
2949 Flags |= DDBLT_KEYSRC;
2950 if(trans & DDBLTFAST_DESTCOLORKEY)
2951 Flags |= DDBLT_KEYDEST;
2952 if(trans & DDBLTFAST_WAIT)
2953 Flags |= DDBLT_WAIT;
2954 if(trans & DDBLTFAST_DONOTWAIT)
2955 Flags |= DDBLT_DONOTWAIT;
2957 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2961 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2964 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2965 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2966 TRACE("(%p)->(%p)\n", This, Pal);
2968 *Pal = (IWineD3DPalette *) This->palette;
2972 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2973 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2975 IWineD3DPaletteImpl *pal = This->palette;
2977 TRACE("(%p)\n", This);
2979 if(This->resource.format == WINED3DFMT_P8 ||
2980 This->resource.format == WINED3DFMT_A8P8)
2982 if(!This->Flags & SFLAG_INSYSMEM) {
2983 FIXME("Palette changed with surface that does not have an up to date system memory copy\n");
2985 TRACE("Dirtifying surface\n");
2986 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
2989 if(This->Flags & SFLAG_DIBSECTION) {
2990 TRACE("(%p): Updating the hdc's palette\n", This);
2991 for (n=0; n<256; n++) {
2993 col[n].rgbRed = pal->palents[n].peRed;
2994 col[n].rgbGreen = pal->palents[n].peGreen;
2995 col[n].rgbBlue = pal->palents[n].peBlue;
2997 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2998 /* Use the default device palette */
2999 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
3000 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
3001 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
3003 col[n].rgbReserved = 0;
3005 SetDIBColorTable(This->hDC, 0, 256, col);
3011 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
3012 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3013 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
3014 TRACE("(%p)->(%p)\n", This, Pal);
3016 if(This->palette != NULL)
3017 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3018 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
3020 if(PalImpl != NULL) {
3021 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3022 /* Set the device's main palette if the palette
3023 * wasn't a primary palette before
3025 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
3026 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
3029 for(i=0; i < 256; i++) {
3030 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
3034 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
3037 This->palette = PalImpl;
3039 return IWineD3DSurface_RealizePalette(iface);
3042 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
3043 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3044 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
3046 if ((Flags & DDCKEY_COLORSPACE) != 0) {
3047 FIXME(" colorkey value not supported (%08x) !\n", Flags);
3048 return DDERR_INVALIDPARAMS;
3051 /* Dirtify the surface, but only if a key was changed */
3053 switch (Flags & ~DDCKEY_COLORSPACE) {
3054 case DDCKEY_DESTBLT:
3055 This->DestBltCKey = *CKey;
3056 This->CKeyFlags |= DDSD_CKDESTBLT;
3059 case DDCKEY_DESTOVERLAY:
3060 This->DestOverlayCKey = *CKey;
3061 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
3064 case DDCKEY_SRCOVERLAY:
3065 This->SrcOverlayCKey = *CKey;
3066 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
3070 This->SrcBltCKey = *CKey;
3071 This->CKeyFlags |= DDSD_CKSRCBLT;
3076 switch (Flags & ~DDCKEY_COLORSPACE) {
3077 case DDCKEY_DESTBLT:
3078 This->CKeyFlags &= ~DDSD_CKDESTBLT;
3081 case DDCKEY_DESTOVERLAY:
3082 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
3085 case DDCKEY_SRCOVERLAY:
3086 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
3090 This->CKeyFlags &= ~DDSD_CKSRCBLT;
3098 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3099 /** Check against the maximum texture sizes supported by the video card **/
3100 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3102 TRACE("%p\n", This);
3103 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3104 /* one of three options
3105 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)
3106 2: Set the texture to the maxium size (bad idea)
3107 3: WARN and return WINED3DERR_NOTAVAILABLE;
3108 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.
3110 WARN("(%p) Creating an oversized surface\n", This);
3111 This->Flags |= SFLAG_OVERSIZE;
3113 /* This will be initialized on the first blt */
3114 This->glRect.left = 0;
3115 This->glRect.top = 0;
3116 This->glRect.right = 0;
3117 This->glRect.bottom = 0;
3119 /* No oversize, gl rect is the full texture size */
3120 This->Flags &= ~SFLAG_OVERSIZE;
3121 This->glRect.left = 0;
3122 This->glRect.top = 0;
3123 This->glRect.right = This->pow2Width;
3124 This->glRect.bottom = This->pow2Height;
3130 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3131 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3133 TRACE("(%p)\n", This);
3135 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3136 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3137 ie pitch = (width/4) * bytes per block */
3138 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3139 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3140 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3141 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3142 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3144 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3145 /* Surfaces are 32 bit aligned */
3146 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3148 TRACE("(%p) Returning %d\n", This, ret);
3152 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3153 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3155 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3157 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3159 TRACE("(%p): Not an overlay surface\n", This);
3160 return DDERR_NOTAOVERLAYSURFACE;
3166 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3167 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3169 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3171 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3173 TRACE("(%p): Not an overlay surface\n", This);
3174 return DDERR_NOTAOVERLAYSURFACE;
3180 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3181 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3182 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3184 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3186 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3188 TRACE("(%p): Not an overlay surface\n", This);
3189 return DDERR_NOTAOVERLAYSURFACE;
3195 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3196 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3197 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3198 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3200 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3202 TRACE("(%p): Not an overlay surface\n", This);
3203 return DDERR_NOTAOVERLAYSURFACE;
3209 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3212 IWineD3DSurfaceImpl_QueryInterface,
3213 IWineD3DSurfaceImpl_AddRef,
3214 IWineD3DSurfaceImpl_Release,
3215 /* IWineD3DResource */
3216 IWineD3DSurfaceImpl_GetParent,
3217 IWineD3DSurfaceImpl_GetDevice,
3218 IWineD3DSurfaceImpl_SetPrivateData,
3219 IWineD3DSurfaceImpl_GetPrivateData,
3220 IWineD3DSurfaceImpl_FreePrivateData,
3221 IWineD3DSurfaceImpl_SetPriority,
3222 IWineD3DSurfaceImpl_GetPriority,
3223 IWineD3DSurfaceImpl_PreLoad,
3224 IWineD3DSurfaceImpl_GetType,
3225 /* IWineD3DSurface */
3226 IWineD3DSurfaceImpl_GetContainer,
3227 IWineD3DSurfaceImpl_GetDesc,
3228 IWineD3DSurfaceImpl_LockRect,
3229 IWineD3DSurfaceImpl_UnlockRect,
3230 IWineD3DSurfaceImpl_GetDC,
3231 IWineD3DSurfaceImpl_ReleaseDC,
3232 IWineD3DSurfaceImpl_Flip,
3233 IWineD3DSurfaceImpl_Blt,
3234 IWineD3DSurfaceImpl_GetBltStatus,
3235 IWineD3DSurfaceImpl_GetFlipStatus,
3236 IWineD3DSurfaceImpl_IsLost,
3237 IWineD3DSurfaceImpl_Restore,
3238 IWineD3DSurfaceImpl_BltFast,
3239 IWineD3DSurfaceImpl_GetPalette,
3240 IWineD3DSurfaceImpl_SetPalette,
3241 IWineD3DSurfaceImpl_RealizePalette,
3242 IWineD3DSurfaceImpl_SetColorKey,
3243 IWineD3DSurfaceImpl_GetPitch,
3244 IWineD3DSurfaceImpl_SetMem,
3245 IWineD3DSurfaceImpl_SetOverlayPosition,
3246 IWineD3DSurfaceImpl_GetOverlayPosition,
3247 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3248 IWineD3DSurfaceImpl_UpdateOverlay,
3250 IWineD3DSurfaceImpl_AddDirtyRect,
3251 IWineD3DSurfaceImpl_LoadTexture,
3252 IWineD3DSurfaceImpl_SaveSnapshot,
3253 IWineD3DSurfaceImpl_SetContainer,
3254 IWineD3DSurfaceImpl_SetGlTextureDesc,
3255 IWineD3DSurfaceImpl_GetGlDesc,
3256 IWineD3DSurfaceImpl_GetData,
3257 IWineD3DSurfaceImpl_SetFormat,
3258 IWineD3DSurfaceImpl_PrivateSetup