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
50 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf);
52 static void surface_download_data(IWineD3DSurfaceImpl *This) {
53 if (This->resource.format == WINED3DFMT_DXT1 ||
54 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
55 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
56 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* We can assume this as the texture would not have been created otherwise */
57 FIXME("(%p) : Attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
59 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
60 This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
64 GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory));
65 checkGLcall("glGetCompressedTexImageARB()");
70 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
71 This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
75 glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
76 This->glDescription.glType, This->resource.allocatedMemory);
77 checkGLcall("glGetTexImage()");
81 if (wined3d_settings.nonpower2_mode == NP2_REPACK) {
83 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
84 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
85 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
89 * instead of boxing the texture :
90 * |<-texture width ->| -->pow2width| /\
91 * |111111111111111111| | |
92 * |222 Texture 222222| boxed empty | texture height
93 * |3333 Data 33333333| | |
94 * |444444444444444444| | \/
95 * ----------------------------------- |
96 * | boxed empty | boxed empty | pow2height
98 * -----------------------------------
101 * we're repacking the data to the expected texture width
103 * |<-texture width ->| -->pow2width| /\
104 * |111111111111111111222222222222222| |
105 * |222333333333333333333444444444444| texture height
109 * | empty | pow2height
111 * -----------------------------------
115 * |<-texture width ->| /\
116 * |111111111111111111|
117 * |222222222222222222|texture height
118 * |333333333333333333|
119 * |444444444444444444| \/
120 * --------------------
122 * this also means that any references to allocatedMemory should work with the data as if were a
123 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
125 * internally the texture is still stored in a boxed format so any references to textureName will
126 * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
129 if (This->Flags & SFLAG_NONPOW2) {
130 LPBYTE src_data, dst_data;
131 int src_pitch = This->bytesPerPixel * This->pow2Width;
132 int dst_pitch = This->bytesPerPixel * This->currentDesc.Width;
135 src_data = dst_data = This->resource.allocatedMemory;
136 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
137 for (y = 1 ; y < This->currentDesc.Height; y++) {
138 /* skip the first row */
139 src_data += src_pitch;
140 dst_data += dst_pitch;
141 memcpy(dst_data, src_data, dst_pitch);
148 static void surface_upload_data(IWineD3DSurfaceImpl *This, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data) {
149 if (This->resource.format == WINED3DFMT_DXT1 ||
150 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
151 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
152 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
153 FIXME("Using DXT1/3/5 without advertized support\n");
155 TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data);
157 GL_EXTCALL(glCompressedTexSubImage2DARB(This->glDescription.target, This->glDescription.level, 0, 0, width, height,
158 This->glDescription.glFormatInternal, This->resource.size, data));
159 checkGLcall("glCompressedTexSubImage2D");
163 TRACE("(%p) : Calling glTexSubImage2D w %d, h %d, data, %p\n", This, width, height, data);
165 glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data);
166 checkGLcall("glTexSubImage2D");
171 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type) {
172 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,
173 This->glDescription.target, This->glDescription.level, debug_d3dformat(This->resource.format), internal, width, height, format, type);
177 glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, NULL);
178 checkGLcall("glTexImage2D");
183 /* *******************************************
184 IWineD3DSurface IUnknown parts follow
185 ******************************************* */
186 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
188 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
189 /* Warn ,but be nice about things */
190 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
192 if (IsEqualGUID(riid, &IID_IUnknown)
193 || IsEqualGUID(riid, &IID_IWineD3DBase)
194 || IsEqualGUID(riid, &IID_IWineD3DResource)
195 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
196 IUnknown_AddRef((IUnknown*)iface);
201 return E_NOINTERFACE;
204 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
205 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
206 ULONG ref = InterlockedIncrement(&This->resource.ref);
207 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
211 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
212 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
213 ULONG ref = InterlockedDecrement(&This->resource.ref);
214 TRACE("(%p) : Releasing from %d\n", This, ref + 1);
216 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
217 TRACE("(%p) : cleaning up\n", This);
218 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
220 TRACE("Deleting texture %d\n", This->glDescription.textureName);
221 glDeleteTextures(1, &This->glDescription.textureName);
225 if(This->Flags & SFLAG_DIBSECTION) {
227 SelectObject(This->hDC, This->dib.holdbitmap);
229 /* Release the DIB section */
230 DeleteObject(This->dib.DIBsection);
231 This->dib.bitmap_data = NULL;
232 This->resource.allocatedMemory = NULL;
234 if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
236 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
237 if(iface == device->ddraw_primary)
238 device->ddraw_primary = NULL;
240 if(iface == device->lastActiveRenderTarget) {
241 device->lastActiveRenderTarget = NULL;
244 TRACE("(%p) Released\n", This);
245 HeapFree(GetProcessHeap(), 0, This);
251 /* ****************************************************
252 IWineD3DSurface IWineD3DResource parts follow
253 **************************************************** */
254 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
255 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
258 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
259 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
262 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
263 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
266 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
267 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
270 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
271 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
274 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
275 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
278 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
279 /* TODO: re-write the way textures and managed,
280 * use a 'opengl context manager' to manage RenderTarget surfaces
281 ** *********************************************************/
283 /* TODO: check for locks */
284 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
285 IWineD3DBaseTexture *baseTexture = NULL;
286 TRACE("(%p)Checking to see if the container is a base texture\n", This);
287 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
288 TRACE("Passing to conatiner\n");
289 IWineD3DBaseTexture_PreLoad(baseTexture);
290 IWineD3DBaseTexture_Release(baseTexture);
292 TRACE("(%p) : About to load surface\n", This);
294 #if 0 /* TODO: context manager support */
295 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
297 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
298 if (!This->glDescription.level) {
299 if (!This->glDescription.textureName) {
300 glGenTextures(1, &This->glDescription.textureName);
301 checkGLcall("glGenTextures");
302 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
304 glBindTexture(This->glDescription.target, This->glDescription.textureName);
305 checkGLcall("glBindTexture");
306 IWineD3DSurface_LoadTexture(iface);
307 /* This is where we should be reducing the amount of GLMemoryUsed */
308 } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
309 /* assume this is a coding error not a real error for now */
310 FIXME("Mipmap surface has a glTexture bound to it!\n");
312 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
313 /* Tell opengl to try and keep this texture in video ram (well mostly) */
316 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
318 /* TODO: disable texture support, if it wastn't enabled when we entered. */
319 #if 0 /* TODO: context manager support */
320 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
321 /* we don't care when the state is disabled(if atall) */);
328 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
329 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
330 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
333 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
334 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
335 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
338 /* ******************************************************
339 IWineD3DSurface IWineD3DSurface parts follow
340 ****************************************************** */
342 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
343 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
344 IWineD3DBase *container = 0;
346 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
349 ERR("Called without a valid ppContainer.\n");
353 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
354 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
355 * GetContainer will return the Direct3D device used to create the surface.
357 if (This->container) {
358 container = This->container;
360 container = (IWineD3DBase *)This->resource.wineD3DDevice;
363 TRACE("Relaying to QueryInterface\n");
364 return IUnknown_QueryInterface(container, riid, ppContainer);
367 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
368 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
370 TRACE("(%p) : copying into %p\n", This, pDesc);
371 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
372 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
373 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
374 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
375 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
376 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
377 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
378 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
379 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
383 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
384 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
385 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
386 if (This->glDescription.textureName == 0 && textureName != 0) {
387 This->Flags |= SFLAG_DIRTY;
388 IWineD3DSurface_AddDirtyRect(iface, NULL);
390 This->glDescription.textureName = textureName;
391 This->glDescription.target = target;
394 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
395 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
396 TRACE("(%p) : returning %p\n", This, &This->glDescription);
397 *glDescription = &This->glDescription;
400 /* TODO: think about moving this down to resource? */
401 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
402 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
403 /* 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 */
404 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
405 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
407 return (CONST void*)(This->resource.allocatedMemory);
410 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) {
416 switch(This->resource.format)
420 /* GL can't return palettized data, so read ARGB pixels into a
421 * separate block of memory and convert them into palettized format
422 * in software. Slow, but if the app means to use palettized render
423 * targets and locks it...
425 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
426 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
427 * for the color channels when palettizing the colors.
430 type = GL_UNSIGNED_BYTE;
432 mem = HeapAlloc(GetProcessHeap(), 0, (rect->bottom - rect->top) * pitch);
434 ERR("Out of memory\n");
442 fmt = This->glDescription.glFormat;
443 type = This->glDescription.glType;
446 if (rect->left == 0 &&
447 rect->right == This->currentDesc.Width ) {
448 BYTE *row, *top, *bottom;
451 glReadPixels(0, rect->top,
452 This->currentDesc.Width,
453 rect->bottom - rect->top,
458 /* glReadPixels returns the image upside down, and there is no way to prevent this.
459 Flip the lines in software */
460 row = HeapAlloc(GetProcessHeap(), 0, pitch);
462 ERR("Out of memory\n");
466 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
467 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
468 memcpy(row, top, pitch);
469 memcpy(top, bottom, pitch);
470 memcpy(bottom, row, pitch);
474 HeapFree(GetProcessHeap(), 0, row);
476 if(This->lockedRect.top == 0 && This->lockedRect.bottom == This->currentDesc.Height) {
477 This->Flags &= ~SFLAG_GLDIRTY;
480 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
481 glReadPixels(rect->left,
482 rect->bottom - j - 1,
483 rect->right - rect->left,
487 (char *)mem + (pitch * (j-rect->top)));
491 vcheckGLcall("glReadPixels");
493 if(This->resource.format == WINED3DFMT_P8) {
495 DWORD width = pitch / 3;
498 pal = This->palette->palents;
500 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
503 for(y = rect->top; y < rect->bottom; y++) {
504 for(x = rect->left; x < rect->right; x++) {
505 /* start lines pixels */
506 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
507 BYTE *green = blue + 1;
508 BYTE *red = green + 1;
510 for(c = 0; c < 256; c++) {
511 if(*red == pal[c].peRed &&
512 *green == pal[c].peGreen &&
513 *blue == pal[c].peBlue)
515 *((BYTE *) dest + y * width + x) = c;
521 HeapFree(GetProcessHeap(), 0, mem);
525 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
526 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
527 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
528 IWineD3DSwapChainImpl *swapchain = NULL;
530 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
532 if (!(This->Flags & SFLAG_LOCKABLE)) {
533 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
534 texture regions, and since the destination is an unlockable region we need
536 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
537 /*return WINED3DERR_INVALIDCALL; */
540 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
542 /* Mark the surface locked */
543 This->Flags |= SFLAG_LOCKED;
545 /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy */
546 if(!This->resource.allocatedMemory) {
547 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + 4);
548 This->Flags |= SFLAG_GLDIRTY; /* This is the marker that surface data has to be downloaded */
551 /* Calculate the correct start address to report */
553 pLockedRect->pBits = This->resource.allocatedMemory;
554 This->lockedRect.left = 0;
555 This->lockedRect.top = 0;
556 This->lockedRect.right = This->currentDesc.Width;
557 This->lockedRect.bottom = This->currentDesc.Height;
558 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);
560 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
562 if ((pRect->top < 0) ||
564 (pRect->left >= pRect->right) ||
565 (pRect->top >= pRect->bottom) ||
566 (pRect->right > This->currentDesc.Width) ||
567 (pRect->bottom > This->currentDesc.Height))
569 WARN(" Invalid values in pRect !!!\n");
570 return D3DERR_INVALIDCALL;
573 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
574 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
576 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
578 This->lockedRect.left = pRect->left;
579 This->lockedRect.top = pRect->top;
580 This->lockedRect.right = pRect->right;
581 This->lockedRect.bottom = pRect->bottom;
584 if (This->Flags & SFLAG_NONPOW2) {
585 TRACE("Locking non-power 2 texture\n");
588 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
589 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
592 if(!(This->Flags & SFLAG_DYNLOCK)) {
594 /* MAXLOCKCOUNT is defined in wined3d_private.h */
595 if(This->lockCount > MAXLOCKCOUNT) {
596 TRACE("Surface is locked regularily, not freeing the system memory copy any more\n");
597 This->Flags |= SFLAG_DYNLOCK;
601 if((Flags & WINED3DLOCK_DISCARD) || !(This->Flags & SFLAG_GLDIRTY) ) {
602 TRACE("WINED3DLOCK_DISCARD flag passed, or local copy is up to date, not downloading data\n");
606 /* Now download the surface content from opengl
607 * Use the render target readback if the surface is on a swapchain(=onscreen render target) or the current primary target
608 * Offscreen targets which are not active at the moment or are higher targets(fbos) can be locked with the texture path
610 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
611 if(swapchain || iface == myDevice->render_targets[0]) {
612 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
613 static BOOL warned = FALSE;
615 ERR("The application tries to lock the render target, but render target locking is disabled\n");
618 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
622 /* FIXME: Partial surface locking is broken */
623 if(This->lockedRect.left != 0 ||
624 This->lockedRect.top != 0 ||
625 This->lockedRect.right != This->currentDesc.Width ||
626 This->lockedRect.bottom != This->currentDesc.Height) {
627 FIXME("Add Support for partial render target locking\n");
628 This->lockedRect.left = 0;
629 This->lockedRect.top = 0;
630 This->lockedRect.right = This->currentDesc.Width;
631 This->lockedRect.bottom = This->currentDesc.Height;
633 /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
634 * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
635 * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
636 * context->last_was_blit set on the unlock.
639 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
641 /* Select the correct read buffer, and give some debug output.
642 * There is no need to keep track of the current read buffer or reset it, every part of the code
643 * that reads sets the read buffer as desired.
646 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
647 * Read from the back buffer
649 TRACE("Locking offscreen render target\n");
650 glReadBuffer(GL_BACK);
652 if(iface == swapchain->frontBuffer) {
653 TRACE("Locking the front buffer\n");
654 glReadBuffer(GL_FRONT);
655 } else if(swapchain->backBuffer && iface == swapchain->backBuffer[0]) {
656 TRACE("Locking the back buffer\n");
657 glReadBuffer(GL_BACK);
659 /* Ok, there is an issue: OpenGL does not guarant any back buffer number, so all we can do is to read GL_BACK
660 * and hope it gives what the app wants
662 FIXME("Application is locking a 2nd or higher back buffer\n");
663 glReadBuffer(GL_BACK);
665 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
668 switch(wined3d_settings.rendertargetlock_mode) {
672 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch);
677 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch);
678 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
682 } else if(iface == myDevice->stencilBufferTarget) {
683 /** the depth stencil in openGL has a format of GL_FLOAT
684 * which should be good for WINED3DFMT_D16_LOCKABLE
686 * it is unclear what format the stencil buffer is in except.
687 * 'Each index is converted to fixed point...
688 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
689 * mappings in the table GL_PIXEL_MAP_S_TO_S.
690 * glReadPixels(This->lockedRect.left,
691 * This->lockedRect.bottom - j - 1,
692 * This->lockedRect.right - This->lockedRect.left,
694 * GL_DEPTH_COMPONENT,
696 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
698 * Depth Stencil surfaces which are not the current depth stencil target should have their data in a
699 * gl texture(next path), or in local memory(early return because of missing SFLAG_GLDIRTY above). If
700 * none of that is the case the problem is not in this function :-)
701 ********************************************/
702 FIXME("Depth stencil locking not supported yet\n");
704 /* This path is for normal surfaces, offscreen render targets and everything else that is in a gl texture */
705 TRACE("locking an ordinarary surface\n");
707 /* TODO: Make sure that *any* context is active for this thread. It is not important which context that is,
708 * nor that is has any special setup(CTXUSAGE_LOADRESOURCE is fine), but the code below needs a context.
709 * A context is guaranted to be there in a single threaded environment, but not with multithreading
711 if (0 != This->glDescription.textureName) {
712 /* Now I have to copy thing bits back */
714 /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
715 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
717 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
718 checkGLcall("glActiveTextureARB");
721 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
722 IWineD3DSurface_PreLoad(iface);
724 surface_download_data(This);
729 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
732 IWineD3DBaseTexture *pBaseTexture;
735 * as seen in msdn docs
737 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
739 /** Dirtify Container if needed */
740 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
741 TRACE("Making container dirty\n");
742 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
743 IWineD3DBaseTexture_Release(pBaseTexture);
745 TRACE("Surface is standalone, no need to dirty the container\n");
749 /* The local copy is now up to date to the opengl one */
750 This->Flags &= ~SFLAG_GLDIRTY;
752 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
756 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
758 GLint prev_rasterpos[4];
760 BOOL storechanged = FALSE, memory_allocated = FALSE;
764 glDisable(GL_TEXTURE_2D);
765 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
768 vcheckGLcall("glFlush");
769 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
770 vcheckGLcall("glIntegerv");
771 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
772 vcheckGLcall("glIntegerv");
773 glPixelZoom(1.0, -1.0);
774 vcheckGLcall("glPixelZoom");
776 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
777 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
778 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
780 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
781 vcheckGLcall("glRasterPos2f");
783 /* Some drivers(radeon dri, others?) don't like exceptions during
784 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
785 * after ReleaseDC. Reading it will cause an exception, which x11drv will
786 * catch to put the dib section in InSync mode, which leads to a crash
787 * and a blocked x server on my radeon card.
789 * The following lines read the dib section so it is put in inSync mode
790 * before glDrawPixels is called and the crash is prevented. There won't
791 * be any interfering gdi accesses, because UnlockRect is called from
792 * ReleaseDC, and the app won't use the dc any more afterwards.
794 if(This->Flags & SFLAG_DIBSECTION) {
796 read = This->resource.allocatedMemory[0];
799 switch (This->resource.format) {
800 /* No special care needed */
801 case WINED3DFMT_A4R4G4B4:
802 case WINED3DFMT_R5G6B5:
803 case WINED3DFMT_A1R5G5B5:
804 case WINED3DFMT_R8G8B8:
805 type = This->glDescription.glType;
806 fmt = This->glDescription.glFormat;
807 mem = This->resource.allocatedMemory;
810 case WINED3DFMT_X4R4G4B4:
813 unsigned short *data;
814 data = (unsigned short *)This->resource.allocatedMemory;
815 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
821 type = This->glDescription.glType;
822 fmt = This->glDescription.glFormat;
823 mem = This->resource.allocatedMemory;
827 case WINED3DFMT_X1R5G5B5:
830 unsigned short *data;
831 data = (unsigned short *)This->resource.allocatedMemory;
832 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
838 type = This->glDescription.glType;
839 fmt = This->glDescription.glFormat;
840 mem = This->resource.allocatedMemory;
844 case WINED3DFMT_X8R8G8B8:
846 /* make sure the X byte is set to alpha on, since it
847 could be any random value. This fixes the intro movie in Pirates! */
850 data = (unsigned int *)This->resource.allocatedMemory;
851 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
860 case WINED3DFMT_A8R8G8B8:
862 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
863 vcheckGLcall("glPixelStorei");
865 type = This->glDescription.glType;
866 fmt = This->glDescription.glFormat;
867 mem = This->resource.allocatedMemory;
871 case WINED3DFMT_A2R10G10B10:
873 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
874 vcheckGLcall("glPixelStorei");
876 type = This->glDescription.glType;
877 fmt = This->glDescription.glFormat;
878 mem = This->resource.allocatedMemory;
884 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
885 int height = This->glRect.bottom - This->glRect.top;
886 type = GL_UNSIGNED_BYTE;
889 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
891 ERR("Out of memory\n");
894 memory_allocated = TRUE;
895 d3dfmt_convert_surface(This->resource.allocatedMemory,
907 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
910 type = This->glDescription.glType;
911 fmt = This->glDescription.glFormat;
912 mem = This->resource.allocatedMemory;
915 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
916 (This->lockedRect.bottom - This->lockedRect.top)-1,
919 checkGLcall("glDrawPixels");
920 glPixelZoom(1.0,1.0);
921 vcheckGLcall("glPixelZoom");
923 glRasterPos3iv(&prev_rasterpos[0]);
924 vcheckGLcall("glRasterPos3iv");
926 /* Reset to previous pack row length */
927 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
928 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
930 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
931 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
934 if(memory_allocated) HeapFree(GetProcessHeap(), 0, mem);
938 static void flush_to_framebuffer_texture(IWineD3DSurface *iface) {
939 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
942 glTexCoord[0] = 0.0; /* left */
943 glTexCoord[1] = (float) This->currentDesc.Width / (float) This->pow2Width; /* right */
944 glTexCoord[2] = 0.0; /* top */
945 glTexCoord[3] = (float) This->currentDesc.Height / (float) This->pow2Height; /* bottom */
947 IWineD3DSurface_PreLoad(iface);
951 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
952 checkGLcall("glEnable glBindTexture");
954 /* No filtering for blts */
955 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
956 checkGLcall("glTexParameteri");
957 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
958 checkGLcall("glTexParameteri");
960 /* Start drawing a quad */
963 glColor3d(1.0f, 1.0f, 1.0f);
964 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
965 glVertex3f(0, 0, 0.0);
967 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
968 glVertex3f(0, This->currentDesc.Height, 0.0);
970 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
971 glVertex3d(This->currentDesc.Width, This->currentDesc.Height, 0.0);
973 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
974 glVertex3f(This->currentDesc.Width, 0, 0.0);
977 checkGLcall("glEnd");
979 /* Unbind the texture */
980 glBindTexture(GL_TEXTURE_2D, 0);
981 checkGLcall("glEnable glBindTexture");
986 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
987 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
988 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
989 IWineD3DSwapChainImpl *swapchain = NULL;
991 if (!(This->Flags & SFLAG_LOCKED)) {
992 WARN("trying to Unlock an unlocked surf@%p\n", This);
993 return WINED3DERR_INVALIDCALL;
996 TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0);
998 if (!(This->Flags & SFLAG_DIRTY)) {
999 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1003 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1004 if(swapchain || iface == myDevice->render_targets[0]) {
1005 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1006 static BOOL warned = FALSE;
1008 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1011 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1015 /* Activate the correct context for the render target */
1017 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
1020 /* Primary offscreen render target */
1021 TRACE("Offscreen render target\n");
1022 glDrawBuffer(GL_BACK);
1023 checkGLcall("glDrawBuffer(GL_BACK)");
1025 if(iface == swapchain->frontBuffer) {
1026 TRACE("Onscreen front buffer\n");
1027 glDrawBuffer(GL_FRONT);
1028 checkGLcall("glDrawBuffer(GL_FRONT)");
1029 } else if(iface == swapchain->backBuffer[0]) {
1030 TRACE("Onscreen back buffer\n");
1031 glDrawBuffer(GL_BACK);
1032 checkGLcall("glDrawBuffer(GL_BACK)");
1034 FIXME("Unlocking a higher back buffer\n");
1035 glDrawBuffer(GL_BACK);
1036 checkGLcall("glDrawBuffer(GL_BACK)");
1038 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1041 switch(wined3d_settings.rendertargetlock_mode) {
1045 flush_to_framebuffer_drawpixels(This);
1050 flush_to_framebuffer_texture(iface);
1053 if(!swapchain || swapchain->backBuffer) {
1054 glDrawBuffer(GL_BACK);
1055 checkGLcall("glDrawBuffer(GL_BACK)");
1057 glDrawBuffer(GL_FRONT);
1058 checkGLcall("glDrawBuffer(GL_FRONT)");
1062 /** restore clean dirty state */
1063 IWineD3DSurface_CleanDirtyRect(iface);
1064 } else if(iface == myDevice->stencilBufferTarget) {
1065 FIXME("Depth Stencil buffer locking is not implemented\n");
1067 /* The rest should be a normal texture */
1068 IWineD3DBaseTextureImpl *impl;
1069 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1070 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1071 * states need resetting
1073 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1074 if(impl->baseTexture.bindCount) {
1075 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1077 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1082 This->Flags &= ~SFLAG_LOCKED;
1083 memset(&This->lockedRect, 0, sizeof(RECT));
1087 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1088 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1089 WINED3DLOCKED_RECT lock;
1096 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1098 TRACE("(%p)->(%p)\n",This,pHDC);
1100 if(This->Flags & SFLAG_USERPTR) {
1101 ERR("Not supported on surfaces with an application-provided surfaces\n");
1105 /* Give more detailed info for ddraw */
1106 if (This->Flags & SFLAG_DCINUSE)
1107 return DDERR_DCALREADYCREATED;
1109 /* Can't GetDC if the surface is locked */
1110 if (This->Flags & SFLAG_LOCKED)
1111 return WINED3DERR_INVALIDCALL;
1113 memset(&lock, 0, sizeof(lock)); /* To be sure */
1115 /* Create a DIB section if there isn't a hdc yet */
1118 SYSTEM_INFO sysInfo;
1120 switch (This->bytesPerPixel) {
1123 /* Allocate extra space to store the RGB bit masks. */
1124 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1128 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1132 /* Allocate extra space for a palette. */
1133 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1134 sizeof(BITMAPINFOHEADER)
1136 * (1 << (This->bytesPerPixel * 8)));
1141 return E_OUTOFMEMORY;
1143 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1144 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1145 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1146 * add an extra line to the dib section
1148 GetSystemInfo(&sysInfo);
1149 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1151 TRACE("Adding an extra line to the dib section\n");
1154 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1155 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1156 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1157 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1158 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1159 /* Use the full pow2 image size(assigned below) because LockRect
1160 * will need it for a full glGetTexImage call
1163 b_info->bmiHeader.biWidth = This->pow2Width;
1164 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1165 b_info->bmiHeader.biSizeImage = This->resource.size + extraline * IWineD3DSurface_GetPitch(iface);
1167 b_info->bmiHeader.biPlanes = 1;
1168 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1170 b_info->bmiHeader.biXPelsPerMeter = 0;
1171 b_info->bmiHeader.biYPelsPerMeter = 0;
1172 b_info->bmiHeader.biClrUsed = 0;
1173 b_info->bmiHeader.biClrImportant = 0;
1175 /* Get the bit masks */
1176 masks = (DWORD *) &(b_info->bmiColors);
1177 switch (This->resource.format) {
1178 case WINED3DFMT_R8G8B8:
1179 usage = DIB_RGB_COLORS;
1180 b_info->bmiHeader.biCompression = BI_RGB;
1183 case WINED3DFMT_X1R5G5B5:
1184 case WINED3DFMT_A1R5G5B5:
1185 case WINED3DFMT_A4R4G4B4:
1186 case WINED3DFMT_X4R4G4B4:
1187 case WINED3DFMT_R3G3B2:
1188 case WINED3DFMT_A8R3G3B2:
1189 case WINED3DFMT_A2B10G10R10:
1190 case WINED3DFMT_A8B8G8R8:
1191 case WINED3DFMT_X8B8G8R8:
1192 case WINED3DFMT_A2R10G10B10:
1193 case WINED3DFMT_R5G6B5:
1194 case WINED3DFMT_A16B16G16R16:
1196 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1197 masks[0] = formatEntry->redMask;
1198 masks[1] = formatEntry->greenMask;
1199 masks[2] = formatEntry->blueMask;
1203 /* Don't know palette */
1204 b_info->bmiHeader.biCompression = BI_RGB;
1211 HeapFree(GetProcessHeap(), 0, b_info);
1212 return HRESULT_FROM_WIN32(GetLastError());
1215 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);
1216 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1219 if (!This->dib.DIBsection) {
1220 ERR("CreateDIBSection failed!\n");
1221 HeapFree(GetProcessHeap(), 0, b_info);
1222 return HRESULT_FROM_WIN32(GetLastError());
1225 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1227 /* copy the existing surface to the dib section */
1228 if(This->resource.allocatedMemory) {
1229 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1230 /* We won't need that any more */
1231 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1233 /* This is to make LockRect read the gl Texture although memory is allocated */
1234 This->Flags |= SFLAG_GLDIRTY;
1237 HeapFree(GetProcessHeap(), 0, b_info);
1239 /* Use the dib section from now on */
1240 This->resource.allocatedMemory = This->dib.bitmap_data;
1242 /* Now allocate a HDC */
1243 This->hDC = CreateCompatibleDC(0);
1244 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1245 TRACE("using wined3d palette %p\n", This->palette);
1246 SelectPalette(This->hDC,
1247 This->palette ? This->palette->hpal : 0,
1250 This->Flags |= SFLAG_DIBSECTION;
1253 /* Lock the surface */
1254 hr = IWineD3DSurface_LockRect(iface,
1259 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1260 /* keep the dib section */
1264 if(This->resource.format == WINED3DFMT_P8 ||
1265 This->resource.format == WINED3DFMT_A8P8) {
1268 PALETTEENTRY ent[256];
1270 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1271 for (n=0; n<256; n++) {
1272 col[n].rgbRed = ent[n].peRed;
1273 col[n].rgbGreen = ent[n].peGreen;
1274 col[n].rgbBlue = ent[n].peBlue;
1275 col[n].rgbReserved = 0;
1278 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1280 for (n=0; n<256; n++) {
1281 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1282 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1283 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1284 col[n].rgbReserved = 0;
1288 SetDIBColorTable(This->hDC, 0, 256, col);
1292 TRACE("returning %p\n",*pHDC);
1293 This->Flags |= SFLAG_DCINUSE;
1298 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1299 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1301 TRACE("(%p)->(%p)\n",This,hDC);
1303 if (!(This->Flags & SFLAG_DCINUSE))
1304 return D3DERR_INVALIDCALL;
1306 /* we locked first, so unlock now */
1307 IWineD3DSurface_UnlockRect(iface);
1309 This->Flags &= ~SFLAG_DCINUSE;
1314 /* ******************************************************
1315 IWineD3DSurface Internal (No mapping to directx api) parts follow
1316 ****************************************************** */
1318 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) {
1319 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1320 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1322 /* Default values: From the surface */
1323 *format = formatEntry->glFormat;
1324 *internal = formatEntry->glInternal;
1325 *type = formatEntry->glType;
1326 *convert = NO_CONVERSION;
1327 *target_bpp = This->bytesPerPixel;
1329 /* Ok, now look if we have to do any conversion */
1330 switch(This->resource.format) {
1335 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1336 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1338 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1340 *internal = GL_RGBA;
1341 *type = GL_UNSIGNED_BYTE;
1343 if(colorkey_active) {
1344 *convert = CONVERT_PALETTED_CK;
1346 *convert = CONVERT_PALETTED;
1352 case WINED3DFMT_R3G3B2:
1353 /* **********************
1354 GL_UNSIGNED_BYTE_3_3_2
1355 ********************** */
1356 if (colorkey_active) {
1357 /* This texture format will never be used.. So do not care about color keying
1358 up until the point in time it will be needed :-) */
1359 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1363 case WINED3DFMT_R5G6B5:
1364 if (colorkey_active) {
1365 *convert = CONVERT_CK_565;
1367 *internal = GL_RGBA;
1368 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1372 case WINED3DFMT_R8G8B8:
1373 if (colorkey_active) {
1374 *convert = CONVERT_CK_RGB24;
1376 *internal = GL_RGBA;
1377 *type = GL_UNSIGNED_INT_8_8_8_8;
1382 case WINED3DFMT_X8R8G8B8:
1383 if (colorkey_active) {
1384 *convert = CONVERT_RGB32_888;
1386 *internal = GL_RGBA;
1387 *type = GL_UNSIGNED_INT_8_8_8_8;
1398 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1399 BYTE *source, *dest;
1400 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1405 memcpy(dst, src, pitch * height);
1408 case CONVERT_PALETTED:
1409 case CONVERT_PALETTED_CK:
1411 IWineD3DPaletteImpl* pal = surf->palette;
1417 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1421 /* Still no palette? Use the device's palette */
1422 /* Get the surface's palette */
1423 for (i = 0; i < 256; i++) {
1424 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1426 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1427 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1428 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1429 if ((convert == CONVERT_PALETTED_CK) &&
1430 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1431 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1432 /* We should maybe here put a more 'neutral' color than the standard bright purple
1433 one often used by application to prevent the nice purple borders when bi-linear
1441 TRACE("Using surface palette %p\n", pal);
1442 /* Get the surface's palette */
1443 for (i = 0; i < 256; i++) {
1444 table[i][0] = pal->palents[i].peRed;
1445 table[i][1] = pal->palents[i].peGreen;
1446 table[i][2] = pal->palents[i].peBlue;
1447 if ((convert == CONVERT_PALETTED_CK) &&
1448 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1449 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1450 /* We should maybe here put a more 'neutral' color than the standard bright purple
1451 one often used by application to prevent the nice purple borders when bi-linear
1460 for (y = 0; y < height; y++)
1462 source = src + pitch * y;
1463 dest = dst + outpitch * y;
1464 /* This is an 1 bpp format, using the width here is fine */
1465 for (x = 0; x < width; x++) {
1466 BYTE color = *source++;
1467 *dest++ = table[color][0];
1468 *dest++ = table[color][1];
1469 *dest++ = table[color][2];
1470 *dest++ = table[color][3];
1476 case CONVERT_CK_565:
1478 /* Converting the 565 format in 5551 packed to emulate color-keying.
1480 Note : in all these conversion, it would be best to average the averaging
1481 pixels to get the color of the pixel that will be color-keyed to
1482 prevent 'color bleeding'. This will be done later on if ever it is
1485 Note2: Nvidia documents say that their driver does not support alpha + color keying
1486 on the same surface and disables color keying in such a case
1492 TRACE("Color keyed 565\n");
1494 for (y = 0; y < height; y++) {
1495 Source = (WORD *) (src + y * pitch);
1496 Dest = (WORD *) (dst + y * outpitch);
1497 for (x = 0; x < width; x++ ) {
1498 WORD color = *Source++;
1499 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1500 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1501 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1511 ERR("Unsupported conversation type %d\n", convert);
1516 /* This function is used in case of 8bit paletted textures to upload the palette.
1517 For now it only supports GL_EXT_paletted_texture extension but support for other
1518 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1520 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1521 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1522 IWineD3DPaletteImpl* pal = This->palette;
1527 /* Still no palette? Use the device's palette */
1528 /* Get the surface's palette */
1529 for (i = 0; i < 256; i++) {
1530 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1532 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1533 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1534 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1535 if ((convert == CONVERT_PALETTED_CK) &&
1536 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1537 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1538 /* We should maybe here put a more 'neutral' color than the standard bright purple
1539 one often used by application to prevent the nice purple borders when bi-linear
1547 TRACE("Using surface palette %p\n", pal);
1548 /* Get the surface's palette */
1549 for (i = 0; i < 256; i++) {
1550 table[i][0] = pal->palents[i].peRed;
1551 table[i][1] = pal->palents[i].peGreen;
1552 table[i][2] = pal->palents[i].peBlue;
1553 if ((convert == CONVERT_PALETTED_CK) &&
1554 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1555 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1556 /* We should maybe here put a more 'neutral' color than the standard bright purple
1557 one often used by application to prevent the nice purple borders when bi-linear
1565 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1568 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1569 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1570 GLenum format, internal, type;
1571 CONVERT_TYPES convert;
1573 int width, pitch, outpitch;
1576 if (This->Flags & SFLAG_INTEXTURE) {
1577 TRACE("Surface already in texture\n");
1580 if (This->Flags & SFLAG_DIRTY) {
1581 TRACE("Reloading because surface is dirty\n");
1582 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1583 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1584 /* Reload: vice versa OR */
1585 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1586 /* Also reload: Color key is active AND the color key has changed */
1587 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1588 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1589 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1590 TRACE("Reloading because of color keying\n");
1592 TRACE("surface isn't dirty\n");
1596 This->Flags &= ~SFLAG_DIRTY;
1598 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1599 * These resources are not bound by device size or format restrictions. Because of this,
1600 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1601 * However, these resources can always be created, locked, and copied.
1603 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1605 FIXME("(%p) Operation not supported for scratch textures\n",This);
1606 return WINED3DERR_INVALIDCALL;
1609 if (This->Flags & SFLAG_INPBUFFER) {
1610 if (This->glDescription.level != 0)
1611 FIXME("Surface in texture is only supported for level 0\n");
1612 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1613 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1614 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1615 This->resource.format == WINED3DFMT_DXT5)
1616 FIXME("Format %d not supported\n", This->resource.format);
1622 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1623 vcheckGLcall("glGetIntegerv");
1624 glReadBuffer(GL_BACK);
1625 vcheckGLcall("glReadBuffer");
1627 glCopyTexImage2D(This->glDescription.target,
1628 This->glDescription.level,
1629 This->glDescription.glFormatInternal,
1632 This->currentDesc.Width,
1633 This->currentDesc.Height,
1636 checkGLcall("glCopyTexImage2D");
1637 glReadBuffer(prevRead);
1638 vcheckGLcall("glReadBuffer");
1642 TRACE("Updating target %d\n", This->glDescription.target);
1643 This->Flags |= SFLAG_INTEXTURE;
1648 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1649 This->Flags |= SFLAG_GLCKEY;
1650 This->glCKey = This->SrcBltCKey;
1652 else This->Flags &= ~SFLAG_GLCKEY;
1654 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1656 /* The width is in 'length' not in bytes */
1657 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)
1658 width = This->currentDesc.Width;
1660 width = This->pow2Width;
1662 pitch = IWineD3DSurface_GetPitch(iface);
1664 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1665 int height = This->glRect.bottom - This->glRect.top;
1667 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1668 outpitch = width * bpp;
1669 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1671 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1673 ERR("Out of memory %d, %d!\n", outpitch, height);
1674 return WINED3DERR_OUTOFVIDEOMEMORY;
1676 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1678 This->Flags |= SFLAG_CONVERTED;
1679 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1680 d3dfmt_p8_upload_palette(iface, convert);
1681 This->Flags &= ~SFLAG_CONVERTED;
1682 mem = This->resource.allocatedMemory;
1684 This->Flags &= ~SFLAG_CONVERTED;
1685 mem = This->resource.allocatedMemory;
1688 /* Make sure the correct pitch is used */
1689 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1691 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1692 TRACE("non power of two support\n");
1693 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1695 surface_upload_data(This, This->pow2Width, This->pow2Height, format, type, mem);
1698 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1700 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1704 /* Restore the default pitch */
1705 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1707 if (mem != This->resource.allocatedMemory)
1708 HeapFree(GetProcessHeap(), 0, mem);
1712 static unsigned int gen = 0;
1715 if ((gen % 10) == 0) {
1716 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1717 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1720 * debugging crash code
1729 if (!(This->Flags & SFLAG_DONOTFREE)) {
1730 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1731 This->resource.allocatedMemory = NULL;
1739 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1742 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1743 char *allocatedMemory;
1745 IWineD3DSwapChain *swapChain = NULL;
1747 GLuint tmpTexture = 0;
1750 Textures my not be stored in ->allocatedgMemory and a GlTexture
1751 so we should lock the surface before saving a snapshot, or at least check that
1753 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1754 by calling GetTexImage and in compressed form by calling
1755 GetCompressedTexImageARB. Queried compressed images can be saved and
1756 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1757 texture images do not need to be processed by the GL and should
1758 significantly improve texture loading performance relative to uncompressed
1761 /* Setup the width and height to be the internal texture width and height. */
1762 width = This->pow2Width;
1763 height = This->pow2Height;
1764 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1765 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1767 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1768 /* 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 */
1771 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1772 glEnable(GL_TEXTURE_2D);
1774 glGenTextures(1, &tmpTexture);
1775 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1777 glTexImage2D(GL_TEXTURE_2D,
1784 GL_UNSIGNED_INT_8_8_8_8_REV,
1787 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1788 vcheckGLcall("glGetIntegerv");
1789 glReadBuffer(GL_BACK);
1790 vcheckGLcall("glReadBuffer");
1791 glCopyTexImage2D(GL_TEXTURE_2D,
1800 checkGLcall("glCopyTexImage2D");
1801 glReadBuffer(prevRead);
1804 } else { /* bind the real texture */
1805 IWineD3DSurface_PreLoad(iface);
1807 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1809 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1810 glGetTexImage(GL_TEXTURE_2D,
1811 This->glDescription.level,
1813 GL_UNSIGNED_INT_8_8_8_8_REV,
1815 checkGLcall("glTexImage2D");
1817 glBindTexture(GL_TEXTURE_2D, 0);
1818 glDeleteTextures(1, &tmpTexture);
1822 f = fopen(filename, "w+");
1824 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1825 return WINED3DERR_INVALIDCALL;
1827 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1828 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1843 fwrite(&width,2,1,f);
1845 fwrite(&height,2,1,f);
1850 /* 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*/
1852 textureRow = allocatedMemory + (width * (height - 1) *4);
1854 textureRow = allocatedMemory;
1855 for (y = 0 ; y < height; y++) {
1856 for (i = 0; i < width; i++) {
1857 color = *((DWORD*)textureRow);
1858 fputc((color >> 16) & 0xFF, f); /* B */
1859 fputc((color >> 8) & 0xFF, f); /* G */
1860 fputc((color >> 0) & 0xFF, f); /* R */
1861 fputc((color >> 24) & 0xFF, f); /* A */
1864 /* take two rows of the pointer to the texture memory */
1866 (textureRow-= width << 3);
1869 TRACE("Closing file\n");
1873 IWineD3DSwapChain_Release(swapChain);
1875 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1879 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1880 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1881 This->Flags &= ~SFLAG_DIRTY;
1882 This->dirtyRect.left = This->currentDesc.Width;
1883 This->dirtyRect.top = This->currentDesc.Height;
1884 This->dirtyRect.right = 0;
1885 This->dirtyRect.bottom = 0;
1886 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1887 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1892 * Slightly inefficient way to handle multiple dirty rects but it works :)
1894 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1895 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1896 IWineD3DBaseTexture *baseTexture = NULL;
1897 This->Flags |= SFLAG_DIRTY;
1898 if (NULL != pDirtyRect) {
1899 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
1900 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
1901 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
1902 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1904 This->dirtyRect.left = 0;
1905 This->dirtyRect.top = 0;
1906 This->dirtyRect.right = This->currentDesc.Width;
1907 This->dirtyRect.bottom = This->currentDesc.Height;
1909 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
1910 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1911 /* if the container is a basetexture then mark it dirty. */
1912 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1913 TRACE("Passing to conatiner\n");
1914 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1915 IWineD3DBaseTexture_Release(baseTexture);
1920 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
1921 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1923 TRACE("This %p, container %p\n", This, container);
1925 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
1927 TRACE("Setting container to %p from %p\n", container, This->container);
1928 This->container = container;
1933 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1934 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1935 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
1937 if (This->resource.format != WINED3DFMT_UNKNOWN) {
1938 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1939 return WINED3DERR_INVALIDCALL;
1942 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1943 if (format == WINED3DFMT_UNKNOWN) {
1944 This->resource.size = 0;
1945 } else if (format == WINED3DFMT_DXT1) {
1946 /* DXT1 is half byte per pixel */
1947 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
1949 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1950 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1951 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
1953 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1954 This->resource.size *= This->pow2Height;
1958 /* Setup some glformat defaults */
1959 This->glDescription.glFormat = formatEntry->glFormat;
1960 This->glDescription.glFormatInternal = formatEntry->glInternal;
1961 This->glDescription.glType = formatEntry->glType;
1963 if (format != WINED3DFMT_UNKNOWN) {
1964 This->bytesPerPixel = formatEntry->bpp;
1966 This->bytesPerPixel = 0;
1969 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
1971 This->resource.format = format;
1973 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);
1978 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
1979 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1981 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
1982 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
1983 ERR("Not supported on render targets\n");
1984 return WINED3DERR_INVALIDCALL;
1987 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
1988 WARN("Surface is locked or the HDC is in use\n");
1989 return WINED3DERR_INVALIDCALL;
1992 if(Mem && Mem != This->resource.allocatedMemory) {
1994 /* Do I have to copy the old surface content? */
1995 if(This->Flags & SFLAG_DIBSECTION) {
1996 /* Release the DC. No need to hold the critical section for the update
1997 * Thread because this thread runs only on front buffers, but this method
1998 * fails for render targets in the check above.
2000 SelectObject(This->hDC, This->dib.holdbitmap);
2001 DeleteDC(This->hDC);
2002 /* Release the DIB section */
2003 DeleteObject(This->dib.DIBsection);
2004 This->dib.bitmap_data = NULL;
2005 This->resource.allocatedMemory = NULL;
2007 This->Flags &= ~SFLAG_DIBSECTION;
2008 } else if(!(This->Flags & SFLAG_USERPTR)) {
2009 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2011 This->resource.allocatedMemory = Mem;
2012 This->Flags |= SFLAG_USERPTR;
2013 } else if(This->Flags & SFLAG_USERPTR) {
2014 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2015 This->resource.allocatedMemory = NULL;
2016 This->Flags &= ~SFLAG_USERPTR;
2021 /* TODO: replace this function with context management routines */
2022 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2023 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2026 This->Flags |= SFLAG_INPBUFFER;
2028 This->Flags &= ~SFLAG_INPBUFFER;
2032 This->Flags |= SFLAG_INTEXTURE;
2034 This->Flags &= ~SFLAG_INTEXTURE;
2040 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2041 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2042 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2043 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2045 /* Flipping is only supported on RenderTargets */
2046 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2049 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2050 * FIXME("(%p) Target override is not supported by now\n", This);
2051 * Additionally, it isn't really possible to support triple-buffering
2052 * properly on opengl at all
2056 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2057 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2060 /* Does a direct frame buffer -> texture copy. Stretching is done
2061 * with single pixel copy calls
2063 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2064 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2067 BOOL warned = FALSE; /* deliberately not static */
2068 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2072 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2074 /* Bind the target texture */
2075 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2076 checkGLcall("glBindTexture");
2077 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2078 glReadBuffer(GL_BACK);
2080 glReadBuffer(GL_FRONT);
2082 checkGLcall("glReadBuffer");
2084 xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1);
2085 yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1);
2087 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2088 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2092 !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) &&
2093 !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2094 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2096 glCopyTexSubImage2D(This->glDescription.target,
2097 This->glDescription.level,
2098 drect->x1, drect->y1, /* xoffset, yoffset */
2099 srect->x1, Src->currentDesc.Height - srect->y2,
2100 drect->x2 - drect->x1, drect->y2 - drect->y1);
2102 UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1;
2103 /* I have to process this row by row to swap the image,
2104 * otherwise it would be upside down, so streching in y direction
2105 * doesn't cost extra time
2107 * However, streching in x direction can be avoided if not necessary
2109 for(row = drect->y1; row < drect->y2; row++) {
2110 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2111 /* Well, that stuff works, but it's very slow.
2112 * find a better way instead
2118 FIXME("Doing a pixel by pixel render target -> texture copy, expect performance issues\n");
2121 for(col = drect->x1; col < drect->x2; col++) {
2122 glCopyTexSubImage2D(This->glDescription.target,
2123 This->glDescription.level,
2124 drect->x1 + col, row, /* xoffset, yoffset */
2125 srect->x1 + col * xrel, yoffset - (int) (row * yrel),
2129 glCopyTexSubImage2D(This->glDescription.target,
2130 This->glDescription.level,
2131 drect->x1, row, /* xoffset, yoffset */
2132 srect->x1, yoffset - (int) (row * yrel),
2133 drect->x2-drect->x1, 1);
2138 vcheckGLcall("glCopyTexSubImage2D");
2142 /* Uses the hardware to stretch and flip the image */
2143 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2145 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2146 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2147 float left, right, top, bottom; /* Texture coordinates */
2148 UINT fbwidth = Src->currentDesc.Width;
2149 UINT fbheight = Src->currentDesc.Height;
2151 TRACE("Using hwstretch blit\n");
2152 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2154 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2156 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2157 * we are reading from the back buffer, the backup can be used as source texture
2159 glGenTextures(1, &backup);
2160 checkGLcall("glGenTextures(1, &backup)");
2161 glBindTexture(GL_TEXTURE_2D, backup);
2162 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
2164 glReadBuffer(GL_BACK);
2165 checkGLcall("glReadBuffer(GL_BACK)");
2167 /* TODO: Only back up the part that will be overwritten */
2168 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2169 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2170 checkGLcall("glTexImage2D");
2172 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2173 0, 0 /* read offsets */,
2178 checkGLcall("glCopyTexSubImage2D");
2180 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2181 checkGLcall("glTexParameteri");
2182 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2183 checkGLcall("glTexParameteri");
2185 if((IWineD3DSurface *) This == swapchain->backBuffer[0] || TRUE) {
2188 glReadBuffer(GL_FRONT);
2189 checkGLcall("glReadBuffer(GL_FRONT)");
2191 glGenTextures(1, &src);
2192 checkGLcall("glGenTextures(1, &src)");
2193 glBindTexture(GL_TEXTURE_2D, src);
2194 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
2196 /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
2197 * out for power of 2 sizes
2199 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2200 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2201 checkGLcall("glTexImage2D");
2202 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2203 0, 0 /* read offsets */,
2208 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2209 checkGLcall("glTexParameteri");
2210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2211 checkGLcall("glTexParameteri");
2213 glReadBuffer(GL_BACK);
2214 checkGLcall("glReadBuffer(GL_BACK)");
2216 checkGLcall("glEnd and previous");
2218 left = (float) srect->x1 / (float) Src->pow2Width;
2219 right = (float) srect->x2 / (float) Src->pow2Width;
2222 top = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2223 bottom = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2225 top = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2226 bottom = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2229 /* draw the source texture stretched and upside down. The correct surface is bound already */
2230 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2231 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2235 glTexCoord2f(left, bottom);
2236 glVertex2i(0, fbheight);
2239 glTexCoord2f(left, top);
2240 glVertex2i(0, fbheight - drect->y2 - drect->y1);
2243 glTexCoord2f(right, top);
2244 glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1);
2247 glTexCoord2f(right, bottom);
2248 glVertex2i(drect->x2 - drect->x1, fbheight);
2250 checkGLcall("glEnd and previous");
2252 /* Now read the stretched and upside down image into the destination texture */
2253 glBindTexture(This->glDescription.target, This->glDescription.textureName);
2254 checkGLcall("glBindTexture");
2255 glCopyTexSubImage2D(This->glDescription.target,
2257 drect->x1, drect->y1, /* xoffset, yoffset */
2258 0, 0, /* We blitted the image to the origin */
2259 drect->x2 - drect->x1, drect->y2 - drect->y1);
2260 checkGLcall("glCopyTexSubImage2D");
2262 /* Write the back buffer backup back */
2263 glBindTexture(GL_TEXTURE_2D, backup);
2264 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
2268 glTexCoord2f(0.0, (float) fbheight / (float) Src->pow2Height);
2272 glTexCoord2f(0.0, 0.0);
2273 glVertex2i(0, fbheight);
2276 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, 0.0);
2277 glVertex2i(fbwidth, Src->currentDesc.Height);
2280 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
2281 glVertex2i(fbwidth, 0);
2286 glDeleteTextures(1, &src);
2287 checkGLcall("glDeleteTextures(1, &src)");
2289 glDeleteTextures(1, &backup);
2290 checkGLcall("glDeleteTextures(1, &backup)");
2294 /* Not called from the VTable */
2295 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2297 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2298 IWineD3DSwapChainImpl *swapchain = NULL;
2299 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2302 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2304 /* Get the swapchain. One of the surfaces has to be a primary surface */
2305 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2306 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2308 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2309 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2310 else return WINED3DERR_INVALIDCALL;
2316 rect.x1 = DestRect->left;
2317 rect.y1 = DestRect->top;
2318 rect.x2 = DestRect->right;
2319 rect.y2 = DestRect->bottom;
2323 rect.x2 = This->currentDesc.Width;
2324 rect.y2 = This->currentDesc.Height;
2327 /* Half-life does a Blt from the back buffer to the front buffer,
2328 * Full surface size, no flags... Use present instead
2332 /* First, check if we can do a Flip */
2334 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2336 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2337 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2344 /* Check the Destination rect and the surface sizes */
2346 (rect.x1 == 0) && (rect.y1 == 0) &&
2347 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2348 (This->currentDesc.Width == Src->currentDesc.Width) &&
2349 (This->currentDesc.Height == Src->currentDesc.Height)) {
2350 /* These flags are unimportant for the flag check, remove them */
2352 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2353 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2355 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2357 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2358 * take very long, while a flip is fast.
2359 * This applies to Half-Life, which does such Blts every time it finished
2360 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2361 * menu. This is also used by all apps when they do windowed rendering
2363 * The problem is that flipping is not really the same as copying. After a
2364 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2365 * untouched. Therefore it's necessary to override the swap effect
2366 * and to set it back after the flip.
2369 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2371 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2372 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2373 NULL, NULL, 0, NULL);
2375 swapchain->presentParms.SwapEffect = orig_swap;
2382 /* Blt from texture to rendertarget? */
2383 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2384 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2386 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2387 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2388 float glTexCoord[4];
2390 DDCOLORKEY oldBltCKey = {0,0};
2391 RECT SourceRectangle;
2394 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2397 SourceRectangle.left = SrcRect->left;
2398 SourceRectangle.right = SrcRect->right;
2399 SourceRectangle.top = SrcRect->top;
2400 SourceRectangle.bottom = SrcRect->bottom;
2402 SourceRectangle.left = 0;
2403 SourceRectangle.right = Src->currentDesc.Width;
2404 SourceRectangle.top = 0;
2405 SourceRectangle.bottom = Src->currentDesc.Height;
2408 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2409 /* Fall back to software */
2410 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2411 SourceRectangle.left, SourceRectangle.top,
2412 SourceRectangle.right, SourceRectangle.bottom);
2413 return WINED3DERR_INVALIDCALL;
2416 /* Color keying: Check if we have to do a color keyed blt,
2417 * and if not check if a color key is activated.
2419 oldCKey = Src->CKeyFlags;
2420 if(!(Flags & DDBLT_KEYSRC) &&
2421 Src->CKeyFlags & DDSD_CKSRCBLT) {
2422 /* Ok, the surface has a color key, but we shall not use it -
2423 * Deactivate it for now, LoadTexture will catch this
2425 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2429 if(Flags & DDBLT_KEYDEST) {
2430 oldBltCKey = This->SrcBltCKey;
2431 /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
2432 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
2434 This->SrcBltCKey = This->DestBltCKey;
2435 } else if (Flags & DDBLT_KEYSRC)
2436 oldBltCKey = This->SrcBltCKey;
2438 /* Now load the surface */
2439 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2443 ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
2445 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2446 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2447 TRACE("Drawing to front buffer\n");
2448 glDrawBuffer(GL_FRONT);
2449 checkGLcall("glDrawBuffer GL_FRONT");
2452 /* Bind the texture */
2453 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2454 checkGLcall("glBindTexture");
2456 /* No filtering for blts */
2457 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2459 checkGLcall("glTexParameteri");
2460 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2462 checkGLcall("glTexParameteri");
2463 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2464 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2465 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2466 checkGLcall("glTexEnvi");
2468 /* This is for color keying */
2469 if(Flags & DDBLT_KEYSRC) {
2470 glEnable(GL_ALPHA_TEST);
2471 checkGLcall("glEnable GL_ALPHA_TEST");
2472 glAlphaFunc(GL_NOTEQUAL, 0.0);
2473 checkGLcall("glAlphaFunc\n");
2475 glDisable(GL_ALPHA_TEST);
2476 checkGLcall("glDisable GL_ALPHA_TEST");
2479 /* Draw a textured quad
2483 glColor3d(1.0f, 1.0f, 1.0f);
2484 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2489 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2490 glVertex3f(rect.x1, rect.y2, 0.0);
2492 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2497 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2502 checkGLcall("glEnd");
2504 /* Unbind the texture */
2505 glBindTexture(GL_TEXTURE_2D, 0);
2506 checkGLcall("glEnable glBindTexture");
2508 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2509 glDrawBuffer(oldDraw);
2512 /* Restore the color key flags */
2513 if(oldCKey != Src->CKeyFlags) {
2514 Src->CKeyFlags = oldCKey;
2517 /* Restore the old color key */
2518 if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST))
2519 This->SrcBltCKey = oldBltCKey;
2523 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2524 This->Flags |= SFLAG_GLDIRTY;
2530 /* Blt from rendertarget to texture? */
2531 if( (SrcSurface == swapchain->frontBuffer) ||
2532 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2533 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2534 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2536 BOOL upsideDown, stretchx;
2538 TRACE("Blt from rendertarget to texture\n");
2540 /* Call preload for the surface to make sure it isn't dirty */
2541 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2543 /* Make sure that the top pixel is always above the bottom pixel, and keep a seperate upside down flag
2544 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2547 if(SrcRect->top < SrcRect->bottom) {
2548 srect.y1 = SrcRect->top;
2549 srect.y2 = SrcRect->bottom;
2552 srect.y1 = SrcRect->bottom;
2553 srect.y2 = SrcRect->top;
2556 srect.x1 = SrcRect->left;
2557 srect.x2 = SrcRect->right;
2561 srect.x2 = Src->currentDesc.Width;
2562 srect.y2 = Src->currentDesc.Height;
2565 if(rect.x1 > rect.x2) {
2569 upsideDown = !upsideDown;
2572 if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
2578 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2579 * flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully,
2580 * not implemented by now). Otherwise:
2582 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2583 * -> If the app wants a image width an unscaled width, copy it line per line
2584 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
2585 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2586 * back buffer. This is slower than reading line per line, thus not used for flipping
2587 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2590 if(FALSE /* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */) {
2591 TRACE("Using GL_EXT_framebuffer_blit for copying\n");
2592 } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
2593 rect.y2 - rect.y1 > Src->currentDesc.Height) {
2594 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
2595 fb_copy_to_texture_direct(This, SrcSurface, swapchain, &srect, &rect, upsideDown);
2597 TRACE("Using hardware stretching to flip / stretch the texture\n");
2598 fb_copy_to_texture_hwstretch(This, SrcSurface, swapchain, &srect, &rect, upsideDown);
2601 if(!(This->Flags & SFLAG_DONOTFREE)) {
2602 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2603 This->resource.allocatedMemory = NULL;
2605 This->Flags |= SFLAG_GLDIRTY;
2613 if (Flags & DDBLT_COLORFILL) {
2614 /* This is easy to handle for the D3D Device... */
2616 IWineD3DSwapChainImpl *implSwapChain;
2618 TRACE("Colorfill\n");
2620 /* The color as given in the Blt function is in the format of the frame-buffer...
2621 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2623 if (This->resource.format == WINED3DFMT_P8) {
2624 if (This->palette) {
2625 color = ((0xFF000000) |
2626 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2627 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2628 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2633 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2634 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2637 color = ((0xFF000000) |
2638 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2639 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2640 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2643 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2644 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2645 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2647 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2648 color = DDBltFx->u5.dwFillColor;
2651 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2652 return WINED3DERR_INVALIDCALL;
2655 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2656 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2657 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2658 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2659 glDrawBuffer(GL_BACK);
2660 checkGLcall("glDrawBuffer(GL_BACK)");
2662 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2663 glDrawBuffer(GL_FRONT);
2664 checkGLcall("glDrawBuffer(GL_FRONT)");
2667 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2668 return WINED3DERR_INVALIDCALL;
2671 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2673 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2674 1 /* Number of rectangles */,
2676 WINED3DCLEAR_TARGET,
2681 /* Restore the original draw buffer */
2682 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2683 glDrawBuffer(GL_BACK);
2684 vcheckGLcall("glDrawBuffer");
2690 /* Default: Fall back to the generic blt */
2691 return WINED3DERR_INVALIDCALL;
2694 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2695 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2696 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2697 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2698 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2699 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2701 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair */
2702 if(myDevice->inScene &&
2703 (iface == myDevice->stencilBufferTarget ||
2704 (SrcSurface && SrcSurface == myDevice->stencilBufferTarget))) {
2705 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2706 return WINED3DERR_INVALIDCALL;
2709 /* Special cases for RenderTargets */
2710 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2711 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2712 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2715 /* For the rest call the X11 surface implementation.
2716 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2717 * other Blts are rather rare
2719 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2722 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2723 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2724 TRACE("(%p)->(%x)\n", This, Flags);
2729 case DDGBS_ISBLTDONE:
2733 return DDERR_INVALIDPARAMS;
2737 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2738 /* XXX: DDERR_INVALIDSURFACETYPE */
2740 TRACE("(%p)->(%08x)\n",iface,Flags);
2743 case DDGFS_ISFLIPDONE:
2747 return DDERR_INVALIDPARAMS;
2751 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2752 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2753 TRACE("(%p)\n", This);
2755 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2758 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2759 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2760 TRACE("(%p)\n", This);
2762 /* So far we don't lose anything :) */
2763 This->Flags &= ~SFLAG_LOST;
2767 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2768 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2769 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2770 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2771 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2773 if(myDevice->inScene &&
2774 (iface == myDevice->stencilBufferTarget ||
2775 (Source && Source == myDevice->stencilBufferTarget))) {
2776 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2777 return WINED3DERR_INVALIDCALL;
2780 /* Special cases for RenderTargets */
2781 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2782 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2784 RECT SrcRect, DstRect;
2788 SrcRect.left = rsrc->left;
2789 SrcRect.top= rsrc->top;
2790 SrcRect.bottom = rsrc->bottom;
2791 SrcRect.right = rsrc->right;
2795 SrcRect.right = srcImpl->currentDesc.Width;
2796 SrcRect.bottom = srcImpl->currentDesc.Height;
2799 DstRect.left = dstx;
2801 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2802 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2804 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2805 if(trans & DDBLTFAST_SRCCOLORKEY)
2806 Flags |= DDBLT_KEYSRC;
2807 if(trans & DDBLTFAST_DESTCOLORKEY)
2808 Flags |= DDBLT_KEYDEST;
2809 if(trans & DDBLTFAST_WAIT)
2810 Flags |= DDBLT_WAIT;
2811 if(trans & DDBLTFAST_DONOTWAIT)
2812 Flags |= DDBLT_DONOTWAIT;
2814 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2818 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2821 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2822 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2823 TRACE("(%p)->(%p)\n", This, Pal);
2825 *Pal = (IWineD3DPalette *) This->palette;
2829 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2830 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2832 IWineD3DPaletteImpl *pal = This->palette;
2834 TRACE("(%p)\n", This);
2836 if(This->resource.format == WINED3DFMT_P8 ||
2837 This->resource.format == WINED3DFMT_A8P8)
2839 TRACE("Dirtifying surface\n");
2840 This->Flags |= SFLAG_DIRTY;
2843 if(This->Flags & SFLAG_DIBSECTION) {
2844 TRACE("(%p): Updating the hdc's palette\n", This);
2845 for (n=0; n<256; n++) {
2847 col[n].rgbRed = pal->palents[n].peRed;
2848 col[n].rgbGreen = pal->palents[n].peGreen;
2849 col[n].rgbBlue = pal->palents[n].peBlue;
2851 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2852 /* Use the default device palette */
2853 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2854 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2855 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2857 col[n].rgbReserved = 0;
2859 SetDIBColorTable(This->hDC, 0, 256, col);
2865 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2866 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2867 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2868 TRACE("(%p)->(%p)\n", This, Pal);
2870 if(This->palette != NULL)
2871 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2872 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2874 if(PalImpl != NULL) {
2875 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2876 /* Set the device's main palette if the palette
2877 * wasn't a primary palette before
2879 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2880 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2883 for(i=0; i < 256; i++) {
2884 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2888 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2891 This->palette = PalImpl;
2893 return IWineD3DSurface_RealizePalette(iface);
2896 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2897 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2898 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
2900 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2901 FIXME(" colorkey value not supported (%08x) !\n", Flags);
2902 return DDERR_INVALIDPARAMS;
2905 /* Dirtify the surface, but only if a key was changed */
2907 switch (Flags & ~DDCKEY_COLORSPACE) {
2908 case DDCKEY_DESTBLT:
2909 This->DestBltCKey = *CKey;
2910 This->CKeyFlags |= DDSD_CKDESTBLT;
2913 case DDCKEY_DESTOVERLAY:
2914 This->DestOverlayCKey = *CKey;
2915 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2918 case DDCKEY_SRCOVERLAY:
2919 This->SrcOverlayCKey = *CKey;
2920 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2924 This->SrcBltCKey = *CKey;
2925 This->CKeyFlags |= DDSD_CKSRCBLT;
2930 switch (Flags & ~DDCKEY_COLORSPACE) {
2931 case DDCKEY_DESTBLT:
2932 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2935 case DDCKEY_DESTOVERLAY:
2936 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2939 case DDCKEY_SRCOVERLAY:
2940 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2944 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2952 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2953 /** Check against the maximum texture sizes supported by the video card **/
2954 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2956 TRACE("%p\n", This);
2957 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2958 /* one of three options
2959 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)
2960 2: Set the texture to the maxium size (bad idea)
2961 3: WARN and return WINED3DERR_NOTAVAILABLE;
2962 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.
2964 WARN("(%p) Creating an oversized surface\n", This);
2965 This->Flags |= SFLAG_OVERSIZE;
2967 /* This will be initialized on the first blt */
2968 This->glRect.left = 0;
2969 This->glRect.top = 0;
2970 This->glRect.right = 0;
2971 This->glRect.bottom = 0;
2973 /* No oversize, gl rect is the full texture size */
2974 This->Flags &= ~SFLAG_OVERSIZE;
2975 This->glRect.left = 0;
2976 This->glRect.top = 0;
2977 This->glRect.right = This->pow2Width;
2978 This->glRect.bottom = This->pow2Height;
2984 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
2985 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2987 TRACE("(%p)\n", This);
2989 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
2990 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
2991 ie pitch = (width/4) * bytes per block */
2992 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
2993 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
2994 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
2995 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
2996 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
2998 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2999 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
3000 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3002 ret = This->bytesPerPixel * This->pow2Width;
3004 /* Surfaces are 32 bit aligned */
3005 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3007 TRACE("(%p) Returning %d\n", This, ret);
3011 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3012 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3014 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3016 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3018 TRACE("(%p): Not an overlay surface\n", This);
3019 return DDERR_NOTAOVERLAYSURFACE;
3025 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3026 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3028 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3030 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3032 TRACE("(%p): Not an overlay surface\n", This);
3033 return DDERR_NOTAOVERLAYSURFACE;
3039 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3040 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3041 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3043 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3045 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3047 TRACE("(%p): Not an overlay surface\n", This);
3048 return DDERR_NOTAOVERLAYSURFACE;
3054 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3055 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3056 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3057 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3059 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3061 TRACE("(%p): Not an overlay surface\n", This);
3062 return DDERR_NOTAOVERLAYSURFACE;
3068 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3071 IWineD3DSurfaceImpl_QueryInterface,
3072 IWineD3DSurfaceImpl_AddRef,
3073 IWineD3DSurfaceImpl_Release,
3074 /* IWineD3DResource */
3075 IWineD3DSurfaceImpl_GetParent,
3076 IWineD3DSurfaceImpl_GetDevice,
3077 IWineD3DSurfaceImpl_SetPrivateData,
3078 IWineD3DSurfaceImpl_GetPrivateData,
3079 IWineD3DSurfaceImpl_FreePrivateData,
3080 IWineD3DSurfaceImpl_SetPriority,
3081 IWineD3DSurfaceImpl_GetPriority,
3082 IWineD3DSurfaceImpl_PreLoad,
3083 IWineD3DSurfaceImpl_GetType,
3084 /* IWineD3DSurface */
3085 IWineD3DSurfaceImpl_GetContainer,
3086 IWineD3DSurfaceImpl_GetDesc,
3087 IWineD3DSurfaceImpl_LockRect,
3088 IWineD3DSurfaceImpl_UnlockRect,
3089 IWineD3DSurfaceImpl_GetDC,
3090 IWineD3DSurfaceImpl_ReleaseDC,
3091 IWineD3DSurfaceImpl_Flip,
3092 IWineD3DSurfaceImpl_Blt,
3093 IWineD3DSurfaceImpl_GetBltStatus,
3094 IWineD3DSurfaceImpl_GetFlipStatus,
3095 IWineD3DSurfaceImpl_IsLost,
3096 IWineD3DSurfaceImpl_Restore,
3097 IWineD3DSurfaceImpl_BltFast,
3098 IWineD3DSurfaceImpl_GetPalette,
3099 IWineD3DSurfaceImpl_SetPalette,
3100 IWineD3DSurfaceImpl_RealizePalette,
3101 IWineD3DSurfaceImpl_SetColorKey,
3102 IWineD3DSurfaceImpl_GetPitch,
3103 IWineD3DSurfaceImpl_SetMem,
3104 IWineD3DSurfaceImpl_SetOverlayPosition,
3105 IWineD3DSurfaceImpl_GetOverlayPosition,
3106 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3107 IWineD3DSurfaceImpl_UpdateOverlay,
3109 IWineD3DSurfaceImpl_CleanDirtyRect,
3110 IWineD3DSurfaceImpl_AddDirtyRect,
3111 IWineD3DSurfaceImpl_LoadTexture,
3112 IWineD3DSurfaceImpl_SaveSnapshot,
3113 IWineD3DSurfaceImpl_SetContainer,
3114 IWineD3DSurfaceImpl_SetPBufferState,
3115 IWineD3DSurfaceImpl_SetGlTextureDesc,
3116 IWineD3DSurfaceImpl_GetGlDesc,
3117 IWineD3DSurfaceImpl_GetData,
3118 IWineD3DSurfaceImpl_SetFormat,
3119 IWineD3DSurfaceImpl_PrivateSetup