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