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