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