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