2 * IWineD3DSurface Implementation
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006 Stefan Dösinger for CodeWeavers
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
29 #include "wined3d_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
32 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
51 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf);
53 static void surface_download_data(IWineD3DSurfaceImpl *This) {
54 if (This->resource.format == WINED3DFMT_DXT1 ||
55 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
56 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
57 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* We can assume this as the texture would not have been created otherwise */
58 FIXME("(%p) : Attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
60 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
61 This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
65 GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory));
66 checkGLcall("glGetCompressedTexImageARB()");
75 if(This->Flags & SFLAG_CONVERTED) {
76 FIXME("Read back converted textures unsupported\n");
80 if (This->Flags & SFLAG_NONPOW2) {
81 src_pitch = This->bytesPerPixel * This->pow2Width;
82 dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
83 src_pitch = (src_pitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
84 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
86 mem = This->resource.allocatedMemory;
89 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
90 This->glDescription.glFormat, This->glDescription.glType, mem);
94 glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
95 This->glDescription.glType, mem);
96 checkGLcall("glGetTexImage()");
100 if (This->Flags & SFLAG_NONPOW2) {
101 LPBYTE src_data, dst_data;
104 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
105 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
106 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
108 * We're doing this...
110 * instead of boxing the texture :
111 * |<-texture width ->| -->pow2width| /\
112 * |111111111111111111| | |
113 * |222 Texture 222222| boxed empty | texture height
114 * |3333 Data 33333333| | |
115 * |444444444444444444| | \/
116 * ----------------------------------- |
117 * | boxed empty | boxed empty | pow2height
119 * -----------------------------------
122 * we're repacking the data to the expected texture width
124 * |<-texture width ->| -->pow2width| /\
125 * |111111111111111111222222222222222| |
126 * |222333333333333333333444444444444| texture height
130 * | empty | pow2height
132 * -----------------------------------
136 * |<-texture width ->| /\
137 * |111111111111111111|
138 * |222222222222222222|texture height
139 * |333333333333333333|
140 * |444444444444444444| \/
141 * --------------------
143 * this also means that any references to allocatedMemory should work with the data as if were a
144 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
146 * internally the texture is still stored in a boxed format so any references to textureName will
147 * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
149 * Performance should not be an issue, because applications normally do not lock the surfaces when
150 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
151 * and doesn't have to be re-read.
154 dst_data = This->resource.allocatedMemory;
155 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
156 for (y = 1 ; y < This->currentDesc.Height; y++) {
157 /* skip the first row */
158 src_data += src_pitch;
159 dst_data += dst_pitch;
160 memcpy(dst_data, src_data, dst_pitch);
163 HeapFree(GetProcessHeap(), 0, mem);
168 static void surface_upload_data(IWineD3DSurfaceImpl *This, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data) {
169 if (This->resource.format == WINED3DFMT_DXT1 ||
170 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
171 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
172 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
173 FIXME("Using DXT1/3/5 without advertized support\n");
175 TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data);
177 /* glCompressedTexSubImage2D for uploading and glTexImage2D for allocating does not work well on some drivers(r200 dri, MacOS ATI driver)
178 * glCompressedTexImage2D does not accept NULL pointers. So for compressed textures surface_allocate_surface does nothing, and this
179 * function uses glCompressedTexImage2D instead of the SubImage call
181 GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, This->glDescription.glFormatInternal,
182 width, height, 0 /* border */, This->resource.size, data));
183 checkGLcall("glCompressedTexSubImage2D");
187 TRACE("(%p) : Calling glTexSubImage2D w %d, h %d, data, %p\n", This, width, height, data);
189 glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data);
190 checkGLcall("glTexSubImage2D");
195 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type) {
196 TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n", This,
197 This->glDescription.target, This->glDescription.level, debug_d3dformat(This->resource.format), internal, width, height, format, type);
199 if (This->resource.format == WINED3DFMT_DXT1 ||
200 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
201 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
202 /* glCompressedTexImage2D does not accept NULL pointers, so we cannot allocate a compressed texture without uploading data */
203 TRACE("Not allocating compressed surfaces, surface_upload_data will specify them\n");
209 glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, NULL);
210 checkGLcall("glTexImage2D");
215 /* *******************************************
216 IWineD3DSurface IUnknown parts follow
217 ******************************************* */
218 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
220 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
221 /* Warn ,but be nice about things */
222 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
224 if (IsEqualGUID(riid, &IID_IUnknown)
225 || IsEqualGUID(riid, &IID_IWineD3DBase)
226 || IsEqualGUID(riid, &IID_IWineD3DResource)
227 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
228 IUnknown_AddRef((IUnknown*)iface);
233 return E_NOINTERFACE;
236 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
237 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
238 ULONG ref = InterlockedIncrement(&This->resource.ref);
239 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
243 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
244 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
245 ULONG ref = InterlockedDecrement(&This->resource.ref);
246 TRACE("(%p) : Releasing from %d\n", This, ref + 1);
248 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
249 TRACE("(%p) : cleaning up\n", This);
251 if(iface == device->lastActiveRenderTarget) {
252 IWineD3DSwapChainImpl *swapchain = device->swapchains ? (IWineD3DSwapChainImpl *) device->swapchains[0] : NULL;
254 TRACE("Last active render target destroyed\n");
255 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
256 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
257 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
258 * and the lastActiveRenderTarget member shouldn't matter
261 if(swapchain->backBuffer && swapchain->backBuffer[0] != iface) {
262 TRACE("Activating primary back buffer\n");
263 ActivateContext(device, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
264 } else if(!swapchain->backBuffer && swapchain->frontBuffer != iface) {
265 /* Single buffering environment */
266 TRACE("Activating primary front buffer\n");
267 ActivateContext(device, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
269 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
270 /* Implicit render target destroyed, that means the device is being destroyed
271 * whatever we set here, it shouldn't matter
273 device->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
276 /* May happen during ddraw uninitialization */
277 TRACE("Render target set, but swapchain does not exist!\n");
278 device->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
282 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
284 TRACE("Deleting texture %d\n", This->glDescription.textureName);
285 glDeleteTextures(1, &This->glDescription.textureName);
289 if(This->Flags & SFLAG_DIBSECTION) {
291 SelectObject(This->hDC, This->dib.holdbitmap);
293 /* Release the DIB section */
294 DeleteObject(This->dib.DIBsection);
295 This->dib.bitmap_data = NULL;
296 This->resource.allocatedMemory = NULL;
298 if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
300 HeapFree(GetProcessHeap(), 0, This->palette9);
302 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
303 if(iface == device->ddraw_primary)
304 device->ddraw_primary = NULL;
306 TRACE("(%p) Released\n", This);
307 HeapFree(GetProcessHeap(), 0, This);
313 /* ****************************************************
314 IWineD3DSurface IWineD3DResource parts follow
315 **************************************************** */
316 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
317 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
320 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
321 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
324 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
325 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
328 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
329 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
332 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
333 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
336 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
337 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
340 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
341 /* TODO: re-write the way textures and managed,
342 * use a 'opengl context manager' to manage RenderTarget surfaces
343 ** *********************************************************/
345 /* TODO: check for locks */
346 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
347 IWineD3DBaseTexture *baseTexture = NULL;
348 TRACE("(%p)Checking to see if the container is a base texture\n", This);
349 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
350 TRACE("Passing to conatiner\n");
351 IWineD3DBaseTexture_PreLoad(baseTexture);
352 IWineD3DBaseTexture_Release(baseTexture);
354 TRACE("(%p) : About to load surface\n", This);
356 #if 0 /* TODO: context manager support */
357 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
359 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
360 if (!This->glDescription.level) {
361 if (!This->glDescription.textureName) {
362 glGenTextures(1, &This->glDescription.textureName);
363 checkGLcall("glGenTextures");
364 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
366 glBindTexture(This->glDescription.target, This->glDescription.textureName);
367 checkGLcall("glBindTexture");
368 IWineD3DSurface_LoadTexture(iface);
369 /* This is where we should be reducing the amount of GLMemoryUsed */
370 } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
371 /* assume this is a coding error not a real error for now */
372 FIXME("Mipmap surface has a glTexture bound to it!\n");
374 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
375 /* Tell opengl to try and keep this texture in video ram (well mostly) */
378 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
380 /* TODO: disable texture support, if it wastn't enabled when we entered. */
381 #if 0 /* TODO: context manager support */
382 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
383 /* we don't care when the state is disabled(if atall) */);
390 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
391 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
392 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
395 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
396 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
397 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
400 /* ******************************************************
401 IWineD3DSurface IWineD3DSurface parts follow
402 ****************************************************** */
404 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
405 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
406 IWineD3DBase *container = 0;
408 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
411 ERR("Called without a valid ppContainer.\n");
415 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
416 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
417 * GetContainer will return the Direct3D device used to create the surface.
419 if (This->container) {
420 container = This->container;
422 container = (IWineD3DBase *)This->resource.wineD3DDevice;
425 TRACE("Relaying to QueryInterface\n");
426 return IUnknown_QueryInterface(container, riid, ppContainer);
429 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
430 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
432 TRACE("(%p) : copying into %p\n", This, pDesc);
433 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
434 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
435 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
436 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
437 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
438 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
439 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
440 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
441 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
445 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
446 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
447 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
448 if (This->glDescription.textureName == 0 && textureName != 0) {
449 This->Flags |= SFLAG_DIRTY;
450 IWineD3DSurface_AddDirtyRect(iface, NULL);
452 This->glDescription.textureName = textureName;
453 This->glDescription.target = target;
456 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
457 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
458 TRACE("(%p) : returning %p\n", This, &This->glDescription);
459 *glDescription = &This->glDescription;
462 /* TODO: think about moving this down to resource? */
463 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
464 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
465 /* This should only be called for sysmem textures, it may be a good idea to extend this to all pools at some point in the futture */
466 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
467 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
469 return (CONST void*)(This->resource.allocatedMemory);
472 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch, BOOL srcUpsideDown) {
476 BYTE *row, *top, *bottom;
480 switch(This->resource.format)
484 /* GL can't return palettized data, so read ARGB pixels into a
485 * separate block of memory and convert them into palettized format
486 * in software. Slow, but if the app means to use palettized render
487 * targets and locks it...
489 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
490 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
491 * for the color channels when palettizing the colors.
494 type = GL_UNSIGNED_BYTE;
496 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
498 ERR("Out of memory\n");
501 bpp = This->bytesPerPixel * 3;
507 fmt = This->glDescription.glFormat;
508 type = This->glDescription.glType;
509 bpp = This->bytesPerPixel;
512 glReadPixels(rect->left, rect->top,
513 rect->right - rect->left,
514 rect->bottom - rect->top,
516 vcheckGLcall("glReadPixels");
518 /* TODO: Merge this with the palettization loop below for P8 targets */
522 /* glReadPixels returns the image upside down, and there is no way to prevent this.
523 Flip the lines in software */
524 len = (rect->right - rect->left) * bpp;
525 off = rect->left * bpp;
527 row = HeapAlloc(GetProcessHeap(), 0, len);
529 ERR("Out of memory\n");
530 if(This->resource.format == WINED3DFMT_P8) HeapFree(GetProcessHeap(), 0, mem);
534 top = mem + pitch * rect->top;
535 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
536 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
537 memcpy(row, top + off, len);
538 memcpy(top + off, bottom + off, len);
539 memcpy(bottom + off, row, len);
543 HeapFree(GetProcessHeap(), 0, row);
546 if(This->resource.format == WINED3DFMT_P8) {
548 DWORD width = pitch / 3;
551 pal = This->palette->palents;
553 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
556 for(y = rect->top; y < rect->bottom; y++) {
557 for(x = rect->left; x < rect->right; x++) {
558 /* start lines pixels */
559 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
560 BYTE *green = blue + 1;
561 BYTE *red = green + 1;
563 for(c = 0; c < 256; c++) {
564 if(*red == pal[c].peRed &&
565 *green == pal[c].peGreen &&
566 *blue == pal[c].peBlue)
568 *((BYTE *) dest + y * width + x) = c;
574 HeapFree(GetProcessHeap(), 0, mem);
578 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
579 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
580 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
581 IWineD3DSwapChainImpl *swapchain = NULL;
583 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
585 if (!(This->Flags & SFLAG_LOCKABLE)) {
586 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
587 texture regions, and since the destination is an unlockable region we need
589 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
590 /*return WINED3DERR_INVALIDCALL; */
593 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
595 /* Mark the surface locked */
596 This->Flags |= SFLAG_LOCKED;
598 /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy */
599 if(!This->resource.allocatedMemory) {
600 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + 4);
601 This->Flags |= SFLAG_GLDIRTY; /* This is the marker that surface data has to be downloaded */
604 /* Calculate the correct start address to report */
606 pLockedRect->pBits = This->resource.allocatedMemory;
607 This->lockedRect.left = 0;
608 This->lockedRect.top = 0;
609 This->lockedRect.right = This->currentDesc.Width;
610 This->lockedRect.bottom = This->currentDesc.Height;
611 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
613 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
615 if ((pRect->top < 0) ||
617 (pRect->left >= pRect->right) ||
618 (pRect->top >= pRect->bottom) ||
619 (pRect->right > This->currentDesc.Width) ||
620 (pRect->bottom > This->currentDesc.Height))
622 WARN(" Invalid values in pRect !!!\n");
623 return WINED3DERR_INVALIDCALL;
626 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
627 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
629 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
631 This->lockedRect.left = pRect->left;
632 This->lockedRect.top = pRect->top;
633 This->lockedRect.right = pRect->right;
634 This->lockedRect.bottom = pRect->bottom;
637 if (This->Flags & SFLAG_NONPOW2) {
638 TRACE("Locking non-power 2 texture\n");
641 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
642 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
645 if(!(This->Flags & SFLAG_DYNLOCK)) {
647 /* MAXLOCKCOUNT is defined in wined3d_private.h */
648 if(This->lockCount > MAXLOCKCOUNT) {
649 TRACE("Surface is locked regularily, not freeing the system memory copy any more\n");
650 This->Flags |= SFLAG_DYNLOCK;
654 if((Flags & WINED3DLOCK_DISCARD) || !(This->Flags & SFLAG_GLDIRTY) ) {
655 TRACE("WINED3DLOCK_DISCARD flag passed, or local copy is up to date, not downloading data\n");
659 /* Now download the surface content from opengl
660 * Use the render target readback if the surface is on a swapchain(=onscreen render target) or the current primary target
661 * Offscreen targets which are not active at the moment or are higher targets(fbos) can be locked with the texture path
663 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
664 if(swapchain || iface == myDevice->render_targets[0]) {
665 BOOL srcIsUpsideDown;
667 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
668 static BOOL warned = FALSE;
670 ERR("The application tries to lock the render target, but render target locking is disabled\n");
673 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
677 /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
678 * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
679 * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
680 * context->last_was_blit set on the unlock.
683 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
685 /* Select the correct read buffer, and give some debug output.
686 * There is no need to keep track of the current read buffer or reset it, every part of the code
687 * that reads sets the read buffer as desired.
690 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
691 * Read from the back buffer
693 TRACE("Locking offscreen render target\n");
694 glReadBuffer(myDevice->offscreenBuffer);
695 srcIsUpsideDown = TRUE;
697 if(iface == swapchain->frontBuffer) {
698 TRACE("Locking the front buffer\n");
699 glReadBuffer(GL_FRONT);
700 } else if(swapchain->backBuffer && iface == swapchain->backBuffer[0]) {
701 TRACE("Locking the back buffer\n");
702 glReadBuffer(GL_BACK);
704 /* Ok, there is an issue: OpenGL does not guarant any back buffer number, so all we can do is to read GL_BACK
705 * and hope it gives what the app wants
707 FIXME("Application is locking a 2nd or higher back buffer\n");
708 glReadBuffer(GL_BACK);
710 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
711 srcIsUpsideDown = FALSE;
714 switch(wined3d_settings.rendertargetlock_mode) {
718 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
723 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
724 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
729 /* Mark the local copy up to date if a full download was done */
730 if(This->lockedRect.left == 0 &&
731 This->lockedRect.top == 0 &&
732 This->lockedRect.right == This->currentDesc.Width &&
733 This->lockedRect.bottom == This->currentDesc.Height) {
734 This->Flags &= ~SFLAG_GLDIRTY;
736 } else if(iface == myDevice->stencilBufferTarget) {
737 /** the depth stencil in openGL has a format of GL_FLOAT
738 * which should be good for WINED3DFMT_D16_LOCKABLE
740 * it is unclear what format the stencil buffer is in except.
741 * 'Each index is converted to fixed point...
742 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
743 * mappings in the table GL_PIXEL_MAP_S_TO_S.
744 * glReadPixels(This->lockedRect.left,
745 * This->lockedRect.bottom - j - 1,
746 * This->lockedRect.right - This->lockedRect.left,
748 * GL_DEPTH_COMPONENT,
750 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
752 * Depth Stencil surfaces which are not the current depth stencil target should have their data in a
753 * gl texture(next path), or in local memory(early return because of missing SFLAG_GLDIRTY above). If
754 * none of that is the case the problem is not in this function :-)
755 ********************************************/
756 FIXME("Depth stencil locking not supported yet\n");
758 /* This path is for normal surfaces, offscreen render targets and everything else that is in a gl texture */
759 TRACE("locking an ordinarary surface\n");
761 /* TODO: Make sure that *any* context is active for this thread. It is not important which context that is,
762 * nor that is has any special setup(CTXUSAGE_LOADRESOURCE is fine), but the code below needs a context.
763 * A context is guaranteed to be there in a single threaded environment, but not with multithreading
765 if (0 != This->glDescription.textureName) {
766 /* Now I have to copy thing bits back */
768 /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
769 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
771 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
772 checkGLcall("glActiveTextureARB");
775 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
776 IWineD3DSurface_PreLoad(iface);
778 surface_download_data(This);
781 /* The local copy is now up to date to the opengl one because a full download was done */
782 This->Flags &= ~SFLAG_GLDIRTY;
786 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
789 IWineD3DBaseTexture *pBaseTexture;
792 * as seen in msdn docs
794 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
796 /** Dirtify Container if needed */
797 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
798 TRACE("Making container dirty\n");
799 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
800 IWineD3DBaseTexture_Release(pBaseTexture);
802 TRACE("Surface is standalone, no need to dirty the container\n");
806 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
810 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
812 GLint prev_rasterpos[4];
814 BOOL storechanged = FALSE, memory_allocated = FALSE;
818 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
820 glDisable(GL_TEXTURE_2D);
821 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
824 vcheckGLcall("glFlush");
825 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
826 vcheckGLcall("glIntegerv");
827 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
828 vcheckGLcall("glIntegerv");
829 glPixelZoom(1.0, -1.0);
830 vcheckGLcall("glPixelZoom");
832 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
833 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
834 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
836 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
837 vcheckGLcall("glRasterPos2f");
839 /* Some drivers(radeon dri, others?) don't like exceptions during
840 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
841 * after ReleaseDC. Reading it will cause an exception, which x11drv will
842 * catch to put the dib section in InSync mode, which leads to a crash
843 * and a blocked x server on my radeon card.
845 * The following lines read the dib section so it is put in inSync mode
846 * before glDrawPixels is called and the crash is prevented. There won't
847 * be any interfering gdi accesses, because UnlockRect is called from
848 * ReleaseDC, and the app won't use the dc any more afterwards.
850 if(This->Flags & SFLAG_DIBSECTION) {
852 read = This->resource.allocatedMemory[0];
855 switch (This->resource.format) {
856 /* No special care needed */
857 case WINED3DFMT_A4R4G4B4:
858 case WINED3DFMT_R5G6B5:
859 case WINED3DFMT_A1R5G5B5:
860 case WINED3DFMT_R8G8B8:
861 type = This->glDescription.glType;
862 fmt = This->glDescription.glFormat;
863 mem = This->resource.allocatedMemory;
864 bpp = This->bytesPerPixel;
867 case WINED3DFMT_X4R4G4B4:
870 unsigned short *data;
871 data = (unsigned short *)This->resource.allocatedMemory;
872 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
878 type = This->glDescription.glType;
879 fmt = This->glDescription.glFormat;
880 mem = This->resource.allocatedMemory;
881 bpp = This->bytesPerPixel;
885 case WINED3DFMT_X1R5G5B5:
888 unsigned short *data;
889 data = (unsigned short *)This->resource.allocatedMemory;
890 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
896 type = This->glDescription.glType;
897 fmt = This->glDescription.glFormat;
898 mem = This->resource.allocatedMemory;
899 bpp = This->bytesPerPixel;
903 case WINED3DFMT_X8R8G8B8:
905 /* make sure the X byte is set to alpha on, since it
906 could be any random value. This fixes the intro movie in Pirates! */
909 data = (unsigned int *)This->resource.allocatedMemory;
910 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
919 case WINED3DFMT_A8R8G8B8:
921 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
922 vcheckGLcall("glPixelStorei");
924 type = This->glDescription.glType;
925 fmt = This->glDescription.glFormat;
926 mem = This->resource.allocatedMemory;
927 bpp = This->bytesPerPixel;
931 case WINED3DFMT_A2R10G10B10:
933 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
934 vcheckGLcall("glPixelStorei");
936 type = This->glDescription.glType;
937 fmt = This->glDescription.glFormat;
938 mem = This->resource.allocatedMemory;
939 bpp = This->bytesPerPixel;
945 int height = This->glRect.bottom - This->glRect.top;
946 type = GL_UNSIGNED_BYTE;
949 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
951 ERR("Out of memory\n");
954 memory_allocated = TRUE;
955 d3dfmt_convert_surface(This->resource.allocatedMemory,
963 bpp = This->bytesPerPixel * 4;
969 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
972 type = This->glDescription.glType;
973 fmt = This->glDescription.glFormat;
974 mem = This->resource.allocatedMemory;
975 bpp = This->bytesPerPixel;
978 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
979 (This->lockedRect.bottom - This->lockedRect.top)-1,
981 mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
982 checkGLcall("glDrawPixels");
983 glPixelZoom(1.0,1.0);
984 vcheckGLcall("glPixelZoom");
986 glRasterPos3iv(&prev_rasterpos[0]);
987 vcheckGLcall("glRasterPos3iv");
989 /* Reset to previous pack row length */
990 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
991 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
993 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
994 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
997 /* Blitting environment requires that 2D texturing is enabled. It was turned off before,
1000 glEnable(GL_TEXTURE_2D);
1001 checkGLcall("glEnable(GL_TEXTURE_2D)");
1003 if(memory_allocated) HeapFree(GetProcessHeap(), 0, mem);
1007 static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl *This) {
1008 float glTexCoord[4];
1010 glTexCoord[0] = (float) This->lockedRect.left / (float) This->pow2Width; /* left */
1011 glTexCoord[1] = (float) This->lockedRect.right / (float) This->pow2Width; /* right */
1012 glTexCoord[2] = (float) This->lockedRect.top / (float) This->pow2Height; /* top */
1013 glTexCoord[3] = (float) This->lockedRect.bottom / (float) This->pow2Height; /* bottom */
1015 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
1019 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1020 checkGLcall("glEnable glBindTexture");
1022 /* No filtering for blts */
1023 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1024 checkGLcall("glTexParameteri");
1025 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1026 checkGLcall("glTexParameteri");
1028 /* Start drawing a quad */
1031 glColor3d(1.0f, 1.0f, 1.0f);
1032 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1033 glVertex3f(This->lockedRect.left, This->lockedRect.top, 0.0);
1035 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1036 glVertex3f(This->lockedRect.left, This->lockedRect.bottom, 0.0);
1038 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1039 glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.0);
1041 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1042 glVertex3f(This->lockedRect.right, This->lockedRect.top, 0.0);
1045 checkGLcall("glEnd");
1047 /* Unbind the texture */
1048 glBindTexture(GL_TEXTURE_2D, 0);
1049 checkGLcall("glEnable glBindTexture");
1054 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1055 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1056 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1057 IWineD3DSwapChainImpl *swapchain = NULL;
1059 if (!(This->Flags & SFLAG_LOCKED)) {
1060 WARN("trying to Unlock an unlocked surf@%p\n", This);
1061 return WINED3DERR_INVALIDCALL;
1064 TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0);
1066 if (!(This->Flags & SFLAG_DIRTY)) {
1067 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1071 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1072 if(swapchain || iface == myDevice->render_targets[0]) {
1073 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1074 static BOOL warned = FALSE;
1076 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1079 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1083 /* Activate the correct context for the render target */
1085 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
1088 /* Primary offscreen render target */
1089 TRACE("Offscreen render target\n");
1090 glDrawBuffer(myDevice->offscreenBuffer);
1091 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1093 if(iface == swapchain->frontBuffer) {
1094 TRACE("Onscreen front buffer\n");
1095 glDrawBuffer(GL_FRONT);
1096 checkGLcall("glDrawBuffer(GL_FRONT)");
1097 } else if(iface == swapchain->backBuffer[0]) {
1098 TRACE("Onscreen back buffer\n");
1099 glDrawBuffer(GL_BACK);
1100 checkGLcall("glDrawBuffer(GL_BACK)");
1102 FIXME("Unlocking a higher back buffer\n");
1103 glDrawBuffer(GL_BACK);
1104 checkGLcall("glDrawBuffer(GL_BACK)");
1106 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1109 switch(wined3d_settings.rendertargetlock_mode) {
1113 flush_to_framebuffer_drawpixels(This);
1118 flush_to_framebuffer_texture(This);
1122 glDrawBuffer(myDevice->offscreenBuffer);
1123 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1124 } else if(swapchain->backBuffer) {
1125 glDrawBuffer(GL_BACK);
1126 checkGLcall("glDrawBuffer(GL_BACK)");
1128 glDrawBuffer(GL_FRONT);
1129 checkGLcall("glDrawBuffer(GL_FRONT)");
1133 /** restore clean dirty state */
1134 IWineD3DSurface_CleanDirtyRect(iface);
1135 } else if(iface == myDevice->stencilBufferTarget) {
1136 FIXME("Depth Stencil buffer locking is not implemented\n");
1138 /* The rest should be a normal texture */
1139 IWineD3DBaseTextureImpl *impl;
1140 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1141 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1142 * states need resetting
1144 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1145 if(impl->baseTexture.bindCount) {
1146 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1148 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1153 This->Flags &= ~SFLAG_LOCKED;
1154 memset(&This->lockedRect, 0, sizeof(RECT));
1158 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1159 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1160 WINED3DLOCKED_RECT lock;
1167 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1169 TRACE("(%p)->(%p)\n",This,pHDC);
1171 if(This->Flags & SFLAG_USERPTR) {
1172 ERR("Not supported on surfaces with an application-provided surfaces\n");
1176 /* Give more detailed info for ddraw */
1177 if (This->Flags & SFLAG_DCINUSE)
1178 return DDERR_DCALREADYCREATED;
1180 /* Can't GetDC if the surface is locked */
1181 if (This->Flags & SFLAG_LOCKED)
1182 return WINED3DERR_INVALIDCALL;
1184 memset(&lock, 0, sizeof(lock)); /* To be sure */
1186 /* Create a DIB section if there isn't a hdc yet */
1189 SYSTEM_INFO sysInfo;
1191 switch (This->bytesPerPixel) {
1194 /* Allocate extra space to store the RGB bit masks. */
1195 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1199 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1203 /* Allocate extra space for a palette. */
1204 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1205 sizeof(BITMAPINFOHEADER)
1207 * (1 << (This->bytesPerPixel * 8)));
1212 return E_OUTOFMEMORY;
1214 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1215 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1216 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1217 * add an extra line to the dib section
1219 GetSystemInfo(&sysInfo);
1220 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1222 TRACE("Adding an extra line to the dib section\n");
1225 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1226 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1227 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1228 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1229 b_info->bmiHeader.biPlanes = 1;
1230 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1232 b_info->bmiHeader.biXPelsPerMeter = 0;
1233 b_info->bmiHeader.biYPelsPerMeter = 0;
1234 b_info->bmiHeader.biClrUsed = 0;
1235 b_info->bmiHeader.biClrImportant = 0;
1237 /* Get the bit masks */
1238 masks = (DWORD *) &(b_info->bmiColors);
1239 switch (This->resource.format) {
1240 case WINED3DFMT_R8G8B8:
1241 usage = DIB_RGB_COLORS;
1242 b_info->bmiHeader.biCompression = BI_RGB;
1245 case WINED3DFMT_X1R5G5B5:
1246 case WINED3DFMT_A1R5G5B5:
1247 case WINED3DFMT_A4R4G4B4:
1248 case WINED3DFMT_X4R4G4B4:
1249 case WINED3DFMT_R3G3B2:
1250 case WINED3DFMT_A8R3G3B2:
1251 case WINED3DFMT_A2B10G10R10:
1252 case WINED3DFMT_A8B8G8R8:
1253 case WINED3DFMT_X8B8G8R8:
1254 case WINED3DFMT_A2R10G10B10:
1255 case WINED3DFMT_R5G6B5:
1256 case WINED3DFMT_A16B16G16R16:
1258 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1259 masks[0] = formatEntry->redMask;
1260 masks[1] = formatEntry->greenMask;
1261 masks[2] = formatEntry->blueMask;
1265 /* Don't know palette */
1266 b_info->bmiHeader.biCompression = BI_RGB;
1273 HeapFree(GetProcessHeap(), 0, b_info);
1274 return HRESULT_FROM_WIN32(GetLastError());
1277 TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
1278 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1281 if (!This->dib.DIBsection) {
1282 ERR("CreateDIBSection failed!\n");
1283 HeapFree(GetProcessHeap(), 0, b_info);
1284 return HRESULT_FROM_WIN32(GetLastError());
1287 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1289 /* copy the existing surface to the dib section */
1290 if(This->resource.allocatedMemory) {
1291 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1292 /* We won't need that any more */
1293 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1295 /* This is to make LockRect read the gl Texture although memory is allocated */
1296 This->Flags |= SFLAG_GLDIRTY;
1299 HeapFree(GetProcessHeap(), 0, b_info);
1301 /* Use the dib section from now on */
1302 This->resource.allocatedMemory = This->dib.bitmap_data;
1304 /* Now allocate a HDC */
1305 This->hDC = CreateCompatibleDC(0);
1306 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1307 TRACE("using wined3d palette %p\n", This->palette);
1308 SelectPalette(This->hDC,
1309 This->palette ? This->palette->hpal : 0,
1312 This->Flags |= SFLAG_DIBSECTION;
1315 /* Lock the surface */
1316 hr = IWineD3DSurface_LockRect(iface,
1321 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1322 /* keep the dib section */
1326 if(This->resource.format == WINED3DFMT_P8 ||
1327 This->resource.format == WINED3DFMT_A8P8) {
1330 PALETTEENTRY ent[256];
1332 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1333 for (n=0; n<256; n++) {
1334 col[n].rgbRed = ent[n].peRed;
1335 col[n].rgbGreen = ent[n].peGreen;
1336 col[n].rgbBlue = ent[n].peBlue;
1337 col[n].rgbReserved = 0;
1340 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1342 for (n=0; n<256; n++) {
1343 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1344 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1345 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1346 col[n].rgbReserved = 0;
1350 SetDIBColorTable(This->hDC, 0, 256, col);
1354 TRACE("returning %p\n",*pHDC);
1355 This->Flags |= SFLAG_DCINUSE;
1360 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1361 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1363 TRACE("(%p)->(%p)\n",This,hDC);
1365 if (!(This->Flags & SFLAG_DCINUSE))
1366 return WINED3DERR_INVALIDCALL;
1368 /* we locked first, so unlock now */
1369 IWineD3DSurface_UnlockRect(iface);
1371 This->Flags &= ~SFLAG_DCINUSE;
1376 /* ******************************************************
1377 IWineD3DSurface Internal (No mapping to directx api) parts follow
1378 ****************************************************** */
1380 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_texturing, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp) {
1381 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1382 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1384 /* Default values: From the surface */
1385 *format = formatEntry->glFormat;
1386 *internal = formatEntry->glInternal;
1387 *type = formatEntry->glType;
1388 *convert = NO_CONVERSION;
1389 *target_bpp = This->bytesPerPixel;
1391 /* Ok, now look if we have to do any conversion */
1392 switch(This->resource.format) {
1397 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1398 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1400 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1402 *internal = GL_RGBA;
1403 *type = GL_UNSIGNED_BYTE;
1405 if(colorkey_active) {
1406 *convert = CONVERT_PALETTED_CK;
1408 *convert = CONVERT_PALETTED;
1414 case WINED3DFMT_R3G3B2:
1415 /* **********************
1416 GL_UNSIGNED_BYTE_3_3_2
1417 ********************** */
1418 if (colorkey_active) {
1419 /* This texture format will never be used.. So do not care about color keying
1420 up until the point in time it will be needed :-) */
1421 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1425 case WINED3DFMT_R5G6B5:
1426 if (colorkey_active) {
1427 *convert = CONVERT_CK_565;
1429 *internal = GL_RGBA;
1430 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1434 case WINED3DFMT_R8G8B8:
1435 if (colorkey_active) {
1436 *convert = CONVERT_CK_RGB24;
1438 *internal = GL_RGBA;
1439 *type = GL_UNSIGNED_INT_8_8_8_8;
1444 case WINED3DFMT_X8R8G8B8:
1445 if (colorkey_active) {
1446 *convert = CONVERT_RGB32_888;
1448 *internal = GL_RGBA;
1449 *type = GL_UNSIGNED_INT_8_8_8_8;
1453 case WINED3DFMT_V8U8:
1454 /* TODO: GL_NV_texture_shader and GL_ATI_envmap_bumpmap provide suitable formats.
1455 * use one of them instead of converting
1456 * Remember to adjust the texbem instruction in the shader
1458 *convert = CONVERT_V8U8;
1460 *internal = GL_RGB8;
1472 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1473 BYTE *source, *dest;
1474 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1479 memcpy(dst, src, pitch * height);
1482 case CONVERT_PALETTED:
1483 case CONVERT_PALETTED_CK:
1485 IWineD3DPaletteImpl* pal = surf->palette;
1491 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1495 /* Still no palette? Use the device's palette */
1496 /* Get the surface's palette */
1497 for (i = 0; i < 256; i++) {
1498 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1500 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1501 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1502 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1503 if ((convert == CONVERT_PALETTED_CK) &&
1504 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1505 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1506 /* We should maybe here put a more 'neutral' color than the standard bright purple
1507 one often used by application to prevent the nice purple borders when bi-linear
1515 TRACE("Using surface palette %p\n", pal);
1516 /* Get the surface's palette */
1517 for (i = 0; i < 256; i++) {
1518 table[i][0] = pal->palents[i].peRed;
1519 table[i][1] = pal->palents[i].peGreen;
1520 table[i][2] = pal->palents[i].peBlue;
1521 if ((convert == CONVERT_PALETTED_CK) &&
1522 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1523 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1524 /* We should maybe here put a more 'neutral' color than the standard bright purple
1525 one often used by application to prevent the nice purple borders when bi-linear
1534 for (y = 0; y < height; y++)
1536 source = src + pitch * y;
1537 dest = dst + outpitch * y;
1538 /* This is an 1 bpp format, using the width here is fine */
1539 for (x = 0; x < width; x++) {
1540 BYTE color = *source++;
1541 *dest++ = table[color][0];
1542 *dest++ = table[color][1];
1543 *dest++ = table[color][2];
1544 *dest++ = table[color][3];
1550 case CONVERT_CK_565:
1552 /* Converting the 565 format in 5551 packed to emulate color-keying.
1554 Note : in all these conversion, it would be best to average the averaging
1555 pixels to get the color of the pixel that will be color-keyed to
1556 prevent 'color bleeding'. This will be done later on if ever it is
1559 Note2: Nvidia documents say that their driver does not support alpha + color keying
1560 on the same surface and disables color keying in such a case
1566 TRACE("Color keyed 565\n");
1568 for (y = 0; y < height; y++) {
1569 Source = (WORD *) (src + y * pitch);
1570 Dest = (WORD *) (dst + y * outpitch);
1571 for (x = 0; x < width; x++ ) {
1572 WORD color = *Source++;
1573 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1574 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1575 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1588 unsigned char *Dest;
1589 for(y = 0; y < height; y++) {
1590 Source = (short *) (src + y * pitch);
1591 Dest = (unsigned char *) (dst + y * outpitch);
1592 for (x = 0; x < width; x++ ) {
1593 long color = (*Source++);
1594 /* B */ Dest[0] = 0xff;
1595 /* G */ Dest[1] = (color >> 8) + 128; /* V */
1596 /* R */ Dest[2] = (color) + 128; /* U */
1604 ERR("Unsupported conversation type %d\n", convert);
1609 /* This function is used in case of 8bit paletted textures to upload the palette.
1610 For now it only supports GL_EXT_paletted_texture extension but support for other
1611 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1613 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1614 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1615 IWineD3DPaletteImpl* pal = This->palette;
1620 /* Still no palette? Use the device's palette */
1621 /* Get the surface's palette */
1622 for (i = 0; i < 256; i++) {
1623 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1625 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1626 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1627 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1628 if ((convert == CONVERT_PALETTED_CK) &&
1629 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1630 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1631 /* We should maybe here put a more 'neutral' color than the standard bright purple
1632 one often used by application to prevent the nice purple borders when bi-linear
1640 TRACE("Using surface palette %p\n", pal);
1641 /* Get the surface's palette */
1642 for (i = 0; i < 256; i++) {
1643 table[i][0] = pal->palents[i].peRed;
1644 table[i][1] = pal->palents[i].peGreen;
1645 table[i][2] = pal->palents[i].peBlue;
1646 if ((convert == CONVERT_PALETTED_CK) &&
1647 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1648 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1649 /* We should maybe here put a more 'neutral' color than the standard bright purple
1650 one often used by application to prevent the nice purple borders when bi-linear
1658 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1661 static BOOL palette9_changed(IWineD3DSurfaceImpl *This) {
1662 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1664 if(This->palette || (This->resource.format != WINED3DFMT_P8 && This->resource.format != WINED3DFMT_A8P8)) {
1665 /* If a ddraw-style palette is attached assume no d3d9 palette change.
1666 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
1671 if(This->palette9) {
1672 if(memcmp(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256) == 0) {
1676 This->palette9 = (PALETTEENTRY *) HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1678 memcpy(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
1682 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1683 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1684 GLenum format, internal, type;
1685 CONVERT_TYPES convert;
1687 int width, pitch, outpitch;
1690 if (This->Flags & SFLAG_INTEXTURE) {
1691 TRACE("Surface already in texture\n");
1694 if (This->Flags & SFLAG_DIRTY) {
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 isn't dirty\n");
1712 This->Flags &= ~SFLAG_DIRTY;
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_INPBUFFER) {
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);
1738 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1739 vcheckGLcall("glGetIntegerv");
1740 glReadBuffer(This->resource.wineD3DDevice->offscreenBuffer);
1741 vcheckGLcall("glReadBuffer");
1743 glCopyTexImage2D(This->glDescription.target,
1744 This->glDescription.level,
1745 This->glDescription.glFormatInternal,
1748 This->currentDesc.Width,
1749 This->currentDesc.Height,
1752 checkGLcall("glCopyTexImage2D");
1753 glReadBuffer(prevRead);
1754 vcheckGLcall("glReadBuffer");
1758 TRACE("Updating target %d\n", This->glDescription.target);
1759 This->Flags |= SFLAG_INTEXTURE;
1764 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1765 This->Flags |= SFLAG_GLCKEY;
1766 This->glCKey = This->SrcBltCKey;
1768 else This->Flags &= ~SFLAG_GLCKEY;
1770 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1772 /* The width is in 'length' not in bytes */
1773 width = This->currentDesc.Width;
1774 pitch = IWineD3DSurface_GetPitch(iface);
1776 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1777 int height = This->currentDesc.Height;
1779 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1780 outpitch = width * bpp;
1781 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1783 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1785 ERR("Out of memory %d, %d!\n", outpitch, height);
1786 return WINED3DERR_OUTOFVIDEOMEMORY;
1788 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1790 This->Flags |= SFLAG_CONVERTED;
1791 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1792 d3dfmt_p8_upload_palette(iface, convert);
1793 This->Flags &= ~SFLAG_CONVERTED;
1794 mem = This->resource.allocatedMemory;
1796 This->Flags &= ~SFLAG_CONVERTED;
1797 mem = This->resource.allocatedMemory;
1800 /* Make sure the correct pitch is used */
1801 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1803 if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1804 TRACE("non power of two support\n");
1805 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1807 surface_upload_data(This, This->currentDesc.Width, This->currentDesc.Height, format, type, mem);
1810 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1812 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1816 /* Restore the default pitch */
1817 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1819 if (mem != This->resource.allocatedMemory)
1820 HeapFree(GetProcessHeap(), 0, mem);
1824 static unsigned int gen = 0;
1827 if ((gen % 10) == 0) {
1828 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1829 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1832 * debugging crash code
1841 if (!(This->Flags & SFLAG_DONOTFREE)) {
1842 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1843 This->resource.allocatedMemory = NULL;
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 (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1880 /* we don't want to interfere with the back buffer so read the data into a temporary texture and then save the data out of the temporary texture */
1883 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1884 glEnable(GL_TEXTURE_2D);
1886 glGenTextures(1, &tmpTexture);
1887 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1889 glTexImage2D(GL_TEXTURE_2D,
1896 GL_UNSIGNED_INT_8_8_8_8_REV,
1899 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1900 vcheckGLcall("glGetIntegerv");
1901 glReadBuffer(swapChain ? GL_BACK : This->resource.wineD3DDevice->offscreenBuffer);
1902 vcheckGLcall("glReadBuffer");
1903 glCopyTexImage2D(GL_TEXTURE_2D,
1912 checkGLcall("glCopyTexImage2D");
1913 glReadBuffer(prevRead);
1916 } else { /* bind the real texture */
1917 IWineD3DSurface_PreLoad(iface);
1919 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1921 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1922 glGetTexImage(GL_TEXTURE_2D,
1923 This->glDescription.level,
1925 GL_UNSIGNED_INT_8_8_8_8_REV,
1927 checkGLcall("glTexImage2D");
1929 glBindTexture(GL_TEXTURE_2D, 0);
1930 glDeleteTextures(1, &tmpTexture);
1934 f = fopen(filename, "w+");
1936 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1937 return WINED3DERR_INVALIDCALL;
1939 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1940 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1955 fwrite(&width,2,1,f);
1957 fwrite(&height,2,1,f);
1962 /* 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*/
1964 textureRow = allocatedMemory + (width * (height - 1) *4);
1966 textureRow = allocatedMemory;
1967 for (y = 0 ; y < height; y++) {
1968 for (i = 0; i < width; i++) {
1969 color = *((DWORD*)textureRow);
1970 fputc((color >> 16) & 0xFF, f); /* B */
1971 fputc((color >> 8) & 0xFF, f); /* G */
1972 fputc((color >> 0) & 0xFF, f); /* R */
1973 fputc((color >> 24) & 0xFF, f); /* A */
1976 /* take two rows of the pointer to the texture memory */
1978 (textureRow-= width << 3);
1981 TRACE("Closing file\n");
1985 IWineD3DSwapChain_Release(swapChain);
1987 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1991 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1992 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1993 This->Flags &= ~SFLAG_DIRTY;
1994 This->dirtyRect.left = This->currentDesc.Width;
1995 This->dirtyRect.top = This->currentDesc.Height;
1996 This->dirtyRect.right = 0;
1997 This->dirtyRect.bottom = 0;
1998 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1999 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2004 * Slightly inefficient way to handle multiple dirty rects but it works :)
2006 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2007 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2008 IWineD3DBaseTexture *baseTexture = NULL;
2009 This->Flags |= SFLAG_DIRTY;
2010 if (NULL != pDirtyRect) {
2011 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2012 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2013 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2014 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2016 This->dirtyRect.left = 0;
2017 This->dirtyRect.top = 0;
2018 This->dirtyRect.right = This->currentDesc.Width;
2019 This->dirtyRect.bottom = This->currentDesc.Height;
2021 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2022 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2023 /* if the container is a basetexture then mark it dirty. */
2024 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2025 TRACE("Passing to conatiner\n");
2026 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2027 IWineD3DBaseTexture_Release(baseTexture);
2032 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2033 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2035 TRACE("This %p, container %p\n", This, container);
2037 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2039 TRACE("Setting container to %p from %p\n", container, This->container);
2040 This->container = container;
2045 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2046 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2047 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2049 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2050 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2051 return WINED3DERR_INVALIDCALL;
2054 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2055 if (format == WINED3DFMT_UNKNOWN) {
2056 This->resource.size = 0;
2057 } else if (format == WINED3DFMT_DXT1) {
2058 /* DXT1 is half byte per pixel */
2059 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2061 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2062 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2063 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2065 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
2066 This->resource.size *= This->pow2Height;
2070 /* Setup some glformat defaults */
2071 This->glDescription.glFormat = formatEntry->glFormat;
2072 This->glDescription.glFormatInternal = formatEntry->glInternal;
2073 This->glDescription.glType = formatEntry->glType;
2075 if (format != WINED3DFMT_UNKNOWN) {
2076 This->bytesPerPixel = formatEntry->bpp;
2078 This->bytesPerPixel = 0;
2081 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2083 This->resource.format = format;
2085 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);
2090 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2091 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2093 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2094 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2095 ERR("Not supported on render targets\n");
2096 return WINED3DERR_INVALIDCALL;
2099 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2100 WARN("Surface is locked or the HDC is in use\n");
2101 return WINED3DERR_INVALIDCALL;
2104 if(Mem && Mem != This->resource.allocatedMemory) {
2106 /* Do I have to copy the old surface content? */
2107 if(This->Flags & SFLAG_DIBSECTION) {
2108 /* Release the DC. No need to hold the critical section for the update
2109 * Thread because this thread runs only on front buffers, but this method
2110 * fails for render targets in the check above.
2112 SelectObject(This->hDC, This->dib.holdbitmap);
2113 DeleteDC(This->hDC);
2114 /* Release the DIB section */
2115 DeleteObject(This->dib.DIBsection);
2116 This->dib.bitmap_data = NULL;
2117 This->resource.allocatedMemory = NULL;
2119 This->Flags &= ~SFLAG_DIBSECTION;
2120 } else if(!(This->Flags & SFLAG_USERPTR)) {
2121 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2123 This->resource.allocatedMemory = Mem;
2124 This->Flags |= SFLAG_USERPTR;
2125 } else if(This->Flags & SFLAG_USERPTR) {
2126 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2127 This->resource.allocatedMemory = NULL;
2128 This->Flags &= ~SFLAG_USERPTR;
2133 /* TODO: replace this function with context management routines */
2134 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2135 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2138 This->Flags |= SFLAG_INPBUFFER;
2140 This->Flags &= ~SFLAG_INPBUFFER;
2144 This->Flags |= SFLAG_INTEXTURE;
2146 This->Flags &= ~SFLAG_INTEXTURE;
2152 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2153 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2154 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2155 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2157 /* Flipping is only supported on RenderTargets */
2158 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2161 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2162 * FIXME("(%p) Target override is not supported by now\n", This);
2163 * Additionally, it isn't really possible to support triple-buffering
2164 * properly on opengl at all
2168 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2169 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2172 /* Does a direct frame buffer -> texture copy. Stretching is done
2173 * with single pixel copy calls
2175 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2176 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2179 BOOL warned = FALSE; /* deliberately not static */
2180 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2184 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2186 /* Bind the target texture */
2187 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2188 checkGLcall("glBindTexture");
2190 glReadBuffer(myDevice->offscreenBuffer);
2191 } else if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2192 glReadBuffer(GL_BACK);
2194 glReadBuffer(GL_FRONT);
2196 checkGLcall("glReadBuffer");
2198 xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1);
2199 yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1);
2201 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2202 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2206 !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) &&
2207 !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2208 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2210 glCopyTexSubImage2D(This->glDescription.target,
2211 This->glDescription.level,
2212 drect->x1, drect->y1, /* xoffset, yoffset */
2213 srect->x1, Src->currentDesc.Height - srect->y2,
2214 drect->x2 - drect->x1, drect->y2 - drect->y1);
2216 UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1;
2217 /* I have to process this row by row to swap the image,
2218 * otherwise it would be upside down, so streching in y direction
2219 * doesn't cost extra time
2221 * However, streching in x direction can be avoided if not necessary
2223 for(row = drect->y1; row < drect->y2; row++) {
2224 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2225 /* Well, that stuff works, but it's very slow.
2226 * find a better way instead
2232 FIXME("Doing a pixel by pixel render target -> texture copy, expect performance issues\n");
2235 for(col = drect->x1; col < drect->x2; col++) {
2236 glCopyTexSubImage2D(This->glDescription.target,
2237 This->glDescription.level,
2238 drect->x1 + col, row, /* xoffset, yoffset */
2239 srect->x1 + col * xrel, yoffset - (int) (row * yrel),
2243 glCopyTexSubImage2D(This->glDescription.target,
2244 This->glDescription.level,
2245 drect->x1, row, /* xoffset, yoffset */
2246 srect->x1, yoffset - (int) (row * yrel),
2247 drect->x2-drect->x1, 1);
2252 vcheckGLcall("glCopyTexSubImage2D");
2256 /* Uses the hardware to stretch and flip the image */
2257 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2258 GLuint src, backup = 0;
2259 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2260 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2261 float left, right, top, bottom; /* Texture coordinates */
2262 UINT fbwidth = Src->currentDesc.Width;
2263 UINT fbheight = Src->currentDesc.Height;
2264 GLenum drawBuffer = GL_BACK;
2266 TRACE("Using hwstretch blit\n");
2267 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2269 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2271 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2272 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2274 if(GL_LIMITS(aux_buffers) >= 2) {
2275 /* Got more than one aux buffer? Use the 2nd aux buffer */
2276 drawBuffer = GL_AUX1;
2277 } else if((swapchain || myDevice->offscreenBuffer == GL_BACK) && GL_LIMITS(aux_buffers) >= 1) {
2278 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2279 drawBuffer = GL_AUX0;
2282 if(!swapchain && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2283 glGenTextures(1, &backup);
2284 checkGLcall("glGenTextures\n");
2285 glBindTexture(GL_TEXTURE_2D, backup);
2286 checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2288 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2289 * we are reading from the back buffer, the backup can be used as source texture
2291 if(Src->glDescription.textureName == 0) {
2292 /* Get it a description */
2293 IWineD3DSurface_PreLoad(SrcSurface);
2295 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2296 checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2299 glReadBuffer(GL_BACK);
2300 checkGLcall("glReadBuffer(GL_BACK)");
2302 /* TODO: Only back up the part that will be overwritten */
2303 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2304 0, 0 /* read offsets */,
2309 checkGLcall("glCopyTexSubImage2D");
2311 /* No issue with overriding these - the sampler is dirty due to blit usage */
2312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2313 checkGLcall("glTexParameteri");
2314 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2315 checkGLcall("glTexParameteri");
2317 if(!swapchain || (IWineD3DSurface *) Src == swapchain->backBuffer[0]) {
2318 src = backup ? backup : Src->glDescription.textureName;
2320 glReadBuffer(GL_FRONT);
2321 checkGLcall("glReadBuffer(GL_FRONT)");
2323 glGenTextures(1, &src);
2324 checkGLcall("glGenTextures(1, &src)");
2325 glBindTexture(GL_TEXTURE_2D, src);
2326 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
2328 /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
2329 * out for power of 2 sizes
2331 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2332 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2333 checkGLcall("glTexImage2D");
2334 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2335 0, 0 /* read offsets */,
2340 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2341 checkGLcall("glTexParameteri");
2342 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2343 checkGLcall("glTexParameteri");
2345 glReadBuffer(GL_BACK);
2346 checkGLcall("glReadBuffer(GL_BACK)");
2348 checkGLcall("glEnd and previous");
2350 left = (float) srect->x1 / (float) Src->pow2Width;
2351 right = (float) srect->x2 / (float) Src->pow2Width;
2354 top = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2355 bottom = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2357 top = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2358 bottom = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2361 /* draw the source texture stretched and upside down. The correct surface is bound already */
2362 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2363 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2365 glDrawBuffer(drawBuffer);
2366 glReadBuffer(drawBuffer);
2370 glTexCoord2f(left, bottom);
2371 glVertex2i(0, fbheight);
2374 glTexCoord2f(left, top);
2375 glVertex2i(0, fbheight - drect->y2 - drect->y1);
2378 glTexCoord2f(right, top);
2379 glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1);
2382 glTexCoord2f(right, bottom);
2383 glVertex2i(drect->x2 - drect->x1, fbheight);
2385 checkGLcall("glEnd and previous");
2387 /* Now read the stretched and upside down image into the destination texture */
2388 glBindTexture(This->glDescription.target, This->glDescription.textureName);
2389 checkGLcall("glBindTexture");
2390 glCopyTexSubImage2D(This->glDescription.target,
2392 drect->x1, drect->y1, /* xoffset, yoffset */
2393 0, 0, /* We blitted the image to the origin */
2394 drect->x2 - drect->x1, drect->y2 - drect->y1);
2395 checkGLcall("glCopyTexSubImage2D");
2397 /* Write the back buffer backup back */
2398 glBindTexture(GL_TEXTURE_2D, backup ? backup : Src->glDescription.textureName);
2399 checkGLcall("glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName)");
2401 if(drawBuffer == GL_BACK) {
2404 glTexCoord2f(0.0, (float) fbheight / (float) Src->pow2Height);
2408 glTexCoord2f(0.0, 0.0);
2409 glVertex2i(0, fbheight);
2412 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, 0.0);
2413 glVertex2i(fbwidth, Src->currentDesc.Height);
2416 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
2417 glVertex2i(fbwidth, 0);
2420 /* Restore the old draw buffer */
2421 glDrawBuffer(GL_BACK);
2425 if(src != Src->glDescription.textureName && src != backup) {
2426 glDeleteTextures(1, &src);
2427 checkGLcall("glDeleteTextures(1, &src)");
2430 glDeleteTextures(1, &backup);
2431 checkGLcall("glDeleteTextures(1, &backup)");
2436 /* Not called from the VTable */
2437 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2439 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2440 IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
2441 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2444 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2446 /* Get the swapchain. One of the surfaces has to be a primary surface */
2447 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
2448 if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
2450 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
2451 if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
2454 /* Early sort out of cases where no render target is used */
2455 if(!dstSwapchain && !srcSwapchain &&
2456 SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2457 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
2458 return WINED3DERR_INVALIDCALL;
2461 /* No destination color keying supported */
2462 if(Flags & (DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE)) {
2463 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2464 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2465 return WINED3DERR_INVALIDCALL;
2469 rect.x1 = DestRect->left;
2470 rect.y1 = DestRect->top;
2471 rect.x2 = DestRect->right;
2472 rect.y2 = DestRect->bottom;
2476 rect.x2 = This->currentDesc.Width;
2477 rect.y2 = This->currentDesc.Height;
2480 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
2481 if(dstSwapchain && dstSwapchain == srcSwapchain) {
2482 /* Half-life does a Blt from the back buffer to the front buffer,
2483 * Full surface size, no flags... Use present instead
2486 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2488 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2489 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2496 /* Check the Destination rect and the surface sizes */
2498 (rect.x1 == 0) && (rect.y1 == 0) &&
2499 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2500 (This->currentDesc.Width == Src->currentDesc.Width) &&
2501 (This->currentDesc.Height == Src->currentDesc.Height)) {
2502 /* These flags are unimportant for the flag check, remove them */
2504 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2505 if( dstSwapchain->backBuffer && ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) &&
2506 SrcSurface == dstSwapchain->backBuffer[0] ) {
2508 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
2510 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2511 * take very long, while a flip is fast.
2512 * This applies to Half-Life, which does such Blts every time it finished
2513 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2514 * menu. This is also used by all apps when they do windowed rendering
2516 * The problem is that flipping is not really the same as copying. After a
2517 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2518 * untouched. Therefore it's necessary to override the swap effect
2519 * and to set it back after the flip.
2522 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2524 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2525 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2526 NULL, NULL, 0, NULL);
2528 dstSwapchain->presentParms.SwapEffect = orig_swap;
2535 TRACE("Unsupported blit between buffers on the same swapchain\n");
2536 return WINED3DERR_INVALIDCALL;
2537 } else if((dstSwapchain || This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) &&
2538 (srcSwapchain || SrcSurface == myDevice->render_targets[0]) ) {
2539 ERR("Can't perform hardware blit between 2 different swapchains, falling back to software\n");
2540 return WINED3DERR_INVALIDCALL;
2543 if(srcSwapchain || SrcSurface == myDevice->render_targets[0]) {
2544 /* Blit from render target to texture */
2546 BOOL upsideDown, stretchx;
2548 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2549 TRACE("Color keying not supported by frame buffer to texture blit\n");
2550 return WINED3DERR_INVALIDCALL;
2551 /* Destination color key is checked above */
2554 /* Call preload for the surface to make sure it isn't dirty */
2555 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2557 /* Make sure that the top pixel is always above the bottom pixel, and keep a seperate upside down flag
2558 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2561 if(SrcRect->top < SrcRect->bottom) {
2562 srect.y1 = SrcRect->top;
2563 srect.y2 = SrcRect->bottom;
2566 srect.y1 = SrcRect->bottom;
2567 srect.y2 = SrcRect->top;
2570 srect.x1 = SrcRect->left;
2571 srect.x2 = SrcRect->right;
2575 srect.x2 = Src->currentDesc.Width;
2576 srect.y2 = Src->currentDesc.Height;
2579 if(rect.x1 > rect.x2) {
2583 upsideDown = !upsideDown;
2586 TRACE("Reading from an offscreen target\n");
2587 upsideDown = !upsideDown;
2590 if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
2596 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2597 * flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully,
2598 * not implemented by now). Otherwise:
2600 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2601 * -> If the app wants a image width an unscaled width, copy it line per line
2602 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
2603 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2604 * back buffer. This is slower than reading line per line, thus not used for flipping
2605 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2608 if(FALSE /* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */) {
2609 TRACE("Using GL_EXT_framebuffer_blit for copying\n");
2610 } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
2611 rect.y2 - rect.y1 > Src->currentDesc.Height) {
2612 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
2613 fb_copy_to_texture_direct(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
2615 TRACE("Using hardware stretching to flip / stretch the texture\n");
2616 fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
2619 if(!(This->Flags & SFLAG_DONOTFREE)) {
2620 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2621 This->resource.allocatedMemory = NULL;
2623 This->Flags |= SFLAG_GLDIRTY;
2628 /* Blit from offscreen surface to render target */
2629 float glTexCoord[4];
2630 DWORD oldCKeyFlags = Src->CKeyFlags;
2631 DDCOLORKEY oldBltCKey = This->SrcBltCKey;
2632 RECT SourceRectangle;
2635 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2638 SourceRectangle.left = SrcRect->left;
2639 SourceRectangle.right = SrcRect->right;
2640 SourceRectangle.top = SrcRect->top;
2641 SourceRectangle.bottom = SrcRect->bottom;
2643 SourceRectangle.left = 0;
2644 SourceRectangle.right = Src->currentDesc.Width;
2645 SourceRectangle.top = 0;
2646 SourceRectangle.bottom = Src->currentDesc.Height;
2649 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2650 /* Fall back to software */
2651 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2652 SourceRectangle.left, SourceRectangle.top,
2653 SourceRectangle.right, SourceRectangle.bottom);
2654 return WINED3DERR_INVALIDCALL;
2657 /* Color keying: Check if we have to do a color keyed blt,
2658 * and if not check if a color key is activated.
2660 * Just modify the color keying parameters in the surface and restore them afterwards
2661 * The surface keeps track of the color key last used to load the opengl surface.
2662 * PreLoad will catch the change to the flags and color key and reload if neccessary.
2664 if(Flags & DDBLT_KEYSRC) {
2665 /* Use color key from surface */
2666 } else if(Flags & DDBLT_KEYSRCOVERRIDE) {
2667 /* Use color key from DDBltFx */
2668 Src->CKeyFlags |= DDSD_CKSRCBLT;
2669 This->SrcBltCKey = DDBltFx->ddckSrcColorkey;
2671 /* Do not use color key */
2672 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2675 /* Now load the surface */
2676 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2680 /* Activate the destination context, set it up for blitting */
2681 ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
2683 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2684 if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer) {
2685 TRACE("Drawing to front buffer\n");
2686 glDrawBuffer(GL_FRONT);
2687 checkGLcall("glDrawBuffer GL_FRONT");
2690 /* Bind the texture */
2691 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2692 checkGLcall("glBindTexture");
2694 /* No filtering for blts */
2695 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2697 checkGLcall("glTexParameteri");
2698 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2700 checkGLcall("glTexParameteri");
2701 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2702 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2703 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2704 checkGLcall("glTexEnvi");
2706 /* This is for color keying */
2707 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2708 glEnable(GL_ALPHA_TEST);
2709 checkGLcall("glEnable GL_ALPHA_TEST");
2710 glAlphaFunc(GL_NOTEQUAL, 0.0);
2711 checkGLcall("glAlphaFunc\n");
2713 glDisable(GL_ALPHA_TEST);
2714 checkGLcall("glDisable GL_ALPHA_TEST");
2717 /* Draw a textured quad
2721 glColor3d(1.0f, 1.0f, 1.0f);
2722 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2727 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2728 glVertex3f(rect.x1, rect.y2, 0.0);
2730 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2735 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2740 checkGLcall("glEnd");
2742 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2743 glDisable(GL_ALPHA_TEST);
2744 checkGLcall("glDisable(GL_ALPHA_TEST)");
2747 /* Unbind the texture */
2748 glBindTexture(GL_TEXTURE_2D, 0);
2749 checkGLcall("glEnable glBindTexture");
2751 if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer && oldDraw == GL_BACK) {
2752 glDrawBuffer(oldDraw);
2754 /* Restore the color key parameters */
2755 Src->CKeyFlags = oldCKeyFlags;
2756 This->SrcBltCKey = oldBltCKey;
2760 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2761 This->Flags |= SFLAG_GLDIRTY;
2765 /* Source-Less Blit to render target */
2766 if (Flags & DDBLT_COLORFILL) {
2767 /* This is easy to handle for the D3D Device... */
2770 TRACE("Colorfill\n");
2772 /* The color as given in the Blt function is in the format of the frame-buffer...
2773 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2775 if (This->resource.format == WINED3DFMT_P8) {
2776 if (This->palette) {
2777 color = ((0xFF000000) |
2778 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2779 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2780 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2785 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2786 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2789 color = ((0xFF000000) |
2790 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2791 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2792 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2795 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2796 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2797 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2799 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2800 color = DDBltFx->u5.dwFillColor;
2803 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2804 return WINED3DERR_INVALIDCALL;
2807 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2808 if(dstSwapchain && dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]) {
2809 glDrawBuffer(GL_BACK);
2810 checkGLcall("glDrawBuffer(GL_BACK)");
2811 } else if (dstSwapchain && This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer) {
2812 glDrawBuffer(GL_FRONT);
2813 checkGLcall("glDrawBuffer(GL_FRONT)");
2814 } else if(This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2815 glDrawBuffer(myDevice->offscreenBuffer);
2816 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer3)");
2818 TRACE("Surface is higher back buffer, falling back to software\n");
2819 return WINED3DERR_INVALIDCALL;
2822 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2824 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2825 1 /* Number of rectangles */,
2827 WINED3DCLEAR_TARGET,
2832 /* Restore the original draw buffer */
2834 glDrawBuffer(myDevice->offscreenBuffer);
2835 } else if(dstSwapchain->backBuffer && dstSwapchain->backBuffer[0]) {
2836 glDrawBuffer(GL_BACK);
2838 vcheckGLcall("glDrawBuffer");
2844 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2845 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2846 return WINED3DERR_INVALIDCALL;
2849 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2850 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2851 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2852 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2853 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2854 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2856 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair */
2857 if(myDevice->inScene &&
2858 (iface == myDevice->stencilBufferTarget ||
2859 (SrcSurface && SrcSurface == myDevice->stencilBufferTarget))) {
2860 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2861 return WINED3DERR_INVALIDCALL;
2864 /* Special cases for RenderTargets */
2865 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2866 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2867 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2870 /* For the rest call the X11 surface implementation.
2871 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2872 * other Blts are rather rare
2874 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2877 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2878 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2879 TRACE("(%p)->(%x)\n", This, Flags);
2884 case DDGBS_ISBLTDONE:
2888 return DDERR_INVALIDPARAMS;
2892 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2893 /* XXX: DDERR_INVALIDSURFACETYPE */
2895 TRACE("(%p)->(%08x)\n",iface,Flags);
2898 case DDGFS_ISFLIPDONE:
2902 return DDERR_INVALIDPARAMS;
2906 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2907 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2908 TRACE("(%p)\n", This);
2910 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2913 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2914 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2915 TRACE("(%p)\n", This);
2917 /* So far we don't lose anything :) */
2918 This->Flags &= ~SFLAG_LOST;
2922 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2923 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2924 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2925 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2926 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2928 if(myDevice->inScene &&
2929 (iface == myDevice->stencilBufferTarget ||
2930 (Source && Source == myDevice->stencilBufferTarget))) {
2931 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2932 return WINED3DERR_INVALIDCALL;
2935 /* Special cases for RenderTargets */
2936 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2937 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2939 RECT SrcRect, DstRect;
2943 SrcRect.left = rsrc->left;
2944 SrcRect.top= rsrc->top;
2945 SrcRect.bottom = rsrc->bottom;
2946 SrcRect.right = rsrc->right;
2950 SrcRect.right = srcImpl->currentDesc.Width;
2951 SrcRect.bottom = srcImpl->currentDesc.Height;
2954 DstRect.left = dstx;
2956 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2957 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2959 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2960 if(trans & DDBLTFAST_SRCCOLORKEY)
2961 Flags |= DDBLT_KEYSRC;
2962 if(trans & DDBLTFAST_DESTCOLORKEY)
2963 Flags |= DDBLT_KEYDEST;
2964 if(trans & DDBLTFAST_WAIT)
2965 Flags |= DDBLT_WAIT;
2966 if(trans & DDBLTFAST_DONOTWAIT)
2967 Flags |= DDBLT_DONOTWAIT;
2969 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2973 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2976 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2977 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2978 TRACE("(%p)->(%p)\n", This, Pal);
2980 *Pal = (IWineD3DPalette *) This->palette;
2984 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2985 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2987 IWineD3DPaletteImpl *pal = This->palette;
2989 TRACE("(%p)\n", This);
2991 if(This->resource.format == WINED3DFMT_P8 ||
2992 This->resource.format == WINED3DFMT_A8P8)
2994 TRACE("Dirtifying surface\n");
2995 This->Flags |= SFLAG_DIRTY;
2998 if(This->Flags & SFLAG_DIBSECTION) {
2999 TRACE("(%p): Updating the hdc's palette\n", This);
3000 for (n=0; n<256; n++) {
3002 col[n].rgbRed = pal->palents[n].peRed;
3003 col[n].rgbGreen = pal->palents[n].peGreen;
3004 col[n].rgbBlue = pal->palents[n].peBlue;
3006 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
3007 /* Use the default device palette */
3008 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
3009 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
3010 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
3012 col[n].rgbReserved = 0;
3014 SetDIBColorTable(This->hDC, 0, 256, col);
3020 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
3021 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3022 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
3023 TRACE("(%p)->(%p)\n", This, Pal);
3025 if(This->palette != NULL)
3026 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3027 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
3029 if(PalImpl != NULL) {
3030 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3031 /* Set the device's main palette if the palette
3032 * wasn't a primary palette before
3034 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
3035 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
3038 for(i=0; i < 256; i++) {
3039 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
3043 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
3046 This->palette = PalImpl;
3048 return IWineD3DSurface_RealizePalette(iface);
3051 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
3052 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3053 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
3055 if ((Flags & DDCKEY_COLORSPACE) != 0) {
3056 FIXME(" colorkey value not supported (%08x) !\n", Flags);
3057 return DDERR_INVALIDPARAMS;
3060 /* Dirtify the surface, but only if a key was changed */
3062 switch (Flags & ~DDCKEY_COLORSPACE) {
3063 case DDCKEY_DESTBLT:
3064 This->DestBltCKey = *CKey;
3065 This->CKeyFlags |= DDSD_CKDESTBLT;
3068 case DDCKEY_DESTOVERLAY:
3069 This->DestOverlayCKey = *CKey;
3070 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
3073 case DDCKEY_SRCOVERLAY:
3074 This->SrcOverlayCKey = *CKey;
3075 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
3079 This->SrcBltCKey = *CKey;
3080 This->CKeyFlags |= DDSD_CKSRCBLT;
3085 switch (Flags & ~DDCKEY_COLORSPACE) {
3086 case DDCKEY_DESTBLT:
3087 This->CKeyFlags &= ~DDSD_CKDESTBLT;
3090 case DDCKEY_DESTOVERLAY:
3091 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
3094 case DDCKEY_SRCOVERLAY:
3095 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
3099 This->CKeyFlags &= ~DDSD_CKSRCBLT;
3107 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3108 /** Check against the maximum texture sizes supported by the video card **/
3109 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3111 TRACE("%p\n", This);
3112 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3113 /* one of three options
3114 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)
3115 2: Set the texture to the maxium size (bad idea)
3116 3: WARN and return WINED3DERR_NOTAVAILABLE;
3117 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.
3119 WARN("(%p) Creating an oversized surface\n", This);
3120 This->Flags |= SFLAG_OVERSIZE;
3122 /* This will be initialized on the first blt */
3123 This->glRect.left = 0;
3124 This->glRect.top = 0;
3125 This->glRect.right = 0;
3126 This->glRect.bottom = 0;
3128 /* No oversize, gl rect is the full texture size */
3129 This->Flags &= ~SFLAG_OVERSIZE;
3130 This->glRect.left = 0;
3131 This->glRect.top = 0;
3132 This->glRect.right = This->pow2Width;
3133 This->glRect.bottom = This->pow2Height;
3139 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3140 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3142 TRACE("(%p)\n", This);
3144 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3145 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3146 ie pitch = (width/4) * bytes per block */
3147 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3148 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3149 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3150 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3151 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3153 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3154 /* Surfaces are 32 bit aligned */
3155 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3157 TRACE("(%p) Returning %d\n", This, ret);
3161 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3162 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3164 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3166 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3168 TRACE("(%p): Not an overlay surface\n", This);
3169 return DDERR_NOTAOVERLAYSURFACE;
3175 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3176 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3178 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3180 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3182 TRACE("(%p): Not an overlay surface\n", This);
3183 return DDERR_NOTAOVERLAYSURFACE;
3189 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3190 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3191 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3193 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3195 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3197 TRACE("(%p): Not an overlay surface\n", This);
3198 return DDERR_NOTAOVERLAYSURFACE;
3204 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3205 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3206 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3207 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3209 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3211 TRACE("(%p): Not an overlay surface\n", This);
3212 return DDERR_NOTAOVERLAYSURFACE;
3218 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3221 IWineD3DSurfaceImpl_QueryInterface,
3222 IWineD3DSurfaceImpl_AddRef,
3223 IWineD3DSurfaceImpl_Release,
3224 /* IWineD3DResource */
3225 IWineD3DSurfaceImpl_GetParent,
3226 IWineD3DSurfaceImpl_GetDevice,
3227 IWineD3DSurfaceImpl_SetPrivateData,
3228 IWineD3DSurfaceImpl_GetPrivateData,
3229 IWineD3DSurfaceImpl_FreePrivateData,
3230 IWineD3DSurfaceImpl_SetPriority,
3231 IWineD3DSurfaceImpl_GetPriority,
3232 IWineD3DSurfaceImpl_PreLoad,
3233 IWineD3DSurfaceImpl_GetType,
3234 /* IWineD3DSurface */
3235 IWineD3DSurfaceImpl_GetContainer,
3236 IWineD3DSurfaceImpl_GetDesc,
3237 IWineD3DSurfaceImpl_LockRect,
3238 IWineD3DSurfaceImpl_UnlockRect,
3239 IWineD3DSurfaceImpl_GetDC,
3240 IWineD3DSurfaceImpl_ReleaseDC,
3241 IWineD3DSurfaceImpl_Flip,
3242 IWineD3DSurfaceImpl_Blt,
3243 IWineD3DSurfaceImpl_GetBltStatus,
3244 IWineD3DSurfaceImpl_GetFlipStatus,
3245 IWineD3DSurfaceImpl_IsLost,
3246 IWineD3DSurfaceImpl_Restore,
3247 IWineD3DSurfaceImpl_BltFast,
3248 IWineD3DSurfaceImpl_GetPalette,
3249 IWineD3DSurfaceImpl_SetPalette,
3250 IWineD3DSurfaceImpl_RealizePalette,
3251 IWineD3DSurfaceImpl_SetColorKey,
3252 IWineD3DSurfaceImpl_GetPitch,
3253 IWineD3DSurfaceImpl_SetMem,
3254 IWineD3DSurfaceImpl_SetOverlayPosition,
3255 IWineD3DSurfaceImpl_GetOverlayPosition,
3256 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3257 IWineD3DSurfaceImpl_UpdateOverlay,
3259 IWineD3DSurfaceImpl_CleanDirtyRect,
3260 IWineD3DSurfaceImpl_AddDirtyRect,
3261 IWineD3DSurfaceImpl_LoadTexture,
3262 IWineD3DSurfaceImpl_SaveSnapshot,
3263 IWineD3DSurfaceImpl_SetContainer,
3264 IWineD3DSurfaceImpl_SetPBufferState,
3265 IWineD3DSurfaceImpl_SetGlTextureDesc,
3266 IWineD3DSurfaceImpl_GetGlDesc,
3267 IWineD3DSurfaceImpl_GetData,
3268 IWineD3DSurfaceImpl_SetFormat,
3269 IWineD3DSurfaceImpl_PrivateSetup