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