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