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