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 if(memory_allocated) HeapFree(GetProcessHeap(), 0, mem);
971 static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl *This) {
974 glTexCoord[0] = (float) This->lockedRect.left / (float) This->pow2Width; /* left */
975 glTexCoord[1] = (float) This->lockedRect.right / (float) This->pow2Width; /* right */
976 glTexCoord[2] = (float) This->lockedRect.top / (float) This->pow2Height; /* top */
977 glTexCoord[3] = (float) This->lockedRect.bottom / (float) This->pow2Height; /* bottom */
979 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
983 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
984 checkGLcall("glEnable glBindTexture");
986 /* No filtering for blts */
987 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
988 checkGLcall("glTexParameteri");
989 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
990 checkGLcall("glTexParameteri");
992 /* Start drawing a quad */
995 glColor3d(1.0f, 1.0f, 1.0f);
996 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
997 glVertex3f(This->lockedRect.left, This->lockedRect.top, 0.0);
999 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1000 glVertex3f(This->lockedRect.left, This->lockedRect.bottom, 0.0);
1002 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1003 glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.0);
1005 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1006 glVertex3f(This->lockedRect.right, This->lockedRect.top, 0.0);
1009 checkGLcall("glEnd");
1011 /* Unbind the texture */
1012 glBindTexture(GL_TEXTURE_2D, 0);
1013 checkGLcall("glEnable glBindTexture");
1018 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1019 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1020 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1021 IWineD3DSwapChainImpl *swapchain = NULL;
1023 if (!(This->Flags & SFLAG_LOCKED)) {
1024 WARN("trying to Unlock an unlocked surf@%p\n", This);
1025 return WINED3DERR_INVALIDCALL;
1028 TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0);
1030 if (!(This->Flags & SFLAG_DIRTY)) {
1031 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1035 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1036 if(swapchain || iface == myDevice->render_targets[0]) {
1037 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1038 static BOOL warned = FALSE;
1040 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1043 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1047 /* Activate the correct context for the render target */
1049 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
1052 /* Primary offscreen render target */
1053 TRACE("Offscreen render target\n");
1054 glDrawBuffer(GL_BACK);
1055 checkGLcall("glDrawBuffer(GL_BACK)");
1057 if(iface == swapchain->frontBuffer) {
1058 TRACE("Onscreen front buffer\n");
1059 glDrawBuffer(GL_FRONT);
1060 checkGLcall("glDrawBuffer(GL_FRONT)");
1061 } else if(iface == swapchain->backBuffer[0]) {
1062 TRACE("Onscreen back buffer\n");
1063 glDrawBuffer(GL_BACK);
1064 checkGLcall("glDrawBuffer(GL_BACK)");
1066 FIXME("Unlocking a higher back buffer\n");
1067 glDrawBuffer(GL_BACK);
1068 checkGLcall("glDrawBuffer(GL_BACK)");
1070 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1073 switch(wined3d_settings.rendertargetlock_mode) {
1077 flush_to_framebuffer_drawpixels(This);
1082 flush_to_framebuffer_texture(This);
1085 if(!swapchain || swapchain->backBuffer) {
1086 glDrawBuffer(GL_BACK);
1087 checkGLcall("glDrawBuffer(GL_BACK)");
1089 glDrawBuffer(GL_FRONT);
1090 checkGLcall("glDrawBuffer(GL_FRONT)");
1094 /** restore clean dirty state */
1095 IWineD3DSurface_CleanDirtyRect(iface);
1096 } else if(iface == myDevice->stencilBufferTarget) {
1097 FIXME("Depth Stencil buffer locking is not implemented\n");
1099 /* The rest should be a normal texture */
1100 IWineD3DBaseTextureImpl *impl;
1101 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1102 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1103 * states need resetting
1105 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1106 if(impl->baseTexture.bindCount) {
1107 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1109 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1114 This->Flags &= ~SFLAG_LOCKED;
1115 memset(&This->lockedRect, 0, sizeof(RECT));
1119 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1120 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1121 WINED3DLOCKED_RECT lock;
1128 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1130 TRACE("(%p)->(%p)\n",This,pHDC);
1132 if(This->Flags & SFLAG_USERPTR) {
1133 ERR("Not supported on surfaces with an application-provided surfaces\n");
1137 /* Give more detailed info for ddraw */
1138 if (This->Flags & SFLAG_DCINUSE)
1139 return DDERR_DCALREADYCREATED;
1141 /* Can't GetDC if the surface is locked */
1142 if (This->Flags & SFLAG_LOCKED)
1143 return WINED3DERR_INVALIDCALL;
1145 memset(&lock, 0, sizeof(lock)); /* To be sure */
1147 /* Create a DIB section if there isn't a hdc yet */
1150 SYSTEM_INFO sysInfo;
1152 switch (This->bytesPerPixel) {
1155 /* Allocate extra space to store the RGB bit masks. */
1156 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1160 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1164 /* Allocate extra space for a palette. */
1165 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1166 sizeof(BITMAPINFOHEADER)
1168 * (1 << (This->bytesPerPixel * 8)));
1173 return E_OUTOFMEMORY;
1175 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1176 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1177 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1178 * add an extra line to the dib section
1180 GetSystemInfo(&sysInfo);
1181 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1183 TRACE("Adding an extra line to the dib section\n");
1186 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1187 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1188 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1189 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1190 b_info->bmiHeader.biPlanes = 1;
1191 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1193 b_info->bmiHeader.biXPelsPerMeter = 0;
1194 b_info->bmiHeader.biYPelsPerMeter = 0;
1195 b_info->bmiHeader.biClrUsed = 0;
1196 b_info->bmiHeader.biClrImportant = 0;
1198 /* Get the bit masks */
1199 masks = (DWORD *) &(b_info->bmiColors);
1200 switch (This->resource.format) {
1201 case WINED3DFMT_R8G8B8:
1202 usage = DIB_RGB_COLORS;
1203 b_info->bmiHeader.biCompression = BI_RGB;
1206 case WINED3DFMT_X1R5G5B5:
1207 case WINED3DFMT_A1R5G5B5:
1208 case WINED3DFMT_A4R4G4B4:
1209 case WINED3DFMT_X4R4G4B4:
1210 case WINED3DFMT_R3G3B2:
1211 case WINED3DFMT_A8R3G3B2:
1212 case WINED3DFMT_A2B10G10R10:
1213 case WINED3DFMT_A8B8G8R8:
1214 case WINED3DFMT_X8B8G8R8:
1215 case WINED3DFMT_A2R10G10B10:
1216 case WINED3DFMT_R5G6B5:
1217 case WINED3DFMT_A16B16G16R16:
1219 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1220 masks[0] = formatEntry->redMask;
1221 masks[1] = formatEntry->greenMask;
1222 masks[2] = formatEntry->blueMask;
1226 /* Don't know palette */
1227 b_info->bmiHeader.biCompression = BI_RGB;
1234 HeapFree(GetProcessHeap(), 0, b_info);
1235 return HRESULT_FROM_WIN32(GetLastError());
1238 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);
1239 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1242 if (!This->dib.DIBsection) {
1243 ERR("CreateDIBSection failed!\n");
1244 HeapFree(GetProcessHeap(), 0, b_info);
1245 return HRESULT_FROM_WIN32(GetLastError());
1248 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1250 /* copy the existing surface to the dib section */
1251 if(This->resource.allocatedMemory) {
1252 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1253 /* We won't need that any more */
1254 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1256 /* This is to make LockRect read the gl Texture although memory is allocated */
1257 This->Flags |= SFLAG_GLDIRTY;
1260 HeapFree(GetProcessHeap(), 0, b_info);
1262 /* Use the dib section from now on */
1263 This->resource.allocatedMemory = This->dib.bitmap_data;
1265 /* Now allocate a HDC */
1266 This->hDC = CreateCompatibleDC(0);
1267 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1268 TRACE("using wined3d palette %p\n", This->palette);
1269 SelectPalette(This->hDC,
1270 This->palette ? This->palette->hpal : 0,
1273 This->Flags |= SFLAG_DIBSECTION;
1276 /* Lock the surface */
1277 hr = IWineD3DSurface_LockRect(iface,
1282 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1283 /* keep the dib section */
1287 if(This->resource.format == WINED3DFMT_P8 ||
1288 This->resource.format == WINED3DFMT_A8P8) {
1291 PALETTEENTRY ent[256];
1293 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1294 for (n=0; n<256; n++) {
1295 col[n].rgbRed = ent[n].peRed;
1296 col[n].rgbGreen = ent[n].peGreen;
1297 col[n].rgbBlue = ent[n].peBlue;
1298 col[n].rgbReserved = 0;
1301 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1303 for (n=0; n<256; n++) {
1304 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1305 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1306 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1307 col[n].rgbReserved = 0;
1311 SetDIBColorTable(This->hDC, 0, 256, col);
1315 TRACE("returning %p\n",*pHDC);
1316 This->Flags |= SFLAG_DCINUSE;
1321 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1322 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1324 TRACE("(%p)->(%p)\n",This,hDC);
1326 if (!(This->Flags & SFLAG_DCINUSE))
1327 return D3DERR_INVALIDCALL;
1329 /* we locked first, so unlock now */
1330 IWineD3DSurface_UnlockRect(iface);
1332 This->Flags &= ~SFLAG_DCINUSE;
1337 /* ******************************************************
1338 IWineD3DSurface Internal (No mapping to directx api) parts follow
1339 ****************************************************** */
1341 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) {
1342 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1343 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1345 /* Default values: From the surface */
1346 *format = formatEntry->glFormat;
1347 *internal = formatEntry->glInternal;
1348 *type = formatEntry->glType;
1349 *convert = NO_CONVERSION;
1350 *target_bpp = This->bytesPerPixel;
1352 /* Ok, now look if we have to do any conversion */
1353 switch(This->resource.format) {
1358 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1359 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1361 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1363 *internal = GL_RGBA;
1364 *type = GL_UNSIGNED_BYTE;
1366 if(colorkey_active) {
1367 *convert = CONVERT_PALETTED_CK;
1369 *convert = CONVERT_PALETTED;
1375 case WINED3DFMT_R3G3B2:
1376 /* **********************
1377 GL_UNSIGNED_BYTE_3_3_2
1378 ********************** */
1379 if (colorkey_active) {
1380 /* This texture format will never be used.. So do not care about color keying
1381 up until the point in time it will be needed :-) */
1382 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1386 case WINED3DFMT_R5G6B5:
1387 if (colorkey_active) {
1388 *convert = CONVERT_CK_565;
1390 *internal = GL_RGBA;
1391 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1395 case WINED3DFMT_R8G8B8:
1396 if (colorkey_active) {
1397 *convert = CONVERT_CK_RGB24;
1399 *internal = GL_RGBA;
1400 *type = GL_UNSIGNED_INT_8_8_8_8;
1405 case WINED3DFMT_X8R8G8B8:
1406 if (colorkey_active) {
1407 *convert = CONVERT_RGB32_888;
1409 *internal = GL_RGBA;
1410 *type = GL_UNSIGNED_INT_8_8_8_8;
1414 case WINED3DFMT_V8U8:
1415 *convert = CONVERT_V8U8;
1417 *internal = GL_RGB8;
1429 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1430 BYTE *source, *dest;
1431 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1436 memcpy(dst, src, pitch * height);
1439 case CONVERT_PALETTED:
1440 case CONVERT_PALETTED_CK:
1442 IWineD3DPaletteImpl* pal = surf->palette;
1448 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1452 /* Still no palette? Use the device's palette */
1453 /* Get the surface's palette */
1454 for (i = 0; i < 256; i++) {
1455 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1457 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1458 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1459 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1460 if ((convert == CONVERT_PALETTED_CK) &&
1461 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1462 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1463 /* We should maybe here put a more 'neutral' color than the standard bright purple
1464 one often used by application to prevent the nice purple borders when bi-linear
1472 TRACE("Using surface palette %p\n", pal);
1473 /* Get the surface's palette */
1474 for (i = 0; i < 256; i++) {
1475 table[i][0] = pal->palents[i].peRed;
1476 table[i][1] = pal->palents[i].peGreen;
1477 table[i][2] = pal->palents[i].peBlue;
1478 if ((convert == CONVERT_PALETTED_CK) &&
1479 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1480 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1481 /* We should maybe here put a more 'neutral' color than the standard bright purple
1482 one often used by application to prevent the nice purple borders when bi-linear
1491 for (y = 0; y < height; y++)
1493 source = src + pitch * y;
1494 dest = dst + outpitch * y;
1495 /* This is an 1 bpp format, using the width here is fine */
1496 for (x = 0; x < width; x++) {
1497 BYTE color = *source++;
1498 *dest++ = table[color][0];
1499 *dest++ = table[color][1];
1500 *dest++ = table[color][2];
1501 *dest++ = table[color][3];
1507 case CONVERT_CK_565:
1509 /* Converting the 565 format in 5551 packed to emulate color-keying.
1511 Note : in all these conversion, it would be best to average the averaging
1512 pixels to get the color of the pixel that will be color-keyed to
1513 prevent 'color bleeding'. This will be done later on if ever it is
1516 Note2: Nvidia documents say that their driver does not support alpha + color keying
1517 on the same surface and disables color keying in such a case
1523 TRACE("Color keyed 565\n");
1525 for (y = 0; y < height; y++) {
1526 Source = (WORD *) (src + y * pitch);
1527 Dest = (WORD *) (dst + y * outpitch);
1528 for (x = 0; x < width; x++ ) {
1529 WORD color = *Source++;
1530 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1531 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1532 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1546 for(y = 0; y < height; y++) {
1547 Source = (short *) (src + y * pitch);
1548 Dest = (char *) (dst + y * outpitch);
1549 for (x = 0; x < width; x++ ) {
1550 long color = (*Source++);
1551 Dest[0] = color >> 8;
1561 ERR("Unsupported conversation type %d\n", convert);
1566 /* This function is used in case of 8bit paletted textures to upload the palette.
1567 For now it only supports GL_EXT_paletted_texture extension but support for other
1568 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1570 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1571 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1572 IWineD3DPaletteImpl* pal = This->palette;
1577 /* Still no palette? Use the device's palette */
1578 /* Get the surface's palette */
1579 for (i = 0; i < 256; i++) {
1580 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1582 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1583 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1584 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1585 if ((convert == CONVERT_PALETTED_CK) &&
1586 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1587 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1588 /* We should maybe here put a more 'neutral' color than the standard bright purple
1589 one often used by application to prevent the nice purple borders when bi-linear
1597 TRACE("Using surface palette %p\n", pal);
1598 /* Get the surface's palette */
1599 for (i = 0; i < 256; i++) {
1600 table[i][0] = pal->palents[i].peRed;
1601 table[i][1] = pal->palents[i].peGreen;
1602 table[i][2] = pal->palents[i].peBlue;
1603 if ((convert == CONVERT_PALETTED_CK) &&
1604 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1605 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1606 /* We should maybe here put a more 'neutral' color than the standard bright purple
1607 one often used by application to prevent the nice purple borders when bi-linear
1615 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1618 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1619 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1620 GLenum format, internal, type;
1621 CONVERT_TYPES convert;
1623 int width, pitch, outpitch;
1626 if (This->Flags & SFLAG_INTEXTURE) {
1627 TRACE("Surface already in texture\n");
1630 if (This->Flags & SFLAG_DIRTY) {
1631 TRACE("Reloading because surface is dirty\n");
1632 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1633 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1634 /* Reload: vice versa OR */
1635 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1636 /* Also reload: Color key is active AND the color key has changed */
1637 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1638 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1639 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1640 TRACE("Reloading because of color keying\n");
1642 TRACE("surface isn't dirty\n");
1646 This->Flags &= ~SFLAG_DIRTY;
1648 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1649 * These resources are not bound by device size or format restrictions. Because of this,
1650 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1651 * However, these resources can always be created, locked, and copied.
1653 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1655 FIXME("(%p) Operation not supported for scratch textures\n",This);
1656 return WINED3DERR_INVALIDCALL;
1659 if (This->Flags & SFLAG_INPBUFFER) {
1660 if (This->glDescription.level != 0)
1661 FIXME("Surface in texture is only supported for level 0\n");
1662 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1663 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1664 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1665 This->resource.format == WINED3DFMT_DXT5)
1666 FIXME("Format %d not supported\n", This->resource.format);
1672 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1673 vcheckGLcall("glGetIntegerv");
1674 glReadBuffer(GL_BACK);
1675 vcheckGLcall("glReadBuffer");
1677 glCopyTexImage2D(This->glDescription.target,
1678 This->glDescription.level,
1679 This->glDescription.glFormatInternal,
1682 This->currentDesc.Width,
1683 This->currentDesc.Height,
1686 checkGLcall("glCopyTexImage2D");
1687 glReadBuffer(prevRead);
1688 vcheckGLcall("glReadBuffer");
1692 TRACE("Updating target %d\n", This->glDescription.target);
1693 This->Flags |= SFLAG_INTEXTURE;
1698 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1699 This->Flags |= SFLAG_GLCKEY;
1700 This->glCKey = This->SrcBltCKey;
1702 else This->Flags &= ~SFLAG_GLCKEY;
1704 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1706 /* The width is in 'length' not in bytes */
1707 width = This->currentDesc.Width;
1708 pitch = IWineD3DSurface_GetPitch(iface);
1710 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1711 int height = This->glRect.bottom - This->glRect.top;
1713 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1714 outpitch = width * bpp;
1715 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1717 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1719 ERR("Out of memory %d, %d!\n", outpitch, height);
1720 return WINED3DERR_OUTOFVIDEOMEMORY;
1722 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1724 This->Flags |= SFLAG_CONVERTED;
1725 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1726 d3dfmt_p8_upload_palette(iface, convert);
1727 This->Flags &= ~SFLAG_CONVERTED;
1728 mem = This->resource.allocatedMemory;
1730 This->Flags &= ~SFLAG_CONVERTED;
1731 mem = This->resource.allocatedMemory;
1734 /* Make sure the correct pitch is used */
1735 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1737 if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1738 TRACE("non power of two support\n");
1739 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1741 surface_upload_data(This, This->currentDesc.Width, This->currentDesc.Height, format, type, mem);
1744 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1746 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1750 /* Restore the default pitch */
1751 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1753 if (mem != This->resource.allocatedMemory)
1754 HeapFree(GetProcessHeap(), 0, mem);
1758 static unsigned int gen = 0;
1761 if ((gen % 10) == 0) {
1762 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1763 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1766 * debugging crash code
1775 if (!(This->Flags & SFLAG_DONOTFREE)) {
1776 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1777 This->resource.allocatedMemory = NULL;
1785 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1788 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1789 char *allocatedMemory;
1791 IWineD3DSwapChain *swapChain = NULL;
1793 GLuint tmpTexture = 0;
1796 Textures my not be stored in ->allocatedgMemory and a GlTexture
1797 so we should lock the surface before saving a snapshot, or at least check that
1799 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1800 by calling GetTexImage and in compressed form by calling
1801 GetCompressedTexImageARB. Queried compressed images can be saved and
1802 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1803 texture images do not need to be processed by the GL and should
1804 significantly improve texture loading performance relative to uncompressed
1807 /* Setup the width and height to be the internal texture width and height. */
1808 width = This->pow2Width;
1809 height = This->pow2Height;
1810 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1811 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1813 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1814 /* 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 */
1817 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1818 glEnable(GL_TEXTURE_2D);
1820 glGenTextures(1, &tmpTexture);
1821 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1823 glTexImage2D(GL_TEXTURE_2D,
1830 GL_UNSIGNED_INT_8_8_8_8_REV,
1833 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1834 vcheckGLcall("glGetIntegerv");
1835 glReadBuffer(GL_BACK);
1836 vcheckGLcall("glReadBuffer");
1837 glCopyTexImage2D(GL_TEXTURE_2D,
1846 checkGLcall("glCopyTexImage2D");
1847 glReadBuffer(prevRead);
1850 } else { /* bind the real texture */
1851 IWineD3DSurface_PreLoad(iface);
1853 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1855 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1856 glGetTexImage(GL_TEXTURE_2D,
1857 This->glDescription.level,
1859 GL_UNSIGNED_INT_8_8_8_8_REV,
1861 checkGLcall("glTexImage2D");
1863 glBindTexture(GL_TEXTURE_2D, 0);
1864 glDeleteTextures(1, &tmpTexture);
1868 f = fopen(filename, "w+");
1870 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1871 return WINED3DERR_INVALIDCALL;
1873 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1874 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1889 fwrite(&width,2,1,f);
1891 fwrite(&height,2,1,f);
1896 /* 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*/
1898 textureRow = allocatedMemory + (width * (height - 1) *4);
1900 textureRow = allocatedMemory;
1901 for (y = 0 ; y < height; y++) {
1902 for (i = 0; i < width; i++) {
1903 color = *((DWORD*)textureRow);
1904 fputc((color >> 16) & 0xFF, f); /* B */
1905 fputc((color >> 8) & 0xFF, f); /* G */
1906 fputc((color >> 0) & 0xFF, f); /* R */
1907 fputc((color >> 24) & 0xFF, f); /* A */
1910 /* take two rows of the pointer to the texture memory */
1912 (textureRow-= width << 3);
1915 TRACE("Closing file\n");
1919 IWineD3DSwapChain_Release(swapChain);
1921 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1925 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1926 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1927 This->Flags &= ~SFLAG_DIRTY;
1928 This->dirtyRect.left = This->currentDesc.Width;
1929 This->dirtyRect.top = This->currentDesc.Height;
1930 This->dirtyRect.right = 0;
1931 This->dirtyRect.bottom = 0;
1932 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1933 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1938 * Slightly inefficient way to handle multiple dirty rects but it works :)
1940 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1941 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1942 IWineD3DBaseTexture *baseTexture = NULL;
1943 This->Flags |= SFLAG_DIRTY;
1944 if (NULL != pDirtyRect) {
1945 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1946 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1947 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1948 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1950 This->dirtyRect.left = 0;
1951 This->dirtyRect.top = 0;
1952 This->dirtyRect.right = This->currentDesc.Width;
1953 This->dirtyRect.bottom = This->currentDesc.Height;
1955 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
1956 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1957 /* if the container is a basetexture then mark it dirty. */
1958 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1959 TRACE("Passing to conatiner\n");
1960 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1961 IWineD3DBaseTexture_Release(baseTexture);
1966 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1967 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1969 TRACE("This %p, container %p\n", This, container);
1971 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1973 TRACE("Setting container to %p from %p\n", container, This->container);
1974 This->container = container;
1979 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1980 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1981 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
1983 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1984 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1985 return WINED3DERR_INVALIDCALL;
1988 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1989 if (format == WINED3DFMT_UNKNOWN) {
1990 This->resource.size = 0;
1991 } else if (format == WINED3DFMT_DXT1) {
1992 /* DXT1 is half byte per pixel */
1993 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
1995 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1996 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1997 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
1999 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
2000 This->resource.size *= This->pow2Height;
2004 /* Setup some glformat defaults */
2005 This->glDescription.glFormat = formatEntry->glFormat;
2006 This->glDescription.glFormatInternal = formatEntry->glInternal;
2007 This->glDescription.glType = formatEntry->glType;
2009 if (format != WINED3DFMT_UNKNOWN) {
2010 This->bytesPerPixel = formatEntry->bpp;
2012 This->bytesPerPixel = 0;
2015 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2017 This->resource.format = format;
2019 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);
2024 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2025 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2027 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2028 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2029 ERR("Not supported on render targets\n");
2030 return WINED3DERR_INVALIDCALL;
2033 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2034 WARN("Surface is locked or the HDC is in use\n");
2035 return WINED3DERR_INVALIDCALL;
2038 if(Mem && Mem != This->resource.allocatedMemory) {
2040 /* Do I have to copy the old surface content? */
2041 if(This->Flags & SFLAG_DIBSECTION) {
2042 /* Release the DC. No need to hold the critical section for the update
2043 * Thread because this thread runs only on front buffers, but this method
2044 * fails for render targets in the check above.
2046 SelectObject(This->hDC, This->dib.holdbitmap);
2047 DeleteDC(This->hDC);
2048 /* Release the DIB section */
2049 DeleteObject(This->dib.DIBsection);
2050 This->dib.bitmap_data = NULL;
2051 This->resource.allocatedMemory = NULL;
2053 This->Flags &= ~SFLAG_DIBSECTION;
2054 } else if(!(This->Flags & SFLAG_USERPTR)) {
2055 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2057 This->resource.allocatedMemory = Mem;
2058 This->Flags |= SFLAG_USERPTR;
2059 } else if(This->Flags & SFLAG_USERPTR) {
2060 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2061 This->resource.allocatedMemory = NULL;
2062 This->Flags &= ~SFLAG_USERPTR;
2067 /* TODO: replace this function with context management routines */
2068 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2069 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2072 This->Flags |= SFLAG_INPBUFFER;
2074 This->Flags &= ~SFLAG_INPBUFFER;
2078 This->Flags |= SFLAG_INTEXTURE;
2080 This->Flags &= ~SFLAG_INTEXTURE;
2086 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2087 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2088 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2089 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2091 /* Flipping is only supported on RenderTargets */
2092 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2095 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2096 * FIXME("(%p) Target override is not supported by now\n", This);
2097 * Additionally, it isn't really possible to support triple-buffering
2098 * properly on opengl at all
2102 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2103 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2106 /* Does a direct frame buffer -> texture copy. Stretching is done
2107 * with single pixel copy calls
2109 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2110 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2113 BOOL warned = FALSE; /* deliberately not static */
2114 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2118 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2120 /* Bind the target texture */
2121 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2122 checkGLcall("glBindTexture");
2123 if(!swapchain || (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0])) {
2124 glReadBuffer(GL_BACK);
2126 glReadBuffer(GL_FRONT);
2128 checkGLcall("glReadBuffer");
2130 xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1);
2131 yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1);
2133 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2134 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2138 !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) &&
2139 !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2140 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2142 glCopyTexSubImage2D(This->glDescription.target,
2143 This->glDescription.level,
2144 drect->x1, drect->y1, /* xoffset, yoffset */
2145 srect->x1, Src->currentDesc.Height - srect->y2,
2146 drect->x2 - drect->x1, drect->y2 - drect->y1);
2148 UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1;
2149 /* I have to process this row by row to swap the image,
2150 * otherwise it would be upside down, so streching in y direction
2151 * doesn't cost extra time
2153 * However, streching in x direction can be avoided if not necessary
2155 for(row = drect->y1; row < drect->y2; row++) {
2156 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2157 /* Well, that stuff works, but it's very slow.
2158 * find a better way instead
2164 FIXME("Doing a pixel by pixel render target -> texture copy, expect performance issues\n");
2167 for(col = drect->x1; col < drect->x2; col++) {
2168 glCopyTexSubImage2D(This->glDescription.target,
2169 This->glDescription.level,
2170 drect->x1 + col, row, /* xoffset, yoffset */
2171 srect->x1 + col * xrel, yoffset - (int) (row * yrel),
2175 glCopyTexSubImage2D(This->glDescription.target,
2176 This->glDescription.level,
2177 drect->x1, row, /* xoffset, yoffset */
2178 srect->x1, yoffset - (int) (row * yrel),
2179 drect->x2-drect->x1, 1);
2184 vcheckGLcall("glCopyTexSubImage2D");
2188 /* Uses the hardware to stretch and flip the image */
2189 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2191 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2192 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2193 float left, right, top, bottom; /* Texture coordinates */
2194 UINT fbwidth = Src->currentDesc.Width;
2195 UINT fbheight = Src->currentDesc.Height;
2197 TRACE("Using hwstretch blit\n");
2198 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2200 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2202 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2203 * we are reading from the back buffer, the backup can be used as source texture
2205 glGenTextures(1, &backup);
2206 checkGLcall("glGenTextures(1, &backup)");
2207 glBindTexture(GL_TEXTURE_2D, backup);
2208 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
2210 glReadBuffer(GL_BACK);
2211 checkGLcall("glReadBuffer(GL_BACK)");
2213 /* TODO: Only back up the part that will be overwritten */
2214 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2215 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2216 checkGLcall("glTexImage2D");
2218 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2219 0, 0 /* read offsets */,
2224 checkGLcall("glCopyTexSubImage2D");
2226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2227 checkGLcall("glTexParameteri");
2228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2229 checkGLcall("glTexParameteri");
2231 if(!swapchain || (IWineD3DSurface *) This == swapchain->backBuffer[0]) {
2234 glReadBuffer(GL_FRONT);
2235 checkGLcall("glReadBuffer(GL_FRONT)");
2237 glGenTextures(1, &src);
2238 checkGLcall("glGenTextures(1, &src)");
2239 glBindTexture(GL_TEXTURE_2D, src);
2240 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
2242 /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
2243 * out for power of 2 sizes
2245 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2246 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2247 checkGLcall("glTexImage2D");
2248 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2249 0, 0 /* read offsets */,
2254 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2255 checkGLcall("glTexParameteri");
2256 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2257 checkGLcall("glTexParameteri");
2259 glReadBuffer(GL_BACK);
2260 checkGLcall("glReadBuffer(GL_BACK)");
2262 checkGLcall("glEnd and previous");
2264 left = (float) srect->x1 / (float) Src->pow2Width;
2265 right = (float) srect->x2 / (float) Src->pow2Width;
2268 top = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2269 bottom = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2271 top = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2272 bottom = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2275 /* draw the source texture stretched and upside down. The correct surface is bound already */
2276 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2277 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2281 glTexCoord2f(left, bottom);
2282 glVertex2i(0, fbheight);
2285 glTexCoord2f(left, top);
2286 glVertex2i(0, fbheight - drect->y2 - drect->y1);
2289 glTexCoord2f(right, top);
2290 glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1);
2293 glTexCoord2f(right, bottom);
2294 glVertex2i(drect->x2 - drect->x1, fbheight);
2296 checkGLcall("glEnd and previous");
2298 /* Now read the stretched and upside down image into the destination texture */
2299 glBindTexture(This->glDescription.target, This->glDescription.textureName);
2300 checkGLcall("glBindTexture");
2301 glCopyTexSubImage2D(This->glDescription.target,
2303 drect->x1, drect->y1, /* xoffset, yoffset */
2304 0, 0, /* We blitted the image to the origin */
2305 drect->x2 - drect->x1, drect->y2 - drect->y1);
2306 checkGLcall("glCopyTexSubImage2D");
2308 /* Write the back buffer backup back */
2309 glBindTexture(GL_TEXTURE_2D, backup);
2310 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
2314 glTexCoord2f(0.0, (float) fbheight / (float) Src->pow2Height);
2318 glTexCoord2f(0.0, 0.0);
2319 glVertex2i(0, fbheight);
2322 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, 0.0);
2323 glVertex2i(fbwidth, Src->currentDesc.Height);
2326 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
2327 glVertex2i(fbwidth, 0);
2332 glDeleteTextures(1, &src);
2333 checkGLcall("glDeleteTextures(1, &src)");
2335 glDeleteTextures(1, &backup);
2336 checkGLcall("glDeleteTextures(1, &backup)");
2340 /* Not called from the VTable */
2341 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2343 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2344 IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
2345 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2348 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2350 /* Get the swapchain. One of the surfaces has to be a primary surface */
2351 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
2352 if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
2354 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
2355 if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
2358 /* Early sort out of cases where no render target is used */
2359 if(!dstSwapchain && !srcSwapchain &&
2360 SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2361 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
2362 return WINED3DERR_INVALIDCALL;
2365 /* No destination color keying supported */
2366 if(Flags & (DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE)) {
2367 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2368 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2369 return WINED3DERR_INVALIDCALL;
2373 rect.x1 = DestRect->left;
2374 rect.y1 = DestRect->top;
2375 rect.x2 = DestRect->right;
2376 rect.y2 = DestRect->bottom;
2380 rect.x2 = This->currentDesc.Width;
2381 rect.y2 = This->currentDesc.Height;
2384 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
2385 if(dstSwapchain && dstSwapchain == srcSwapchain) {
2386 /* Half-life does a Blt from the back buffer to the front buffer,
2387 * Full surface size, no flags... Use present instead
2390 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2392 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2393 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2400 /* Check the Destination rect and the surface sizes */
2402 (rect.x1 == 0) && (rect.y1 == 0) &&
2403 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2404 (This->currentDesc.Width == Src->currentDesc.Width) &&
2405 (This->currentDesc.Height == Src->currentDesc.Height)) {
2406 /* These flags are unimportant for the flag check, remove them */
2408 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2409 if( dstSwapchain->backBuffer && ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) &&
2410 SrcSurface == dstSwapchain->backBuffer[0] ) {
2412 D3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
2414 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2415 * take very long, while a flip is fast.
2416 * This applies to Half-Life, which does such Blts every time it finished
2417 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2418 * menu. This is also used by all apps when they do windowed rendering
2420 * The problem is that flipping is not really the same as copying. After a
2421 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2422 * untouched. Therefore it's necessary to override the swap effect
2423 * and to set it back after the flip.
2426 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2428 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2429 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2430 NULL, NULL, 0, NULL);
2432 dstSwapchain->presentParms.SwapEffect = orig_swap;
2439 TRACE("Unsupported blit between buffers on the same swapchain\n");
2440 return WINED3DERR_INVALIDCALL;
2441 } else if((dstSwapchain || This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) &&
2442 (srcSwapchain || SrcSurface == myDevice->render_targets[0]) ) {
2443 ERR("Can't perform hardware blit between 2 different swapchains, falling back to software\n");
2444 return WINED3DERR_INVALIDCALL;
2447 if(srcSwapchain || SrcSurface == myDevice->render_targets[0]) {
2448 /* Blit from render target to texture */
2450 BOOL upsideDown, stretchx;
2452 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2453 TRACE("Color keying not supported by frame buffer to texture blit\n");
2454 return WINED3DERR_INVALIDCALL;
2455 /* Destination color key is checked above */
2458 /* Call preload for the surface to make sure it isn't dirty */
2459 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2461 /* Make sure that the top pixel is always above the bottom pixel, and keep a seperate upside down flag
2462 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2465 if(SrcRect->top < SrcRect->bottom) {
2466 srect.y1 = SrcRect->top;
2467 srect.y2 = SrcRect->bottom;
2470 srect.y1 = SrcRect->bottom;
2471 srect.y2 = SrcRect->top;
2474 srect.x1 = SrcRect->left;
2475 srect.x2 = SrcRect->right;
2479 srect.x2 = Src->currentDesc.Width;
2480 srect.y2 = Src->currentDesc.Height;
2483 if(rect.x1 > rect.x2) {
2487 upsideDown = !upsideDown;
2490 if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
2496 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2497 * flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully,
2498 * not implemented by now). Otherwise:
2500 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2501 * -> If the app wants a image width an unscaled width, copy it line per line
2502 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
2503 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2504 * back buffer. This is slower than reading line per line, thus not used for flipping
2505 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2508 if(FALSE /* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */) {
2509 TRACE("Using GL_EXT_framebuffer_blit for copying\n");
2510 } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
2511 rect.y2 - rect.y1 > Src->currentDesc.Height) {
2512 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
2513 fb_copy_to_texture_direct(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
2515 TRACE("Using hardware stretching to flip / stretch the texture\n");
2516 fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
2519 if(!(This->Flags & SFLAG_DONOTFREE)) {
2520 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2521 This->resource.allocatedMemory = NULL;
2523 This->Flags |= SFLAG_GLDIRTY;
2528 /* Blit from offscreen surface to render target */
2529 float glTexCoord[4];
2530 DWORD oldCKeyFlags = Src->CKeyFlags;
2531 DDCOLORKEY oldBltCKey = This->SrcBltCKey;
2532 RECT SourceRectangle;
2535 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2538 SourceRectangle.left = SrcRect->left;
2539 SourceRectangle.right = SrcRect->right;
2540 SourceRectangle.top = SrcRect->top;
2541 SourceRectangle.bottom = SrcRect->bottom;
2543 SourceRectangle.left = 0;
2544 SourceRectangle.right = Src->currentDesc.Width;
2545 SourceRectangle.top = 0;
2546 SourceRectangle.bottom = Src->currentDesc.Height;
2549 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2550 /* Fall back to software */
2551 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2552 SourceRectangle.left, SourceRectangle.top,
2553 SourceRectangle.right, SourceRectangle.bottom);
2554 return WINED3DERR_INVALIDCALL;
2557 /* Color keying: Check if we have to do a color keyed blt,
2558 * and if not check if a color key is activated.
2560 * Just modify the color keying parameters in the surface and restore them afterwards
2561 * The surface keeps track of the color key last used to load the opengl surface.
2562 * PreLoad will catch the change to the flags and color key and reload if neccessary.
2564 if(Flags & DDBLT_KEYSRC) {
2565 /* Use color key from surface */
2566 } else if(Flags & DDBLT_KEYSRCOVERRIDE) {
2567 /* Use color key from DDBltFx */
2568 Src->CKeyFlags |= DDSD_CKSRCBLT;
2569 This->SrcBltCKey = DDBltFx->ddckSrcColorkey;
2571 /* Do not use color key */
2572 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2575 /* Now load the surface */
2576 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2580 /* Activate the destination context, set it up for blitting */
2581 ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
2583 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2584 if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer) {
2585 TRACE("Drawing to front buffer\n");
2586 glDrawBuffer(GL_FRONT);
2587 checkGLcall("glDrawBuffer GL_FRONT");
2590 /* Bind the texture */
2591 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2592 checkGLcall("glBindTexture");
2594 /* No filtering for blts */
2595 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2597 checkGLcall("glTexParameteri");
2598 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2600 checkGLcall("glTexParameteri");
2601 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2602 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2603 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2604 checkGLcall("glTexEnvi");
2606 /* This is for color keying */
2607 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2608 glEnable(GL_ALPHA_TEST);
2609 checkGLcall("glEnable GL_ALPHA_TEST");
2610 glAlphaFunc(GL_NOTEQUAL, 0.0);
2611 checkGLcall("glAlphaFunc\n");
2613 glDisable(GL_ALPHA_TEST);
2614 checkGLcall("glDisable GL_ALPHA_TEST");
2617 /* Draw a textured quad
2621 glColor3d(1.0f, 1.0f, 1.0f);
2622 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2627 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2628 glVertex3f(rect.x1, rect.y2, 0.0);
2630 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2635 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2640 checkGLcall("glEnd");
2642 /* Unbind the texture */
2643 glBindTexture(GL_TEXTURE_2D, 0);
2644 checkGLcall("glEnable glBindTexture");
2646 if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer && oldDraw == GL_BACK) {
2647 glDrawBuffer(oldDraw);
2649 /* Restore the color key parameters */
2650 Src->CKeyFlags = oldCKeyFlags;
2651 This->SrcBltCKey = oldBltCKey;
2655 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2656 This->Flags |= SFLAG_GLDIRTY;
2660 /* Source-Less Blit to render target */
2661 if (Flags & DDBLT_COLORFILL) {
2662 /* This is easy to handle for the D3D Device... */
2665 TRACE("Colorfill\n");
2667 /* The color as given in the Blt function is in the format of the frame-buffer...
2668 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2670 if (This->resource.format == WINED3DFMT_P8) {
2671 if (This->palette) {
2672 color = ((0xFF000000) |
2673 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2674 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2675 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2680 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2681 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2684 color = ((0xFF000000) |
2685 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2686 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2687 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2690 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2691 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2692 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2694 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2695 color = DDBltFx->u5.dwFillColor;
2698 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2699 return WINED3DERR_INVALIDCALL;
2702 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2703 if(dstSwapchain && dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]) {
2704 glDrawBuffer(GL_BACK);
2705 checkGLcall("glDrawBuffer(GL_BACK)");
2706 } else if (dstSwapchain && This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer) {
2707 glDrawBuffer(GL_FRONT);
2708 checkGLcall("glDrawBuffer(GL_FRONT)");
2709 } else if(This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2710 glDrawBuffer(GL_BACK);
2711 checkGLcall("glDrawBuffer(GL_BACK)");
2713 TRACE("Surface is higher back buffer, falling back to software\n");
2714 return WINED3DERR_INVALIDCALL;
2717 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2719 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2720 1 /* Number of rectangles */,
2722 WINED3DCLEAR_TARGET,
2727 /* Restore the original draw buffer */
2728 if(!dstSwapchain || (dstSwapchain->backBuffer && dstSwapchain->backBuffer[0])) {
2729 glDrawBuffer(GL_BACK);
2730 vcheckGLcall("glDrawBuffer");
2737 /* Default: Fall back to the generic blt. Not an error, a TRACE is enought */
2738 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2739 return WINED3DERR_INVALIDCALL;
2742 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2743 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2744 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2745 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2746 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2747 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2749 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair */
2750 if(myDevice->inScene &&
2751 (iface == myDevice->stencilBufferTarget ||
2752 (SrcSurface && SrcSurface == myDevice->stencilBufferTarget))) {
2753 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2754 return WINED3DERR_INVALIDCALL;
2757 /* Special cases for RenderTargets */
2758 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2759 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2760 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2763 /* For the rest call the X11 surface implementation.
2764 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2765 * other Blts are rather rare
2767 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2770 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2771 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2772 TRACE("(%p)->(%x)\n", This, Flags);
2777 case DDGBS_ISBLTDONE:
2781 return DDERR_INVALIDPARAMS;
2785 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2786 /* XXX: DDERR_INVALIDSURFACETYPE */
2788 TRACE("(%p)->(%08x)\n",iface,Flags);
2791 case DDGFS_ISFLIPDONE:
2795 return DDERR_INVALIDPARAMS;
2799 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2800 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2801 TRACE("(%p)\n", This);
2803 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2806 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2807 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2808 TRACE("(%p)\n", This);
2810 /* So far we don't lose anything :) */
2811 This->Flags &= ~SFLAG_LOST;
2815 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2816 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2817 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2818 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2819 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2821 if(myDevice->inScene &&
2822 (iface == myDevice->stencilBufferTarget ||
2823 (Source && Source == myDevice->stencilBufferTarget))) {
2824 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2825 return WINED3DERR_INVALIDCALL;
2828 /* Special cases for RenderTargets */
2829 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2830 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2832 RECT SrcRect, DstRect;
2836 SrcRect.left = rsrc->left;
2837 SrcRect.top= rsrc->top;
2838 SrcRect.bottom = rsrc->bottom;
2839 SrcRect.right = rsrc->right;
2843 SrcRect.right = srcImpl->currentDesc.Width;
2844 SrcRect.bottom = srcImpl->currentDesc.Height;
2847 DstRect.left = dstx;
2849 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2850 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2852 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2853 if(trans & DDBLTFAST_SRCCOLORKEY)
2854 Flags |= DDBLT_KEYSRC;
2855 if(trans & DDBLTFAST_DESTCOLORKEY)
2856 Flags |= DDBLT_KEYDEST;
2857 if(trans & DDBLTFAST_WAIT)
2858 Flags |= DDBLT_WAIT;
2859 if(trans & DDBLTFAST_DONOTWAIT)
2860 Flags |= DDBLT_DONOTWAIT;
2862 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2866 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2869 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2870 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2871 TRACE("(%p)->(%p)\n", This, Pal);
2873 *Pal = (IWineD3DPalette *) This->palette;
2877 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2878 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2880 IWineD3DPaletteImpl *pal = This->palette;
2882 TRACE("(%p)\n", This);
2884 if(This->resource.format == WINED3DFMT_P8 ||
2885 This->resource.format == WINED3DFMT_A8P8)
2887 TRACE("Dirtifying surface\n");
2888 This->Flags |= SFLAG_DIRTY;
2891 if(This->Flags & SFLAG_DIBSECTION) {
2892 TRACE("(%p): Updating the hdc's palette\n", This);
2893 for (n=0; n<256; n++) {
2895 col[n].rgbRed = pal->palents[n].peRed;
2896 col[n].rgbGreen = pal->palents[n].peGreen;
2897 col[n].rgbBlue = pal->palents[n].peBlue;
2899 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2900 /* Use the default device palette */
2901 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2902 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2903 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2905 col[n].rgbReserved = 0;
2907 SetDIBColorTable(This->hDC, 0, 256, col);
2913 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2914 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2915 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2916 TRACE("(%p)->(%p)\n", This, Pal);
2918 if(This->palette != NULL)
2919 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2920 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2922 if(PalImpl != NULL) {
2923 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2924 /* Set the device's main palette if the palette
2925 * wasn't a primary palette before
2927 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2928 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2931 for(i=0; i < 256; i++) {
2932 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2936 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2939 This->palette = PalImpl;
2941 return IWineD3DSurface_RealizePalette(iface);
2944 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2945 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2946 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
2948 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2949 FIXME(" colorkey value not supported (%08x) !\n", Flags);
2950 return DDERR_INVALIDPARAMS;
2953 /* Dirtify the surface, but only if a key was changed */
2955 switch (Flags & ~DDCKEY_COLORSPACE) {
2956 case DDCKEY_DESTBLT:
2957 This->DestBltCKey = *CKey;
2958 This->CKeyFlags |= DDSD_CKDESTBLT;
2961 case DDCKEY_DESTOVERLAY:
2962 This->DestOverlayCKey = *CKey;
2963 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2966 case DDCKEY_SRCOVERLAY:
2967 This->SrcOverlayCKey = *CKey;
2968 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2972 This->SrcBltCKey = *CKey;
2973 This->CKeyFlags |= DDSD_CKSRCBLT;
2978 switch (Flags & ~DDCKEY_COLORSPACE) {
2979 case DDCKEY_DESTBLT:
2980 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2983 case DDCKEY_DESTOVERLAY:
2984 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2987 case DDCKEY_SRCOVERLAY:
2988 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2992 This->CKeyFlags &= ~DDSD_CKSRCBLT;
3000 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3001 /** Check against the maximum texture sizes supported by the video card **/
3002 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3004 TRACE("%p\n", This);
3005 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3006 /* one of three options
3007 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)
3008 2: Set the texture to the maxium size (bad idea)
3009 3: WARN and return WINED3DERR_NOTAVAILABLE;
3010 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.
3012 WARN("(%p) Creating an oversized surface\n", This);
3013 This->Flags |= SFLAG_OVERSIZE;
3015 /* This will be initialized on the first blt */
3016 This->glRect.left = 0;
3017 This->glRect.top = 0;
3018 This->glRect.right = 0;
3019 This->glRect.bottom = 0;
3021 /* No oversize, gl rect is the full texture size */
3022 This->Flags &= ~SFLAG_OVERSIZE;
3023 This->glRect.left = 0;
3024 This->glRect.top = 0;
3025 This->glRect.right = This->pow2Width;
3026 This->glRect.bottom = This->pow2Height;
3032 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3033 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3035 TRACE("(%p)\n", This);
3037 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3038 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3039 ie pitch = (width/4) * bytes per block */
3040 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3041 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3042 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3043 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3044 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3046 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3047 /* Surfaces are 32 bit aligned */
3048 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3050 TRACE("(%p) Returning %d\n", This, ret);
3054 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3055 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3057 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3059 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3061 TRACE("(%p): Not an overlay surface\n", This);
3062 return DDERR_NOTAOVERLAYSURFACE;
3068 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3069 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3071 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3073 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3075 TRACE("(%p): Not an overlay surface\n", This);
3076 return DDERR_NOTAOVERLAYSURFACE;
3082 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3083 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3084 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3086 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3088 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3090 TRACE("(%p): Not an overlay surface\n", This);
3091 return DDERR_NOTAOVERLAYSURFACE;
3097 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3098 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3099 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3100 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3102 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3104 TRACE("(%p): Not an overlay surface\n", This);
3105 return DDERR_NOTAOVERLAYSURFACE;
3111 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3114 IWineD3DSurfaceImpl_QueryInterface,
3115 IWineD3DSurfaceImpl_AddRef,
3116 IWineD3DSurfaceImpl_Release,
3117 /* IWineD3DResource */
3118 IWineD3DSurfaceImpl_GetParent,
3119 IWineD3DSurfaceImpl_GetDevice,
3120 IWineD3DSurfaceImpl_SetPrivateData,
3121 IWineD3DSurfaceImpl_GetPrivateData,
3122 IWineD3DSurfaceImpl_FreePrivateData,
3123 IWineD3DSurfaceImpl_SetPriority,
3124 IWineD3DSurfaceImpl_GetPriority,
3125 IWineD3DSurfaceImpl_PreLoad,
3126 IWineD3DSurfaceImpl_GetType,
3127 /* IWineD3DSurface */
3128 IWineD3DSurfaceImpl_GetContainer,
3129 IWineD3DSurfaceImpl_GetDesc,
3130 IWineD3DSurfaceImpl_LockRect,
3131 IWineD3DSurfaceImpl_UnlockRect,
3132 IWineD3DSurfaceImpl_GetDC,
3133 IWineD3DSurfaceImpl_ReleaseDC,
3134 IWineD3DSurfaceImpl_Flip,
3135 IWineD3DSurfaceImpl_Blt,
3136 IWineD3DSurfaceImpl_GetBltStatus,
3137 IWineD3DSurfaceImpl_GetFlipStatus,
3138 IWineD3DSurfaceImpl_IsLost,
3139 IWineD3DSurfaceImpl_Restore,
3140 IWineD3DSurfaceImpl_BltFast,
3141 IWineD3DSurfaceImpl_GetPalette,
3142 IWineD3DSurfaceImpl_SetPalette,
3143 IWineD3DSurfaceImpl_RealizePalette,
3144 IWineD3DSurfaceImpl_SetColorKey,
3145 IWineD3DSurfaceImpl_GetPitch,
3146 IWineD3DSurfaceImpl_SetMem,
3147 IWineD3DSurfaceImpl_SetOverlayPosition,
3148 IWineD3DSurfaceImpl_GetOverlayPosition,
3149 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3150 IWineD3DSurfaceImpl_UpdateOverlay,
3152 IWineD3DSurfaceImpl_CleanDirtyRect,
3153 IWineD3DSurfaceImpl_AddDirtyRect,
3154 IWineD3DSurfaceImpl_LoadTexture,
3155 IWineD3DSurfaceImpl_SaveSnapshot,
3156 IWineD3DSurfaceImpl_SetContainer,
3157 IWineD3DSurfaceImpl_SetPBufferState,
3158 IWineD3DSurfaceImpl_SetGlTextureDesc,
3159 IWineD3DSurfaceImpl_GetGlDesc,
3160 IWineD3DSurfaceImpl_GetData,
3161 IWineD3DSurfaceImpl_SetFormat,
3162 IWineD3DSurfaceImpl_PrivateSetup