wined3d: Fix texture coordinate calculation in surface_blt_to_drawable.
[wine] / dlls / wined3d / surface.c
1 /*
2  * IWineD3DSurface Implementation
3  *
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-2007 Stefan Dösinger for CodeWeavers
11  * Copyright 2007 Henri Verbeet
12  * Copyright 2006-2007 Roderick Colenbrander
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2.1 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28
29 #include "config.h"
30 #include "wine/port.h"
31 #include "wined3d_private.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
34 #define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info
35
36 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf);
37 static void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey);
38
39 static void surface_bind_and_dirtify(IWineD3DSurfaceImpl *This) {
40     /* Make sure that a proper texture unit is selected, bind the texture
41      * and dirtify the sampler to restore the texture on the next draw. */
42     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
43         GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
44         checkGLcall("glActiveTextureARB");
45     }
46     IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
47     IWineD3DSurface_BindTexture((IWineD3DSurface *)This);
48 }
49
50 /* This call just downloads data, the caller is responsible for activating the
51  * right context and binding the correct texture. */
52 static void surface_download_data(IWineD3DSurfaceImpl *This) {
53     if (0 == This->glDescription.textureName) {
54         ERR("Surface does not have a texture, but SFLAG_INTEXTURE is set\n");
55         return;
56     }
57
58     if(This->Flags & SFLAG_CONVERTED) {
59         FIXME("Read back converted textures unsupported, format=%s\n", debug_d3dformat(This->resource.format));
60         return;
61     }
62
63     ENTER_GL();
64
65     if (This->resource.format == WINED3DFMT_DXT1 ||
66             This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
67             This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
68         if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* We can assume this as the texture would not have been created otherwise */
69             FIXME("(%p) : Attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
70         } else {
71             TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
72                 This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
73
74             if(This->Flags & SFLAG_PBO) {
75                 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
76                 checkGLcall("glBindBufferARB");
77                 GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, NULL));
78                 checkGLcall("glGetCompressedTexImageARB()");
79                 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
80                 checkGLcall("glBindBufferARB");
81             } else {
82                 GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory));
83                 checkGLcall("glGetCompressedTexImageARB()");
84             }
85         }
86         LEAVE_GL();
87     } else {
88         void *mem;
89         int src_pitch = 0;
90         int dst_pitch = 0;
91
92         if (This->Flags & SFLAG_NONPOW2) {
93             unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
94             src_pitch = This->bytesPerPixel * This->pow2Width;
95             dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
96             src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
97             mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
98         } else {
99             mem = This->resource.allocatedMemory;
100         }
101
102         TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
103                 This->glDescription.glFormat, This->glDescription.glType, mem);
104
105         if(This->Flags & SFLAG_PBO) {
106             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
107             checkGLcall("glBindBufferARB");
108
109             glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
110                           This->glDescription.glType, NULL);
111             checkGLcall("glGetTexImage()");
112
113             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
114             checkGLcall("glBindBufferARB");
115         } else {
116             glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
117                           This->glDescription.glType, mem);
118             checkGLcall("glGetTexImage()");
119         }
120         LEAVE_GL();
121
122         if (This->Flags & SFLAG_NONPOW2) {
123             LPBYTE src_data, dst_data;
124             int y;
125             /*
126              * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
127              * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
128              * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
129              *
130              * We're doing this...
131              *
132              * instead of boxing the texture :
133              * |<-texture width ->|  -->pow2width|   /\
134              * |111111111111111111|              |   |
135              * |222 Texture 222222| boxed empty  | texture height
136              * |3333 Data 33333333|              |   |
137              * |444444444444444444|              |   \/
138              * -----------------------------------   |
139              * |     boxed  empty | boxed empty  | pow2height
140              * |                  |              |   \/
141              * -----------------------------------
142              *
143              *
144              * we're repacking the data to the expected texture width
145              *
146              * |<-texture width ->|  -->pow2width|   /\
147              * |111111111111111111222222222222222|   |
148              * |222333333333333333333444444444444| texture height
149              * |444444                           |   |
150              * |                                 |   \/
151              * |                                 |   |
152              * |            empty                | pow2height
153              * |                                 |   \/
154              * -----------------------------------
155              *
156              * == is the same as
157              *
158              * |<-texture width ->|    /\
159              * |111111111111111111|
160              * |222222222222222222|texture height
161              * |333333333333333333|
162              * |444444444444444444|    \/
163              * --------------------
164              *
165              * this also means that any references to allocatedMemory should work with the data as if were a
166              * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
167              *
168              * internally the texture is still stored in a boxed format so any references to textureName will
169              * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
170              *
171              * Performance should not be an issue, because applications normally do not lock the surfaces when
172              * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
173              * and doesn't have to be re-read.
174              */
175             src_data = mem;
176             dst_data = This->resource.allocatedMemory;
177             TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
178             for (y = 1 ; y < This->currentDesc.Height; y++) {
179                 /* skip the first row */
180                 src_data += src_pitch;
181                 dst_data += dst_pitch;
182                 memcpy(dst_data, src_data, dst_pitch);
183             }
184
185             HeapFree(GetProcessHeap(), 0, mem);
186         }
187     }
188
189     /* Surface has now been downloaded */
190     This->Flags |= SFLAG_INSYSMEM;
191 }
192
193 /* This call just uploads data, the caller is responsible for activating the
194  * right context and binding the correct texture. */
195 static void surface_upload_data(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data) {
196     if (This->resource.format == WINED3DFMT_DXT1 ||
197             This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
198             This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
199         if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
200             FIXME("Using DXT1/3/5 without advertized support\n");
201         } else {
202             /* glCompressedTexSubImage2D for uploading and glTexImage2D for allocating does not work well on some drivers(r200 dri, MacOS ATI driver)
203              * glCompressedTexImage2D does not accept NULL pointers. So for compressed textures surface_allocate_surface does nothing, and this
204              * function uses glCompressedTexImage2D instead of the SubImage call
205              */
206             TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data);
207             ENTER_GL();
208
209             if(This->Flags & SFLAG_PBO) {
210                 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
211                 checkGLcall("glBindBufferARB");
212                 TRACE("(%p) pbo: %#x, data: %p\n", This, This->pbo, data);
213
214                 GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, internal,
215                         width, height, 0 /* border */, This->resource.size, NULL));
216                 checkGLcall("glCompressedTexSubImage2D");
217
218                 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
219                 checkGLcall("glBindBufferARB");
220             } else {
221                 GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, internal,
222                         width, height, 0 /* border */, This->resource.size, data));
223                 checkGLcall("glCompressedTexSubImage2D");
224             }
225             LEAVE_GL();
226         }
227     } else {
228         TRACE("(%p) : Calling glTexSubImage2D w %d,  h %d, data, %p\n", This, width, height, data);
229         ENTER_GL();
230
231         if(This->Flags & SFLAG_PBO) {
232             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
233             checkGLcall("glBindBufferARB");
234             TRACE("(%p) pbo: %#x, data: %p\n", This, This->pbo, data);
235
236             glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, NULL);
237             checkGLcall("glTexSubImage2D");
238
239             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
240             checkGLcall("glBindBufferARB");
241         }
242         else {
243             glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data);
244             checkGLcall("glTexSubImage2D");
245         }
246
247         LEAVE_GL();
248     }
249 }
250
251 /* This call just allocates the texture, the caller is responsible for
252  * activating the right context and binding the correct texture. */
253 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type) {
254     BOOL enable_client_storage = FALSE;
255     BYTE *mem = NULL;
256
257     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,
258             This->glDescription.target, This->glDescription.level, debug_d3dformat(This->resource.format), internal, width, height, format, type);
259
260     if (This->resource.format == WINED3DFMT_DXT1 ||
261             This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
262             This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
263         /* glCompressedTexImage2D does not accept NULL pointers, so we cannot allocate a compressed texture without uploading data */
264         TRACE("Not allocating compressed surfaces, surface_upload_data will specify them\n");
265
266         /* We have to point GL to the client storage memory here, because upload_data might use a PBO. This means a double upload
267          * once, unfortunately
268          */
269         if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
270             /* Neither NONPOW2, DIBSECTION nor OVERSIZE flags can be set on compressed textures */
271             This->Flags |= SFLAG_CLIENT;
272             mem = (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
273             GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, internal,
274                        width, height, 0 /* border */, This->resource.size, mem));
275         }
276
277         return;
278     }
279
280     ENTER_GL();
281
282     if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
283         if(This->Flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_OVERSIZE | SFLAG_CONVERTED) || This->resource.allocatedMemory == NULL) {
284             /* In some cases we want to disable client storage.
285              * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
286              * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
287              * SFLAG_OVERSIZE: The gl texture is smaller than the allocated memory
288              * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
289              * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
290              */
291             glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
292             checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
293             This->Flags &= ~SFLAG_CLIENT;
294             enable_client_storage = TRUE;
295         } else {
296             This->Flags |= SFLAG_CLIENT;
297
298             /* Point opengl to our allocated texture memory. Do not use resource.allocatedMemory here because
299              * it might point into a pbo. Instead use heapMemory, but get the alignment right.
300              */
301             mem = (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
302         }
303     }
304     glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, mem);
305     checkGLcall("glTexImage2D");
306
307     if(enable_client_storage) {
308         glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
309         checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
310     }
311     LEAVE_GL();
312
313     This->Flags |= SFLAG_ALLOCATED;
314 }
315
316 /* In D3D the depth stencil dimensions have to be greater than or equal to the
317  * render target dimensions. With FBOs, the dimensions have to be an exact match. */
318 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
319 void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height) {
320     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
321     renderbuffer_entry_t *entry;
322     GLuint renderbuffer = 0;
323     unsigned int src_width, src_height;
324
325     src_width = This->pow2Width;
326     src_height = This->pow2Height;
327
328     /* A depth stencil smaller than the render target is not valid */
329     if (width > src_width || height > src_height) return;
330
331     /* Remove any renderbuffer set if the sizes match */
332     if (width == src_width && height == src_height) {
333         This->current_renderbuffer = NULL;
334         return;
335     }
336
337     /* Look if we've already got a renderbuffer of the correct dimensions */
338     LIST_FOR_EACH_ENTRY(entry, &This->renderbuffers, renderbuffer_entry_t, entry) {
339         if (entry->width == width && entry->height == height) {
340             renderbuffer = entry->id;
341             This->current_renderbuffer = entry;
342             break;
343         }
344     }
345
346     if (!renderbuffer) {
347         const GlPixelFormatDesc *glDesc;
348         getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc);
349
350         GL_EXTCALL(glGenRenderbuffersEXT(1, &renderbuffer));
351         GL_EXTCALL(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderbuffer));
352         GL_EXTCALL(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, glDesc->glFormat, width, height));
353
354         entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t));
355         entry->width = width;
356         entry->height = height;
357         entry->id = renderbuffer;
358         list_add_head(&This->renderbuffers, &entry->entry);
359
360         This->current_renderbuffer = entry;
361     }
362
363     checkGLcall("set_compatible_renderbuffer");
364 }
365
366 GLenum surface_get_gl_buffer(IWineD3DSurface *iface, IWineD3DSwapChain *swapchain) {
367     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
368     IWineD3DSwapChainImpl *swapchain_impl = (IWineD3DSwapChainImpl *)swapchain;
369
370     TRACE("(%p) : swapchain %p\n", This, swapchain);
371
372     if (swapchain_impl->backBuffer && swapchain_impl->backBuffer[0] == iface) {
373         TRACE("Returning GL_BACK\n");
374         return GL_BACK;
375     } else if (swapchain_impl->frontBuffer == iface) {
376         TRACE("Returning GL_FRONT\n");
377         return GL_FRONT;
378     }
379
380     FIXME("Higher back buffer, returning GL_BACK\n");
381     return GL_BACK;
382 }
383
384 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
385     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
386     ULONG ref = InterlockedDecrement(&This->resource.ref);
387     TRACE("(%p) : Releasing from %d\n", This, ref + 1);
388     if (ref == 0) {
389         IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
390         renderbuffer_entry_t *entry, *entry2;
391         TRACE("(%p) : cleaning up\n", This);
392
393         if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
394
395             /* Need a context to destroy the texture. Use the currently active render target, but only if
396              * the primary render target exists. Otherwise lastActiveRenderTarget is garbage, see above.
397              * When destroying the primary rt, Uninit3D will activate a context before doing anything
398              */
399             if(device->render_targets && device->render_targets[0]) {
400                 ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
401             }
402
403             TRACE("Deleting texture %d\n", This->glDescription.textureName);
404             ENTER_GL();
405             glDeleteTextures(1, &This->glDescription.textureName);
406             LEAVE_GL();
407         }
408
409         if(This->Flags & SFLAG_PBO) {
410             /* Delete the PBO */
411             GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
412         }
413
414         if(This->Flags & SFLAG_DIBSECTION) {
415             /* Release the DC */
416             SelectObject(This->hDC, This->dib.holdbitmap);
417             DeleteDC(This->hDC);
418             /* Release the DIB section */
419             DeleteObject(This->dib.DIBsection);
420             This->dib.bitmap_data = NULL;
421             This->resource.allocatedMemory = NULL;
422         }
423         if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
424
425         HeapFree(GetProcessHeap(), 0, This->palette9);
426
427         IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
428         if(iface == device->ddraw_primary)
429             device->ddraw_primary = NULL;
430
431         LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry) {
432             GL_EXTCALL(glDeleteRenderbuffersEXT(1, &entry->id));
433             HeapFree(GetProcessHeap(), 0, entry);
434         }
435
436         TRACE("(%p) Released\n", This);
437         HeapFree(GetProcessHeap(), 0, This);
438
439     }
440     return ref;
441 }
442
443 /* ****************************************************
444    IWineD3DSurface IWineD3DResource parts follow
445    **************************************************** */
446
447 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
448     /* TODO: check for locks */
449     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
450     IWineD3DBaseTexture *baseTexture = NULL;
451     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
452
453     TRACE("(%p)Checking to see if the container is a base texture\n", This);
454     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
455         TRACE("Passing to container\n");
456         IWineD3DBaseTexture_PreLoad(baseTexture);
457         IWineD3DBaseTexture_Release(baseTexture);
458     } else {
459     TRACE("(%p) : About to load surface\n", This);
460
461     if(!device->isInDraw) {
462         ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
463     }
464
465     ENTER_GL();
466     glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
467     if (!This->glDescription.level) {
468         if (!This->glDescription.textureName) {
469             glGenTextures(1, &This->glDescription.textureName);
470             checkGLcall("glGenTextures");
471             TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
472         }
473         glBindTexture(This->glDescription.target, This->glDescription.textureName);
474         checkGLcall("glBindTexture");
475         IWineD3DSurface_LoadTexture(iface, FALSE);
476         /* This is where we should be reducing the amount of GLMemoryUsed */
477     } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
478         /* assume this is a coding error not a real error for now */
479         FIXME("Mipmap surface has a glTexture bound to it!\n");
480     }
481     if (This->resource.pool == WINED3DPOOL_DEFAULT) {
482        /* Tell opengl to try and keep this texture in video ram (well mostly) */
483        GLclampf tmp;
484        tmp = 0.9f;
485         glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
486     }
487     LEAVE_GL();
488     }
489     return;
490 }
491
492 static void surface_remove_pbo(IWineD3DSurfaceImpl *This) {
493     This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
494     This->resource.allocatedMemory =
495             (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
496
497     ENTER_GL();
498     GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
499     checkGLcall("glBindBuffer(GL_PIXEL_UNPACK_BUFFER, This->pbo)");
500     GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0, This->resource.size, This->resource.allocatedMemory));
501     checkGLcall("glGetBufferSubData");
502     GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
503     checkGLcall("glDeleteBuffers");
504     LEAVE_GL();
505
506     This->pbo = 0;
507     This->Flags &= ~SFLAG_PBO;
508 }
509
510 static void WINAPI IWineD3DSurfaceImpl_UnLoad(IWineD3DSurface *iface) {
511     IWineD3DBaseTexture *texture = NULL;
512     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
513     TRACE("(%p)\n", iface);
514
515     /* Default pool resources are supposed to be destroyed before Reset is called.
516      * Implicit resources stay however. So this means we have an implicit render target
517      * or depth stencil, and the content isn't supposed to survive the reset anyway
518      */
519     if(This->resource.pool == WINED3DPOOL_DEFAULT) {
520         TRACE("Default pool - nothing to do\n");
521         return;
522     }
523
524     /* Load the surface into system memory */
525     IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
526
527     /* Destroy PBOs, but load them into real sysmem before */
528     if(This->Flags & SFLAG_PBO) {
529         surface_remove_pbo(This);
530     }
531
532     /* If we're in a texture, the texture name belongs to the texture. Otherwise,
533      * destroy it
534      */
535     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **) &texture);
536     if(!texture) {
537         ENTER_GL();
538         glDeleteTextures(1, &This->glDescription.textureName);
539         This->glDescription.textureName = 0;
540         LEAVE_GL();
541     } else {
542         IWineD3DBaseTexture_Release(texture);
543     }
544     return;
545 }
546
547 /* ******************************************************
548    IWineD3DSurface IWineD3DSurface parts follow
549    ****************************************************** */
550
551 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
552     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
553     TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
554     if (This->glDescription.textureName == 0 && textureName != 0) {
555         IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
556         IWineD3DSurface_AddDirtyRect(iface, NULL);
557     }
558     This->glDescription.textureName = textureName;
559     This->glDescription.target      = target;
560     This->Flags &= ~SFLAG_ALLOCATED;
561 }
562
563 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
564     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
565     TRACE("(%p) : returning %p\n", This, &This->glDescription);
566     *glDescription = &This->glDescription;
567 }
568
569 /* TODO: think about moving this down to resource? */
570 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
571     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
572     /* 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 future  */
573     if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
574         FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
575     }
576     return (CONST void*)(This->resource.allocatedMemory);
577 }
578
579 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) {
580     IWineD3DSwapChainImpl *swapchain;
581     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
582     BYTE *mem;
583     GLint fmt;
584     GLint type;
585     BYTE *row, *top, *bottom;
586     int i;
587     BOOL bpp;
588     RECT local_rect;
589     BOOL srcIsUpsideDown;
590
591     if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
592         static BOOL warned = FALSE;
593         if(!warned) {
594             ERR("The application tries to lock the render target, but render target locking is disabled\n");
595             warned = TRUE;
596         }
597         return;
598     }
599
600     IWineD3DSurface_GetContainer((IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
601     /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
602      * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
603      * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
604      * context->last_was_blit set on the unlock.
605      */
606     ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
607     ENTER_GL();
608
609     /* Select the correct read buffer, and give some debug output.
610      * There is no need to keep track of the current read buffer or reset it, every part of the code
611      * that reads sets the read buffer as desired.
612      */
613     if(!swapchain) {
614         /* Locking the primary render target which is not on a swapchain(=offscreen render target).
615          * Read from the back buffer
616          */
617         TRACE("Locking offscreen render target\n");
618         glReadBuffer(myDevice->offscreenBuffer);
619         srcIsUpsideDown = TRUE;
620     } else {
621         GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *) This, (IWineD3DSwapChain *)swapchain);
622         TRACE("Locking %#x buffer\n", buffer);
623         glReadBuffer(buffer);
624         checkGLcall("glReadBuffer");
625
626         IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
627         srcIsUpsideDown = FALSE;
628     }
629
630     /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
631     if(!rect) {
632         local_rect.left = 0;
633         local_rect.top = 0;
634         local_rect.right = This->currentDesc.Width;
635         local_rect.bottom = This->currentDesc.Height;
636     } else {
637         local_rect = *rect;
638     }
639     /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
640
641     switch(This->resource.format)
642     {
643         case WINED3DFMT_P8:
644         {
645             if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
646                 /* In case of P8 render targets the index is stored in the alpha component */
647                 fmt = GL_ALPHA;
648                 type = GL_UNSIGNED_BYTE;
649                 mem = dest;
650                 bpp = This->bytesPerPixel;
651             } else {
652                 /* GL can't return palettized data, so read ARGB pixels into a
653                  * separate block of memory and convert them into palettized format
654                  * in software. Slow, but if the app means to use palettized render
655                  * targets and locks it...
656                  *
657                  * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
658                  * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
659                  * for the color channels when palettizing the colors.
660                  */
661                 fmt = GL_RGB;
662                 type = GL_UNSIGNED_BYTE;
663                 pitch *= 3;
664                 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
665                 if(!mem) {
666                     ERR("Out of memory\n");
667                     LEAVE_GL();
668                     return;
669                 }
670                 bpp = This->bytesPerPixel * 3;
671             }
672         }
673         break;
674
675         default:
676             mem = dest;
677             fmt = This->glDescription.glFormat;
678             type = This->glDescription.glType;
679             bpp = This->bytesPerPixel;
680     }
681
682     if(This->Flags & SFLAG_PBO) {
683         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
684         checkGLcall("glBindBufferARB");
685     }
686
687     glReadPixels(local_rect.left, local_rect.top,
688                  local_rect.right - local_rect.left,
689                  local_rect.bottom - local_rect.top,
690                  fmt, type, mem);
691     vcheckGLcall("glReadPixels");
692
693     if(This->Flags & SFLAG_PBO) {
694         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
695         checkGLcall("glBindBufferARB");
696
697         /* Check if we need to flip the image. If we need to flip use glMapBufferARB
698          * to get a pointer to it and perform the flipping in software. This is a lot
699          * faster than calling glReadPixels for each line. In case we want more speed
700          * we should rerender it flipped in a FBO and read the data back from the FBO. */
701         if(!srcIsUpsideDown) {
702             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
703             checkGLcall("glBindBufferARB");
704
705             mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
706             checkGLcall("glMapBufferARB");
707         }
708     }
709
710     /* TODO: Merge this with the palettization loop below for P8 targets */
711     if(!srcIsUpsideDown) {
712         UINT len, off;
713         /* glReadPixels returns the image upside down, and there is no way to prevent this.
714             Flip the lines in software */
715         len = (local_rect.right - local_rect.left) * bpp;
716         off = local_rect.left * bpp;
717
718         row = HeapAlloc(GetProcessHeap(), 0, len);
719         if(!row) {
720             ERR("Out of memory\n");
721             if(This->resource.format == WINED3DFMT_P8) HeapFree(GetProcessHeap(), 0, mem);
722             LEAVE_GL();
723             return;
724         }
725
726         top = mem + pitch * local_rect.top;
727         bottom = ((BYTE *) mem) + pitch * ( local_rect.bottom - local_rect.top - 1);
728         for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
729             memcpy(row, top + off, len);
730             memcpy(top + off, bottom + off, len);
731             memcpy(bottom + off, row, len);
732             top += pitch;
733             bottom -= pitch;
734         }
735         HeapFree(GetProcessHeap(), 0, row);
736
737         /* Unmap the temp PBO buffer */
738         if(This->Flags & SFLAG_PBO) {
739             GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
740             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
741         }
742     }
743
744     /* For P8 textures we need to perform an inverse palette lookup. This is done by searching for a palette
745      * index which matches the RGB value. Note this isn't guaranteed to work when there are multiple entries for
746      * the same color but we have no choice.
747      * In case of render targets, the index is stored in the alpha component so no conversion is needed.
748      */
749     if((This->resource.format == WINED3DFMT_P8) && !(This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
750         PALETTEENTRY *pal;
751         DWORD width = pitch / 3;
752         int x, y, c;
753         if(This->palette) {
754             pal = This->palette->palents;
755         } else {
756             pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
757         }
758
759         for(y = local_rect.top; y < local_rect.bottom; y++) {
760             for(x = local_rect.left; x < local_rect.right; x++) {
761                 /*                      start              lines            pixels      */
762                 BYTE *blue =  (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
763                 BYTE *green = blue  + 1;
764                 BYTE *red =   green + 1;
765
766                 for(c = 0; c < 256; c++) {
767                     if(*red   == pal[c].peRed   &&
768                        *green == pal[c].peGreen &&
769                        *blue  == pal[c].peBlue)
770                     {
771                         *((BYTE *) dest + y * width + x) = c;
772                         break;
773                     }
774                 }
775             }
776         }
777         HeapFree(GetProcessHeap(), 0, mem);
778     }
779     LEAVE_GL();
780 }
781
782 static void surface_prepare_system_memory(IWineD3DSurfaceImpl *This) {
783     /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
784      * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
785      * changed
786      */
787     if(!(This->Flags & SFLAG_DYNLOCK)) {
788         This->lockCount++;
789         /* MAXLOCKCOUNT is defined in wined3d_private.h */
790         if(This->lockCount > MAXLOCKCOUNT) {
791             TRACE("Surface is locked regularly, not freeing the system memory copy any more\n");
792             This->Flags |= SFLAG_DYNLOCK;
793         }
794     }
795
796     /* Create a PBO for dynamically locked surfaces but don't do it for converted or non-pow2 surfaces.
797      * Also don't create a PBO for systemmem surfaces.
798      */
799     if(GL_SUPPORT(ARB_PIXEL_BUFFER_OBJECT) && (This->Flags & SFLAG_DYNLOCK) && !(This->Flags & (SFLAG_PBO | SFLAG_CONVERTED | SFLAG_NONPOW2)) && (This->resource.pool != WINED3DPOOL_SYSTEMMEM)) {
800         GLenum error;
801         ENTER_GL();
802
803         GL_EXTCALL(glGenBuffersARB(1, &This->pbo));
804         error = glGetError();
805         if(This->pbo == 0 || error != GL_NO_ERROR) {
806             ERR("Failed to bind the PBO with error %s (%#x)\n", debug_glerror(error), error);
807         }
808
809         TRACE("Attaching pbo=%#x to (%p)\n", This->pbo, This);
810
811         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
812         checkGLcall("glBindBufferARB");
813
814         GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->resource.size + 4, This->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
815         checkGLcall("glBufferDataARB");
816
817         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
818         checkGLcall("glBindBufferARB");
819
820         /* We don't need the system memory anymore and we can't even use it for PBOs */
821         if(!(This->Flags & SFLAG_CLIENT)) {
822             HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
823             This->resource.heapMemory = NULL;
824         }
825         This->resource.allocatedMemory = NULL;
826         This->Flags |= SFLAG_PBO;
827         LEAVE_GL();
828     } else if(!(This->resource.allocatedMemory || This->Flags & SFLAG_PBO)) {
829         /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy,
830          * or a pbo to map
831          */
832         if(!This->resource.heapMemory) {
833             This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
834         }
835         This->resource.allocatedMemory =
836                 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
837         if(This->Flags & SFLAG_INSYSMEM) {
838             ERR("Surface without memory or pbo has SFLAG_INSYSMEM set!\n");
839         }
840     }
841 }
842
843 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
844     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
845     IWineD3DDeviceImpl  *myDevice = This->resource.wineD3DDevice;
846     IWineD3DSwapChain *swapchain = NULL;
847
848     TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
849
850     /* This is also done in the base class, but we have to verify this before loading any data from
851      * gl into the sysmem copy. The PBO may be mapped, a different rectangle locked, the discard flag
852      * may interfere, and all other bad things may happen
853      */
854     if (This->Flags & SFLAG_LOCKED) {
855         WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n");
856         return WINED3DERR_INVALIDCALL;
857     }
858     This->Flags |= SFLAG_LOCKED;
859
860     if (!(This->Flags & SFLAG_LOCKABLE))
861     {
862         TRACE("Warning: trying to lock unlockable surf@%p\n", This);
863     }
864
865     if (Flags & WINED3DLOCK_DISCARD) {
866         /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */
867         TRACE("WINED3DLOCK_DISCARD flag passed, marking local copy as up to date\n");
868         This->Flags |= SFLAG_INSYSMEM;
869     }
870
871     if (This->Flags & SFLAG_INSYSMEM) {
872         TRACE("Local copy is up to date, not downloading data\n");
873         surface_prepare_system_memory(This); /* Makes sure memory is allocated */
874         goto lock_end;
875     }
876
877     /* Now download the surface content from opengl
878      * Use the render target readback if the surface is on a swapchain(=onscreen render target) or the current primary target
879      * Offscreen targets which are not active at the moment or are higher targets(fbos) can be locked with the texture path
880      */
881     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
882     if(swapchain || iface == myDevice->render_targets[0]) {
883         const RECT *pass_rect = pRect;
884
885         /* IWineD3DSurface_LoadLocation does not check if the rectangle specifies the full surfaces
886          * because most caller functions do not need that. So do that here
887          */
888         if(pRect &&
889            pRect->top    == 0 &&
890            pRect->left   == 0 &&
891            pRect->right  == This->currentDesc.Width &&
892            pRect->bottom == This->currentDesc.Height) {
893             pass_rect = NULL;
894         }
895
896         switch(wined3d_settings.rendertargetlock_mode) {
897             case RTL_TEXDRAW:
898             case RTL_TEXTEX:
899                 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
900 #if 0
901                 /* Disabled for now. LoadLocation prefers the texture over the drawable as the source. So if we copy to the
902                  * texture first, then to sysmem, we'll avoid glReadPixels and use glCopyTexImage and glGetTexImage2D instead.
903                  * This may be faster on some cards
904                  */
905                 IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL /* No partial texture copy yet */);
906 #endif
907                 /* drop through */
908
909             case RTL_AUTO:
910             case RTL_READDRAW:
911             case RTL_READTEX:
912                 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, pRect);
913                 break;
914
915             case RTL_DISABLE:
916                 break;
917         }
918         if(swapchain) IWineD3DSwapChain_Release(swapchain);
919
920     } else if(iface == myDevice->stencilBufferTarget) {
921         /** the depth stencil in openGL has a format of GL_FLOAT
922          * which should be good for WINED3DFMT_D16_LOCKABLE
923          * and WINED3DFMT_D16
924          * it is unclear what format the stencil buffer is in except.
925          * 'Each index is converted to fixed point...
926          * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
927          * mappings in the table GL_PIXEL_MAP_S_TO_S.
928          * glReadPixels(This->lockedRect.left,
929          *             This->lockedRect.bottom - j - 1,
930          *             This->lockedRect.right - This->lockedRect.left,
931          *             1,
932          *             GL_DEPTH_COMPONENT,
933          *             type,
934          *             (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
935          *
936          * Depth Stencil surfaces which are not the current depth stencil target should have their data in a
937          * gl texture(next path), or in local memory(early return because of set SFLAG_INSYSMEM above). If
938          * none of that is the case the problem is not in this function :-)
939          ********************************************/
940         FIXME("Depth stencil locking not supported yet\n");
941     } else {
942         /* This path is for normal surfaces, offscreen render targets and everything else that is in a gl texture */
943         TRACE("locking an ordinary surface\n");
944         IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL /* no partial locking for textures yet */);
945     }
946
947 lock_end:
948     if(This->Flags & SFLAG_PBO) {
949         ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
950         ENTER_GL();
951         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
952         checkGLcall("glBindBufferARB");
953
954         /* This shouldn't happen but could occur if some other function didn't handle the PBO properly */
955         if(This->resource.allocatedMemory) {
956             ERR("The surface already has PBO memory allocated!\n");
957         }
958
959         This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
960         checkGLcall("glMapBufferARB");
961
962         /* Make sure the pbo isn't set anymore in order not to break non-pbo calls */
963         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
964         checkGLcall("glBindBufferARB");
965
966         LEAVE_GL();
967     }
968
969     if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
970         /* Don't dirtify */
971     } else {
972         IWineD3DBaseTexture *pBaseTexture;
973         /**
974          * Dirtify on lock
975          * as seen in msdn docs
976          */
977         IWineD3DSurface_AddDirtyRect(iface, pRect);
978
979         /** Dirtify Container if needed */
980         if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
981             TRACE("Making container dirty\n");
982             IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
983             IWineD3DBaseTexture_Release(pBaseTexture);
984         } else {
985             TRACE("Surface is standalone, no need to dirty the container\n");
986         }
987     }
988
989     return IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags);
990 }
991
992 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem) {
993     GLint  prev_store;
994     GLint  prev_rasterpos[4];
995     GLint skipBytes = 0;
996     BOOL storechanged = FALSE;
997     UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);    /* target is argb, 4 byte */
998     IWineD3DDeviceImpl *myDevice = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
999     IWineD3DSwapChainImpl *swapchain;
1000
1001     /* Activate the correct context for the render target */
1002     ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
1003     ENTER_GL();
1004
1005     IWineD3DSurface_GetContainer((IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
1006     if(!swapchain) {
1007         /* Primary offscreen render target */
1008         TRACE("Offscreen render target\n");
1009         glDrawBuffer(myDevice->offscreenBuffer);
1010         checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1011     } else {
1012         GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *) This, (IWineD3DSwapChain *)swapchain);
1013         TRACE("Unlocking %#x buffer\n", buffer);
1014         glDrawBuffer(buffer);
1015         checkGLcall("glDrawBuffer");
1016
1017         IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1018     }
1019
1020     glFlush();
1021     vcheckGLcall("glFlush");
1022     glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
1023     vcheckGLcall("glIntegerv");
1024     glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
1025     vcheckGLcall("glIntegerv");
1026     glPixelZoom(1.0, -1.0);
1027     vcheckGLcall("glPixelZoom");
1028
1029     /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
1030     glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
1031     glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
1032
1033     glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
1034     vcheckGLcall("glRasterPos2f");
1035
1036     /* Some drivers(radeon dri, others?) don't like exceptions during
1037      * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
1038      * after ReleaseDC. Reading it will cause an exception, which x11drv will
1039      * catch to put the dib section in InSync mode, which leads to a crash
1040      * and a blocked x server on my radeon card.
1041      *
1042      * The following lines read the dib section so it is put in inSync mode
1043      * before glDrawPixels is called and the crash is prevented. There won't
1044      * be any interfering gdi accesses, because UnlockRect is called from
1045      * ReleaseDC, and the app won't use the dc any more afterwards.
1046      */
1047     if((This->Flags & SFLAG_DIBSECTION) && !(This->Flags & SFLAG_PBO)) {
1048         volatile BYTE read;
1049         read = This->resource.allocatedMemory[0];
1050     }
1051
1052     if(This->Flags & SFLAG_PBO) {
1053         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1054         checkGLcall("glBindBufferARB");
1055     }
1056
1057     glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1058                  (This->lockedRect.bottom - This->lockedRect.top)-1,
1059                  fmt, type,
1060                  mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
1061     checkGLcall("glDrawPixels");
1062
1063     if(This->Flags & SFLAG_PBO) {
1064         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1065         checkGLcall("glBindBufferARB");
1066     }
1067
1068     glPixelZoom(1.0,1.0);
1069     vcheckGLcall("glPixelZoom");
1070
1071     glRasterPos3iv(&prev_rasterpos[0]);
1072     vcheckGLcall("glRasterPos3iv");
1073
1074     /* Reset to previous pack row length */
1075     glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1076     vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1077     if(storechanged) {
1078         glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
1079         vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1080     }
1081
1082     if(!swapchain) {
1083         glDrawBuffer(myDevice->offscreenBuffer);
1084         checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1085     } else if(swapchain->backBuffer) {
1086         glDrawBuffer(GL_BACK);
1087         checkGLcall("glDrawBuffer(GL_BACK)");
1088     } else {
1089         glDrawBuffer(GL_FRONT);
1090         checkGLcall("glDrawBuffer(GL_FRONT)");
1091     }
1092     LEAVE_GL();
1093
1094     return;
1095 }
1096
1097 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1098     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1099     IWineD3DDeviceImpl  *myDevice = This->resource.wineD3DDevice;
1100     IWineD3DSwapChainImpl *swapchain = NULL;
1101     BOOL fullsurface;
1102
1103     if (!(This->Flags & SFLAG_LOCKED)) {
1104         WARN("trying to Unlock an unlocked surf@%p\n", This);
1105         return WINED3DERR_INVALIDCALL;
1106     }
1107
1108     if (This->Flags & SFLAG_PBO) {
1109         TRACE("Freeing PBO memory\n");
1110         ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1111         ENTER_GL();
1112         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1113         GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1114         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1115         checkGLcall("glUnmapBufferARB");
1116         LEAVE_GL();
1117         This->resource.allocatedMemory = NULL;
1118     }
1119
1120     TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1121
1122     if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) {
1123         TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1124         goto unlock_end;
1125     }
1126
1127     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1128     if(swapchain || (myDevice->render_targets && iface == myDevice->render_targets[0])) {
1129         if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1130             static BOOL warned = FALSE;
1131             if(!warned) {
1132                 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1133                 warned = TRUE;
1134             }
1135             if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1136             goto unlock_end;
1137         }
1138
1139         if(This->dirtyRect.left   == 0 &&
1140            This->dirtyRect.top    == 0 &&
1141            This->dirtyRect.right  == This->currentDesc.Width &&
1142            This->dirtyRect.bottom == This->currentDesc.Height) {
1143             fullsurface = TRUE;
1144         } else {
1145             /* TODO: Proper partial rectangle tracking */
1146             fullsurface = FALSE;
1147             This->Flags |= SFLAG_INSYSMEM;
1148         }
1149
1150         switch(wined3d_settings.rendertargetlock_mode) {
1151             case RTL_READTEX:
1152             case RTL_TEXTEX:
1153                 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
1154                 ENTER_GL();
1155                 if (This->glDescription.textureName == 0) {
1156                     glGenTextures(1, &This->glDescription.textureName);
1157                     checkGLcall("glGenTextures");
1158                 }
1159                 glBindTexture(This->glDescription.target, This->glDescription.textureName);
1160                 checkGLcall("glBindTexture(This->glDescription.target, This->glDescription.textureName)");
1161                 LEAVE_GL();
1162                 IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL /* partial texture loading not supported yet */);
1163                 /* drop through */
1164
1165             case RTL_AUTO:
1166             case RTL_READDRAW:
1167             case RTL_TEXDRAW:
1168                 IWineD3DSurface_LoadLocation(iface, SFLAG_INDRAWABLE, fullsurface ? NULL : &This->dirtyRect);
1169                 break;
1170         }
1171
1172         if(!fullsurface) {
1173             /* Partial rectangle tracking is not commonly implemented, it is only done for render targets. Overwrite
1174              * the flags to bring them back into a sane state. INSYSMEM was set before to tell LoadLocation where
1175              * to read the rectangle from. Indrawable is set because all modifications from the partial sysmem copy
1176              * are written back to the drawable, thus the surface is merged again in the drawable. The sysmem copy is
1177              * not fully up to date because only a subrectangle was read in LockRect.
1178              */
1179             This->Flags &= ~SFLAG_INSYSMEM;
1180             This->Flags |= SFLAG_INDRAWABLE;
1181         }
1182
1183         This->dirtyRect.left   = This->currentDesc.Width;
1184         This->dirtyRect.top    = This->currentDesc.Height;
1185         This->dirtyRect.right  = 0;
1186         This->dirtyRect.bottom = 0;
1187     } else if(iface == myDevice->stencilBufferTarget) {
1188         FIXME("Depth Stencil buffer locking is not implemented\n");
1189     } else {
1190         /* The rest should be a normal texture */
1191         IWineD3DBaseTextureImpl *impl;
1192         /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1193          * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1194          * states need resetting
1195          */
1196         if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1197             if(impl->baseTexture.bindCount) {
1198                 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1199             }
1200             IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1201         }
1202     }
1203
1204     unlock_end:
1205     This->Flags &= ~SFLAG_LOCKED;
1206     memset(&This->lockedRect, 0, sizeof(RECT));
1207     return WINED3D_OK;
1208 }
1209
1210 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1211     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1212     WINED3DLOCKED_RECT lock;
1213     HRESULT hr;
1214     RGBQUAD col[256];
1215
1216     TRACE("(%p)->(%p)\n",This,pHDC);
1217
1218     if(This->Flags & SFLAG_USERPTR) {
1219         ERR("Not supported on surfaces with an application-provided surfaces\n");
1220         return WINEDDERR_NODC;
1221     }
1222
1223     /* Give more detailed info for ddraw */
1224     if (This->Flags & SFLAG_DCINUSE)
1225         return WINEDDERR_DCALREADYCREATED;
1226
1227     /* Can't GetDC if the surface is locked */
1228     if (This->Flags & SFLAG_LOCKED)
1229         return WINED3DERR_INVALIDCALL;
1230
1231     memset(&lock, 0, sizeof(lock)); /* To be sure */
1232
1233     /* Create a DIB section if there isn't a hdc yet */
1234     if(!This->hDC) {
1235         IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
1236         if(This->Flags & SFLAG_CLIENT) {
1237             IWineD3DSurface_PreLoad(iface);
1238         }
1239
1240         /* Use the dib section from now on if we are not using a PBO */
1241         if(!(This->Flags & SFLAG_PBO))
1242             This->resource.allocatedMemory = This->dib.bitmap_data;
1243     }
1244
1245     /* Lock the surface */
1246     hr = IWineD3DSurface_LockRect(iface,
1247                                   &lock,
1248                                   NULL,
1249                                   0);
1250
1251     if(This->Flags & SFLAG_PBO) {
1252         /* Sync the DIB with the PBO. This can't be done earlier because LockRect activates the allocatedMemory */
1253         memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->dib.bitmap_size);
1254     }
1255
1256     if(FAILED(hr)) {
1257         ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1258         /* keep the dib section */
1259         return hr;
1260     }
1261
1262     if(This->resource.format == WINED3DFMT_P8 ||
1263         This->resource.format == WINED3DFMT_A8P8) {
1264         unsigned int n;
1265         if(This->palette) {
1266             PALETTEENTRY ent[256];
1267
1268             GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1269             for (n=0; n<256; n++) {
1270                 col[n].rgbRed   = ent[n].peRed;
1271                 col[n].rgbGreen = ent[n].peGreen;
1272                 col[n].rgbBlue  = ent[n].peBlue;
1273                 col[n].rgbReserved = 0;
1274             }
1275         } else {
1276             IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1277
1278             for (n=0; n<256; n++) {
1279                 col[n].rgbRed   = device->palettes[device->currentPalette][n].peRed;
1280                 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1281                 col[n].rgbBlue  = device->palettes[device->currentPalette][n].peBlue;
1282                 col[n].rgbReserved = 0;
1283             }
1284
1285         }
1286         SetDIBColorTable(This->hDC, 0, 256, col);
1287     }
1288
1289     *pHDC = This->hDC;
1290     TRACE("returning %p\n",*pHDC);
1291     This->Flags |= SFLAG_DCINUSE;
1292
1293     return WINED3D_OK;
1294 }
1295
1296 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1297     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1298
1299     TRACE("(%p)->(%p)\n",This,hDC);
1300
1301     if (!(This->Flags & SFLAG_DCINUSE))
1302         return WINED3DERR_INVALIDCALL;
1303
1304     if (This->hDC !=hDC) {
1305         WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
1306         return WINED3DERR_INVALIDCALL;
1307     }
1308
1309     if((This->Flags & SFLAG_PBO) && This->resource.allocatedMemory) {
1310         /* Copy the contents of the DIB over to the PBO */
1311         memcpy(This->resource.allocatedMemory, This->dib.bitmap_data, This->dib.bitmap_size);
1312     }
1313
1314     /* we locked first, so unlock now */
1315     IWineD3DSurface_UnlockRect(iface);
1316
1317     This->Flags &= ~SFLAG_DCINUSE;
1318
1319     return WINED3D_OK;
1320 }
1321
1322 /* ******************************************************
1323    IWineD3DSurface Internal (No mapping to directx api) parts follow
1324    ****************************************************** */
1325
1326 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, BOOL srgb_mode) {
1327     BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
1328     const GlPixelFormatDesc *glDesc;
1329     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1330     BOOL p8_render_target = FALSE;
1331     getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc);
1332
1333     /* Default values: From the surface */
1334     *format = glDesc->glFormat;
1335     *type = glDesc->glType;
1336     *convert = NO_CONVERSION;
1337     *target_bpp = This->bytesPerPixel;
1338
1339     if(srgb_mode) {
1340         *internal = glDesc->glGammaInternal;
1341     } else if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
1342         *internal = glDesc->rtInternal;
1343     } else {
1344         *internal = glDesc->glInternal;
1345     }
1346
1347     /* Ok, now look if we have to do any conversion */
1348     switch(This->resource.format) {
1349         case WINED3DFMT_P8:
1350             /* ****************
1351                 Paletted Texture
1352                 **************** */
1353
1354             if (device->render_targets && device->render_targets[0]) {
1355                 IWineD3DSurfaceImpl* render_target = (IWineD3DSurfaceImpl*)device->render_targets[0];
1356                 if((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET) && (render_target->resource.format == WINED3DFMT_P8))
1357                     p8_render_target = TRUE;
1358             }
1359
1360              /* Use conversion when the paletted texture extension OR fragment shaders are available. When either
1361              * of the two is available make sure texturing is requested as neither of the two works in
1362              * conjunction with calls like glDraw-/glReadPixels. Further also use conversion in case of color keying.
1363              * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
1364              * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
1365              * conflicts with this.
1366              */
1367             if( !(GL_SUPPORT(EXT_PALETTED_TEXTURE) || (GL_SUPPORT(ARB_FRAGMENT_PROGRAM) && p8_render_target)) || colorkey_active || !use_texturing ) {
1368                 *format = GL_RGBA;
1369                 *internal = GL_RGBA;
1370                 *type = GL_UNSIGNED_BYTE;
1371                 *target_bpp = 4;
1372                 if(colorkey_active) {
1373                     *convert = CONVERT_PALETTED_CK;
1374                 } else {
1375                     *convert = CONVERT_PALETTED;
1376                 }
1377             }
1378             else if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) && GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) {
1379                 *format = GL_RED;
1380                 *internal = GL_RGBA;
1381                 *type = GL_UNSIGNED_BYTE;
1382                 *target_bpp = 1;
1383             }
1384
1385             break;
1386
1387         case WINED3DFMT_R3G3B2:
1388             /* **********************
1389                 GL_UNSIGNED_BYTE_3_3_2
1390                 ********************** */
1391             if (colorkey_active) {
1392                 /* This texture format will never be used.. So do not care about color keying
1393                     up until the point in time it will be needed :-) */
1394                 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1395             }
1396             break;
1397
1398         case WINED3DFMT_R5G6B5:
1399             if (colorkey_active) {
1400                 *convert = CONVERT_CK_565;
1401                 *format = GL_RGBA;
1402                 *internal = GL_RGBA;
1403                 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1404             }
1405             break;
1406
1407         case WINED3DFMT_X1R5G5B5:
1408             if (colorkey_active) {
1409                 *convert = CONVERT_CK_5551;
1410                 *format = GL_BGRA;
1411                 *internal = GL_RGBA;
1412                 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
1413             }
1414             break;
1415
1416         case WINED3DFMT_R8G8B8:
1417             if (colorkey_active) {
1418                 *convert = CONVERT_CK_RGB24;
1419                 *format = GL_RGBA;
1420                 *internal = GL_RGBA;
1421                 *type = GL_UNSIGNED_INT_8_8_8_8;
1422                 *target_bpp = 4;
1423             }
1424             break;
1425
1426         case WINED3DFMT_X8R8G8B8:
1427             if (colorkey_active) {
1428                 *convert = CONVERT_RGB32_888;
1429                 *format = GL_RGBA;
1430                 *internal = GL_RGBA;
1431                 *type = GL_UNSIGNED_INT_8_8_8_8;
1432             }
1433             break;
1434
1435         case WINED3DFMT_V8U8:
1436             if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1437             else if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) {
1438                 *format = GL_DUDV_ATI;
1439                 *internal = GL_DU8DV8_ATI;
1440                 *type = GL_BYTE;
1441                 /* No conversion - Just change the gl type */
1442                 break;
1443             }
1444             *convert = CONVERT_V8U8;
1445             *format = GL_BGR;
1446             *internal = GL_RGB8;
1447             *type = GL_UNSIGNED_BYTE;
1448             *target_bpp = 3;
1449             break;
1450
1451         case WINED3DFMT_L6V5U5:
1452             *convert = CONVERT_L6V5U5;
1453             if(GL_SUPPORT(NV_TEXTURE_SHADER)) {
1454                 *target_bpp = 3;
1455                 /* Use format and types from table */
1456             } else {
1457                 /* Load it into unsigned R5G6B5, swap L and V channels, and revert that in the shader */
1458                 *target_bpp = 2;
1459                 *format = GL_RGB;
1460                 *internal = GL_RGB5;
1461                 *type = GL_UNSIGNED_SHORT_5_6_5;
1462             }
1463             break;
1464
1465         case WINED3DFMT_X8L8V8U8:
1466             *convert = CONVERT_X8L8V8U8;
1467             *target_bpp = 4;
1468             if(GL_SUPPORT(NV_TEXTURE_SHADER)) {
1469                 /* Use formats from gl table. It is a bit unfortunate, but the conversion
1470                  * is needed to set the X format to 255 to get 1.0 for alpha when sampling
1471                  * the texture. OpenGL can't use GL_DSDT8_MAG8_NV as internal format with
1472                  * the needed type and format parameter, so the internal format contains a
1473                  * 4th component, which is returned as alpha
1474                  */
1475             } else {
1476                 /* Not supported by GL_ATI_envmap_bumpmap */
1477                 *format = GL_BGRA;
1478                 *internal = GL_RGB8;
1479                 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
1480             }
1481             break;
1482
1483         case WINED3DFMT_Q8W8V8U8:
1484             if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1485             *convert = CONVERT_Q8W8V8U8;
1486             *format = GL_BGRA;
1487             *internal = GL_RGBA8;
1488             *type = GL_UNSIGNED_BYTE;
1489             *target_bpp = 4;
1490             /* Not supported by GL_ATI_envmap_bumpmap */
1491             break;
1492
1493         case WINED3DFMT_V16U16:
1494             if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1495             *convert = CONVERT_V16U16;
1496             *format = GL_BGR;
1497             *internal = GL_RGB16_EXT;
1498             *type = GL_UNSIGNED_SHORT;
1499             *target_bpp = 6;
1500             /* What should I do here about GL_ATI_envmap_bumpmap?
1501              * Convert it or allow data loss by loading it into a 8 bit / channel texture?
1502              */
1503             break;
1504
1505         case WINED3DFMT_A4L4:
1506             /* A4L4 exists as an internal gl format, but for some reason there is not
1507              * format+type combination to load it. Thus convert it to A8L8, then load it
1508              * with A4L4 internal, but A8L8 format+type
1509              */
1510             *convert = CONVERT_A4L4;
1511             *format = GL_LUMINANCE_ALPHA;
1512             *internal = GL_LUMINANCE4_ALPHA4;
1513             *type = GL_UNSIGNED_BYTE;
1514             *target_bpp = 2;
1515             break;
1516
1517         case WINED3DFMT_R32F:
1518             /* Can be loaded in theory with fmt=GL_RED, type=GL_FLOAT, but this fails. The reason
1519              * is that D3D expects the undefined green, blue and alpha channels to return 1.0
1520              * when sampling, but OpenGL sets green and blue to 0.0 instead. Thus we have to inject
1521              * 1.0 instead.
1522              *
1523              * The alpha channel defaults to 1.0 in opengl, so nothing has to be done about it.
1524              */
1525             *convert = CONVERT_R32F;
1526             *format = GL_RGB;
1527             *internal = GL_RGB32F_ARB;
1528             *type = GL_FLOAT;
1529             *target_bpp = 12;
1530             break;
1531
1532         case WINED3DFMT_R16F:
1533             /* Similar to R32F */
1534             *convert = CONVERT_R16F;
1535             *format = GL_RGB;
1536             *internal = GL_RGB16F_ARB;
1537             *type = GL_HALF_FLOAT_ARB;
1538             *target_bpp = 6;
1539             break;
1540
1541         case WINED3DFMT_G16R16:
1542             *convert = CONVERT_G16R16;
1543             *format = GL_RGB;
1544             *internal = GL_RGB16_EXT;
1545             *type = GL_UNSIGNED_SHORT;
1546             *target_bpp = 6;
1547             break;
1548
1549         default:
1550             break;
1551     }
1552
1553     return WINED3D_OK;
1554 }
1555
1556 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *This) {
1557     BYTE *source, *dest;
1558     TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert,This);
1559
1560     switch (convert) {
1561         case NO_CONVERSION:
1562         {
1563             memcpy(dst, src, pitch * height);
1564             break;
1565         }
1566         case CONVERT_PALETTED:
1567         case CONVERT_PALETTED_CK:
1568         {
1569             IWineD3DPaletteImpl* pal = This->palette;
1570             BYTE table[256][4];
1571             unsigned int x, y;
1572
1573             if( pal == NULL) {
1574                 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1575             }
1576
1577             d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
1578
1579             for (y = 0; y < height; y++)
1580             {
1581                 source = src + pitch * y;
1582                 dest = dst + outpitch * y;
1583                 /* This is an 1 bpp format, using the width here is fine */
1584                 for (x = 0; x < width; x++) {
1585                     BYTE color = *source++;
1586                     *dest++ = table[color][0];
1587                     *dest++ = table[color][1];
1588                     *dest++ = table[color][2];
1589                     *dest++ = table[color][3];
1590                 }
1591             }
1592         }
1593         break;
1594
1595         case CONVERT_CK_565:
1596         {
1597             /* Converting the 565 format in 5551 packed to emulate color-keying.
1598
1599               Note : in all these conversion, it would be best to average the averaging
1600                       pixels to get the color of the pixel that will be color-keyed to
1601                       prevent 'color bleeding'. This will be done later on if ever it is
1602                       too visible.
1603
1604               Note2: Nvidia documents say that their driver does not support alpha + color keying
1605                      on the same surface and disables color keying in such a case
1606             */
1607             unsigned int x, y;
1608             WORD *Source;
1609             WORD *Dest;
1610
1611             TRACE("Color keyed 565\n");
1612
1613             for (y = 0; y < height; y++) {
1614                 Source = (WORD *) (src + y * pitch);
1615                 Dest = (WORD *) (dst + y * outpitch);
1616                 for (x = 0; x < width; x++ ) {
1617                     WORD color = *Source++;
1618                     *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1619                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
1620                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
1621                         *Dest |= 0x0001;
1622                     }
1623                     Dest++;
1624                 }
1625             }
1626         }
1627         break;
1628
1629         case CONVERT_CK_5551:
1630         {
1631             /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
1632             unsigned int x, y;
1633             WORD *Source;
1634             WORD *Dest;
1635             TRACE("Color keyed 5551\n");
1636             for (y = 0; y < height; y++) {
1637                 Source = (WORD *) (src + y * pitch);
1638                 Dest = (WORD *) (dst + y * outpitch);
1639                 for (x = 0; x < width; x++ ) {
1640                     WORD color = *Source++;
1641                     *Dest = color;
1642                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
1643                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
1644                         *Dest |= (1 << 15);
1645                     }
1646                     else {
1647                         *Dest &= ~(1 << 15);
1648                     }
1649                     Dest++;
1650                 }
1651             }
1652         }
1653         break;
1654
1655         case CONVERT_V8U8:
1656         {
1657             unsigned int x, y;
1658             short *Source;
1659             unsigned char *Dest;
1660             for(y = 0; y < height; y++) {
1661                 Source = (short *) (src + y * pitch);
1662                 Dest = (unsigned char *) (dst + y * outpitch);
1663                 for (x = 0; x < width; x++ ) {
1664                     long color = (*Source++);
1665                     /* B */ Dest[0] = 0xff;
1666                     /* G */ Dest[1] = (color >> 8) + 128; /* V */
1667                     /* R */ Dest[2] = (color) + 128;      /* U */
1668                     Dest += 3;
1669                 }
1670             }
1671             break;
1672         }
1673
1674         case CONVERT_V16U16:
1675         {
1676             unsigned int x, y;
1677             DWORD *Source;
1678             unsigned short *Dest;
1679             for(y = 0; y < height; y++) {
1680                 Source = (DWORD *) (src + y * pitch);
1681                 Dest = (unsigned short *) (dst + y * outpitch);
1682                 for (x = 0; x < width; x++ ) {
1683                     DWORD color = (*Source++);
1684                     /* B */ Dest[0] = 0xffff;
1685                     /* G */ Dest[1] = (color >> 16) + 32768; /* V */
1686                     /* R */ Dest[2] = (color      ) + 32768; /* U */
1687                     Dest += 3;
1688                 }
1689             }
1690             break;
1691         }
1692
1693         case CONVERT_Q8W8V8U8:
1694         {
1695             unsigned int x, y;
1696             DWORD *Source;
1697             unsigned char *Dest;
1698             for(y = 0; y < height; y++) {
1699                 Source = (DWORD *) (src + y * pitch);
1700                 Dest = (unsigned char *) (dst + y * outpitch);
1701                 for (x = 0; x < width; x++ ) {
1702                     long color = (*Source++);
1703                     /* B */ Dest[0] = ((color >> 16) & 0xff) + 128; /* W */
1704                     /* G */ Dest[1] = ((color >> 8 ) & 0xff) + 128; /* V */
1705                     /* R */ Dest[2] = (color         & 0xff) + 128; /* U */
1706                     /* A */ Dest[3] = ((color >> 24) & 0xff) + 128; /* Q */
1707                     Dest += 4;
1708                 }
1709             }
1710             break;
1711         }
1712
1713         case CONVERT_L6V5U5:
1714         {
1715             unsigned int x, y;
1716             WORD *Source;
1717             unsigned char *Dest;
1718
1719             if(GL_SUPPORT(NV_TEXTURE_SHADER)) {
1720                 /* This makes the gl surface bigger(24 bit instead of 16), but it works with
1721                  * fixed function and shaders without further conversion once the surface is
1722                  * loaded
1723                  */
1724                 for(y = 0; y < height; y++) {
1725                     Source = (WORD *) (src + y * pitch);
1726                     Dest = (unsigned char *) (dst + y * outpitch);
1727                     for (x = 0; x < width; x++ ) {
1728                         short color = (*Source++);
1729                         unsigned char l = ((color >> 10) & 0xfc);
1730                                   char v = ((color >>  5) & 0x3e);
1731                                   char u = ((color      ) & 0x1f);
1732
1733                         /* 8 bits destination, 6 bits source, 8th bit is the sign. gl ignores the sign
1734                          * and doubles the positive range. Thus shift left only once, gl does the 2nd
1735                          * shift. GL reads a signed value and converts it into an unsigned value.
1736                          */
1737                         /* M */ Dest[2] = l << 1;
1738
1739                         /* Those are read as signed, but kept signed. Just left-shift 3 times to scale
1740                          * from 5 bit values to 8 bit values.
1741                          */
1742                         /* V */ Dest[1] = v << 3;
1743                         /* U */ Dest[0] = u << 3;
1744                         Dest += 3;
1745                     }
1746                 }
1747             } else {
1748                 for(y = 0; y < height; y++) {
1749                     unsigned short *Dest_s = (unsigned short *) (dst + y * outpitch);
1750                     Source = (WORD *) (src + y * pitch);
1751                     for (x = 0; x < width; x++ ) {
1752                         short color = (*Source++);
1753                         unsigned char l = ((color >> 10) & 0xfc);
1754                                  short v = ((color >>  5) & 0x3e);
1755                                  short u = ((color      ) & 0x1f);
1756                         short v_conv = v + 16;
1757                         short u_conv = u + 16;
1758
1759                         *Dest_s = ((v_conv << 11) & 0xf800) | ((l << 5) & 0x7e0) | (u_conv & 0x1f);
1760                         Dest_s += 1;
1761                     }
1762                 }
1763             }
1764             break;
1765         }
1766
1767         case CONVERT_X8L8V8U8:
1768         {
1769             unsigned int x, y;
1770             DWORD *Source;
1771             unsigned char *Dest;
1772
1773             if(GL_SUPPORT(NV_TEXTURE_SHADER)) {
1774                 /* This implementation works with the fixed function pipeline and shaders
1775                  * without further modification after converting the surface.
1776                  */
1777                 for(y = 0; y < height; y++) {
1778                     Source = (DWORD *) (src + y * pitch);
1779                     Dest = (unsigned char *) (dst + y * outpitch);
1780                     for (x = 0; x < width; x++ ) {
1781                         long color = (*Source++);
1782                         /* L */ Dest[2] = ((color >> 16) & 0xff);   /* L */
1783                         /* V */ Dest[1] = ((color >> 8 ) & 0xff);   /* V */
1784                         /* U */ Dest[0] = (color         & 0xff);   /* U */
1785                         /* I */ Dest[3] = 255;                      /* X */
1786                         Dest += 4;
1787                     }
1788                 }
1789             } else {
1790                 /* Doesn't work correctly with the fixed function pipeline, but can work in
1791                  * shaders if the shader is adjusted. (There's no use for this format in gl's
1792                  * standard fixed function pipeline anyway).
1793                  */
1794                 for(y = 0; y < height; y++) {
1795                     Source = (DWORD *) (src + y * pitch);
1796                     Dest = (unsigned char *) (dst + y * outpitch);
1797                     for (x = 0; x < width; x++ ) {
1798                         long color = (*Source++);
1799                         /* B */ Dest[0] = ((color >> 16) & 0xff);       /* L */
1800                         /* G */ Dest[1] = ((color >> 8 ) & 0xff) + 128; /* V */
1801                         /* R */ Dest[2] = (color         & 0xff) + 128;  /* U */
1802                         Dest += 4;
1803                     }
1804                 }
1805             }
1806             break;
1807         }
1808
1809         case CONVERT_A4L4:
1810         {
1811             unsigned int x, y;
1812             unsigned char *Source;
1813             unsigned char *Dest;
1814             for(y = 0; y < height; y++) {
1815                 Source = (unsigned char *) (src + y * pitch);
1816                 Dest = (unsigned char *) (dst + y * outpitch);
1817                 for (x = 0; x < width; x++ ) {
1818                     unsigned char color = (*Source++);
1819                     /* A */ Dest[1] = (color & 0xf0) << 0;
1820                     /* L */ Dest[0] = (color & 0x0f) << 4;
1821                     Dest += 2;
1822                 }
1823             }
1824             break;
1825         }
1826
1827         case CONVERT_R32F:
1828         {
1829             unsigned int x, y;
1830             float *Source;
1831             float *Dest;
1832             for(y = 0; y < height; y++) {
1833                 Source = (float *) (src + y * pitch);
1834                 Dest = (float *) (dst + y * outpitch);
1835                 for (x = 0; x < width; x++ ) {
1836                     float color = (*Source++);
1837                     Dest[0] = color;
1838                     Dest[1] = 1.0;
1839                     Dest[2] = 1.0;
1840                     Dest += 3;
1841                 }
1842             }
1843             break;
1844         }
1845
1846         case CONVERT_R16F:
1847         {
1848             unsigned int x, y;
1849             WORD *Source;
1850             WORD *Dest;
1851             WORD one = 0x3c00;
1852             for(y = 0; y < height; y++) {
1853                 Source = (WORD *) (src + y * pitch);
1854                 Dest = (WORD *) (dst + y * outpitch);
1855                 for (x = 0; x < width; x++ ) {
1856                     WORD color = (*Source++);
1857                     Dest[0] = color;
1858                     Dest[1] = one;
1859                     Dest[2] = one;
1860                     Dest += 3;
1861                 }
1862             }
1863             break;
1864         }
1865
1866         case CONVERT_G16R16:
1867         {
1868             unsigned int x, y;
1869             WORD *Source;
1870             WORD *Dest;
1871
1872             for(y = 0; y < height; y++) {
1873                 Source = (WORD *) (src + y * pitch);
1874                 Dest = (WORD *) (dst + y * outpitch);
1875                 for (x = 0; x < width; x++ ) {
1876                     WORD green = (*Source++);
1877                     WORD red = (*Source++);
1878                     Dest[0] = green;
1879                     Dest[1] = red;
1880                     Dest[2] = 0xffff;
1881                     Dest += 3;
1882                 }
1883             }
1884             break;
1885         }
1886
1887         default:
1888             ERR("Unsupported conversation type %d\n", convert);
1889     }
1890     return WINED3D_OK;
1891 }
1892
1893 static void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey) {
1894     IWineD3DPaletteImpl* pal = This->palette;
1895     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1896     BOOL index_in_alpha = FALSE;
1897     int i;
1898
1899     /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
1900     * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
1901     * is slow. Further RGB->P8 conversion is not possible because palettes can have
1902     * duplicate entries. Store the color key in the unused alpha component to speed the
1903     * download up and to make conversion unneeded. */
1904     if (device->render_targets && device->render_targets[0]) {
1905         IWineD3DSurfaceImpl* render_target = (IWineD3DSurfaceImpl*)device->render_targets[0];
1906
1907         if((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET) && (render_target->resource.format == WINED3DFMT_P8))
1908             index_in_alpha = TRUE;
1909     }
1910
1911     if (pal == NULL) {
1912         /* Still no palette? Use the device's palette */
1913         /* Get the surface's palette */
1914         for (i = 0; i < 256; i++) {
1915             table[i][0] = device->palettes[device->currentPalette][i].peRed;
1916             table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1917             table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1918
1919             if(index_in_alpha) {
1920                 table[i][3] = i;
1921             } else if (colorkey &&
1922                 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1923                 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1924                 /* We should maybe here put a more 'neutral' color than the standard bright purple
1925                    one often used by application to prevent the nice purple borders when bi-linear
1926                    filtering is on */
1927                 table[i][3] = 0x00;
1928             } else {
1929                 table[i][3] = 0xFF;
1930             }
1931         }
1932     } else {
1933         TRACE("Using surface palette %p\n", pal);
1934         /* Get the surface's palette */
1935         for (i = 0; i < 256; i++) {
1936             table[i][0] = pal->palents[i].peRed;
1937             table[i][1] = pal->palents[i].peGreen;
1938             table[i][2] = pal->palents[i].peBlue;
1939
1940             if(index_in_alpha) {
1941                 table[i][3] = i;
1942             }
1943             else if (colorkey &&
1944                 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1945                 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1946                 /* We should maybe here put a more 'neutral' color than the standard bright purple
1947                    one often used by application to prevent the nice purple borders when bi-linear
1948                    filtering is on */
1949                 table[i][3] = 0x00;
1950             } else if(pal->Flags & WINEDDPCAPS_ALPHA) {
1951                 table[i][3] = pal->palents[i].peFlags;
1952             } else {
1953                 table[i][3] = 0xFF;
1954             }
1955         }
1956     }
1957 }
1958
1959 const char *fragment_palette_conversion =
1960     "!!ARBfp1.0\n"
1961     "TEMP index;\n"
1962     "PARAM constants = { 0.996, 0.00195, 0, 0 };\n" /* { 255/256, 0.5/255*255/256, 0, 0 } */
1963     "TEX index.x, fragment.texcoord[0], texture[0], 2D;\n" /* store the red-component of the current pixel */
1964     "MAD index.x, index.x, constants.x, constants.y;\n" /* Scale the index by 255/256 and add a bias of '0.5' in order to sample in the middle */
1965     "TEX result.color, index, texture[1], 1D;\n" /* use the red-component as a index in the palette to get the final color */
1966     "END";
1967
1968 /* This function is used in case of 8bit paletted textures to upload the palette.
1969    It supports GL_EXT_paletted_texture and GL_ARB_fragment_program, support for other
1970    extensions like ATI_fragment_shaders is possible.
1971 */
1972 static void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1973     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1974     BYTE table[256][4];
1975     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1976
1977     d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
1978
1979     /* Try to use the paletted texture extension */
1980     if(GL_SUPPORT(EXT_PALETTED_TEXTURE))
1981     {
1982         TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
1983         GL_EXTCALL(glColorTableEXT(This->glDescription.target,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1984     }
1985     else
1986     {
1987         /* Let a fragment shader do the color conversion by uploading the palette to a 1D texture.
1988          * The 8bit pixel data will be used as an index in this palette texture to retrieve the final color. */
1989         TRACE("Using fragment shaders for emulating 8-bit paletted texture support\n");
1990
1991         /* Create the fragment program if we don't have it */
1992         if(!device->paletteConversionShader)
1993         {
1994             glEnable(GL_FRAGMENT_PROGRAM_ARB);
1995             GL_EXTCALL(glGenProgramsARB(1, &device->paletteConversionShader));
1996             GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, device->paletteConversionShader));
1997             GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(fragment_palette_conversion), (const GLbyte *)fragment_palette_conversion));
1998             glDisable(GL_FRAGMENT_PROGRAM_ARB);
1999         }
2000
2001         glEnable(GL_FRAGMENT_PROGRAM_ARB);
2002         GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, device->paletteConversionShader));
2003
2004         GL_EXTCALL(glActiveTextureARB(GL_TEXTURE1));
2005         glEnable(GL_TEXTURE_1D);
2006         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2007
2008         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2009         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); /* Make sure we have discrete color levels. */
2010         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2011         glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, table); /* Upload the palette */
2012
2013         /* Switch back to unit 0 in which the 2D texture will be stored. */
2014         GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0));
2015
2016         /* Rebind the texture because it isn't bound anymore */
2017         glBindTexture(This->glDescription.target, This->glDescription.textureName);
2018     }
2019 }
2020
2021 static BOOL palette9_changed(IWineD3DSurfaceImpl *This) {
2022     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2023
2024     if(This->palette || (This->resource.format != WINED3DFMT_P8 && This->resource.format != WINED3DFMT_A8P8)) {
2025         /* If a ddraw-style palette is attached assume no d3d9 palette change.
2026          * Also the palette isn't interesting if the surface format isn't P8 or A8P8
2027          */
2028         return FALSE;
2029     }
2030
2031     if(This->palette9) {
2032         if(memcmp(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256) == 0) {
2033             return FALSE;
2034         }
2035     } else {
2036         This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2037     }
2038     memcpy(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
2039     return TRUE;
2040 }
2041
2042 static inline void clear_unused_channels(IWineD3DSurfaceImpl *This) {
2043     GLboolean oldwrite[4];
2044
2045     /* Some formats have only some color channels, and the others are 1.0.
2046      * since our rendering renders to all channels, and those pixel formats
2047      * are emulated by using a full texture with the other channels set to 1.0
2048      * manually, clear the unused channels.
2049      *
2050      * This could be done with hacking colorwriteenable to mask the colors,
2051      * but before drawing the buffer would have to be cleared too, so there's
2052      * no gain in that
2053      */
2054     switch(This->resource.format) {
2055         case WINED3DFMT_R16F:
2056         case WINED3DFMT_R32F:
2057             TRACE("R16F or R32F format, clearing green, blue and alpha to 1.0\n");
2058             /* Do not activate a context, the correct drawable is active already
2059              * though just the read buffer is set, make sure to have the correct draw
2060              * buffer too
2061              */
2062             glDrawBuffer(This->resource.wineD3DDevice->offscreenBuffer);
2063             glDisable(GL_SCISSOR_TEST);
2064             glGetBooleanv(GL_COLOR_WRITEMASK, oldwrite);
2065             glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE);
2066             glClearColor(0.0, 1.0, 1.0, 1.0);
2067             glClear(GL_COLOR_BUFFER_BIT);
2068             glColorMask(oldwrite[0], oldwrite[1], oldwrite[2], oldwrite[3]);
2069             if(!This->resource.wineD3DDevice->render_offscreen) glDrawBuffer(GL_BACK);
2070             checkGLcall("Unused channel clear\n");
2071             break;
2072
2073         default: break;
2074     }
2075 }
2076
2077 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) {
2078     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2079
2080     if (!(This->Flags & SFLAG_INTEXTURE)) {
2081         TRACE("Reloading because surface is dirty\n");
2082     } else if(/* Reload: gl texture has ck, now no ckey is set OR */
2083               ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & WINEDDSD_CKSRCBLT))) ||
2084               /* Reload: vice versa  OR */
2085               ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & WINEDDSD_CKSRCBLT)) ||
2086               /* Also reload: Color key is active AND the color key has changed */
2087               ((This->CKeyFlags & WINEDDSD_CKSRCBLT) && (
2088                 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
2089                 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
2090         TRACE("Reloading because of color keying\n");
2091         /* To perform the color key conversion we need a sysmem copy of
2092          * the surface. Make sure we have it
2093          */
2094         IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
2095     } else if(palette9_changed(This)) {
2096         TRACE("Reloading surface because the d3d8/9 palette was changed\n");
2097         /* TODO: This is not necessarily needed with hw palettized texture support */
2098         IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
2099     } else {
2100         TRACE("surface is already in texture\n");
2101         return WINED3D_OK;
2102     }
2103
2104     /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
2105      *  These resources are not bound by device size or format restrictions. Because of this,
2106      *  these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
2107      *  However, these resources can always be created, locked, and copied.
2108      */
2109     if (This->resource.pool == WINED3DPOOL_SCRATCH )
2110     {
2111         FIXME("(%p) Operation not supported for scratch textures\n",This);
2112         return WINED3DERR_INVALIDCALL;
2113     }
2114
2115     This->srgb = srgb_mode;
2116     IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL /* no partial locking for textures yet */);
2117
2118 #if 0
2119     {
2120         static unsigned int gen = 0;
2121         char buffer[4096];
2122         ++gen;
2123         if ((gen % 10) == 0) {
2124             snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
2125             IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
2126         }
2127         /*
2128          * debugging crash code
2129          if (gen == 250) {
2130          void** test = NULL;
2131          *test = 0;
2132          }
2133          */
2134     }
2135 #endif
2136
2137     if (!(This->Flags & SFLAG_DONOTFREE)) {
2138         HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
2139         This->resource.allocatedMemory = NULL;
2140         This->resource.heapMemory = NULL;
2141         IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, FALSE);
2142     }
2143
2144     return WINED3D_OK;
2145 }
2146
2147 static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface) {
2148     /* TODO: check for locks */
2149     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2150     IWineD3DBaseTexture *baseTexture = NULL;
2151     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2152
2153     TRACE("(%p)Checking to see if the container is a base texture\n", This);
2154     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2155         TRACE("Passing to container\n");
2156         IWineD3DBaseTexture_BindTexture(baseTexture);
2157         IWineD3DBaseTexture_Release(baseTexture);
2158     } else {
2159         TRACE("(%p) : Binding surface\n", This);
2160
2161         if(!device->isInDraw) {
2162             ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2163         }
2164         ENTER_GL();
2165         glBindTexture(This->glDescription.target, This->glDescription.textureName);
2166         LEAVE_GL();
2167     }
2168     return;
2169 }
2170
2171 #include <errno.h>
2172 #include <stdio.h>
2173 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
2174     FILE* f = NULL;
2175     UINT i, y;
2176     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2177     char *allocatedMemory;
2178     char *textureRow;
2179     IWineD3DSwapChain *swapChain = NULL;
2180     int width, height;
2181     GLuint tmpTexture = 0;
2182     DWORD color;
2183     /*FIXME:
2184     Textures may not be stored in ->allocatedgMemory and a GlTexture
2185     so we should lock the surface before saving a snapshot, or at least check that
2186     */
2187     /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
2188     by calling GetTexImage and in compressed form by calling
2189     GetCompressedTexImageARB.  Queried compressed images can be saved and
2190     later reused by calling CompressedTexImage[123]DARB.  Pre-compressed
2191     texture images do not need to be processed by the GL and should
2192     significantly improve texture loading performance relative to uncompressed
2193     images. */
2194
2195 /* Setup the width and height to be the internal texture width and height. */
2196     width  = This->pow2Width;
2197     height = This->pow2Height;
2198 /* check to see if we're a 'virtual' texture, e.g. we're not a pbuffer of texture, we're a back buffer*/
2199     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
2200
2201     if (This->Flags & SFLAG_INDRAWABLE && !(This->Flags & SFLAG_INTEXTURE)) {
2202         /* if were not a real texture then read the back buffer into a real texture */
2203         /* we don't want to interfere with the back buffer so read the data into a temporary
2204          * texture and then save the data out of the temporary texture
2205          */
2206         GLint prevRead;
2207         ENTER_GL();
2208         TRACE("(%p) Reading render target into texture\n", This);
2209         glEnable(GL_TEXTURE_2D);
2210
2211         glGenTextures(1, &tmpTexture);
2212         glBindTexture(GL_TEXTURE_2D, tmpTexture);
2213
2214         glTexImage2D(GL_TEXTURE_2D,
2215                         0,
2216                         GL_RGBA,
2217                         width,
2218                         height,
2219                         0/*border*/,
2220                         GL_RGBA,
2221                         GL_UNSIGNED_INT_8_8_8_8_REV,
2222                         NULL);
2223
2224         glGetIntegerv(GL_READ_BUFFER, &prevRead);
2225         vcheckGLcall("glGetIntegerv");
2226         glReadBuffer(swapChain ? GL_BACK : This->resource.wineD3DDevice->offscreenBuffer);
2227         vcheckGLcall("glReadBuffer");
2228         glCopyTexImage2D(GL_TEXTURE_2D,
2229                             0,
2230                             GL_RGBA,
2231                             0,
2232                             0,
2233                             width,
2234                             height,
2235                             0);
2236
2237         checkGLcall("glCopyTexImage2D");
2238         glReadBuffer(prevRead);
2239         LEAVE_GL();
2240
2241     } else { /* bind the real texture, and make sure it up to date */
2242         IWineD3DSurface_PreLoad(iface);
2243     }
2244     allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width  * height * 4);
2245     ENTER_GL();
2246     FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
2247     glGetTexImage(GL_TEXTURE_2D,
2248                 This->glDescription.level,
2249                 GL_RGBA,
2250                 GL_UNSIGNED_INT_8_8_8_8_REV,
2251                 allocatedMemory);
2252     checkGLcall("glTexImage2D");
2253     if (tmpTexture) {
2254         glBindTexture(GL_TEXTURE_2D, 0);
2255         glDeleteTextures(1, &tmpTexture);
2256     }
2257     LEAVE_GL();
2258
2259     f = fopen(filename, "w+");
2260     if (NULL == f) {
2261         ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2262         return WINED3DERR_INVALIDCALL;
2263     }
2264 /* Save the data out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha channel */
2265     TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2266 /* TGA header */
2267     fputc(0,f);
2268     fputc(0,f);
2269     fputc(2,f);
2270     fputc(0,f);
2271     fputc(0,f);
2272     fputc(0,f);
2273     fputc(0,f);
2274     fputc(0,f);
2275     fputc(0,f);
2276     fputc(0,f);
2277     fputc(0,f);
2278     fputc(0,f);
2279 /* short width*/
2280     fwrite(&width,2,1,f);
2281 /* short height */
2282     fwrite(&height,2,1,f);
2283 /* format rgba */
2284     fputc(0x20,f);
2285     fputc(0x28,f);
2286 /* raw data */
2287     /* 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 */
2288     if(swapChain)
2289         textureRow = allocatedMemory + (width * (height - 1) *4);
2290     else
2291         textureRow = allocatedMemory;
2292     for (y = 0 ; y < height; y++) {
2293         for (i = 0; i < width;  i++) {
2294             color = *((DWORD*)textureRow);
2295             fputc((color >> 16) & 0xFF, f); /* B */
2296             fputc((color >>  8) & 0xFF, f); /* G */
2297             fputc((color >>  0) & 0xFF, f); /* R */
2298             fputc((color >> 24) & 0xFF, f); /* A */
2299             textureRow += 4;
2300         }
2301         /* take two rows of the pointer to the texture memory */
2302         if(swapChain)
2303             (textureRow-= width << 3);
2304
2305     }
2306     TRACE("Closing file\n");
2307     fclose(f);
2308
2309     if(swapChain) {
2310         IWineD3DSwapChain_Release(swapChain);
2311     }
2312     HeapFree(GetProcessHeap(), 0, allocatedMemory);
2313     return WINED3D_OK;
2314 }
2315
2316 /**
2317  *   Slightly inefficient way to handle multiple dirty rects but it works :)
2318  */
2319 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2320     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2321     IWineD3DBaseTexture *baseTexture = NULL;
2322
2323     if (!(This->Flags & SFLAG_INSYSMEM) && (This->Flags & SFLAG_INTEXTURE))
2324         IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL /* no partial locking for textures yet */);
2325
2326     IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
2327     if (NULL != pDirtyRect) {
2328         This->dirtyRect.left   = min(This->dirtyRect.left,   pDirtyRect->left);
2329         This->dirtyRect.top    = min(This->dirtyRect.top,    pDirtyRect->top);
2330         This->dirtyRect.right  = max(This->dirtyRect.right,  pDirtyRect->right);
2331         This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2332     } else {
2333         This->dirtyRect.left   = 0;
2334         This->dirtyRect.top    = 0;
2335         This->dirtyRect.right  = This->currentDesc.Width;
2336         This->dirtyRect.bottom = This->currentDesc.Height;
2337     }
2338     TRACE("(%p) : Dirty: yes, Rect:(%d,%d,%d,%d)\n", This, This->dirtyRect.left,
2339           This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2340     /* if the container is a basetexture then mark it dirty. */
2341     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2342         TRACE("Passing to container\n");
2343         IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2344         IWineD3DBaseTexture_Release(baseTexture);
2345     }
2346     return WINED3D_OK;
2347 }
2348
2349 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2350     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2351     HRESULT hr;
2352     const GlPixelFormatDesc *glDesc;
2353     getFormatDescEntry(format, &GLINFO_LOCATION, &glDesc);
2354
2355     TRACE("(%p) : Calling base function first\n", This);
2356     hr = IWineD3DBaseSurfaceImpl_SetFormat(iface, format);
2357     if(SUCCEEDED(hr)) {
2358         /* Setup some glformat defaults */
2359         This->glDescription.glFormat         = glDesc->glFormat;
2360         This->glDescription.glFormatInternal = glDesc->glInternal;
2361         This->glDescription.glType           = glDesc->glType;
2362
2363         This->Flags &= ~SFLAG_ALLOCATED;
2364         TRACE("(%p) : glFormat %d, glFotmatInternal %d, glType %d\n", This,
2365               This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType);
2366     }
2367     return hr;
2368 }
2369
2370 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2371     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2372
2373     if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2374         WARN("Surface is locked or the HDC is in use\n");
2375         return WINED3DERR_INVALIDCALL;
2376     }
2377
2378     if(Mem && Mem != This->resource.allocatedMemory) {
2379         void *release = NULL;
2380
2381         /* Do I have to copy the old surface content? */
2382         if(This->Flags & SFLAG_DIBSECTION) {
2383                 /* Release the DC. No need to hold the critical section for the update
2384                  * Thread because this thread runs only on front buffers, but this method
2385                  * fails for render targets in the check above.
2386                  */
2387                 SelectObject(This->hDC, This->dib.holdbitmap);
2388                 DeleteDC(This->hDC);
2389                 /* Release the DIB section */
2390                 DeleteObject(This->dib.DIBsection);
2391                 This->dib.bitmap_data = NULL;
2392                 This->resource.allocatedMemory = NULL;
2393                 This->hDC = NULL;
2394                 This->Flags &= ~SFLAG_DIBSECTION;
2395         } else if(!(This->Flags & SFLAG_USERPTR)) {
2396             release = This->resource.heapMemory;
2397             This->resource.heapMemory = NULL;
2398         }
2399         This->resource.allocatedMemory = Mem;
2400         This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
2401
2402         /* Now the surface memory is most up do date. Invalidate drawable and texture */
2403         IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
2404
2405         /* For client textures opengl has to be notified */
2406         if(This->Flags & SFLAG_CLIENT) {
2407             This->Flags &= ~SFLAG_ALLOCATED;
2408             IWineD3DSurface_PreLoad(iface);
2409             /* And hope that the app behaves correctly and did not free the old surface memory before setting a new pointer */
2410         }
2411
2412         /* Now free the old memory if any */
2413         HeapFree(GetProcessHeap(), 0, release);
2414     } else if(This->Flags & SFLAG_USERPTR) {
2415         /* Lockrect and GetDC will re-create the dib section and allocated memory */
2416         This->resource.allocatedMemory = NULL;
2417         /* HeapMemory should be NULL already */
2418         if(This->resource.heapMemory != NULL) ERR("User pointer surface has heap memory allocated\n");
2419         This->Flags &= ~SFLAG_USERPTR;
2420
2421         if(This->Flags & SFLAG_CLIENT) {
2422             This->Flags &= ~SFLAG_ALLOCATED;
2423             /* This respecifies an empty texture and opengl knows that the old memory is gone */
2424             IWineD3DSurface_PreLoad(iface);
2425         }
2426     }
2427     return WINED3D_OK;
2428 }
2429
2430 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2431     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2432     IWineD3DSwapChainImpl *swapchain = NULL;
2433     HRESULT hr;
2434     TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2435
2436     /* Flipping is only supported on RenderTargets */
2437     if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return WINEDDERR_NOTFLIPPABLE;
2438
2439     if(override) {
2440         /* DDraw sets this for the X11 surfaces, so don't confuse the user 
2441          * FIXME("(%p) Target override is not supported by now\n", This);
2442          * Additionally, it isn't really possible to support triple-buffering
2443          * properly on opengl at all
2444          */
2445     }
2446
2447     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **) &swapchain);
2448     if(!swapchain) {
2449         ERR("Flipped surface is not on a swapchain\n");
2450         return WINEDDERR_NOTFLIPPABLE;
2451     }
2452
2453     /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
2454      * and only d3d8 and d3d9 apps specify the presentation interval
2455      */
2456     if((Flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)) == 0) {
2457         /* Most common case first to avoid wasting time on all the other cases */
2458         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
2459     } else if(Flags & WINEDDFLIP_NOVSYNC) {
2460         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
2461     } else if(Flags & WINEDDFLIP_INTERVAL2) {
2462         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
2463     } else if(Flags & WINEDDFLIP_INTERVAL3) {
2464         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
2465     } else {
2466         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
2467     }
2468
2469     /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2470     hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *) swapchain, NULL, NULL, 0, NULL, 0);
2471     IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2472     return hr;
2473 }
2474
2475 /* Does a direct frame buffer -> texture copy. Stretching is done
2476  * with single pixel copy calls
2477  */
2478 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown, WINED3DTEXTUREFILTERTYPE Filter) {
2479     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2480     float xrel, yrel;
2481     UINT row;
2482     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2483
2484
2485     ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2486     ENTER_GL();
2487     IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2488
2489     /* TODO: Do we need GL_TEXTURE_2D enabled fpr copyteximage? */
2490     glEnable(This->glDescription.target);
2491     checkGLcall("glEnable(This->glDescription.target)");
2492
2493     /* Bind the target texture */
2494     glBindTexture(This->glDescription.target, This->glDescription.textureName);
2495     checkGLcall("glBindTexture");
2496     if(!swapchain) {
2497         glReadBuffer(myDevice->offscreenBuffer);
2498     } else {
2499         GLenum buffer = surface_get_gl_buffer(SrcSurface, (IWineD3DSwapChain *)swapchain);
2500         glReadBuffer(buffer);
2501     }
2502     checkGLcall("glReadBuffer");
2503
2504     xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1);
2505     yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1);
2506
2507     if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2508         FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2509
2510         if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
2511             ERR("Texture filtering not supported in direct blit\n");
2512         }
2513     } else if((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) && ((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2514         ERR("Texture filtering not supported in direct blit\n");
2515     }
2516
2517     if(upsidedown &&
2518        !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) &&
2519        !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2520         /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2521
2522         glCopyTexSubImage2D(This->glDescription.target,
2523                             This->glDescription.level,
2524                             drect->x1, drect->y1, /* xoffset, yoffset */
2525                             srect->x1, Src->currentDesc.Height - srect->y2,
2526                             drect->x2 - drect->x1, drect->y2 - drect->y1);
2527     } else {
2528         UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1;
2529         /* I have to process this row by row to swap the image,
2530          * otherwise it would be upside down, so stretching in y direction
2531          * doesn't cost extra time
2532          *
2533          * However, stretching in x direction can be avoided if not necessary
2534          */
2535         for(row = drect->y1; row < drect->y2; row++) {
2536             if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2537                 /* Well, that stuff works, but it's very slow.
2538                  * find a better way instead
2539                  */
2540                 UINT col;
2541
2542                 for(col = drect->x1; col < drect->x2; col++) {
2543                     glCopyTexSubImage2D(This->glDescription.target,
2544                                         This->glDescription.level,
2545                                         drect->x1 + col, row, /* xoffset, yoffset */
2546                                         srect->x1 + col * xrel, yoffset - (int) (row * yrel),
2547                                         1, 1);
2548                 }
2549             } else {
2550                 glCopyTexSubImage2D(This->glDescription.target,
2551                                     This->glDescription.level,
2552                                     drect->x1, row, /* xoffset, yoffset */
2553                                     srect->x1, yoffset - (int) (row * yrel),
2554                                     drect->x2-drect->x1, 1);
2555             }
2556         }
2557     }
2558     vcheckGLcall("glCopyTexSubImage2D");
2559
2560     /* Leave the opengl state valid for blitting */
2561     glDisable(This->glDescription.target);
2562     checkGLcall("glDisable(This->glDescription.target)");
2563
2564     LEAVE_GL();
2565 }
2566
2567 /* Uses the hardware to stretch and flip the image */
2568 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown, WINED3DTEXTUREFILTERTYPE Filter) {
2569     GLuint src, backup = 0;
2570     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2571     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2572     float left, right, top, bottom; /* Texture coordinates */
2573     UINT fbwidth = Src->currentDesc.Width;
2574     UINT fbheight = Src->currentDesc.Height;
2575     GLenum drawBuffer = GL_BACK;
2576     GLenum texture_target;
2577
2578     TRACE("Using hwstretch blit\n");
2579     /* Activate the Proper context for reading from the source surface, set it up for blitting */
2580     ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2581     ENTER_GL();
2582
2583     IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2584
2585     /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2586      * This way we don't have to wait for the 2nd readback to finish to leave this function.
2587      */
2588     if(GL_LIMITS(aux_buffers) >= 2) {
2589         /* Got more than one aux buffer? Use the 2nd aux buffer */
2590         drawBuffer = GL_AUX1;
2591     } else if((swapchain || myDevice->offscreenBuffer == GL_BACK) && GL_LIMITS(aux_buffers) >= 1) {
2592         /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2593         drawBuffer = GL_AUX0;
2594     }
2595
2596     if(!swapchain && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2597         glGenTextures(1, &backup);
2598         checkGLcall("glGenTextures\n");
2599         glBindTexture(GL_TEXTURE_2D, backup);
2600         checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2601         texture_target = GL_TEXTURE_2D;
2602     } else {
2603         /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2604          * we are reading from the back buffer, the backup can be used as source texture
2605          */
2606         if(Src->glDescription.textureName == 0) {
2607             /* Get it a description */
2608             IWineD3DSurface_PreLoad(SrcSurface);
2609         }
2610         texture_target = Src->glDescription.target;
2611         glBindTexture(texture_target, Src->glDescription.textureName);
2612         checkGLcall("glBindTexture(texture_target, Src->glDescription.textureName)");
2613         glEnable(texture_target);
2614         checkGLcall("glEnable(texture_target)");
2615
2616         /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2617         Src->Flags &= ~SFLAG_INTEXTURE;
2618     }
2619
2620     glReadBuffer(GL_BACK);
2621     checkGLcall("glReadBuffer(GL_BACK)");
2622
2623     /* TODO: Only back up the part that will be overwritten */
2624     glCopyTexSubImage2D(texture_target, 0,
2625                         0, 0 /* read offsets */,
2626                         0, 0,
2627                         fbwidth,
2628                         fbheight);
2629
2630     checkGLcall("glCopyTexSubImage2D");
2631
2632     /* No issue with overriding these - the sampler is dirty due to blit usage */
2633     glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
2634                     stateLookup[WINELOOKUP_MAGFILTER][Filter - minLookup[WINELOOKUP_MAGFILTER]]);
2635     checkGLcall("glTexParameteri");
2636     glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
2637                     minMipLookup[Filter][WINED3DTEXF_NONE]);
2638     checkGLcall("glTexParameteri");
2639
2640     if(!swapchain || (IWineD3DSurface *) Src == swapchain->backBuffer[0]) {
2641         src = backup ? backup : Src->glDescription.textureName;
2642     } else {
2643         glReadBuffer(GL_FRONT);
2644         checkGLcall("glReadBuffer(GL_FRONT)");
2645
2646         glGenTextures(1, &src);
2647         checkGLcall("glGenTextures(1, &src)");
2648         glBindTexture(GL_TEXTURE_2D, src);
2649         checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
2650
2651         /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
2652          * out for power of 2 sizes
2653          */
2654         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2655                     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2656         checkGLcall("glTexImage2D");
2657         glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2658                             0, 0 /* read offsets */,
2659                             0, 0,
2660                             fbwidth,
2661                             fbheight);
2662
2663         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2664         checkGLcall("glTexParameteri");
2665         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2666         checkGLcall("glTexParameteri");
2667
2668         glReadBuffer(GL_BACK);
2669         checkGLcall("glReadBuffer(GL_BACK)");
2670
2671         if(texture_target != GL_TEXTURE_2D) {
2672             glDisable(texture_target);
2673             glEnable(GL_TEXTURE_2D);
2674             texture_target = GL_TEXTURE_2D;
2675         }
2676     }
2677     checkGLcall("glEnd and previous");
2678
2679     left = (float) srect->x1 / (float) Src->pow2Width;
2680     right = (float) srect->x2 / (float) Src->pow2Width;
2681
2682     if(upsidedown) {
2683         top = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2684         bottom = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2685     } else {
2686         top = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2687         bottom = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2688     }
2689
2690     /* draw the source texture stretched and upside down. The correct surface is bound already */
2691     glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
2692     glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
2693
2694     glDrawBuffer(drawBuffer);
2695     glReadBuffer(drawBuffer);
2696
2697     glBegin(GL_QUADS);
2698         /* bottom left */
2699         glTexCoord2f(left, bottom);
2700         glVertex2i(0, fbheight);
2701
2702         /* top left */
2703         glTexCoord2f(left, top);
2704         glVertex2i(0, fbheight - drect->y2 - drect->y1);
2705
2706         /* top right */
2707         glTexCoord2f(right, top);
2708         glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1);
2709
2710         /* bottom right */
2711         glTexCoord2f(right, bottom);
2712         glVertex2i(drect->x2 - drect->x1, fbheight);
2713     glEnd();
2714     checkGLcall("glEnd and previous");
2715
2716     if(texture_target != This->glDescription.target) {
2717         glDisable(texture_target);
2718         glEnable(This->glDescription.target);
2719         texture_target = This->glDescription.target;
2720     }
2721
2722     /* Now read the stretched and upside down image into the destination texture */
2723     glBindTexture(texture_target, This->glDescription.textureName);
2724     checkGLcall("glBindTexture");
2725     glCopyTexSubImage2D(texture_target,
2726                         0,
2727                         drect->x1, drect->y1, /* xoffset, yoffset */
2728                         0, 0, /* We blitted the image to the origin */
2729                         drect->x2 - drect->x1, drect->y2 - drect->y1);
2730     checkGLcall("glCopyTexSubImage2D");
2731
2732     if(drawBuffer == GL_BACK) {
2733         /* Write the back buffer backup back */
2734         if(backup) {
2735             if(texture_target != GL_TEXTURE_2D) {
2736                 glDisable(texture_target);
2737                 glEnable(GL_TEXTURE_2D);
2738                 texture_target = GL_TEXTURE_2D;
2739             }
2740             glBindTexture(GL_TEXTURE_2D, backup);
2741             checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
2742         } else {
2743             if(texture_target != Src->glDescription.target) {
2744                 glDisable(texture_target);
2745                 glEnable(Src->glDescription.target);
2746                 texture_target = Src->glDescription.target;
2747             }
2748             glBindTexture(Src->glDescription.target, Src->glDescription.textureName);
2749             checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2750         }
2751
2752         glBegin(GL_QUADS);
2753             /* top left */
2754             glTexCoord2f(0.0, (float) fbheight / (float) Src->pow2Height);
2755             glVertex2i(0, 0);
2756
2757             /* bottom left */
2758             glTexCoord2f(0.0, 0.0);
2759             glVertex2i(0, fbheight);
2760
2761             /* bottom right */
2762             glTexCoord2f((float) fbwidth / (float) Src->pow2Width, 0.0);
2763             glVertex2i(fbwidth, Src->currentDesc.Height);
2764
2765             /* top right */
2766             glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
2767             glVertex2i(fbwidth, 0);
2768         glEnd();
2769     } else {
2770         /* Restore the old draw buffer */
2771         glDrawBuffer(GL_BACK);
2772     }
2773     glDisable(texture_target);
2774     checkGLcall("glDisable(texture_target)");
2775
2776     /* Cleanup */
2777     if(src != Src->glDescription.textureName && src != backup) {
2778         glDeleteTextures(1, &src);
2779         checkGLcall("glDeleteTextures(1, &src)");
2780     }
2781     if(backup) {
2782         glDeleteTextures(1, &backup);
2783         checkGLcall("glDeleteTextures(1, &backup)");
2784     }
2785
2786     LEAVE_GL();
2787 }
2788
2789 /* Not called from the VTable */
2790 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
2791     WINED3DRECT rect;
2792     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2793     IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
2794     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2795
2796     TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2797
2798     /* Get the swapchain. One of the surfaces has to be a primary surface */
2799     if(This->resource.pool == WINED3DPOOL_SYSTEMMEM) {
2800         WARN("Destination is in sysmem, rejecting gl blt\n");
2801         return WINED3DERR_INVALIDCALL;
2802     }
2803     IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
2804     if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
2805     if(Src) {
2806         if(Src->resource.pool == WINED3DPOOL_SYSTEMMEM) {
2807             WARN("Src is in sysmem, rejecting gl blt\n");
2808             return WINED3DERR_INVALIDCALL;
2809         }
2810         IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
2811         if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
2812     }
2813
2814     /* Early sort out of cases where no render target is used */
2815     if(!dstSwapchain && !srcSwapchain &&
2816         SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2817         TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
2818         return WINED3DERR_INVALIDCALL;
2819     }
2820
2821     /* No destination color keying supported */
2822     if(Flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) {
2823         /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2824         TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2825         return WINED3DERR_INVALIDCALL;
2826     }
2827
2828     if (DestRect) {
2829         rect.x1 = DestRect->left;
2830         rect.y1 = DestRect->top;
2831         rect.x2 = DestRect->right;
2832         rect.y2 = DestRect->bottom;
2833     } else {
2834         rect.x1 = 0;
2835         rect.y1 = 0;
2836         rect.x2 = This->currentDesc.Width;
2837         rect.y2 = This->currentDesc.Height;
2838     }
2839
2840     /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
2841     if(dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->backBuffer &&
2842        ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) && SrcSurface == dstSwapchain->backBuffer[0]) {
2843         /* Half-life does a Blt from the back buffer to the front buffer,
2844          * Full surface size, no flags... Use present instead
2845          *
2846          * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
2847          */
2848
2849         /* Check rects - IWineD3DDevice_Present doesn't handle them */
2850         while(1)
2851         {
2852             RECT mySrcRect;
2853             TRACE("Looking if a Present can be done...\n");
2854             /* Source Rectangle must be full surface */
2855             if( SrcRect ) {
2856                 if(SrcRect->left != 0 || SrcRect->top != 0 ||
2857                    SrcRect->right != Src->currentDesc.Width || SrcRect->bottom != Src->currentDesc.Height) {
2858                     TRACE("No, Source rectangle doesn't match\n");
2859                     break;
2860                 }
2861             }
2862             mySrcRect.left = 0;
2863             mySrcRect.top = 0;
2864             mySrcRect.right = Src->currentDesc.Width;
2865             mySrcRect.bottom = Src->currentDesc.Height;
2866
2867             /* No stretching may occur */
2868             if(mySrcRect.right != rect.x2 - rect.x1 ||
2869                mySrcRect.bottom != rect.y2 - rect.y1) {
2870                 TRACE("No, stretching is done\n");
2871                 break;
2872             }
2873
2874             /* Destination must be full surface or match the clipping rectangle */
2875             if(This->clipper && ((IWineD3DClipperImpl *) This->clipper)->hWnd)
2876             {
2877                 RECT cliprect;
2878                 POINT pos[2];
2879                 GetClientRect(((IWineD3DClipperImpl *) This->clipper)->hWnd, &cliprect);
2880                 pos[0].x = rect.x1;
2881                 pos[0].y = rect.y1;
2882                 pos[1].x = rect.x2;
2883                 pos[1].y = rect.y2;
2884                 MapWindowPoints(GetDesktopWindow(), ((IWineD3DClipperImpl *) This->clipper)->hWnd,
2885                                 pos, 2);
2886
2887                 if(pos[0].x != cliprect.left  || pos[0].y != cliprect.top   ||
2888                    pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
2889                 {
2890                     TRACE("No, dest rectangle doesn't match(clipper)\n");
2891                     TRACE("Clip rect at (%d,%d)-(%d,%d)\n", cliprect.left, cliprect.top, cliprect.right, cliprect.bottom);
2892                     TRACE("Blt dest: (%d,%d)-(%d,%d)\n", rect.x1, rect.y1, rect.x2, rect.y2);
2893                     break;
2894                 }
2895             }
2896             else
2897             {
2898                 if(rect.x1 != 0 || rect.y1 != 0 ||
2899                    rect.x2 != This->currentDesc.Width || rect.y2 != This->currentDesc.Height) {
2900                     TRACE("No, dest rectangle doesn't match(surface size)\n");
2901                     break;
2902                 }
2903             }
2904
2905             TRACE("Yes\n");
2906
2907             /* These flags are unimportant for the flag check, remove them */
2908             if((Flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)) == 0) {
2909                 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
2910
2911                 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2912                     * take very long, while a flip is fast.
2913                     * This applies to Half-Life, which does such Blts every time it finished
2914                     * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2915                     * menu. This is also used by all apps when they do windowed rendering
2916                     *
2917                     * The problem is that flipping is not really the same as copying. After a
2918                     * Blt the front buffer is a copy of the back buffer, and the back buffer is
2919                     * untouched. Therefore it's necessary to override the swap effect
2920                     * and to set it back after the flip.
2921                     *
2922                     * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
2923                     * testcases.
2924                     */
2925
2926                 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2927                 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
2928
2929                 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2930                 IWineD3DSwapChain_Present((IWineD3DSwapChain *) dstSwapchain, NULL, NULL, 0, NULL, 0);
2931
2932                 dstSwapchain->presentParms.SwapEffect = orig_swap;
2933
2934                 return WINED3D_OK;
2935             }
2936             break;
2937         }
2938
2939         TRACE("Unsupported blit between buffers on the same swapchain\n");
2940         return WINED3DERR_INVALIDCALL;
2941     } else if(dstSwapchain && dstSwapchain == srcSwapchain) {
2942         FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
2943         return WINED3DERR_INVALIDCALL;
2944     } else if(dstSwapchain && srcSwapchain) {
2945         FIXME("Implement hardware blit between two different swapchains\n");
2946         return WINED3DERR_INVALIDCALL;
2947     } else if(dstSwapchain) {
2948         if(SrcSurface == myDevice->render_targets[0]) {
2949             TRACE("Blit from active render target to a swapchain\n");
2950             /* Handled with regular texture -> swapchain blit */
2951         }
2952     } else if(srcSwapchain && This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2953         FIXME("Implement blit from a swapchain to the active render target\n");
2954         return WINED3DERR_INVALIDCALL;
2955     }
2956
2957     if((srcSwapchain || SrcSurface == myDevice->render_targets[0]) && !dstSwapchain) {
2958         /* Blit from render target to texture */
2959         WINED3DRECT srect;
2960         BOOL upsideDown, stretchx;
2961
2962         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
2963             TRACE("Color keying not supported by frame buffer to texture blit\n");
2964             return WINED3DERR_INVALIDCALL;
2965             /* Destination color key is checked above */
2966         }
2967
2968         /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2969          * glCopyTexSubImage is a bit picky about the parameters we pass to it
2970          */
2971         if(SrcRect) {
2972             if(SrcRect->top < SrcRect->bottom) {
2973                 srect.y1 = SrcRect->top;
2974                 srect.y2 = SrcRect->bottom;
2975                 upsideDown = FALSE;
2976             } else {
2977                 srect.y1 = SrcRect->bottom;
2978                 srect.y2 = SrcRect->top;
2979                 upsideDown = TRUE;
2980             }
2981             srect.x1 = SrcRect->left;
2982             srect.x2 = SrcRect->right;
2983         } else {
2984             srect.x1 = 0;
2985             srect.y1 = 0;
2986             srect.x2 = Src->currentDesc.Width;
2987             srect.y2 = Src->currentDesc.Height;
2988             upsideDown = FALSE;
2989         }
2990         if(rect.x1 > rect.x2) {
2991             UINT tmp = rect.x2;
2992             rect.x2 = rect.x1;
2993             rect.x1 = tmp;
2994             upsideDown = !upsideDown;
2995         }
2996         if(!srcSwapchain) {
2997             TRACE("Reading from an offscreen target\n");
2998             upsideDown = !upsideDown;
2999         }
3000
3001         if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
3002             stretchx = TRUE;
3003         } else {
3004             stretchx = FALSE;
3005         }
3006
3007         /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3008          * flip the image nor scale it.
3009          *
3010          * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3011          * -> If the app wants a image width an unscaled width, copy it line per line
3012          * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
3013          *    than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3014          *    back buffer. This is slower than reading line per line, thus not used for flipping
3015          * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3016          *    pixel by pixel
3017          *
3018          * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
3019          * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
3020          * backends.
3021          */
3022         if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && GL_SUPPORT(EXT_FRAMEBUFFER_BLIT)) {
3023             stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &srect,
3024                     (IWineD3DSurface *)This, &rect, Filter, upsideDown);
3025         } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
3026                                     rect.y2 - rect.y1 > Src->currentDesc.Height) {
3027             TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
3028             fb_copy_to_texture_direct(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown, Filter);
3029         } else {
3030             TRACE("Using hardware stretching to flip / stretch the texture\n");
3031             fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown, Filter);
3032         }
3033
3034         if(!(This->Flags & SFLAG_DONOTFREE)) {
3035             HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
3036             This->resource.allocatedMemory = NULL;
3037             This->resource.heapMemory = NULL;
3038         } else {
3039             This->Flags &= ~SFLAG_INSYSMEM;
3040         }
3041         /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3042          * path is never entered
3043          */
3044         IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INTEXTURE, TRUE);
3045
3046         return WINED3D_OK;
3047     } else if(Src) {
3048         /* Blit from offscreen surface to render target */
3049         float glTexCoord[4];
3050         DWORD oldCKeyFlags = Src->CKeyFlags;
3051         WINEDDCOLORKEY oldBltCKey = This->SrcBltCKey;
3052         RECT SourceRectangle;
3053
3054         TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
3055
3056         if(SrcRect) {
3057             SourceRectangle.left = SrcRect->left;
3058             SourceRectangle.right = SrcRect->right;
3059             SourceRectangle.top = SrcRect->top;
3060             SourceRectangle.bottom = SrcRect->bottom;
3061         } else {
3062             SourceRectangle.left = 0;
3063             SourceRectangle.right = Src->currentDesc.Width;
3064             SourceRectangle.top = 0;
3065             SourceRectangle.bottom = Src->currentDesc.Height;
3066         }
3067         if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) &&
3068             (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) == 0) {
3069             TRACE("Using stretch_rect_fbo\n");
3070             /* The source is always a texture, but never the currently active render target, and the texture
3071              * contents are never upside down
3072              */
3073             stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, (WINED3DRECT *) &SourceRectangle,
3074                               (IWineD3DSurface *)This, &rect, Filter, FALSE);
3075             return WINED3D_OK;
3076         }
3077
3078         if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
3079             /* Fall back to software */
3080             WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
3081                     SourceRectangle.left, SourceRectangle.top,
3082                     SourceRectangle.right, SourceRectangle.bottom);
3083             return WINED3DERR_INVALIDCALL;
3084         }
3085
3086         /* Color keying: Check if we have to do a color keyed blt,
3087          * and if not check if a color key is activated.
3088          *
3089          * Just modify the color keying parameters in the surface and restore them afterwards
3090          * The surface keeps track of the color key last used to load the opengl surface.
3091          * PreLoad will catch the change to the flags and color key and reload if necessary.
3092          */
3093         if(Flags & WINEDDBLT_KEYSRC) {
3094             /* Use color key from surface */
3095         } else if(Flags & WINEDDBLT_KEYSRCOVERRIDE) {
3096             /* Use color key from DDBltFx */
3097             Src->CKeyFlags |= WINEDDSD_CKSRCBLT;
3098             This->SrcBltCKey = DDBltFx->ddckSrcColorkey;
3099         } else {
3100             /* Do not use color key */
3101             Src->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3102         }
3103
3104         /* Now load the surface */
3105         IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
3106
3107
3108         /* Activate the destination context, set it up for blitting */
3109         ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
3110         ENTER_GL();
3111
3112         glEnable(Src->glDescription.target);
3113         checkGLcall("glEnable(Src->glDescription.target)");
3114
3115         if(!dstSwapchain) {
3116             TRACE("Drawing to offscreen buffer\n");
3117             glDrawBuffer(myDevice->offscreenBuffer);
3118             checkGLcall("glDrawBuffer");
3119         } else {
3120             GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This, (IWineD3DSwapChain *)dstSwapchain);
3121             TRACE("Drawing to %#x buffer\n", buffer);
3122             glDrawBuffer(buffer);
3123             checkGLcall("glDrawBuffer");
3124         }
3125
3126         /* Bind the texture */
3127         glBindTexture(Src->glDescription.target, Src->glDescription.textureName);
3128         checkGLcall("glBindTexture");
3129
3130         /* Filtering for StretchRect */
3131         glTexParameteri(Src->glDescription.target, GL_TEXTURE_MAG_FILTER,
3132                         stateLookup[WINELOOKUP_MAGFILTER][Filter - minLookup[WINELOOKUP_MAGFILTER]]);
3133         checkGLcall("glTexParameteri");
3134         glTexParameteri(Src->glDescription.target, GL_TEXTURE_MIN_FILTER,
3135                         minMipLookup[Filter][WINED3DTEXF_NONE]);
3136         checkGLcall("glTexParameteri");
3137         glTexParameteri(Src->glDescription.target, GL_TEXTURE_WRAP_S, GL_CLAMP);
3138         glTexParameteri(Src->glDescription.target, GL_TEXTURE_WRAP_T, GL_CLAMP);
3139         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3140         checkGLcall("glTexEnvi");
3141
3142         /* This is for color keying */
3143         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3144             glEnable(GL_ALPHA_TEST);
3145             checkGLcall("glEnable GL_ALPHA_TEST");
3146             glAlphaFunc(GL_NOTEQUAL, 0.0);
3147             checkGLcall("glAlphaFunc\n");
3148         } else {
3149             glDisable(GL_ALPHA_TEST);
3150             checkGLcall("glDisable GL_ALPHA_TEST");
3151         }
3152
3153         /* Draw a textured quad
3154          */
3155         glBegin(GL_QUADS);
3156
3157         glColor3d(1.0f, 1.0f, 1.0f);
3158         glTexCoord2f(glTexCoord[0], glTexCoord[2]);
3159         glVertex3f(rect.x1,
3160                     rect.y1,
3161                     0.0);
3162
3163         glTexCoord2f(glTexCoord[0], glTexCoord[3]);
3164         glVertex3f(rect.x1, rect.y2, 0.0);
3165
3166         glTexCoord2f(glTexCoord[1], glTexCoord[3]);
3167         glVertex3f(rect.x2,
3168                     rect.y2,
3169                     0.0);
3170
3171         glTexCoord2f(glTexCoord[1], glTexCoord[2]);
3172         glVertex3f(rect.x2,
3173                     rect.y1,
3174                     0.0);
3175         glEnd();
3176         checkGLcall("glEnd");
3177
3178         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3179             glDisable(GL_ALPHA_TEST);
3180             checkGLcall("glDisable(GL_ALPHA_TEST)");
3181         }
3182
3183         /* Flush in case the drawable is used by multiple GL contexts */
3184         if(dstSwapchain && (dstSwapchain->num_contexts >= 2))
3185             glFlush();
3186
3187         glBindTexture(Src->glDescription.target, 0);
3188         checkGLcall("glBindTexture(Src->glDescription.target, 0)");
3189         /* Leave the opengl state valid for blitting */
3190         glDisable(Src->glDescription.target);
3191         checkGLcall("glDisable(Src->glDescription.target)");
3192
3193         /* The draw buffer should only need to be restored if we were drawing to the front buffer, and there is a back buffer.
3194          * otherwise the context manager should choose between GL_BACK / offscreenDrawBuffer
3195          */
3196         if(dstSwapchain && This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer && dstSwapchain->backBuffer) {
3197             glDrawBuffer(GL_BACK);
3198             checkGLcall("glDrawBuffer");
3199         }
3200         /* Restore the color key parameters */
3201         Src->CKeyFlags = oldCKeyFlags;
3202         This->SrcBltCKey = oldBltCKey;
3203
3204         LEAVE_GL();
3205
3206         /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
3207         /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
3208          * is outdated now
3209          */
3210         IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INDRAWABLE, TRUE);
3211         /* TODO: This should be moved to ModifyLocation() */
3212         if(!(dstSwapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO)) {
3213             This->Flags |= SFLAG_INTEXTURE;
3214         }
3215
3216         return WINED3D_OK;
3217     } else {
3218         /* Source-Less Blit to render target */
3219         if (Flags & WINEDDBLT_COLORFILL) {
3220             /* This is easy to handle for the D3D Device... */
3221             DWORD color;
3222
3223             TRACE("Colorfill\n");
3224
3225             /* This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0] || dstSwapchain
3226                 must be true if we are here */
3227             if (This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0] &&
3228                     !(This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer ||
3229                       (dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]))) {
3230                 TRACE("Surface is higher back buffer, falling back to software\n");
3231                 return WINED3DERR_INVALIDCALL;
3232             }
3233
3234             /* The color as given in the Blt function is in the format of the frame-buffer...
3235              * 'clear' expect it in ARGB format => we need to do some conversion :-)
3236              */
3237             if (This->resource.format == WINED3DFMT_P8) {
3238                 if (This->palette) {
3239                     color = ((0xFF000000) |
3240                             (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
3241                             (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
3242                             (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
3243                 } else {
3244                     color = 0xFF000000;
3245                 }
3246             }
3247             else if (This->resource.format == WINED3DFMT_R5G6B5) {
3248                 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
3249                     color = 0xFFFFFFFF;
3250                 } else {
3251                     color = ((0xFF000000) |
3252                             ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
3253                             ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
3254                             ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
3255                 }
3256             }
3257             else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
3258                     (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
3259                 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
3260             }
3261             else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
3262                 color = DDBltFx->u5.dwFillColor;
3263             }
3264             else {
3265                 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
3266                 return WINED3DERR_INVALIDCALL;
3267             }
3268
3269             TRACE("(%p) executing Render Target override, color = %x\n", This, color);
3270             IWineD3DDeviceImpl_ClearSurface(myDevice, This,
3271                                             1, /* Number of rectangles */
3272                                             &rect, WINED3DCLEAR_TARGET, color,
3273                                             0.0 /* Z */,
3274                                             0 /* Stencil */);
3275             return WINED3D_OK;
3276         }
3277     }
3278
3279     /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
3280     TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
3281     return WINED3DERR_INVALIDCALL;
3282 }
3283
3284 static HRESULT WINAPI IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx)
3285 {
3286     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
3287     float depth;
3288
3289     if (Flags & WINEDDBLT_DEPTHFILL) {
3290         switch(This->resource.format) {
3291             case WINED3DFMT_D16:
3292                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000ffff;
3293                 break;
3294             case WINED3DFMT_D15S1:
3295                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000fffe;
3296                 break;
3297             case WINED3DFMT_D24S8:
3298             case WINED3DFMT_D24X8:
3299                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x00ffffff;
3300                 break;
3301             case WINED3DFMT_D32:
3302                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0xffffffff;
3303                 break;
3304             default:
3305                 depth = 0.0;
3306                 ERR("Unexpected format for depth fill: %s\n", debug_d3dformat(This->resource.format));
3307         }
3308
3309         return IWineD3DDevice_Clear((IWineD3DDevice *) myDevice,
3310                                     DestRect == NULL ? 0 : 1,
3311                                     (WINED3DRECT *) DestRect,
3312                                     WINED3DCLEAR_ZBUFFER,
3313                                     0x00000000,
3314                                     depth,
3315                                     0x00000000);
3316     }
3317
3318     FIXME("(%p): Unsupp depthstencil blit\n", This);
3319     return WINED3DERR_INVALIDCALL;
3320 }
3321
3322 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
3323     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3324     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3325     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
3326     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
3327     TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
3328
3329     /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair,
3330      * except depth blits, which seem to work
3331      */
3332     if(iface == myDevice->stencilBufferTarget || (SrcSurface && SrcSurface == myDevice->stencilBufferTarget)) {
3333         if(myDevice->inScene && !(Flags & WINEDDBLT_DEPTHFILL)) {
3334             TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3335             return WINED3DERR_INVALIDCALL;
3336         } else if(IWineD3DSurfaceImpl_BltZ(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) {
3337             TRACE("Z Blit override handled the blit\n");
3338             return WINED3D_OK;
3339         }
3340     }
3341
3342     /* Special cases for RenderTargets */
3343     if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3344         ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
3345         if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter) == WINED3D_OK) return WINED3D_OK;
3346     }
3347
3348     /* For the rest call the X11 surface implementation.
3349      * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
3350      * other Blts are rather rare
3351      */
3352     return IWineD3DBaseSurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter);
3353 }
3354
3355 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
3356     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3357     IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
3358     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
3359     TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
3360
3361     if(myDevice->inScene &&
3362        (iface == myDevice->stencilBufferTarget ||
3363        (Source && Source == myDevice->stencilBufferTarget))) {
3364         TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3365         return WINED3DERR_INVALIDCALL;
3366     }
3367
3368     /* Special cases for RenderTargets */
3369     if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3370         ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
3371
3372         RECT SrcRect, DstRect;
3373         DWORD Flags=0;
3374
3375         if(rsrc) {
3376             SrcRect.left = rsrc->left;
3377             SrcRect.top= rsrc->top;
3378             SrcRect.bottom = rsrc->bottom;
3379             SrcRect.right = rsrc->right;
3380         } else {
3381             SrcRect.left = 0;
3382             SrcRect.top = 0;
3383             SrcRect.right = srcImpl->currentDesc.Width;
3384             SrcRect.bottom = srcImpl->currentDesc.Height;
3385         }
3386
3387         DstRect.left = dstx;
3388         DstRect.top=dsty;
3389         DstRect.right = dstx + SrcRect.right - SrcRect.left;
3390         DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
3391
3392         /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
3393         if(trans & WINEDDBLTFAST_SRCCOLORKEY)
3394             Flags |= WINEDDBLT_KEYSRC;
3395         if(trans & WINEDDBLTFAST_DESTCOLORKEY)
3396             Flags |= WINEDDBLT_KEYDEST;
3397         if(trans & WINEDDBLTFAST_WAIT)
3398             Flags |= WINEDDBLT_WAIT;
3399         if(trans & WINEDDBLTFAST_DONOTWAIT)
3400             Flags |= WINEDDBLT_DONOTWAIT;
3401
3402         if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL, WINED3DTEXF_POINT) == WINED3D_OK) return WINED3D_OK;
3403     }
3404
3405
3406     return IWineD3DBaseSurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
3407 }
3408
3409 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3410     /** Check against the maximum texture sizes supported by the video card **/
3411     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3412     unsigned int pow2Width, pow2Height;
3413     const GlPixelFormatDesc *glDesc;
3414
3415     getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc);
3416     /* Setup some glformat defaults */
3417     This->glDescription.glFormat         = glDesc->glFormat;
3418     This->glDescription.glFormatInternal = glDesc->glInternal;
3419     This->glDescription.glType           = glDesc->glType;
3420
3421     This->glDescription.textureName      = 0;
3422     This->glDescription.target           = GL_TEXTURE_2D;
3423
3424     /* Non-power2 support */
3425     if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
3426         pow2Width = This->currentDesc.Width;
3427         pow2Height = This->currentDesc.Height;
3428     } else {
3429         /* Find the nearest pow2 match */
3430         pow2Width = pow2Height = 1;
3431         while (pow2Width < This->currentDesc.Width) pow2Width <<= 1;
3432         while (pow2Height < This->currentDesc.Height) pow2Height <<= 1;
3433     }
3434     This->pow2Width  = pow2Width;
3435     This->pow2Height = pow2Height;
3436
3437     if (pow2Width > This->currentDesc.Width || pow2Height > This->currentDesc.Height) {
3438         WINED3DFORMAT Format = This->resource.format;
3439         /** TODO: add support for non power two compressed textures **/
3440         if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
3441             || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
3442             FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
3443                   This, This->currentDesc.Width, This->currentDesc.Height);
3444             return WINED3DERR_NOTAVAILABLE;
3445         }
3446     }
3447
3448     if(pow2Width != This->currentDesc.Width ||
3449        pow2Height != This->currentDesc.Height) {
3450         This->Flags |= SFLAG_NONPOW2;
3451     }
3452
3453     TRACE("%p\n", This);
3454     if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3455         /* one of three options
3456         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)
3457         2: Set the texture to the maximum size (bad idea)
3458         3:    WARN and return WINED3DERR_NOTAVAILABLE;
3459         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.
3460         */
3461         WARN("(%p) Creating an oversized surface\n", This);
3462         This->Flags |= SFLAG_OVERSIZE;
3463
3464         /* This will be initialized on the first blt */
3465         This->glRect.left = 0;
3466         This->glRect.top = 0;
3467         This->glRect.right = 0;
3468         This->glRect.bottom = 0;
3469     } else {
3470         /* Check this after the oversize check - do not make an oversized surface a texture_rectangle one */
3471         if(This->Flags & SFLAG_NONPOW2 && GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
3472             This->glDescription.target = GL_TEXTURE_RECTANGLE_ARB;
3473             This->pow2Width  = This->currentDesc.Width;
3474             This->pow2Height = This->currentDesc.Height;
3475             This->Flags &= ~SFLAG_NONPOW2;
3476         }
3477
3478         /* No oversize, gl rect is the full texture size */
3479         This->Flags &= ~SFLAG_OVERSIZE;
3480         This->glRect.left = 0;
3481         This->glRect.top = 0;
3482         This->glRect.right = This->pow2Width;
3483         This->glRect.bottom = This->pow2Height;
3484     }
3485
3486     if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3487         switch(wined3d_settings.offscreen_rendering_mode) {
3488             case ORM_FBO:        This->get_drawable_size = get_drawable_size_fbo;        break;
3489             case ORM_PBUFFER:    This->get_drawable_size = get_drawable_size_pbuffer;    break;
3490             case ORM_BACKBUFFER: This->get_drawable_size = get_drawable_size_backbuffer; break;
3491         }
3492     }
3493
3494     This->Flags |= SFLAG_INSYSMEM;
3495
3496     return WINED3D_OK;
3497 }
3498
3499 static void WINAPI IWineD3DSurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DWORD flag, BOOL persistent) {
3500     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3501     IWineD3DBaseTexture *texture;
3502
3503     TRACE("(%p)->(%s, %s)\n", iface,
3504           flag == SFLAG_INSYSMEM ? "SFLAG_INSYSMEM" : flag == SFLAG_INDRAWABLE ? "SFLAG_INDRAWABLE" : "SFLAG_INTEXTURE",
3505           persistent ? "TRUE" : "FALSE");
3506
3507     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
3508         IWineD3DSwapChain *swapchain = NULL;
3509
3510         if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
3511             TRACE("Surface %p is an onscreen surface\n", iface);
3512
3513             IWineD3DSwapChain_Release(swapchain);
3514         } else {
3515             /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
3516             if (flag & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)) flag |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
3517         }
3518     }
3519
3520     if(persistent) {
3521         if((This->Flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE)) {
3522             if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) {
3523                 TRACE("Passing to container\n");
3524                 IWineD3DBaseTexture_SetDirty(texture, TRUE);
3525                 IWineD3DBaseTexture_Release(texture);
3526             }
3527         }
3528         This->Flags &= ~SFLAG_LOCATIONS;
3529         This->Flags |= flag;
3530     } else {
3531         if((This->Flags & SFLAG_INTEXTURE) && (flag & SFLAG_INTEXTURE)) {
3532             if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) {
3533                 TRACE("Passing to container\n");
3534                 IWineD3DBaseTexture_SetDirty(texture, TRUE);
3535                 IWineD3DBaseTexture_Release(texture);
3536             }
3537         }
3538         This->Flags &= ~flag;
3539     }
3540 }
3541
3542 struct coords {
3543     GLfloat x, y, z;
3544 };
3545
3546 static inline void surface_blt_to_drawable(IWineD3DSurfaceImpl *This, const RECT *rect_in) {
3547     struct coords coords[4];
3548     RECT rect;
3549     IWineD3DSwapChain *swapchain = NULL;
3550     IWineD3DBaseTexture *texture = NULL;
3551     HRESULT hr;
3552     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
3553
3554     if(rect_in) {
3555         rect = *rect_in;
3556     } else {
3557         rect.left = 0;
3558         rect.top = 0;
3559         rect.right = This->currentDesc.Width;
3560         rect.bottom = This->currentDesc.Height;
3561     }
3562
3563     ActivateContext(device, device->render_targets[0], CTXUSAGE_BLIT);
3564     ENTER_GL();
3565
3566     if(This->glDescription.target == GL_TEXTURE_RECTANGLE_ARB) {
3567         glEnable(GL_TEXTURE_RECTANGLE_ARB);
3568         checkGLcall("glEnable(GL_TEXTURE_RECTANGLE_ARB)");
3569         glBindTexture(GL_TEXTURE_RECTANGLE_ARB, This->glDescription.textureName);
3570         checkGLcall("GL_TEXTURE_RECTANGLE_ARB, This->glDescription.textureName)");
3571         glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3572         checkGLcall("glTexParameteri");
3573         glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3574         checkGLcall("glTexParameteri");
3575
3576         coords[0].x = rect.left;
3577         coords[0].z = 0;
3578
3579         coords[1].x = rect.left;
3580         coords[1].z = 0;
3581
3582         coords[2].x = rect.right;
3583         coords[2].z = 0;
3584
3585         coords[3].x = rect.right;
3586         coords[3].z = 0;
3587
3588         coords[0].y = rect.top;
3589         coords[1].y = rect.bottom;
3590         coords[2].y = rect.bottom;
3591         coords[3].y = rect.top;
3592     } else if(This->glDescription.target == GL_TEXTURE_2D) {
3593         glEnable(GL_TEXTURE_2D);
3594         checkGLcall("glEnable(GL_TEXTURE_2D)");
3595         glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
3596         checkGLcall("GL_TEXTURE_2D, This->glDescription.textureName)");
3597         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3598         checkGLcall("glTexParameteri");
3599         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3600         checkGLcall("glTexParameteri");
3601
3602         coords[0].x = (float)rect.left   / This->pow2Width;
3603         coords[0].z = 0;
3604
3605         coords[1].x = (float)rect.left   / This->pow2Width;
3606         coords[1].z = 0;
3607
3608         coords[2].x = (float)rect.right  / This->pow2Width;
3609         coords[2].z = 0;
3610
3611         coords[3].x = (float)rect.right  / This->pow2Width;
3612         coords[3].z = 0;
3613
3614         coords[0].y = (float)rect.top    / This->pow2Height;
3615         coords[1].y = (float)rect.bottom / This->pow2Height;
3616         coords[2].y = (float)rect.bottom / This->pow2Height;
3617         coords[3].y = (float)rect.top    / This->pow2Height;
3618     } else {
3619         /* Must be a cube map */
3620         glEnable(GL_TEXTURE_CUBE_MAP_ARB);
3621         checkGLcall("glEnable(GL_TEXTURE_CUBE_MAP_ARB)");
3622         glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, This->glDescription.textureName);
3623         checkGLcall("GL_TEXTURE_CUBE_MAP_ARB, This->glDescription.textureName)");
3624         glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3625         checkGLcall("glTexParameteri");
3626         glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3627         checkGLcall("glTexParameteri");
3628
3629         switch(This->glDescription.target) {
3630             case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
3631                 coords[0].x =  1;   coords[0].y = -1;   coords[0].z =  1;
3632                 coords[1].x =  1;   coords[1].y =  1;   coords[1].z =  1;
3633                 coords[2].x =  1;   coords[2].y =  1;   coords[2].z = -1;
3634                 coords[3].x =  1;   coords[3].y = -1;   coords[3].z = -1;
3635                 break;
3636
3637             case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
3638                 coords[0].x = -1;   coords[0].y = -1;   coords[0].z =  1;
3639                 coords[1].x = -1;   coords[1].y =  1;   coords[1].z =  1;
3640                 coords[2].x = -1;   coords[2].y =  1;   coords[2].z = -1;
3641                 coords[3].x = -1;   coords[3].y = -1;   coords[3].z = -1;
3642                 break;
3643
3644             case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
3645                 coords[0].x = -1;   coords[0].y =  1;   coords[0].z =  1;
3646                 coords[1].x =  1;   coords[1].y =  1;   coords[1].z =  1;
3647                 coords[2].x =  1;   coords[2].y =  1;   coords[2].z = -1;
3648                 coords[3].x = -1;   coords[3].y =  1;   coords[3].z = -1;
3649                 break;
3650
3651             case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
3652                 coords[0].x = -1;   coords[0].y = -1;   coords[0].z =  1;
3653                 coords[1].x =  1;   coords[1].y = -1;   coords[1].z =  1;
3654                 coords[2].x =  1;   coords[2].y = -1;   coords[2].z = -1;
3655                 coords[3].x = -1;   coords[3].y = -1;   coords[3].z = -1;
3656                 break;
3657
3658             case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
3659                 coords[0].x = -1;   coords[0].y = -1;   coords[0].z =  1;
3660                 coords[1].x =  1;   coords[1].y = -1;   coords[1].z =  1;
3661                 coords[2].x =  1;   coords[2].y = -1;   coords[2].z =  1;
3662                 coords[3].x = -1;   coords[3].y = -1;   coords[3].z =  1;
3663                 break;
3664
3665             case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
3666                 coords[0].x = -1;   coords[0].y = -1;   coords[0].z = -1;
3667                 coords[1].x =  1;   coords[1].y = -1;   coords[1].z = -1;
3668                 coords[2].x =  1;   coords[2].y = -1;   coords[2].z = -1;
3669                 coords[3].x = -1;   coords[3].y = -1;   coords[3].z = -1;
3670
3671             default:
3672                 ERR("Unexpected texture target\n");
3673                 LEAVE_GL();
3674                 return;
3675         }
3676     }
3677
3678     glBegin(GL_QUADS);
3679     glTexCoord3fv(&coords[0].x);
3680     glVertex2i(rect.left, device->render_offscreen ? rect.bottom : rect.top);
3681
3682     glTexCoord3fv(&coords[1].x);
3683     glVertex2i(rect.left, device->render_offscreen ? rect.top : rect.bottom);
3684
3685     glTexCoord3fv(&coords[2].x);
3686     glVertex2i(rect.right, device->render_offscreen ? rect.top : rect.bottom);
3687
3688     glTexCoord3fv(&coords[3].x);
3689     glVertex2i(rect.right, device->render_offscreen ? rect.bottom : rect.top);
3690     glEnd();
3691     checkGLcall("glEnd");
3692
3693     if(This->glDescription.target != GL_TEXTURE_2D) {
3694         glDisable(GL_TEXTURE_CUBE_MAP_ARB);
3695         checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
3696     } else {
3697         glDisable(GL_TEXTURE_2D);
3698         checkGLcall("glDisable(GL_TEXTURE_2D)");
3699     }
3700
3701     hr = IWineD3DSurface_GetContainer((IWineD3DSurface*)This, &IID_IWineD3DSwapChain, (void **) &swapchain);
3702     if(hr == WINED3D_OK && swapchain) {
3703         /* Make sure to flush the buffers. This is needed in apps like Red Alert II and Tiberian SUN that use multiple WGL contexts. */
3704         if(((IWineD3DSwapChainImpl*)swapchain)->num_contexts >= 2)
3705             glFlush();
3706
3707         IWineD3DSwapChain_Release(swapchain);
3708     } else {
3709         /* We changed the filtering settings on the texture. Inform the container about this to get the filters
3710          * reset properly next draw
3711          */
3712         hr = IWineD3DSurface_GetContainer((IWineD3DSurface*)This, &IID_IWineD3DBaseTexture, (void **) &texture);
3713         if(hr == WINED3D_OK && texture) {
3714             ((IWineD3DBaseTextureImpl *) texture)->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
3715             ((IWineD3DBaseTextureImpl *) texture)->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
3716             ((IWineD3DBaseTextureImpl *) texture)->baseTexture.states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE;
3717             IWineD3DBaseTexture_Release(texture);
3718         }
3719     }
3720     LEAVE_GL();
3721 }
3722
3723 /*****************************************************************************
3724  * IWineD3DSurface::LoadLocation
3725  *
3726  * Copies the current surface data from wherever it is to the requested
3727  * location. The location is one of the surface flags, SFLAG_INSYSMEM,
3728  * SFLAG_INTEXTURE and SFLAG_INDRAWABLE. When the surface is current in
3729  * multiple locations, the gl texture is preferred over the drawable, which is
3730  * preferred over system memory. The PBO counts as system memory. If rect is
3731  * not NULL, only the specified rectangle is copied (only supported for
3732  * sysmem<->drawable copies at the moment). If rect is NULL, the destination
3733  * location is marked up to date after the copy.
3734  *
3735  * Parameters:
3736  *  flag: Surface location flag to be updated
3737  *  rect: rectangle to be copied
3738  *
3739  * Returns:
3740  *  WINED3D_OK on success
3741  *  WINED3DERR_DEVICELOST on an internal error
3742  *
3743  *****************************************************************************/
3744 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect) {
3745     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3746     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
3747     IWineD3DSwapChain *swapchain = NULL;
3748     GLenum format, internal, type;
3749     CONVERT_TYPES convert;
3750     int bpp;
3751     int width, pitch, outpitch;
3752     BYTE *mem;
3753
3754     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
3755         if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
3756             TRACE("Surface %p is an onscreen surface\n", iface);
3757
3758             IWineD3DSwapChain_Release(swapchain);
3759         } else {
3760             /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets.
3761              * Prefer SFLAG_INTEXTURE. */
3762             if (flag == SFLAG_INDRAWABLE) flag = SFLAG_INTEXTURE;
3763         }
3764     }
3765
3766     TRACE("(%p)->(%s, %p)\n", iface,
3767           flag == SFLAG_INSYSMEM ? "SFLAG_INSYSMEM" : flag == SFLAG_INDRAWABLE ? "SFLAG_INDRAWABLE" : "SFLAG_INTEXTURE",
3768           rect);
3769     if(rect) {
3770         TRACE("Rectangle: (%d,%d)-(%d,%d)\n", rect->left, rect->top, rect->right, rect->bottom);
3771     }
3772
3773     if(This->Flags & flag) {
3774         TRACE("Location already up to date\n");
3775         return WINED3D_OK;
3776     }
3777
3778     if(!(This->Flags & SFLAG_LOCATIONS)) {
3779         ERR("Surface does not have any up to date location\n");
3780         This->Flags |= SFLAG_LOST;
3781         return WINED3DERR_DEVICELOST;
3782     }
3783
3784     if(flag == SFLAG_INSYSMEM) {
3785         surface_prepare_system_memory(This);
3786
3787         /* Download the surface to system memory */
3788         if(This->Flags & SFLAG_INTEXTURE) {
3789             ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3790             surface_bind_and_dirtify(This);
3791
3792             surface_download_data(This);
3793         } else {
3794             read_from_framebuffer(This, rect,
3795                                   This->resource.allocatedMemory,
3796                                   IWineD3DSurface_GetPitch(iface));
3797         }
3798     } else if(flag == SFLAG_INDRAWABLE) {
3799         if(This->Flags & SFLAG_INTEXTURE) {
3800             surface_blt_to_drawable(This, rect);
3801         } else {
3802             d3dfmt_get_conv(This, TRUE /* We need color keying */, FALSE /* We won't use textures */, &format, &internal, &type, &convert, &bpp, This->srgb);
3803
3804             /* The width is in 'length' not in bytes */
3805             width = This->currentDesc.Width;
3806             pitch = IWineD3DSurface_GetPitch(iface);
3807
3808             if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
3809                 int height = This->currentDesc.Height;
3810
3811                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
3812                 outpitch = width * bpp;
3813                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
3814
3815                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
3816                 if(!mem) {
3817                     ERR("Out of memory %d, %d!\n", outpitch, height);
3818                     return WINED3DERR_OUTOFVIDEOMEMORY;
3819                 }
3820                 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
3821
3822                 This->Flags |= SFLAG_CONVERTED;
3823             } else {
3824                 This->Flags &= ~SFLAG_CONVERTED;
3825                 mem = This->resource.allocatedMemory;
3826             }
3827
3828             flush_to_framebuffer_drawpixels(This, format, type, bpp, mem);
3829
3830             /* Don't delete PBO memory */
3831             if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
3832                 HeapFree(GetProcessHeap(), 0, mem);
3833         }
3834     } else /* if(flag == SFLAG_INTEXTURE) */ {
3835         d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp, This->srgb);
3836
3837         ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3838         surface_bind_and_dirtify(This);
3839
3840         if (This->Flags & SFLAG_INDRAWABLE) {
3841             GLint prevRead;
3842
3843             ENTER_GL();
3844             glGetIntegerv(GL_READ_BUFFER, &prevRead);
3845             vcheckGLcall("glGetIntegerv");
3846             glReadBuffer(This->resource.wineD3DDevice->offscreenBuffer);
3847             vcheckGLcall("glReadBuffer");
3848
3849             if(!(This->Flags & SFLAG_ALLOCATED)) {
3850                 surface_allocate_surface(This, internal, This->pow2Width,
3851                                             This->pow2Height, format, type);
3852             }
3853
3854             clear_unused_channels(This);
3855
3856             glCopyTexSubImage2D(This->glDescription.target,
3857                                 This->glDescription.level,
3858                                 0, 0, 0, 0,
3859                                 This->currentDesc.Width,
3860                                 This->currentDesc.Height);
3861             checkGLcall("glCopyTexSubImage2D");
3862
3863             glReadBuffer(prevRead);
3864             vcheckGLcall("glReadBuffer");
3865
3866             LEAVE_GL();
3867
3868             TRACE("Updated target %d\n", This->glDescription.target);
3869         } else {
3870             /* The only place where LoadTexture() might get called when isInDraw=1
3871              * is ActivateContext where lastActiveRenderTarget is preloaded.
3872              */
3873             if(iface == device->lastActiveRenderTarget && device->isInDraw)
3874                 ERR("Reading back render target but SFLAG_INDRAWABLE not set\n");
3875
3876             /* Otherwise: System memory copy must be most up to date */
3877
3878             if(This->CKeyFlags & WINEDDSD_CKSRCBLT) {
3879                 This->Flags |= SFLAG_GLCKEY;
3880                 This->glCKey = This->SrcBltCKey;
3881             }
3882             else This->Flags &= ~SFLAG_GLCKEY;
3883
3884             /* The width is in 'length' not in bytes */
3885             width = This->currentDesc.Width;
3886             pitch = IWineD3DSurface_GetPitch(iface);
3887
3888             if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
3889                 int height = This->currentDesc.Height;
3890
3891                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
3892                 outpitch = width * bpp;
3893                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
3894
3895                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
3896                 if(!mem) {
3897                     ERR("Out of memory %d, %d!\n", outpitch, height);
3898                     return WINED3DERR_OUTOFVIDEOMEMORY;
3899                 }
3900                 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
3901
3902                 This->Flags |= SFLAG_CONVERTED;
3903             } else if( (This->resource.format == WINED3DFMT_P8) && (GL_SUPPORT(EXT_PALETTED_TEXTURE) || GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) ) {
3904                 d3dfmt_p8_upload_palette(iface, convert);
3905                 This->Flags &= ~SFLAG_CONVERTED;
3906                 mem = This->resource.allocatedMemory;
3907             } else {
3908                 This->Flags &= ~SFLAG_CONVERTED;
3909                 mem = This->resource.allocatedMemory;
3910             }
3911
3912             /* Make sure the correct pitch is used */
3913             glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
3914
3915             if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
3916                 TRACE("non power of two support\n");
3917                 if(!(This->Flags & SFLAG_ALLOCATED)) {
3918                     surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
3919                 }
3920                 if (mem || (This->Flags & SFLAG_PBO)) {
3921                     surface_upload_data(This, internal, This->currentDesc.Width, This->currentDesc.Height, format, type, mem);
3922                 }
3923             } else {
3924                 /* When making the realloc conditional, keep in mind that GL_APPLE_client_storage may be in use, and This->resource.allocatedMemory
3925                  * changed. So also keep track of memory changes. In this case the texture has to be reallocated
3926                  */
3927                 if(!(This->Flags & SFLAG_ALLOCATED)) {
3928                     surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
3929                 }
3930                 if (mem || (This->Flags & SFLAG_PBO)) {
3931                     surface_upload_data(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
3932                 }
3933             }
3934
3935             /* Restore the default pitch */
3936             glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
3937
3938             /* Don't delete PBO memory */
3939             if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
3940                 HeapFree(GetProcessHeap(), 0, mem);
3941         }
3942     }
3943
3944     if(rect == NULL) {
3945         This->Flags |= flag;
3946     }
3947
3948     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && !swapchain
3949             && (This->Flags & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE))) {
3950         /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
3951         This->Flags |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
3952     }
3953
3954     return WINED3D_OK;
3955 }
3956
3957 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
3958     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3959     IWineD3DSwapChain *swapchain = NULL;
3960
3961     /* Update the drawable size method */
3962     if(container) {
3963         IWineD3DBase_QueryInterface(container, &IID_IWineD3DSwapChain, (void **) &swapchain);
3964     }
3965     if(swapchain) {
3966         This->get_drawable_size = get_drawable_size_swapchain;
3967         IWineD3DSwapChain_Release(swapchain);
3968     } else if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3969         switch(wined3d_settings.offscreen_rendering_mode) {
3970             case ORM_FBO:        This->get_drawable_size = get_drawable_size_fbo;        break;
3971             case ORM_PBUFFER:    This->get_drawable_size = get_drawable_size_pbuffer;    break;
3972             case ORM_BACKBUFFER: This->get_drawable_size = get_drawable_size_backbuffer; break;
3973         }
3974     }
3975
3976     return IWineD3DBaseSurfaceImpl_SetContainer(iface, container);
3977 }
3978
3979 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3980 {
3981     /* IUnknown */
3982     IWineD3DBaseSurfaceImpl_QueryInterface,
3983     IWineD3DBaseSurfaceImpl_AddRef,
3984     IWineD3DSurfaceImpl_Release,
3985     /* IWineD3DResource */
3986     IWineD3DBaseSurfaceImpl_GetParent,
3987     IWineD3DBaseSurfaceImpl_GetDevice,
3988     IWineD3DBaseSurfaceImpl_SetPrivateData,
3989     IWineD3DBaseSurfaceImpl_GetPrivateData,
3990     IWineD3DBaseSurfaceImpl_FreePrivateData,
3991     IWineD3DBaseSurfaceImpl_SetPriority,
3992     IWineD3DBaseSurfaceImpl_GetPriority,
3993     IWineD3DSurfaceImpl_PreLoad,
3994     IWineD3DSurfaceImpl_UnLoad,
3995     IWineD3DBaseSurfaceImpl_GetType,
3996     /* IWineD3DSurface */
3997     IWineD3DBaseSurfaceImpl_GetContainer,
3998     IWineD3DBaseSurfaceImpl_GetDesc,
3999     IWineD3DSurfaceImpl_LockRect,
4000     IWineD3DSurfaceImpl_UnlockRect,
4001     IWineD3DSurfaceImpl_GetDC,
4002     IWineD3DSurfaceImpl_ReleaseDC,
4003     IWineD3DSurfaceImpl_Flip,
4004     IWineD3DSurfaceImpl_Blt,
4005     IWineD3DBaseSurfaceImpl_GetBltStatus,
4006     IWineD3DBaseSurfaceImpl_GetFlipStatus,
4007     IWineD3DBaseSurfaceImpl_IsLost,
4008     IWineD3DBaseSurfaceImpl_Restore,
4009     IWineD3DSurfaceImpl_BltFast,
4010     IWineD3DBaseSurfaceImpl_GetPalette,
4011     IWineD3DBaseSurfaceImpl_SetPalette,
4012     IWineD3DBaseSurfaceImpl_RealizePalette,
4013     IWineD3DBaseSurfaceImpl_SetColorKey,
4014     IWineD3DBaseSurfaceImpl_GetPitch,
4015     IWineD3DSurfaceImpl_SetMem,
4016     IWineD3DBaseSurfaceImpl_SetOverlayPosition,
4017     IWineD3DBaseSurfaceImpl_GetOverlayPosition,
4018     IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
4019     IWineD3DBaseSurfaceImpl_UpdateOverlay,
4020     IWineD3DBaseSurfaceImpl_SetClipper,
4021     IWineD3DBaseSurfaceImpl_GetClipper,
4022     /* Internal use: */
4023     IWineD3DSurfaceImpl_AddDirtyRect,
4024     IWineD3DSurfaceImpl_LoadTexture,
4025     IWineD3DSurfaceImpl_BindTexture,
4026     IWineD3DSurfaceImpl_SaveSnapshot,
4027     IWineD3DSurfaceImpl_SetContainer,
4028     IWineD3DSurfaceImpl_SetGlTextureDesc,
4029     IWineD3DSurfaceImpl_GetGlDesc,
4030     IWineD3DSurfaceImpl_GetData,
4031     IWineD3DSurfaceImpl_SetFormat,
4032     IWineD3DSurfaceImpl_PrivateSetup,
4033     IWineD3DSurfaceImpl_ModifyLocation,
4034     IWineD3DSurfaceImpl_LoadLocation
4035 };