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