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