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);
250 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
252 TRACE("Deleting texture %d\n", This->glDescription.textureName);
253 glDeleteTextures(1, &This->glDescription.textureName);
257 if(This->Flags & SFLAG_DIBSECTION) {
259 SelectObject(This->hDC, This->dib.holdbitmap);
261 /* Release the DIB section */
262 DeleteObject(This->dib.DIBsection);
263 This->dib.bitmap_data = NULL;
264 This->resource.allocatedMemory = NULL;
266 if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
268 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
269 if(iface == device->ddraw_primary)
270 device->ddraw_primary = NULL;
272 if(iface == device->lastActiveRenderTarget) {
273 device->lastActiveRenderTarget = NULL;
276 TRACE("(%p) Released\n", This);
277 HeapFree(GetProcessHeap(), 0, This);
283 /* ****************************************************
284 IWineD3DSurface IWineD3DResource parts follow
285 **************************************************** */
286 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
287 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
290 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
291 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
294 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
295 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
298 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
299 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
302 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
303 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
306 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
307 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
310 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
311 /* TODO: re-write the way textures and managed,
312 * use a 'opengl context manager' to manage RenderTarget surfaces
313 ** *********************************************************/
315 /* TODO: check for locks */
316 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
317 IWineD3DBaseTexture *baseTexture = NULL;
318 TRACE("(%p)Checking to see if the container is a base texture\n", This);
319 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
320 TRACE("Passing to conatiner\n");
321 IWineD3DBaseTexture_PreLoad(baseTexture);
322 IWineD3DBaseTexture_Release(baseTexture);
324 TRACE("(%p) : About to load surface\n", This);
326 #if 0 /* TODO: context manager support */
327 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
329 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
330 if (!This->glDescription.level) {
331 if (!This->glDescription.textureName) {
332 glGenTextures(1, &This->glDescription.textureName);
333 checkGLcall("glGenTextures");
334 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
336 glBindTexture(This->glDescription.target, This->glDescription.textureName);
337 checkGLcall("glBindTexture");
338 IWineD3DSurface_LoadTexture(iface);
339 /* This is where we should be reducing the amount of GLMemoryUsed */
340 } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
341 /* assume this is a coding error not a real error for now */
342 FIXME("Mipmap surface has a glTexture bound to it!\n");
344 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
345 /* Tell opengl to try and keep this texture in video ram (well mostly) */
348 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
350 /* TODO: disable texture support, if it wastn't enabled when we entered. */
351 #if 0 /* TODO: context manager support */
352 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
353 /* we don't care when the state is disabled(if atall) */);
360 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
361 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
362 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
365 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
366 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
367 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
370 /* ******************************************************
371 IWineD3DSurface IWineD3DSurface parts follow
372 ****************************************************** */
374 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
375 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
376 IWineD3DBase *container = 0;
378 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
381 ERR("Called without a valid ppContainer.\n");
385 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
386 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
387 * GetContainer will return the Direct3D device used to create the surface.
389 if (This->container) {
390 container = This->container;
392 container = (IWineD3DBase *)This->resource.wineD3DDevice;
395 TRACE("Relaying to QueryInterface\n");
396 return IUnknown_QueryInterface(container, riid, ppContainer);
399 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
400 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
402 TRACE("(%p) : copying into %p\n", This, pDesc);
403 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
404 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
405 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
406 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
407 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
408 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
409 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
410 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
411 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
415 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
416 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
417 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
418 if (This->glDescription.textureName == 0 && textureName != 0) {
419 This->Flags |= SFLAG_DIRTY;
420 IWineD3DSurface_AddDirtyRect(iface, NULL);
422 This->glDescription.textureName = textureName;
423 This->glDescription.target = target;
426 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
427 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
428 TRACE("(%p) : returning %p\n", This, &This->glDescription);
429 *glDescription = &This->glDescription;
432 /* TODO: think about moving this down to resource? */
433 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
434 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
435 /* 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 */
436 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
437 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
439 return (CONST void*)(This->resource.allocatedMemory);
442 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch, BOOL srcUpsideDown) {
446 BYTE *row, *top, *bottom;
450 switch(This->resource.format)
454 /* GL can't return palettized data, so read ARGB pixels into a
455 * separate block of memory and convert them into palettized format
456 * in software. Slow, but if the app means to use palettized render
457 * targets and locks it...
459 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
460 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
461 * for the color channels when palettizing the colors.
464 type = GL_UNSIGNED_BYTE;
466 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
468 ERR("Out of memory\n");
471 bpp = This->bytesPerPixel * 3;
477 fmt = This->glDescription.glFormat;
478 type = This->glDescription.glType;
479 bpp = This->bytesPerPixel;
482 glReadPixels(rect->left, rect->top,
483 rect->right - rect->left,
484 rect->bottom - rect->top,
486 vcheckGLcall("glReadPixels");
488 /* TODO: Merge this with the palettization loop below for P8 targets */
492 /* glReadPixels returns the image upside down, and there is no way to prevent this.
493 Flip the lines in software */
494 len = (rect->right - rect->left) * bpp;
495 off = rect->left * bpp;
497 row = HeapAlloc(GetProcessHeap(), 0, len);
499 ERR("Out of memory\n");
500 if(This->resource.format == WINED3DFMT_P8) HeapFree(GetProcessHeap(), 0, mem);
504 top = mem + pitch * rect->top;
505 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
506 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
507 memcpy(row, top + off, len);
508 memcpy(top + off, bottom + off, len);
509 memcpy(bottom + off, row, len);
513 HeapFree(GetProcessHeap(), 0, row);
516 if(This->resource.format == WINED3DFMT_P8) {
518 DWORD width = pitch / 3;
521 pal = This->palette->palents;
523 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
526 for(y = rect->top; y < rect->bottom; y++) {
527 for(x = rect->left; x < rect->right; x++) {
528 /* start lines pixels */
529 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
530 BYTE *green = blue + 1;
531 BYTE *red = green + 1;
533 for(c = 0; c < 256; c++) {
534 if(*red == pal[c].peRed &&
535 *green == pal[c].peGreen &&
536 *blue == pal[c].peBlue)
538 *((BYTE *) dest + y * width + x) = c;
544 HeapFree(GetProcessHeap(), 0, mem);
548 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
549 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
550 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
551 IWineD3DSwapChainImpl *swapchain = NULL;
553 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
555 if (!(This->Flags & SFLAG_LOCKABLE)) {
556 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
557 texture regions, and since the destination is an unlockable region we need
559 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
560 /*return WINED3DERR_INVALIDCALL; */
563 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
565 /* Mark the surface locked */
566 This->Flags |= SFLAG_LOCKED;
568 /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy */
569 if(!This->resource.allocatedMemory) {
570 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + 4);
571 This->Flags |= SFLAG_GLDIRTY; /* This is the marker that surface data has to be downloaded */
574 /* Calculate the correct start address to report */
576 pLockedRect->pBits = This->resource.allocatedMemory;
577 This->lockedRect.left = 0;
578 This->lockedRect.top = 0;
579 This->lockedRect.right = This->currentDesc.Width;
580 This->lockedRect.bottom = This->currentDesc.Height;
581 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);
583 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
585 if ((pRect->top < 0) ||
587 (pRect->left >= pRect->right) ||
588 (pRect->top >= pRect->bottom) ||
589 (pRect->right > This->currentDesc.Width) ||
590 (pRect->bottom > This->currentDesc.Height))
592 WARN(" Invalid values in pRect !!!\n");
593 return D3DERR_INVALIDCALL;
596 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
597 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
599 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
601 This->lockedRect.left = pRect->left;
602 This->lockedRect.top = pRect->top;
603 This->lockedRect.right = pRect->right;
604 This->lockedRect.bottom = pRect->bottom;
607 if (This->Flags & SFLAG_NONPOW2) {
608 TRACE("Locking non-power 2 texture\n");
611 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
612 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
615 if(!(This->Flags & SFLAG_DYNLOCK)) {
617 /* MAXLOCKCOUNT is defined in wined3d_private.h */
618 if(This->lockCount > MAXLOCKCOUNT) {
619 TRACE("Surface is locked regularily, not freeing the system memory copy any more\n");
620 This->Flags |= SFLAG_DYNLOCK;
624 if((Flags & WINED3DLOCK_DISCARD) || !(This->Flags & SFLAG_GLDIRTY) ) {
625 TRACE("WINED3DLOCK_DISCARD flag passed, or local copy is up to date, not downloading data\n");
629 /* Now download the surface content from opengl
630 * Use the render target readback if the surface is on a swapchain(=onscreen render target) or the current primary target
631 * Offscreen targets which are not active at the moment or are higher targets(fbos) can be locked with the texture path
633 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
634 if(swapchain || iface == myDevice->render_targets[0]) {
635 BOOL srcIsUpsideDown;
637 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
638 static BOOL warned = FALSE;
640 ERR("The application tries to lock the render target, but render target locking is disabled\n");
643 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
647 /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
648 * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
649 * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
650 * context->last_was_blit set on the unlock.
653 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
655 /* Select the correct read buffer, and give some debug output.
656 * There is no need to keep track of the current read buffer or reset it, every part of the code
657 * that reads sets the read buffer as desired.
660 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
661 * Read from the back buffer
663 TRACE("Locking offscreen render target\n");
664 glReadBuffer(GL_BACK);
665 srcIsUpsideDown = TRUE;
667 if(iface == swapchain->frontBuffer) {
668 TRACE("Locking the front buffer\n");
669 glReadBuffer(GL_FRONT);
670 } else if(swapchain->backBuffer && iface == swapchain->backBuffer[0]) {
671 TRACE("Locking the back buffer\n");
672 glReadBuffer(GL_BACK);
674 /* Ok, there is an issue: OpenGL does not guarant any back buffer number, so all we can do is to read GL_BACK
675 * and hope it gives what the app wants
677 FIXME("Application is locking a 2nd or higher back buffer\n");
678 glReadBuffer(GL_BACK);
680 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
681 srcIsUpsideDown = FALSE;
684 switch(wined3d_settings.rendertargetlock_mode) {
688 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
693 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
694 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
699 /* Mark the local copy up to date if a full download was done */
700 if(This->lockedRect.left == 0 &&
701 This->lockedRect.top == 0 &&
702 This->lockedRect.right == This->currentDesc.Width &&
703 This->lockedRect.bottom == This->currentDesc.Height) {
704 This->Flags &= ~SFLAG_GLDIRTY;
706 } else if(iface == myDevice->stencilBufferTarget) {
707 /** the depth stencil in openGL has a format of GL_FLOAT
708 * which should be good for WINED3DFMT_D16_LOCKABLE
710 * it is unclear what format the stencil buffer is in except.
711 * 'Each index is converted to fixed point...
712 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
713 * mappings in the table GL_PIXEL_MAP_S_TO_S.
714 * glReadPixels(This->lockedRect.left,
715 * This->lockedRect.bottom - j - 1,
716 * This->lockedRect.right - This->lockedRect.left,
718 * GL_DEPTH_COMPONENT,
720 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
722 * Depth Stencil surfaces which are not the current depth stencil target should have their data in a
723 * gl texture(next path), or in local memory(early return because of missing SFLAG_GLDIRTY above). If
724 * none of that is the case the problem is not in this function :-)
725 ********************************************/
726 FIXME("Depth stencil locking not supported yet\n");
728 /* This path is for normal surfaces, offscreen render targets and everything else that is in a gl texture */
729 TRACE("locking an ordinarary surface\n");
731 /* TODO: Make sure that *any* context is active for this thread. It is not important which context that is,
732 * nor that is has any special setup(CTXUSAGE_LOADRESOURCE is fine), but the code below needs a context.
733 * A context is guaranted to be there in a single threaded environment, but not with multithreading
735 if (0 != This->glDescription.textureName) {
736 /* Now I have to copy thing bits back */
738 /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
739 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
741 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
742 checkGLcall("glActiveTextureARB");
745 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
746 IWineD3DSurface_PreLoad(iface);
748 surface_download_data(This);
751 /* The local copy is now up to date to the opengl one because a full download was done */
752 This->Flags &= ~SFLAG_GLDIRTY;
756 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
759 IWineD3DBaseTexture *pBaseTexture;
762 * as seen in msdn docs
764 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
766 /** Dirtify Container if needed */
767 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
768 TRACE("Making container dirty\n");
769 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
770 IWineD3DBaseTexture_Release(pBaseTexture);
772 TRACE("Surface is standalone, no need to dirty the container\n");
776 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
780 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
782 GLint prev_rasterpos[4];
784 BOOL storechanged = FALSE, memory_allocated = FALSE;
788 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
790 glDisable(GL_TEXTURE_2D);
791 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
794 vcheckGLcall("glFlush");
795 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
796 vcheckGLcall("glIntegerv");
797 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
798 vcheckGLcall("glIntegerv");
799 glPixelZoom(1.0, -1.0);
800 vcheckGLcall("glPixelZoom");
802 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
803 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
804 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
806 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
807 vcheckGLcall("glRasterPos2f");
809 /* Some drivers(radeon dri, others?) don't like exceptions during
810 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
811 * after ReleaseDC. Reading it will cause an exception, which x11drv will
812 * catch to put the dib section in InSync mode, which leads to a crash
813 * and a blocked x server on my radeon card.
815 * The following lines read the dib section so it is put in inSync mode
816 * before glDrawPixels is called and the crash is prevented. There won't
817 * be any interfering gdi accesses, because UnlockRect is called from
818 * ReleaseDC, and the app won't use the dc any more afterwards.
820 if(This->Flags & SFLAG_DIBSECTION) {
822 read = This->resource.allocatedMemory[0];
825 switch (This->resource.format) {
826 /* No special care needed */
827 case WINED3DFMT_A4R4G4B4:
828 case WINED3DFMT_R5G6B5:
829 case WINED3DFMT_A1R5G5B5:
830 case WINED3DFMT_R8G8B8:
831 type = This->glDescription.glType;
832 fmt = This->glDescription.glFormat;
833 mem = This->resource.allocatedMemory;
834 bpp = This->bytesPerPixel;
837 case WINED3DFMT_X4R4G4B4:
840 unsigned short *data;
841 data = (unsigned short *)This->resource.allocatedMemory;
842 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
848 type = This->glDescription.glType;
849 fmt = This->glDescription.glFormat;
850 mem = This->resource.allocatedMemory;
851 bpp = This->bytesPerPixel;
855 case WINED3DFMT_X1R5G5B5:
858 unsigned short *data;
859 data = (unsigned short *)This->resource.allocatedMemory;
860 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
866 type = This->glDescription.glType;
867 fmt = This->glDescription.glFormat;
868 mem = This->resource.allocatedMemory;
869 bpp = This->bytesPerPixel;
873 case WINED3DFMT_X8R8G8B8:
875 /* make sure the X byte is set to alpha on, since it
876 could be any random value. This fixes the intro movie in Pirates! */
879 data = (unsigned int *)This->resource.allocatedMemory;
880 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
889 case WINED3DFMT_A8R8G8B8:
891 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
892 vcheckGLcall("glPixelStorei");
894 type = This->glDescription.glType;
895 fmt = This->glDescription.glFormat;
896 mem = This->resource.allocatedMemory;
897 bpp = This->bytesPerPixel;
901 case WINED3DFMT_A2R10G10B10:
903 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
904 vcheckGLcall("glPixelStorei");
906 type = This->glDescription.glType;
907 fmt = This->glDescription.glFormat;
908 mem = This->resource.allocatedMemory;
909 bpp = This->bytesPerPixel;
915 int height = This->glRect.bottom - This->glRect.top;
916 type = GL_UNSIGNED_BYTE;
919 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
921 ERR("Out of memory\n");
924 memory_allocated = TRUE;
925 d3dfmt_convert_surface(This->resource.allocatedMemory,
933 bpp = This->bytesPerPixel * 4;
939 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
942 type = This->glDescription.glType;
943 fmt = This->glDescription.glFormat;
944 mem = This->resource.allocatedMemory;
945 bpp = This->bytesPerPixel;
948 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
949 (This->lockedRect.bottom - This->lockedRect.top)-1,
951 mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
952 checkGLcall("glDrawPixels");
953 glPixelZoom(1.0,1.0);
954 vcheckGLcall("glPixelZoom");
956 glRasterPos3iv(&prev_rasterpos[0]);
957 vcheckGLcall("glRasterPos3iv");
959 /* Reset to previous pack row length */
960 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
961 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
963 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
964 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
967 /* Blitting environment requires that 2D texturing is enabled. It was turned off before,
970 glEnable(GL_TEXTURE_2D);
971 checkGLcall("glEnable(GL_TEXTURE_2D)");
973 if(memory_allocated) HeapFree(GetProcessHeap(), 0, mem);
977 static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl *This) {
980 glTexCoord[0] = (float) This->lockedRect.left / (float) This->pow2Width; /* left */
981 glTexCoord[1] = (float) This->lockedRect.right / (float) This->pow2Width; /* right */
982 glTexCoord[2] = (float) This->lockedRect.top / (float) This->pow2Height; /* top */
983 glTexCoord[3] = (float) This->lockedRect.bottom / (float) This->pow2Height; /* bottom */
985 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
989 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
990 checkGLcall("glEnable glBindTexture");
992 /* No filtering for blts */
993 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
994 checkGLcall("glTexParameteri");
995 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
996 checkGLcall("glTexParameteri");
998 /* Start drawing a quad */
1001 glColor3d(1.0f, 1.0f, 1.0f);
1002 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1003 glVertex3f(This->lockedRect.left, This->lockedRect.top, 0.0);
1005 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1006 glVertex3f(This->lockedRect.left, This->lockedRect.bottom, 0.0);
1008 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1009 glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.0);
1011 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1012 glVertex3f(This->lockedRect.right, This->lockedRect.top, 0.0);
1015 checkGLcall("glEnd");
1017 /* Unbind the texture */
1018 glBindTexture(GL_TEXTURE_2D, 0);
1019 checkGLcall("glEnable glBindTexture");
1024 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1025 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1026 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1027 IWineD3DSwapChainImpl *swapchain = NULL;
1029 if (!(This->Flags & SFLAG_LOCKED)) {
1030 WARN("trying to Unlock an unlocked surf@%p\n", This);
1031 return WINED3DERR_INVALIDCALL;
1034 TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0);
1036 if (!(This->Flags & SFLAG_DIRTY)) {
1037 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1041 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1042 if(swapchain || iface == myDevice->render_targets[0]) {
1043 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1044 static BOOL warned = FALSE;
1046 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1049 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1053 /* Activate the correct context for the render target */
1055 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
1058 /* Primary offscreen render target */
1059 TRACE("Offscreen render target\n");
1060 glDrawBuffer(GL_BACK);
1061 checkGLcall("glDrawBuffer(GL_BACK)");
1063 if(iface == swapchain->frontBuffer) {
1064 TRACE("Onscreen front buffer\n");
1065 glDrawBuffer(GL_FRONT);
1066 checkGLcall("glDrawBuffer(GL_FRONT)");
1067 } else if(iface == swapchain->backBuffer[0]) {
1068 TRACE("Onscreen back buffer\n");
1069 glDrawBuffer(GL_BACK);
1070 checkGLcall("glDrawBuffer(GL_BACK)");
1072 FIXME("Unlocking a higher back buffer\n");
1073 glDrawBuffer(GL_BACK);
1074 checkGLcall("glDrawBuffer(GL_BACK)");
1076 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1079 switch(wined3d_settings.rendertargetlock_mode) {
1083 flush_to_framebuffer_drawpixels(This);
1088 flush_to_framebuffer_texture(This);
1091 if(!swapchain || swapchain->backBuffer) {
1092 glDrawBuffer(GL_BACK);
1093 checkGLcall("glDrawBuffer(GL_BACK)");
1095 glDrawBuffer(GL_FRONT);
1096 checkGLcall("glDrawBuffer(GL_FRONT)");
1100 /** restore clean dirty state */
1101 IWineD3DSurface_CleanDirtyRect(iface);
1102 } else if(iface == myDevice->stencilBufferTarget) {
1103 FIXME("Depth Stencil buffer locking is not implemented\n");
1105 /* The rest should be a normal texture */
1106 IWineD3DBaseTextureImpl *impl;
1107 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1108 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1109 * states need resetting
1111 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1112 if(impl->baseTexture.bindCount) {
1113 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1115 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1120 This->Flags &= ~SFLAG_LOCKED;
1121 memset(&This->lockedRect, 0, sizeof(RECT));
1125 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1126 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1127 WINED3DLOCKED_RECT lock;
1134 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1136 TRACE("(%p)->(%p)\n",This,pHDC);
1138 if(This->Flags & SFLAG_USERPTR) {
1139 ERR("Not supported on surfaces with an application-provided surfaces\n");
1143 /* Give more detailed info for ddraw */
1144 if (This->Flags & SFLAG_DCINUSE)
1145 return DDERR_DCALREADYCREATED;
1147 /* Can't GetDC if the surface is locked */
1148 if (This->Flags & SFLAG_LOCKED)
1149 return WINED3DERR_INVALIDCALL;
1151 memset(&lock, 0, sizeof(lock)); /* To be sure */
1153 /* Create a DIB section if there isn't a hdc yet */
1156 SYSTEM_INFO sysInfo;
1158 switch (This->bytesPerPixel) {
1161 /* Allocate extra space to store the RGB bit masks. */
1162 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1166 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1170 /* Allocate extra space for a palette. */
1171 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1172 sizeof(BITMAPINFOHEADER)
1174 * (1 << (This->bytesPerPixel * 8)));
1179 return E_OUTOFMEMORY;
1181 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1182 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1183 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1184 * add an extra line to the dib section
1186 GetSystemInfo(&sysInfo);
1187 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1189 TRACE("Adding an extra line to the dib section\n");
1192 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1193 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1194 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1195 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1196 b_info->bmiHeader.biPlanes = 1;
1197 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1199 b_info->bmiHeader.biXPelsPerMeter = 0;
1200 b_info->bmiHeader.biYPelsPerMeter = 0;
1201 b_info->bmiHeader.biClrUsed = 0;
1202 b_info->bmiHeader.biClrImportant = 0;
1204 /* Get the bit masks */
1205 masks = (DWORD *) &(b_info->bmiColors);
1206 switch (This->resource.format) {
1207 case WINED3DFMT_R8G8B8:
1208 usage = DIB_RGB_COLORS;
1209 b_info->bmiHeader.biCompression = BI_RGB;
1212 case WINED3DFMT_X1R5G5B5:
1213 case WINED3DFMT_A1R5G5B5:
1214 case WINED3DFMT_A4R4G4B4:
1215 case WINED3DFMT_X4R4G4B4:
1216 case WINED3DFMT_R3G3B2:
1217 case WINED3DFMT_A8R3G3B2:
1218 case WINED3DFMT_A2B10G10R10:
1219 case WINED3DFMT_A8B8G8R8:
1220 case WINED3DFMT_X8B8G8R8:
1221 case WINED3DFMT_A2R10G10B10:
1222 case WINED3DFMT_R5G6B5:
1223 case WINED3DFMT_A16B16G16R16:
1225 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1226 masks[0] = formatEntry->redMask;
1227 masks[1] = formatEntry->greenMask;
1228 masks[2] = formatEntry->blueMask;
1232 /* Don't know palette */
1233 b_info->bmiHeader.biCompression = BI_RGB;
1240 HeapFree(GetProcessHeap(), 0, b_info);
1241 return HRESULT_FROM_WIN32(GetLastError());
1244 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);
1245 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1248 if (!This->dib.DIBsection) {
1249 ERR("CreateDIBSection failed!\n");
1250 HeapFree(GetProcessHeap(), 0, b_info);
1251 return HRESULT_FROM_WIN32(GetLastError());
1254 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1256 /* copy the existing surface to the dib section */
1257 if(This->resource.allocatedMemory) {
1258 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1259 /* We won't need that any more */
1260 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1262 /* This is to make LockRect read the gl Texture although memory is allocated */
1263 This->Flags |= SFLAG_GLDIRTY;
1266 HeapFree(GetProcessHeap(), 0, b_info);
1268 /* Use the dib section from now on */
1269 This->resource.allocatedMemory = This->dib.bitmap_data;
1271 /* Now allocate a HDC */
1272 This->hDC = CreateCompatibleDC(0);
1273 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1274 TRACE("using wined3d palette %p\n", This->palette);
1275 SelectPalette(This->hDC,
1276 This->palette ? This->palette->hpal : 0,
1279 This->Flags |= SFLAG_DIBSECTION;
1282 /* Lock the surface */
1283 hr = IWineD3DSurface_LockRect(iface,
1288 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1289 /* keep the dib section */
1293 if(This->resource.format == WINED3DFMT_P8 ||
1294 This->resource.format == WINED3DFMT_A8P8) {
1297 PALETTEENTRY ent[256];
1299 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1300 for (n=0; n<256; n++) {
1301 col[n].rgbRed = ent[n].peRed;
1302 col[n].rgbGreen = ent[n].peGreen;
1303 col[n].rgbBlue = ent[n].peBlue;
1304 col[n].rgbReserved = 0;
1307 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1309 for (n=0; n<256; n++) {
1310 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1311 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1312 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1313 col[n].rgbReserved = 0;
1317 SetDIBColorTable(This->hDC, 0, 256, col);
1321 TRACE("returning %p\n",*pHDC);
1322 This->Flags |= SFLAG_DCINUSE;
1327 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1328 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1330 TRACE("(%p)->(%p)\n",This,hDC);
1332 if (!(This->Flags & SFLAG_DCINUSE))
1333 return D3DERR_INVALIDCALL;
1335 /* we locked first, so unlock now */
1336 IWineD3DSurface_UnlockRect(iface);
1338 This->Flags &= ~SFLAG_DCINUSE;
1343 /* ******************************************************
1344 IWineD3DSurface Internal (No mapping to directx api) parts follow
1345 ****************************************************** */
1347 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) {
1348 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1349 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1351 /* Default values: From the surface */
1352 *format = formatEntry->glFormat;
1353 *internal = formatEntry->glInternal;
1354 *type = formatEntry->glType;
1355 *convert = NO_CONVERSION;
1356 *target_bpp = This->bytesPerPixel;
1358 /* Ok, now look if we have to do any conversion */
1359 switch(This->resource.format) {
1364 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1365 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1367 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1369 *internal = GL_RGBA;
1370 *type = GL_UNSIGNED_BYTE;
1372 if(colorkey_active) {
1373 *convert = CONVERT_PALETTED_CK;
1375 *convert = CONVERT_PALETTED;
1381 case WINED3DFMT_R3G3B2:
1382 /* **********************
1383 GL_UNSIGNED_BYTE_3_3_2
1384 ********************** */
1385 if (colorkey_active) {
1386 /* This texture format will never be used.. So do not care about color keying
1387 up until the point in time it will be needed :-) */
1388 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1392 case WINED3DFMT_R5G6B5:
1393 if (colorkey_active) {
1394 *convert = CONVERT_CK_565;
1396 *internal = GL_RGBA;
1397 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1401 case WINED3DFMT_R8G8B8:
1402 if (colorkey_active) {
1403 *convert = CONVERT_CK_RGB24;
1405 *internal = GL_RGBA;
1406 *type = GL_UNSIGNED_INT_8_8_8_8;
1411 case WINED3DFMT_X8R8G8B8:
1412 if (colorkey_active) {
1413 *convert = CONVERT_RGB32_888;
1415 *internal = GL_RGBA;
1416 *type = GL_UNSIGNED_INT_8_8_8_8;
1420 case WINED3DFMT_V8U8:
1421 *convert = CONVERT_V8U8;
1423 *internal = GL_RGB8;
1435 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1436 BYTE *source, *dest;
1437 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1442 memcpy(dst, src, pitch * height);
1445 case CONVERT_PALETTED:
1446 case CONVERT_PALETTED_CK:
1448 IWineD3DPaletteImpl* pal = surf->palette;
1454 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1458 /* Still no palette? Use the device's palette */
1459 /* Get the surface's palette */
1460 for (i = 0; i < 256; i++) {
1461 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1463 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1464 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1465 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1466 if ((convert == CONVERT_PALETTED_CK) &&
1467 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1468 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1469 /* We should maybe here put a more 'neutral' color than the standard bright purple
1470 one often used by application to prevent the nice purple borders when bi-linear
1478 TRACE("Using surface palette %p\n", pal);
1479 /* Get the surface's palette */
1480 for (i = 0; i < 256; i++) {
1481 table[i][0] = pal->palents[i].peRed;
1482 table[i][1] = pal->palents[i].peGreen;
1483 table[i][2] = pal->palents[i].peBlue;
1484 if ((convert == CONVERT_PALETTED_CK) &&
1485 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1486 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1487 /* We should maybe here put a more 'neutral' color than the standard bright purple
1488 one often used by application to prevent the nice purple borders when bi-linear
1497 for (y = 0; y < height; y++)
1499 source = src + pitch * y;
1500 dest = dst + outpitch * y;
1501 /* This is an 1 bpp format, using the width here is fine */
1502 for (x = 0; x < width; x++) {
1503 BYTE color = *source++;
1504 *dest++ = table[color][0];
1505 *dest++ = table[color][1];
1506 *dest++ = table[color][2];
1507 *dest++ = table[color][3];
1513 case CONVERT_CK_565:
1515 /* Converting the 565 format in 5551 packed to emulate color-keying.
1517 Note : in all these conversion, it would be best to average the averaging
1518 pixels to get the color of the pixel that will be color-keyed to
1519 prevent 'color bleeding'. This will be done later on if ever it is
1522 Note2: Nvidia documents say that their driver does not support alpha + color keying
1523 on the same surface and disables color keying in such a case
1529 TRACE("Color keyed 565\n");
1531 for (y = 0; y < height; y++) {
1532 Source = (WORD *) (src + y * pitch);
1533 Dest = (WORD *) (dst + y * outpitch);
1534 for (x = 0; x < width; x++ ) {
1535 WORD color = *Source++;
1536 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1537 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1538 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1552 for(y = 0; y < height; y++) {
1553 Source = (short *) (src + y * pitch);
1554 Dest = (char *) (dst + y * outpitch);
1555 for (x = 0; x < width; x++ ) {
1556 long color = (*Source++);
1557 Dest[0] = color >> 8;
1567 ERR("Unsupported conversation type %d\n", convert);
1572 /* This function is used in case of 8bit paletted textures to upload the palette.
1573 For now it only supports GL_EXT_paletted_texture extension but support for other
1574 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1576 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1577 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1578 IWineD3DPaletteImpl* pal = This->palette;
1583 /* Still no palette? Use the device's palette */
1584 /* Get the surface's palette */
1585 for (i = 0; i < 256; i++) {
1586 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1588 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1589 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1590 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1591 if ((convert == CONVERT_PALETTED_CK) &&
1592 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1593 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1594 /* We should maybe here put a more 'neutral' color than the standard bright purple
1595 one often used by application to prevent the nice purple borders when bi-linear
1603 TRACE("Using surface palette %p\n", pal);
1604 /* Get the surface's palette */
1605 for (i = 0; i < 256; i++) {
1606 table[i][0] = pal->palents[i].peRed;
1607 table[i][1] = pal->palents[i].peGreen;
1608 table[i][2] = pal->palents[i].peBlue;
1609 if ((convert == CONVERT_PALETTED_CK) &&
1610 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1611 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1612 /* We should maybe here put a more 'neutral' color than the standard bright purple
1613 one often used by application to prevent the nice purple borders when bi-linear
1621 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1624 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1625 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1626 GLenum format, internal, type;
1627 CONVERT_TYPES convert;
1629 int width, pitch, outpitch;
1632 if (This->Flags & SFLAG_INTEXTURE) {
1633 TRACE("Surface already in texture\n");
1636 if (This->Flags & SFLAG_DIRTY) {
1637 TRACE("Reloading because surface is dirty\n");
1638 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1639 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1640 /* Reload: vice versa OR */
1641 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1642 /* Also reload: Color key is active AND the color key has changed */
1643 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1644 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1645 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1646 TRACE("Reloading because of color keying\n");
1648 TRACE("surface isn't dirty\n");
1652 This->Flags &= ~SFLAG_DIRTY;
1654 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1655 * These resources are not bound by device size or format restrictions. Because of this,
1656 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1657 * However, these resources can always be created, locked, and copied.
1659 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1661 FIXME("(%p) Operation not supported for scratch textures\n",This);
1662 return WINED3DERR_INVALIDCALL;
1665 if (This->Flags & SFLAG_INPBUFFER) {
1666 if (This->glDescription.level != 0)
1667 FIXME("Surface in texture is only supported for level 0\n");
1668 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1669 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1670 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1671 This->resource.format == WINED3DFMT_DXT5)
1672 FIXME("Format %d not supported\n", This->resource.format);
1678 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1679 vcheckGLcall("glGetIntegerv");
1680 glReadBuffer(GL_BACK);
1681 vcheckGLcall("glReadBuffer");
1683 glCopyTexImage2D(This->glDescription.target,
1684 This->glDescription.level,
1685 This->glDescription.glFormatInternal,
1688 This->currentDesc.Width,
1689 This->currentDesc.Height,
1692 checkGLcall("glCopyTexImage2D");
1693 glReadBuffer(prevRead);
1694 vcheckGLcall("glReadBuffer");
1698 TRACE("Updating target %d\n", This->glDescription.target);
1699 This->Flags |= SFLAG_INTEXTURE;
1704 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1705 This->Flags |= SFLAG_GLCKEY;
1706 This->glCKey = This->SrcBltCKey;
1708 else This->Flags &= ~SFLAG_GLCKEY;
1710 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1712 /* The width is in 'length' not in bytes */
1713 width = This->currentDesc.Width;
1714 pitch = IWineD3DSurface_GetPitch(iface);
1716 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1717 int height = This->glRect.bottom - This->glRect.top;
1719 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1720 outpitch = width * bpp;
1721 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1723 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1725 ERR("Out of memory %d, %d!\n", outpitch, height);
1726 return WINED3DERR_OUTOFVIDEOMEMORY;
1728 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1730 This->Flags |= SFLAG_CONVERTED;
1731 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1732 d3dfmt_p8_upload_palette(iface, convert);
1733 This->Flags &= ~SFLAG_CONVERTED;
1734 mem = This->resource.allocatedMemory;
1736 This->Flags &= ~SFLAG_CONVERTED;
1737 mem = This->resource.allocatedMemory;
1740 /* Make sure the correct pitch is used */
1741 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1743 if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1744 TRACE("non power of two support\n");
1745 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1747 surface_upload_data(This, This->currentDesc.Width, This->currentDesc.Height, format, type, mem);
1750 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1752 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1756 /* Restore the default pitch */
1757 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1759 if (mem != This->resource.allocatedMemory)
1760 HeapFree(GetProcessHeap(), 0, mem);
1764 static unsigned int gen = 0;
1767 if ((gen % 10) == 0) {
1768 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1769 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1772 * debugging crash code
1781 if (!(This->Flags & SFLAG_DONOTFREE)) {
1782 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1783 This->resource.allocatedMemory = NULL;
1791 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1794 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1795 char *allocatedMemory;
1797 IWineD3DSwapChain *swapChain = NULL;
1799 GLuint tmpTexture = 0;
1802 Textures my not be stored in ->allocatedgMemory and a GlTexture
1803 so we should lock the surface before saving a snapshot, or at least check that
1805 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1806 by calling GetTexImage and in compressed form by calling
1807 GetCompressedTexImageARB. Queried compressed images can be saved and
1808 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1809 texture images do not need to be processed by the GL and should
1810 significantly improve texture loading performance relative to uncompressed
1813 /* Setup the width and height to be the internal texture width and height. */
1814 width = This->pow2Width;
1815 height = This->pow2Height;
1816 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1817 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1819 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1820 /* 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 */
1823 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1824 glEnable(GL_TEXTURE_2D);
1826 glGenTextures(1, &tmpTexture);
1827 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1829 glTexImage2D(GL_TEXTURE_2D,
1836 GL_UNSIGNED_INT_8_8_8_8_REV,
1839 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1840 vcheckGLcall("glGetIntegerv");
1841 glReadBuffer(GL_BACK);
1842 vcheckGLcall("glReadBuffer");
1843 glCopyTexImage2D(GL_TEXTURE_2D,
1852 checkGLcall("glCopyTexImage2D");
1853 glReadBuffer(prevRead);
1856 } else { /* bind the real texture */
1857 IWineD3DSurface_PreLoad(iface);
1859 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1861 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1862 glGetTexImage(GL_TEXTURE_2D,
1863 This->glDescription.level,
1865 GL_UNSIGNED_INT_8_8_8_8_REV,
1867 checkGLcall("glTexImage2D");
1869 glBindTexture(GL_TEXTURE_2D, 0);
1870 glDeleteTextures(1, &tmpTexture);
1874 f = fopen(filename, "w+");
1876 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1877 return WINED3DERR_INVALIDCALL;
1879 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1880 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1895 fwrite(&width,2,1,f);
1897 fwrite(&height,2,1,f);
1902 /* 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*/
1904 textureRow = allocatedMemory + (width * (height - 1) *4);
1906 textureRow = allocatedMemory;
1907 for (y = 0 ; y < height; y++) {
1908 for (i = 0; i < width; i++) {
1909 color = *((DWORD*)textureRow);
1910 fputc((color >> 16) & 0xFF, f); /* B */
1911 fputc((color >> 8) & 0xFF, f); /* G */
1912 fputc((color >> 0) & 0xFF, f); /* R */
1913 fputc((color >> 24) & 0xFF, f); /* A */
1916 /* take two rows of the pointer to the texture memory */
1918 (textureRow-= width << 3);
1921 TRACE("Closing file\n");
1925 IWineD3DSwapChain_Release(swapChain);
1927 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1931 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1932 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1933 This->Flags &= ~SFLAG_DIRTY;
1934 This->dirtyRect.left = This->currentDesc.Width;
1935 This->dirtyRect.top = This->currentDesc.Height;
1936 This->dirtyRect.right = 0;
1937 This->dirtyRect.bottom = 0;
1938 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1939 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1944 * Slightly inefficient way to handle multiple dirty rects but it works :)
1946 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1947 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1948 IWineD3DBaseTexture *baseTexture = NULL;
1949 This->Flags |= SFLAG_DIRTY;
1950 if (NULL != pDirtyRect) {
1951 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1952 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1953 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1954 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1956 This->dirtyRect.left = 0;
1957 This->dirtyRect.top = 0;
1958 This->dirtyRect.right = This->currentDesc.Width;
1959 This->dirtyRect.bottom = This->currentDesc.Height;
1961 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
1962 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1963 /* if the container is a basetexture then mark it dirty. */
1964 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1965 TRACE("Passing to conatiner\n");
1966 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1967 IWineD3DBaseTexture_Release(baseTexture);
1972 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1973 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1975 TRACE("This %p, container %p\n", This, container);
1977 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1979 TRACE("Setting container to %p from %p\n", container, This->container);
1980 This->container = container;
1985 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1986 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1987 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
1989 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1990 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1991 return WINED3DERR_INVALIDCALL;
1994 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1995 if (format == WINED3DFMT_UNKNOWN) {
1996 This->resource.size = 0;
1997 } else if (format == WINED3DFMT_DXT1) {
1998 /* DXT1 is half byte per pixel */
1999 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2001 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2002 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2003 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2005 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
2006 This->resource.size *= This->pow2Height;
2010 /* Setup some glformat defaults */
2011 This->glDescription.glFormat = formatEntry->glFormat;
2012 This->glDescription.glFormatInternal = formatEntry->glInternal;
2013 This->glDescription.glType = formatEntry->glType;
2015 if (format != WINED3DFMT_UNKNOWN) {
2016 This->bytesPerPixel = formatEntry->bpp;
2018 This->bytesPerPixel = 0;
2021 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2023 This->resource.format = format;
2025 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);
2030 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2031 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2033 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2034 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2035 ERR("Not supported on render targets\n");
2036 return WINED3DERR_INVALIDCALL;
2039 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2040 WARN("Surface is locked or the HDC is in use\n");
2041 return WINED3DERR_INVALIDCALL;
2044 if(Mem && Mem != This->resource.allocatedMemory) {
2046 /* Do I have to copy the old surface content? */
2047 if(This->Flags & SFLAG_DIBSECTION) {
2048 /* Release the DC. No need to hold the critical section for the update
2049 * Thread because this thread runs only on front buffers, but this method
2050 * fails for render targets in the check above.
2052 SelectObject(This->hDC, This->dib.holdbitmap);
2053 DeleteDC(This->hDC);
2054 /* Release the DIB section */
2055 DeleteObject(This->dib.DIBsection);
2056 This->dib.bitmap_data = NULL;
2057 This->resource.allocatedMemory = NULL;
2059 This->Flags &= ~SFLAG_DIBSECTION;
2060 } else if(!(This->Flags & SFLAG_USERPTR)) {
2061 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2063 This->resource.allocatedMemory = Mem;
2064 This->Flags |= SFLAG_USERPTR;
2065 } else if(This->Flags & SFLAG_USERPTR) {
2066 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2067 This->resource.allocatedMemory = NULL;
2068 This->Flags &= ~SFLAG_USERPTR;
2073 /* TODO: replace this function with context management routines */
2074 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2075 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2078 This->Flags |= SFLAG_INPBUFFER;
2080 This->Flags &= ~SFLAG_INPBUFFER;
2084 This->Flags |= SFLAG_INTEXTURE;
2086 This->Flags &= ~SFLAG_INTEXTURE;
2092 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2093 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2094 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2095 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2097 /* Flipping is only supported on RenderTargets */
2098 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2101 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2102 * FIXME("(%p) Target override is not supported by now\n", This);
2103 * Additionally, it isn't really possible to support triple-buffering
2104 * properly on opengl at all
2108 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2109 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2112 /* Does a direct frame buffer -> texture copy. Stretching is done
2113 * with single pixel copy calls
2115 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2116 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2119 BOOL warned = FALSE; /* deliberately not static */
2120 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2124 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2126 /* Bind the target texture */
2127 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2128 checkGLcall("glBindTexture");
2129 if(!swapchain || (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0])) {
2130 glReadBuffer(GL_BACK);
2132 glReadBuffer(GL_FRONT);
2134 checkGLcall("glReadBuffer");
2136 xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1);
2137 yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1);
2139 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2140 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2144 !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) &&
2145 !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2146 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2148 glCopyTexSubImage2D(This->glDescription.target,
2149 This->glDescription.level,
2150 drect->x1, drect->y1, /* xoffset, yoffset */
2151 srect->x1, Src->currentDesc.Height - srect->y2,
2152 drect->x2 - drect->x1, drect->y2 - drect->y1);
2154 UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1;
2155 /* I have to process this row by row to swap the image,
2156 * otherwise it would be upside down, so streching in y direction
2157 * doesn't cost extra time
2159 * However, streching in x direction can be avoided if not necessary
2161 for(row = drect->y1; row < drect->y2; row++) {
2162 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2163 /* Well, that stuff works, but it's very slow.
2164 * find a better way instead
2170 FIXME("Doing a pixel by pixel render target -> texture copy, expect performance issues\n");
2173 for(col = drect->x1; col < drect->x2; col++) {
2174 glCopyTexSubImage2D(This->glDescription.target,
2175 This->glDescription.level,
2176 drect->x1 + col, row, /* xoffset, yoffset */
2177 srect->x1 + col * xrel, yoffset - (int) (row * yrel),
2181 glCopyTexSubImage2D(This->glDescription.target,
2182 This->glDescription.level,
2183 drect->x1, row, /* xoffset, yoffset */
2184 srect->x1, yoffset - (int) (row * yrel),
2185 drect->x2-drect->x1, 1);
2190 vcheckGLcall("glCopyTexSubImage2D");
2194 /* Uses the hardware to stretch and flip the image */
2195 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2197 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2198 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2199 float left, right, top, bottom; /* Texture coordinates */
2200 UINT fbwidth = Src->currentDesc.Width;
2201 UINT fbheight = Src->currentDesc.Height;
2203 TRACE("Using hwstretch blit\n");
2204 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2206 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2208 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2209 * we are reading from the back buffer, the backup can be used as source texture
2211 glGenTextures(1, &backup);
2212 checkGLcall("glGenTextures(1, &backup)");
2213 glBindTexture(GL_TEXTURE_2D, backup);
2214 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
2216 glReadBuffer(GL_BACK);
2217 checkGLcall("glReadBuffer(GL_BACK)");
2219 /* TODO: Only back up the part that will be overwritten */
2220 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2221 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2222 checkGLcall("glTexImage2D");
2224 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2225 0, 0 /* read offsets */,
2230 checkGLcall("glCopyTexSubImage2D");
2232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2233 checkGLcall("glTexParameteri");
2234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2235 checkGLcall("glTexParameteri");
2237 if(!swapchain || (IWineD3DSurface *) This == swapchain->backBuffer[0]) {
2240 glReadBuffer(GL_FRONT);
2241 checkGLcall("glReadBuffer(GL_FRONT)");
2243 glGenTextures(1, &src);
2244 checkGLcall("glGenTextures(1, &src)");
2245 glBindTexture(GL_TEXTURE_2D, src);
2246 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
2248 /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
2249 * out for power of 2 sizes
2251 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2252 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2253 checkGLcall("glTexImage2D");
2254 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2255 0, 0 /* read offsets */,
2260 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2261 checkGLcall("glTexParameteri");
2262 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2263 checkGLcall("glTexParameteri");
2265 glReadBuffer(GL_BACK);
2266 checkGLcall("glReadBuffer(GL_BACK)");
2268 checkGLcall("glEnd and previous");
2270 left = (float) srect->x1 / (float) Src->pow2Width;
2271 right = (float) srect->x2 / (float) Src->pow2Width;
2274 top = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2275 bottom = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2277 top = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2278 bottom = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2281 /* draw the source texture stretched and upside down. The correct surface is bound already */
2282 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2283 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2287 glTexCoord2f(left, bottom);
2288 glVertex2i(0, fbheight);
2291 glTexCoord2f(left, top);
2292 glVertex2i(0, fbheight - drect->y2 - drect->y1);
2295 glTexCoord2f(right, top);
2296 glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1);
2299 glTexCoord2f(right, bottom);
2300 glVertex2i(drect->x2 - drect->x1, fbheight);
2302 checkGLcall("glEnd and previous");
2304 /* Now read the stretched and upside down image into the destination texture */
2305 glBindTexture(This->glDescription.target, This->glDescription.textureName);
2306 checkGLcall("glBindTexture");
2307 glCopyTexSubImage2D(This->glDescription.target,
2309 drect->x1, drect->y1, /* xoffset, yoffset */
2310 0, 0, /* We blitted the image to the origin */
2311 drect->x2 - drect->x1, drect->y2 - drect->y1);
2312 checkGLcall("glCopyTexSubImage2D");
2314 /* Write the back buffer backup back */
2315 glBindTexture(GL_TEXTURE_2D, backup);
2316 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
2320 glTexCoord2f(0.0, (float) fbheight / (float) Src->pow2Height);
2324 glTexCoord2f(0.0, 0.0);
2325 glVertex2i(0, fbheight);
2328 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, 0.0);
2329 glVertex2i(fbwidth, Src->currentDesc.Height);
2332 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
2333 glVertex2i(fbwidth, 0);
2338 glDeleteTextures(1, &src);
2339 checkGLcall("glDeleteTextures(1, &src)");
2341 glDeleteTextures(1, &backup);
2342 checkGLcall("glDeleteTextures(1, &backup)");
2346 /* Not called from the VTable */
2347 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2349 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2350 IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
2351 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2354 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2356 /* Get the swapchain. One of the surfaces has to be a primary surface */
2357 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
2358 if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
2360 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
2361 if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
2364 /* Early sort out of cases where no render target is used */
2365 if(!dstSwapchain && !srcSwapchain &&
2366 SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2367 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
2368 return WINED3DERR_INVALIDCALL;
2371 /* No destination color keying supported */
2372 if(Flags & (DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE)) {
2373 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2374 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2375 return WINED3DERR_INVALIDCALL;
2379 rect.x1 = DestRect->left;
2380 rect.y1 = DestRect->top;
2381 rect.x2 = DestRect->right;
2382 rect.y2 = DestRect->bottom;
2386 rect.x2 = This->currentDesc.Width;
2387 rect.y2 = This->currentDesc.Height;
2390 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
2391 if(dstSwapchain && dstSwapchain == srcSwapchain) {
2392 /* Half-life does a Blt from the back buffer to the front buffer,
2393 * Full surface size, no flags... Use present instead
2396 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2398 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2399 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2406 /* Check the Destination rect and the surface sizes */
2408 (rect.x1 == 0) && (rect.y1 == 0) &&
2409 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2410 (This->currentDesc.Width == Src->currentDesc.Width) &&
2411 (This->currentDesc.Height == Src->currentDesc.Height)) {
2412 /* These flags are unimportant for the flag check, remove them */
2414 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2415 if( dstSwapchain->backBuffer && ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) &&
2416 SrcSurface == dstSwapchain->backBuffer[0] ) {
2418 D3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
2420 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2421 * take very long, while a flip is fast.
2422 * This applies to Half-Life, which does such Blts every time it finished
2423 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2424 * menu. This is also used by all apps when they do windowed rendering
2426 * The problem is that flipping is not really the same as copying. After a
2427 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2428 * untouched. Therefore it's necessary to override the swap effect
2429 * and to set it back after the flip.
2432 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2434 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2435 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2436 NULL, NULL, 0, NULL);
2438 dstSwapchain->presentParms.SwapEffect = orig_swap;
2445 TRACE("Unsupported blit between buffers on the same swapchain\n");
2446 return WINED3DERR_INVALIDCALL;
2447 } else if((dstSwapchain || This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) &&
2448 (srcSwapchain || SrcSurface == myDevice->render_targets[0]) ) {
2449 ERR("Can't perform hardware blit between 2 different swapchains, falling back to software\n");
2450 return WINED3DERR_INVALIDCALL;
2453 if(srcSwapchain || SrcSurface == myDevice->render_targets[0]) {
2454 /* Blit from render target to texture */
2456 BOOL upsideDown, stretchx;
2458 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2459 TRACE("Color keying not supported by frame buffer to texture blit\n");
2460 return WINED3DERR_INVALIDCALL;
2461 /* Destination color key is checked above */
2464 /* Call preload for the surface to make sure it isn't dirty */
2465 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2467 /* Make sure that the top pixel is always above the bottom pixel, and keep a seperate upside down flag
2468 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2471 if(SrcRect->top < SrcRect->bottom) {
2472 srect.y1 = SrcRect->top;
2473 srect.y2 = SrcRect->bottom;
2476 srect.y1 = SrcRect->bottom;
2477 srect.y2 = SrcRect->top;
2480 srect.x1 = SrcRect->left;
2481 srect.x2 = SrcRect->right;
2485 srect.x2 = Src->currentDesc.Width;
2486 srect.y2 = Src->currentDesc.Height;
2489 if(rect.x1 > rect.x2) {
2493 upsideDown = !upsideDown;
2496 if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
2502 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2503 * flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully,
2504 * not implemented by now). Otherwise:
2506 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2507 * -> If the app wants a image width an unscaled width, copy it line per line
2508 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
2509 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2510 * back buffer. This is slower than reading line per line, thus not used for flipping
2511 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2514 if(FALSE /* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */) {
2515 TRACE("Using GL_EXT_framebuffer_blit for copying\n");
2516 } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
2517 rect.y2 - rect.y1 > Src->currentDesc.Height) {
2518 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
2519 fb_copy_to_texture_direct(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
2521 TRACE("Using hardware stretching to flip / stretch the texture\n");
2522 fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
2525 if(!(This->Flags & SFLAG_DONOTFREE)) {
2526 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2527 This->resource.allocatedMemory = NULL;
2529 This->Flags |= SFLAG_GLDIRTY;
2534 /* Blit from offscreen surface to render target */
2535 float glTexCoord[4];
2536 DWORD oldCKeyFlags = Src->CKeyFlags;
2537 DDCOLORKEY oldBltCKey = This->SrcBltCKey;
2538 RECT SourceRectangle;
2541 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2544 SourceRectangle.left = SrcRect->left;
2545 SourceRectangle.right = SrcRect->right;
2546 SourceRectangle.top = SrcRect->top;
2547 SourceRectangle.bottom = SrcRect->bottom;
2549 SourceRectangle.left = 0;
2550 SourceRectangle.right = Src->currentDesc.Width;
2551 SourceRectangle.top = 0;
2552 SourceRectangle.bottom = Src->currentDesc.Height;
2555 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2556 /* Fall back to software */
2557 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2558 SourceRectangle.left, SourceRectangle.top,
2559 SourceRectangle.right, SourceRectangle.bottom);
2560 return WINED3DERR_INVALIDCALL;
2563 /* Color keying: Check if we have to do a color keyed blt,
2564 * and if not check if a color key is activated.
2566 * Just modify the color keying parameters in the surface and restore them afterwards
2567 * The surface keeps track of the color key last used to load the opengl surface.
2568 * PreLoad will catch the change to the flags and color key and reload if neccessary.
2570 if(Flags & DDBLT_KEYSRC) {
2571 /* Use color key from surface */
2572 } else if(Flags & DDBLT_KEYSRCOVERRIDE) {
2573 /* Use color key from DDBltFx */
2574 Src->CKeyFlags |= DDSD_CKSRCBLT;
2575 This->SrcBltCKey = DDBltFx->ddckSrcColorkey;
2577 /* Do not use color key */
2578 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2581 /* Now load the surface */
2582 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2586 /* Activate the destination context, set it up for blitting */
2587 ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
2589 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2590 if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer) {
2591 TRACE("Drawing to front buffer\n");
2592 glDrawBuffer(GL_FRONT);
2593 checkGLcall("glDrawBuffer GL_FRONT");
2596 /* Bind the texture */
2597 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2598 checkGLcall("glBindTexture");
2600 /* No filtering for blts */
2601 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2603 checkGLcall("glTexParameteri");
2604 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2606 checkGLcall("glTexParameteri");
2607 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2608 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2609 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2610 checkGLcall("glTexEnvi");
2612 /* This is for color keying */
2613 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2614 glEnable(GL_ALPHA_TEST);
2615 checkGLcall("glEnable GL_ALPHA_TEST");
2616 glAlphaFunc(GL_NOTEQUAL, 0.0);
2617 checkGLcall("glAlphaFunc\n");
2619 glDisable(GL_ALPHA_TEST);
2620 checkGLcall("glDisable GL_ALPHA_TEST");
2623 /* Draw a textured quad
2627 glColor3d(1.0f, 1.0f, 1.0f);
2628 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2633 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2634 glVertex3f(rect.x1, rect.y2, 0.0);
2636 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2641 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2646 checkGLcall("glEnd");
2648 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2649 glDisable(GL_ALPHA_TEST);
2650 checkGLcall("glDisable(GL_ALPHA_TEST)");
2653 /* Unbind the texture */
2654 glBindTexture(GL_TEXTURE_2D, 0);
2655 checkGLcall("glEnable glBindTexture");
2657 if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer && oldDraw == GL_BACK) {
2658 glDrawBuffer(oldDraw);
2660 /* Restore the color key parameters */
2661 Src->CKeyFlags = oldCKeyFlags;
2662 This->SrcBltCKey = oldBltCKey;
2666 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2667 This->Flags |= SFLAG_GLDIRTY;
2671 /* Source-Less Blit to render target */
2672 if (Flags & DDBLT_COLORFILL) {
2673 /* This is easy to handle for the D3D Device... */
2676 TRACE("Colorfill\n");
2678 /* The color as given in the Blt function is in the format of the frame-buffer...
2679 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2681 if (This->resource.format == WINED3DFMT_P8) {
2682 if (This->palette) {
2683 color = ((0xFF000000) |
2684 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2685 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2686 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2691 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2692 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2695 color = ((0xFF000000) |
2696 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2697 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2698 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2701 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2702 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2703 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2705 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2706 color = DDBltFx->u5.dwFillColor;
2709 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2710 return WINED3DERR_INVALIDCALL;
2713 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2714 if(dstSwapchain && dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]) {
2715 glDrawBuffer(GL_BACK);
2716 checkGLcall("glDrawBuffer(GL_BACK)");
2717 } else if (dstSwapchain && This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer) {
2718 glDrawBuffer(GL_FRONT);
2719 checkGLcall("glDrawBuffer(GL_FRONT)");
2720 } else if(This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2721 glDrawBuffer(GL_BACK);
2722 checkGLcall("glDrawBuffer(GL_BACK)");
2724 TRACE("Surface is higher back buffer, falling back to software\n");
2725 return WINED3DERR_INVALIDCALL;
2728 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2730 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2731 1 /* Number of rectangles */,
2733 WINED3DCLEAR_TARGET,
2738 /* Restore the original draw buffer */
2739 if(!dstSwapchain || (dstSwapchain->backBuffer && dstSwapchain->backBuffer[0])) {
2740 glDrawBuffer(GL_BACK);
2741 vcheckGLcall("glDrawBuffer");
2748 /* Default: Fall back to the generic blt. Not an error, a TRACE is enought */
2749 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2750 return WINED3DERR_INVALIDCALL;
2753 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2754 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2755 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2756 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2757 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2758 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2760 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair */
2761 if(myDevice->inScene &&
2762 (iface == myDevice->stencilBufferTarget ||
2763 (SrcSurface && SrcSurface == myDevice->stencilBufferTarget))) {
2764 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2765 return WINED3DERR_INVALIDCALL;
2768 /* Special cases for RenderTargets */
2769 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2770 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2771 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2774 /* For the rest call the X11 surface implementation.
2775 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2776 * other Blts are rather rare
2778 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2781 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2782 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2783 TRACE("(%p)->(%x)\n", This, Flags);
2788 case DDGBS_ISBLTDONE:
2792 return DDERR_INVALIDPARAMS;
2796 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2797 /* XXX: DDERR_INVALIDSURFACETYPE */
2799 TRACE("(%p)->(%08x)\n",iface,Flags);
2802 case DDGFS_ISFLIPDONE:
2806 return DDERR_INVALIDPARAMS;
2810 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2811 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2812 TRACE("(%p)\n", This);
2814 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2817 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2818 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2819 TRACE("(%p)\n", This);
2821 /* So far we don't lose anything :) */
2822 This->Flags &= ~SFLAG_LOST;
2826 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2827 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2828 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2829 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2830 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2832 if(myDevice->inScene &&
2833 (iface == myDevice->stencilBufferTarget ||
2834 (Source && Source == myDevice->stencilBufferTarget))) {
2835 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2836 return WINED3DERR_INVALIDCALL;
2839 /* Special cases for RenderTargets */
2840 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2841 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2843 RECT SrcRect, DstRect;
2847 SrcRect.left = rsrc->left;
2848 SrcRect.top= rsrc->top;
2849 SrcRect.bottom = rsrc->bottom;
2850 SrcRect.right = rsrc->right;
2854 SrcRect.right = srcImpl->currentDesc.Width;
2855 SrcRect.bottom = srcImpl->currentDesc.Height;
2858 DstRect.left = dstx;
2860 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2861 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2863 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2864 if(trans & DDBLTFAST_SRCCOLORKEY)
2865 Flags |= DDBLT_KEYSRC;
2866 if(trans & DDBLTFAST_DESTCOLORKEY)
2867 Flags |= DDBLT_KEYDEST;
2868 if(trans & DDBLTFAST_WAIT)
2869 Flags |= DDBLT_WAIT;
2870 if(trans & DDBLTFAST_DONOTWAIT)
2871 Flags |= DDBLT_DONOTWAIT;
2873 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2877 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2880 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2881 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2882 TRACE("(%p)->(%p)\n", This, Pal);
2884 *Pal = (IWineD3DPalette *) This->palette;
2888 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2889 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2891 IWineD3DPaletteImpl *pal = This->palette;
2893 TRACE("(%p)\n", This);
2895 if(This->resource.format == WINED3DFMT_P8 ||
2896 This->resource.format == WINED3DFMT_A8P8)
2898 TRACE("Dirtifying surface\n");
2899 This->Flags |= SFLAG_DIRTY;
2902 if(This->Flags & SFLAG_DIBSECTION) {
2903 TRACE("(%p): Updating the hdc's palette\n", This);
2904 for (n=0; n<256; n++) {
2906 col[n].rgbRed = pal->palents[n].peRed;
2907 col[n].rgbGreen = pal->palents[n].peGreen;
2908 col[n].rgbBlue = pal->palents[n].peBlue;
2910 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2911 /* Use the default device palette */
2912 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2913 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2914 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2916 col[n].rgbReserved = 0;
2918 SetDIBColorTable(This->hDC, 0, 256, col);
2924 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2925 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2926 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2927 TRACE("(%p)->(%p)\n", This, Pal);
2929 if(This->palette != NULL)
2930 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2931 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2933 if(PalImpl != NULL) {
2934 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2935 /* Set the device's main palette if the palette
2936 * wasn't a primary palette before
2938 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2939 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2942 for(i=0; i < 256; i++) {
2943 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2947 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2950 This->palette = PalImpl;
2952 return IWineD3DSurface_RealizePalette(iface);
2955 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2956 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2957 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
2959 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2960 FIXME(" colorkey value not supported (%08x) !\n", Flags);
2961 return DDERR_INVALIDPARAMS;
2964 /* Dirtify the surface, but only if a key was changed */
2966 switch (Flags & ~DDCKEY_COLORSPACE) {
2967 case DDCKEY_DESTBLT:
2968 This->DestBltCKey = *CKey;
2969 This->CKeyFlags |= DDSD_CKDESTBLT;
2972 case DDCKEY_DESTOVERLAY:
2973 This->DestOverlayCKey = *CKey;
2974 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2977 case DDCKEY_SRCOVERLAY:
2978 This->SrcOverlayCKey = *CKey;
2979 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2983 This->SrcBltCKey = *CKey;
2984 This->CKeyFlags |= DDSD_CKSRCBLT;
2989 switch (Flags & ~DDCKEY_COLORSPACE) {
2990 case DDCKEY_DESTBLT:
2991 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2994 case DDCKEY_DESTOVERLAY:
2995 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2998 case DDCKEY_SRCOVERLAY:
2999 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
3003 This->CKeyFlags &= ~DDSD_CKSRCBLT;
3011 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3012 /** Check against the maximum texture sizes supported by the video card **/
3013 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3015 TRACE("%p\n", This);
3016 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3017 /* one of three options
3018 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)
3019 2: Set the texture to the maxium size (bad idea)
3020 3: WARN and return WINED3DERR_NOTAVAILABLE;
3021 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.
3023 WARN("(%p) Creating an oversized surface\n", This);
3024 This->Flags |= SFLAG_OVERSIZE;
3026 /* This will be initialized on the first blt */
3027 This->glRect.left = 0;
3028 This->glRect.top = 0;
3029 This->glRect.right = 0;
3030 This->glRect.bottom = 0;
3032 /* No oversize, gl rect is the full texture size */
3033 This->Flags &= ~SFLAG_OVERSIZE;
3034 This->glRect.left = 0;
3035 This->glRect.top = 0;
3036 This->glRect.right = This->pow2Width;
3037 This->glRect.bottom = This->pow2Height;
3043 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3044 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3046 TRACE("(%p)\n", This);
3048 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3049 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3050 ie pitch = (width/4) * bytes per block */
3051 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3052 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3053 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3054 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3055 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3057 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3058 /* Surfaces are 32 bit aligned */
3059 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3061 TRACE("(%p) Returning %d\n", This, ret);
3065 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3066 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3068 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3070 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3072 TRACE("(%p): Not an overlay surface\n", This);
3073 return DDERR_NOTAOVERLAYSURFACE;
3079 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3080 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3082 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3084 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3086 TRACE("(%p): Not an overlay surface\n", This);
3087 return DDERR_NOTAOVERLAYSURFACE;
3093 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3094 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3095 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3097 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3099 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3101 TRACE("(%p): Not an overlay surface\n", This);
3102 return DDERR_NOTAOVERLAYSURFACE;
3108 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3109 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3110 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3111 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3113 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3115 TRACE("(%p): Not an overlay surface\n", This);
3116 return DDERR_NOTAOVERLAYSURFACE;
3122 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3125 IWineD3DSurfaceImpl_QueryInterface,
3126 IWineD3DSurfaceImpl_AddRef,
3127 IWineD3DSurfaceImpl_Release,
3128 /* IWineD3DResource */
3129 IWineD3DSurfaceImpl_GetParent,
3130 IWineD3DSurfaceImpl_GetDevice,
3131 IWineD3DSurfaceImpl_SetPrivateData,
3132 IWineD3DSurfaceImpl_GetPrivateData,
3133 IWineD3DSurfaceImpl_FreePrivateData,
3134 IWineD3DSurfaceImpl_SetPriority,
3135 IWineD3DSurfaceImpl_GetPriority,
3136 IWineD3DSurfaceImpl_PreLoad,
3137 IWineD3DSurfaceImpl_GetType,
3138 /* IWineD3DSurface */
3139 IWineD3DSurfaceImpl_GetContainer,
3140 IWineD3DSurfaceImpl_GetDesc,
3141 IWineD3DSurfaceImpl_LockRect,
3142 IWineD3DSurfaceImpl_UnlockRect,
3143 IWineD3DSurfaceImpl_GetDC,
3144 IWineD3DSurfaceImpl_ReleaseDC,
3145 IWineD3DSurfaceImpl_Flip,
3146 IWineD3DSurfaceImpl_Blt,
3147 IWineD3DSurfaceImpl_GetBltStatus,
3148 IWineD3DSurfaceImpl_GetFlipStatus,
3149 IWineD3DSurfaceImpl_IsLost,
3150 IWineD3DSurfaceImpl_Restore,
3151 IWineD3DSurfaceImpl_BltFast,
3152 IWineD3DSurfaceImpl_GetPalette,
3153 IWineD3DSurfaceImpl_SetPalette,
3154 IWineD3DSurfaceImpl_RealizePalette,
3155 IWineD3DSurfaceImpl_SetColorKey,
3156 IWineD3DSurfaceImpl_GetPitch,
3157 IWineD3DSurfaceImpl_SetMem,
3158 IWineD3DSurfaceImpl_SetOverlayPosition,
3159 IWineD3DSurfaceImpl_GetOverlayPosition,
3160 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3161 IWineD3DSurfaceImpl_UpdateOverlay,
3163 IWineD3DSurfaceImpl_CleanDirtyRect,
3164 IWineD3DSurfaceImpl_AddDirtyRect,
3165 IWineD3DSurfaceImpl_LoadTexture,
3166 IWineD3DSurfaceImpl_SaveSnapshot,
3167 IWineD3DSurfaceImpl_SetContainer,
3168 IWineD3DSurfaceImpl_SetPBufferState,
3169 IWineD3DSurfaceImpl_SetGlTextureDesc,
3170 IWineD3DSurfaceImpl_GetGlDesc,
3171 IWineD3DSurfaceImpl_GetData,
3172 IWineD3DSurfaceImpl_SetFormat,
3173 IWineD3DSurfaceImpl_PrivateSetup