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