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